diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-01-24 22:56:13 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-01-24 22:56:13 +0000 |
commit | c42db0bbd750fae19a91f0a0354240ea6c3bafce (patch) | |
tree | beb7030248280fd8c67eb2b2c9cc4b19c6074c17 /crates/ra_hir/src/ids.rs | |
parent | b308375b82a33687f93468d75c7cc628b83a1351 (diff) | |
parent | 31d3a56b1865c33ef54e5d76e606965c87676695 (diff) |
Merge #623
623: WIP: module id is not def id r=matklad a=matklad
This achieves two things:
* makes module_tree & item_map per crate, not per source_root
* begins the refactoring to remove universal `DefId` in favor of having separate ids for each kind of `Def`. Currently, only modules get a differnt ID though.
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/ids.rs')
-rw-r--r-- | crates/ra_hir/src/ids.rs | 266 |
1 files changed, 164 insertions, 102 deletions
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs index 43f0e81f9..b125a1518 100644 --- a/crates/ra_hir/src/ids.rs +++ b/crates/ra_hir/src/ids.rs | |||
@@ -1,22 +1,41 @@ | |||
1 | use ra_db::{SourceRootId, LocationIntener, FileId}; | 1 | use std::{ |
2 | marker::PhantomData, | ||
3 | hash::{Hash, Hasher}, | ||
4 | }; | ||
5 | |||
6 | use ra_db::{LocationIntener, FileId}; | ||
2 | use ra_syntax::{TreeArc, SyntaxNode, SourceFile, AstNode, ast}; | 7 | use ra_syntax::{TreeArc, SyntaxNode, SourceFile, AstNode, ast}; |
3 | use ra_arena::{Arena, RawId, impl_arena_id}; | 8 | use ra_arena::{Arena, RawId, ArenaId, impl_arena_id}; |
4 | 9 | ||
5 | use crate::{ | 10 | use crate::{ |
6 | HirDatabase, Def, Function, Struct, Enum, EnumVariant, ImplBlock, Crate, | 11 | HirDatabase, |
7 | Module, Trait, Type, Static, Const, | 12 | Module, |
8 | module_tree::ModuleId, | ||
9 | }; | 13 | }; |
10 | 14 | ||
11 | #[derive(Debug, Default)] | 15 | #[derive(Debug, Default)] |
12 | pub struct HirInterner { | 16 | pub struct HirInterner { |
13 | defs: LocationIntener<DefLoc, DefId>, | ||
14 | macros: LocationIntener<MacroCallLoc, MacroCallId>, | 17 | macros: LocationIntener<MacroCallLoc, MacroCallId>, |
18 | fns: LocationIntener<ItemLoc<ast::FnDef>, FunctionId>, | ||
19 | structs: LocationIntener<ItemLoc<ast::StructDef>, StructId>, | ||
20 | enums: LocationIntener<ItemLoc<ast::EnumDef>, EnumId>, | ||
21 | enum_variants: LocationIntener<ItemLoc<ast::EnumVariant>, EnumVariantId>, | ||
22 | consts: LocationIntener<ItemLoc<ast::ConstDef>, ConstId>, | ||
23 | statics: LocationIntener<ItemLoc<ast::StaticDef>, StaticId>, | ||
24 | traits: LocationIntener<ItemLoc<ast::TraitDef>, TraitId>, | ||
25 | types: LocationIntener<ItemLoc<ast::TypeDef>, TypeId>, | ||
15 | } | 26 | } |
16 | 27 | ||
17 | impl HirInterner { | 28 | impl HirInterner { |
18 | pub fn len(&self) -> usize { | 29 | pub fn len(&self) -> usize { |
19 | self.defs.len() + self.macros.len() | 30 | self.macros.len() |
31 | + self.fns.len() | ||
32 | + self.structs.len() | ||
33 | + self.enums.len() | ||
34 | + self.enum_variants.len() | ||
35 | + self.consts.len() | ||
36 | + self.statics.len() | ||
37 | + self.traits.len() | ||
38 | + self.types.len() | ||
20 | } | 39 | } |
21 | } | 40 | } |
22 | 41 | ||
@@ -110,10 +129,9 @@ impl From<MacroCallId> for HirFileId { | |||
110 | pub struct MacroCallId(RawId); | 129 | pub struct MacroCallId(RawId); |
111 | impl_arena_id!(MacroCallId); | 130 | impl_arena_id!(MacroCallId); |
112 | 131 | ||
113 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 132 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
114 | pub struct MacroCallLoc { | 133 | pub struct MacroCallLoc { |
115 | pub(crate) source_root_id: SourceRootId, | 134 | pub(crate) module: Module, |
116 | pub(crate) module_id: ModuleId, | ||
117 | pub(crate) source_item_id: SourceItemId, | 135 | pub(crate) source_item_id: SourceItemId, |
118 | } | 136 | } |
119 | 137 | ||
@@ -130,117 +148,161 @@ impl MacroCallLoc { | |||
130 | } | 148 | } |
131 | } | 149 | } |
132 | 150 | ||
133 | /// Def's are a core concept of hir. A `Def` is an Item (function, module, etc) | 151 | #[derive(Debug)] |
134 | /// in a specific module. | 152 | pub struct ItemLoc<N: AstNode> { |
135 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 153 | pub(crate) module: Module, |
136 | pub struct DefId(RawId); | 154 | raw: SourceItemId, |
137 | impl_arena_id!(DefId); | 155 | _ty: PhantomData<N>, |
138 | |||
139 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | ||
140 | pub struct DefLoc { | ||
141 | pub(crate) kind: DefKind, | ||
142 | pub(crate) source_root_id: SourceRootId, | ||
143 | pub(crate) module_id: ModuleId, | ||
144 | pub(crate) source_item_id: SourceItemId, | ||
145 | } | 156 | } |
146 | 157 | ||
147 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | 158 | impl<N: AstNode> PartialEq for ItemLoc<N> { |
148 | pub(crate) enum DefKind { | 159 | fn eq(&self, other: &Self) -> bool { |
149 | Module, | 160 | self.module == other.module && self.raw == other.raw |
150 | Function, | 161 | } |
151 | Struct, | 162 | } |
152 | Enum, | 163 | impl<N: AstNode> Eq for ItemLoc<N> {} |
153 | EnumVariant, | 164 | impl<N: AstNode> Hash for ItemLoc<N> { |
154 | Const, | 165 | fn hash<H: Hasher>(&self, hasher: &mut H) { |
155 | Static, | 166 | self.module.hash(hasher); |
156 | Trait, | 167 | self.raw.hash(hasher); |
157 | Type, | 168 | } |
158 | Item, | ||
159 | |||
160 | /// The constructor of a struct. E.g. if we have `struct Foo(usize)`, the | ||
161 | /// name `Foo` needs to resolve to different types depending on whether we | ||
162 | /// are in the types or values namespace: As a type, `Foo` of course refers | ||
163 | /// to the struct `Foo`; as a value, `Foo` is a callable type with signature | ||
164 | /// `(usize) -> Foo`. The cleanest approach to handle this seems to be to | ||
165 | /// have different defs in the two namespaces. | ||
166 | /// | ||
167 | /// rustc does the same; note that it even creates a struct constructor if | ||
168 | /// the struct isn't a tuple struct (see `CtorKind::Fictive` in rustc). | ||
169 | StructCtor, | ||
170 | } | 169 | } |
171 | 170 | ||
172 | impl DefId { | 171 | impl<N: AstNode> Clone for ItemLoc<N> { |
173 | pub(crate) fn loc(self, db: &impl AsRef<HirInterner>) -> DefLoc { | 172 | fn clone(&self) -> ItemLoc<N> { |
174 | db.as_ref().defs.id2loc(self) | 173 | ItemLoc { |
174 | module: self.module, | ||
175 | raw: self.raw, | ||
176 | _ty: PhantomData, | ||
177 | } | ||
175 | } | 178 | } |
179 | } | ||
176 | 180 | ||
177 | pub fn resolve(self, db: &impl HirDatabase) -> Def { | 181 | #[derive(Clone, Copy)] |
178 | let loc = self.loc(db); | 182 | pub(crate) struct LocationCtx<DB> { |
179 | match loc.kind { | 183 | db: DB, |
180 | DefKind::Module => { | 184 | module: Module, |
181 | let module = Module::from_module_id(db, loc.source_root_id, loc.module_id); | 185 | file_id: HirFileId, |
182 | Def::Module(module) | 186 | } |
183 | } | ||
184 | DefKind::Function => { | ||
185 | let function = Function::new(self); | ||
186 | Def::Function(function) | ||
187 | } | ||
188 | DefKind::Struct => { | ||
189 | let struct_def = Struct::new(self); | ||
190 | Def::Struct(struct_def) | ||
191 | } | ||
192 | DefKind::Enum => Def::Enum(Enum::new(self)), | ||
193 | DefKind::EnumVariant => Def::EnumVariant(EnumVariant::new(self)), | ||
194 | DefKind::Const => { | ||
195 | let def = Const::new(self); | ||
196 | Def::Const(def) | ||
197 | } | ||
198 | DefKind::Static => { | ||
199 | let def = Static::new(self); | ||
200 | Def::Static(def) | ||
201 | } | ||
202 | DefKind::Trait => { | ||
203 | let def = Trait::new(self); | ||
204 | Def::Trait(def) | ||
205 | } | ||
206 | DefKind::Type => { | ||
207 | let def = Type::new(self); | ||
208 | Def::Type(def) | ||
209 | } | ||
210 | 187 | ||
211 | DefKind::StructCtor => Def::Item, | 188 | impl<'a, DB: HirDatabase> LocationCtx<&'a DB> { |
212 | DefKind::Item => Def::Item, | 189 | pub(crate) fn new(db: &'a DB, module: Module, file_id: HirFileId) -> LocationCtx<&'a DB> { |
190 | LocationCtx { | ||
191 | db, | ||
192 | module, | ||
193 | file_id, | ||
213 | } | 194 | } |
214 | } | 195 | } |
196 | pub(crate) fn to_def<N, DEF>(self, ast: &N) -> DEF | ||
197 | where | ||
198 | N: AstNode, | ||
199 | DEF: AstItemDef<N>, | ||
200 | { | ||
201 | DEF::from_ast(self, ast) | ||
202 | } | ||
203 | } | ||
204 | |||
205 | pub(crate) trait AstItemDef<N: AstNode>: ArenaId + Clone { | ||
206 | fn interner(interner: &HirInterner) -> &LocationIntener<ItemLoc<N>, Self>; | ||
207 | fn from_ast(ctx: LocationCtx<&impl HirDatabase>, ast: &N) -> Self { | ||
208 | let items = ctx.db.file_items(ctx.file_id); | ||
209 | let raw = SourceItemId { | ||
210 | file_id: ctx.file_id, | ||
211 | item_id: Some(items.id_of(ctx.file_id, ast.syntax())), | ||
212 | }; | ||
213 | let loc = ItemLoc { | ||
214 | module: ctx.module, | ||
215 | raw, | ||
216 | _ty: PhantomData, | ||
217 | }; | ||
218 | |||
219 | Self::interner(ctx.db.as_ref()).loc2id(&loc) | ||
220 | } | ||
221 | fn source(self, db: &impl HirDatabase) -> (HirFileId, TreeArc<N>) { | ||
222 | let int = Self::interner(db.as_ref()); | ||
223 | let loc = int.id2loc(self); | ||
224 | let syntax = db.file_item(loc.raw); | ||
225 | let ast = N::cast(&syntax) | ||
226 | .unwrap_or_else(|| panic!("invalid ItemLoc: {:?}", loc.raw)) | ||
227 | .to_owned(); | ||
228 | (loc.raw.file_id, ast) | ||
229 | } | ||
230 | fn module(self, db: &impl HirDatabase) -> Module { | ||
231 | let int = Self::interner(db.as_ref()); | ||
232 | let loc = int.id2loc(self); | ||
233 | loc.module | ||
234 | } | ||
235 | } | ||
236 | |||
237 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
238 | pub struct FunctionId(RawId); | ||
239 | impl_arena_id!(FunctionId); | ||
240 | impl AstItemDef<ast::FnDef> for FunctionId { | ||
241 | fn interner(interner: &HirInterner) -> &LocationIntener<ItemLoc<ast::FnDef>, Self> { | ||
242 | &interner.fns | ||
243 | } | ||
244 | } | ||
245 | |||
246 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
247 | pub struct StructId(RawId); | ||
248 | impl_arena_id!(StructId); | ||
249 | impl AstItemDef<ast::StructDef> for StructId { | ||
250 | fn interner(interner: &HirInterner) -> &LocationIntener<ItemLoc<ast::StructDef>, Self> { | ||
251 | &interner.structs | ||
252 | } | ||
253 | } | ||
215 | 254 | ||
216 | pub(crate) fn source(self, db: &impl HirDatabase) -> (HirFileId, TreeArc<SyntaxNode>) { | 255 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
217 | let loc = self.loc(db); | 256 | pub struct EnumId(RawId); |
218 | let syntax = db.file_item(loc.source_item_id); | 257 | impl_arena_id!(EnumId); |
219 | (loc.source_item_id.file_id, syntax) | 258 | impl AstItemDef<ast::EnumDef> for EnumId { |
259 | fn interner(interner: &HirInterner) -> &LocationIntener<ItemLoc<ast::EnumDef>, Self> { | ||
260 | &interner.enums | ||
220 | } | 261 | } |
262 | } | ||
221 | 263 | ||
222 | /// For a module, returns that module; for any other def, returns the containing module. | 264 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
223 | pub fn module(self, db: &impl HirDatabase) -> Module { | 265 | pub struct EnumVariantId(RawId); |
224 | let loc = self.loc(db); | 266 | impl_arena_id!(EnumVariantId); |
225 | Module::from_module_id(db, loc.source_root_id, loc.module_id) | 267 | impl AstItemDef<ast::EnumVariant> for EnumVariantId { |
268 | fn interner(interner: &HirInterner) -> &LocationIntener<ItemLoc<ast::EnumVariant>, Self> { | ||
269 | &interner.enum_variants | ||
226 | } | 270 | } |
271 | } | ||
227 | 272 | ||
228 | /// Returns the containing crate. | 273 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
229 | pub fn krate(&self, db: &impl HirDatabase) -> Option<Crate> { | 274 | pub struct ConstId(RawId); |
230 | self.module(db).krate(db) | 275 | impl_arena_id!(ConstId); |
276 | impl AstItemDef<ast::ConstDef> for ConstId { | ||
277 | fn interner(interner: &HirInterner) -> &LocationIntener<ItemLoc<ast::ConstDef>, Self> { | ||
278 | &interner.consts | ||
231 | } | 279 | } |
280 | } | ||
232 | 281 | ||
233 | /// Returns the containing impl block, if this is an impl item. | 282 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
234 | pub fn impl_block(self, db: &impl HirDatabase) -> Option<ImplBlock> { | 283 | pub struct StaticId(RawId); |
235 | let loc = self.loc(db); | 284 | impl_arena_id!(StaticId); |
236 | let module_impls = db.impls_in_module(loc.source_root_id, loc.module_id); | 285 | impl AstItemDef<ast::StaticDef> for StaticId { |
237 | ImplBlock::containing(module_impls, self) | 286 | fn interner(interner: &HirInterner) -> &LocationIntener<ItemLoc<ast::StaticDef>, Self> { |
287 | &interner.statics | ||
288 | } | ||
289 | } | ||
290 | |||
291 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
292 | pub struct TraitId(RawId); | ||
293 | impl_arena_id!(TraitId); | ||
294 | impl AstItemDef<ast::TraitDef> for TraitId { | ||
295 | fn interner(interner: &HirInterner) -> &LocationIntener<ItemLoc<ast::TraitDef>, Self> { | ||
296 | &interner.traits | ||
238 | } | 297 | } |
239 | } | 298 | } |
240 | 299 | ||
241 | impl DefLoc { | 300 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
242 | pub(crate) fn id(&self, db: &impl AsRef<HirInterner>) -> DefId { | 301 | pub struct TypeId(RawId); |
243 | db.as_ref().defs.loc2id(&self) | 302 | impl_arena_id!(TypeId); |
303 | impl AstItemDef<ast::TypeDef> for TypeId { | ||
304 | fn interner(interner: &HirInterner) -> &LocationIntener<ItemLoc<ast::TypeDef>, Self> { | ||
305 | &interner.types | ||
244 | } | 306 | } |
245 | } | 307 | } |
246 | 308 | ||