aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ids.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/ids.rs')
-rw-r--r--crates/ra_hir/src/ids.rs266
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 @@
1use ra_db::{SourceRootId, LocationIntener, FileId}; 1use std::{
2 marker::PhantomData,
3 hash::{Hash, Hasher},
4};
5
6use ra_db::{LocationIntener, FileId};
2use ra_syntax::{TreeArc, SyntaxNode, SourceFile, AstNode, ast}; 7use ra_syntax::{TreeArc, SyntaxNode, SourceFile, AstNode, ast};
3use ra_arena::{Arena, RawId, impl_arena_id}; 8use ra_arena::{Arena, RawId, ArenaId, impl_arena_id};
4 9
5use crate::{ 10use 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)]
12pub struct HirInterner { 16pub 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
17impl HirInterner { 28impl 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 {
110pub struct MacroCallId(RawId); 129pub struct MacroCallId(RawId);
111impl_arena_id!(MacroCallId); 130impl_arena_id!(MacroCallId);
112 131
113#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 132#[derive(Debug, Clone, PartialEq, Eq, Hash)]
114pub struct MacroCallLoc { 133pub 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. 152pub struct ItemLoc<N: AstNode> {
135#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 153 pub(crate) module: Module,
136pub struct DefId(RawId); 154 raw: SourceItemId,
137impl_arena_id!(DefId); 155 _ty: PhantomData<N>,
138
139#[derive(Clone, Debug, PartialEq, Eq, Hash)]
140pub 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)] 158impl<N: AstNode> PartialEq for ItemLoc<N> {
148pub(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, 163impl<N: AstNode> Eq for ItemLoc<N> {}
153 EnumVariant, 164impl<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
172impl DefId { 171impl<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); 182pub(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, 188impl<'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
205pub(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)]
238pub struct FunctionId(RawId);
239impl_arena_id!(FunctionId);
240impl 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)]
247pub struct StructId(RawId);
248impl_arena_id!(StructId);
249impl 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); 256pub struct EnumId(RawId);
218 let syntax = db.file_item(loc.source_item_id); 257impl_arena_id!(EnumId);
219 (loc.source_item_id.file_id, syntax) 258impl 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 { 265pub struct EnumVariantId(RawId);
224 let loc = self.loc(db); 266impl_arena_id!(EnumVariantId);
225 Module::from_module_id(db, loc.source_root_id, loc.module_id) 267impl 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> { 274pub struct ConstId(RawId);
230 self.module(db).krate(db) 275impl_arena_id!(ConstId);
276impl 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> { 283pub struct StaticId(RawId);
235 let loc = self.loc(db); 284impl_arena_id!(StaticId);
236 let module_impls = db.impls_in_module(loc.source_root_id, loc.module_id); 285impl 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)]
292pub struct TraitId(RawId);
293impl_arena_id!(TraitId);
294impl AstItemDef<ast::TraitDef> for TraitId {
295 fn interner(interner: &HirInterner) -> &LocationIntener<ItemLoc<ast::TraitDef>, Self> {
296 &interner.traits
238 } 297 }
239} 298}
240 299
241impl DefLoc { 300#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
242 pub(crate) fn id(&self, db: &impl AsRef<HirInterner>) -> DefId { 301pub struct TypeId(RawId);
243 db.as_ref().defs.loc2id(&self) 302impl_arena_id!(TypeId);
303impl AstItemDef<ast::TypeDef> for TypeId {
304 fn interner(interner: &HirInterner) -> &LocationIntener<ItemLoc<ast::TypeDef>, Self> {
305 &interner.types
244 } 306 }
245} 307}
246 308