diff options
Diffstat (limited to 'crates/ra_hir_def/src')
-rw-r--r-- | crates/ra_hir_def/src/db.rs | 22 | ||||
-rw-r--r-- | crates/ra_hir_def/src/lib.rs | 216 |
2 files changed, 238 insertions, 0 deletions
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs new file mode 100644 index 000000000..f6f976c86 --- /dev/null +++ b/crates/ra_hir_def/src/db.rs | |||
@@ -0,0 +1,22 @@ | |||
1 | //! Defines database & queries for name resolution. | ||
2 | |||
3 | use ra_db::{salsa, SourceDatabase}; | ||
4 | use ra_syntax::ast; | ||
5 | |||
6 | #[salsa::query_group(InternDatabaseStorage)] | ||
7 | pub trait InternDatabase: SourceDatabase { | ||
8 | #[salsa::interned] | ||
9 | fn intern_function(&self, loc: crate::ItemLoc<ast::FnDef>) -> crate::FunctionId; | ||
10 | #[salsa::interned] | ||
11 | fn intern_struct(&self, loc: crate::ItemLoc<ast::StructDef>) -> crate::StructId; | ||
12 | #[salsa::interned] | ||
13 | fn intern_enum(&self, loc: crate::ItemLoc<ast::EnumDef>) -> crate::EnumId; | ||
14 | #[salsa::interned] | ||
15 | fn intern_const(&self, loc: crate::ItemLoc<ast::ConstDef>) -> crate::ConstId; | ||
16 | #[salsa::interned] | ||
17 | fn intern_static(&self, loc: crate::ItemLoc<ast::StaticDef>) -> crate::StaticId; | ||
18 | #[salsa::interned] | ||
19 | fn intern_trait(&self, loc: crate::ItemLoc<ast::TraitDef>) -> crate::TraitId; | ||
20 | #[salsa::interned] | ||
21 | fn intern_type_alias(&self, loc: crate::ItemLoc<ast::TypeAliasDef>) -> crate::TypeAliasId; | ||
22 | } | ||
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs new file mode 100644 index 000000000..4d6b9db03 --- /dev/null +++ b/crates/ra_hir_def/src/lib.rs | |||
@@ -0,0 +1,216 @@ | |||
1 | //! `hir_def` crate contains everything between macro expansion and type | ||
2 | //! inference. | ||
3 | //! | ||
4 | //! It defines various items (structs, enums, traits) which comprises Rust code, | ||
5 | //! as well as an algorithm for resolving paths to such entities. | ||
6 | //! | ||
7 | //! Note that `hir_def` is a work in progress, so not all of the above is | ||
8 | //! actually true. | ||
9 | |||
10 | pub mod db; | ||
11 | |||
12 | use std::hash::{Hash, Hasher}; | ||
13 | |||
14 | use hir_expand::{ast_id_map::FileAstId, db::AstDatabase, AstId, HirFileId}; | ||
15 | use ra_arena::{impl_arena_id, RawId}; | ||
16 | use ra_db::{salsa, CrateId}; | ||
17 | use ra_syntax::{ast, AstNode, SyntaxNode}; | ||
18 | |||
19 | use crate::db::InternDatabase; | ||
20 | |||
21 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||
22 | pub struct Source<T> { | ||
23 | pub file_id: HirFileId, | ||
24 | pub ast: T, | ||
25 | } | ||
26 | |||
27 | impl<T> Source<T> { | ||
28 | pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> { | ||
29 | Source { file_id: self.file_id, ast: f(self.ast) } | ||
30 | } | ||
31 | pub fn file_syntax(&self, db: &impl AstDatabase) -> SyntaxNode { | ||
32 | db.parse_or_expand(self.file_id).expect("source created from invalid file") | ||
33 | } | ||
34 | } | ||
35 | |||
36 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
37 | pub struct ModuleId { | ||
38 | pub krate: CrateId, | ||
39 | pub module_id: CrateModuleId, | ||
40 | } | ||
41 | |||
42 | /// An ID of a module, **local** to a specific crate | ||
43 | // FIXME: rename to `LocalModuleId`. | ||
44 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
45 | pub struct CrateModuleId(RawId); | ||
46 | impl_arena_id!(CrateModuleId); | ||
47 | |||
48 | macro_rules! impl_intern_key { | ||
49 | ($name:ident) => { | ||
50 | impl salsa::InternKey for $name { | ||
51 | fn from_intern_id(v: salsa::InternId) -> Self { | ||
52 | $name(v) | ||
53 | } | ||
54 | fn as_intern_id(&self) -> salsa::InternId { | ||
55 | self.0 | ||
56 | } | ||
57 | } | ||
58 | }; | ||
59 | } | ||
60 | |||
61 | #[derive(Debug)] | ||
62 | pub struct ItemLoc<N: AstNode> { | ||
63 | pub(crate) module: ModuleId, | ||
64 | ast_id: AstId<N>, | ||
65 | } | ||
66 | |||
67 | impl<N: AstNode> PartialEq for ItemLoc<N> { | ||
68 | fn eq(&self, other: &Self) -> bool { | ||
69 | self.module == other.module && self.ast_id == other.ast_id | ||
70 | } | ||
71 | } | ||
72 | impl<N: AstNode> Eq for ItemLoc<N> {} | ||
73 | impl<N: AstNode> Hash for ItemLoc<N> { | ||
74 | fn hash<H: Hasher>(&self, hasher: &mut H) { | ||
75 | self.module.hash(hasher); | ||
76 | self.ast_id.hash(hasher); | ||
77 | } | ||
78 | } | ||
79 | |||
80 | impl<N: AstNode> Clone for ItemLoc<N> { | ||
81 | fn clone(&self) -> ItemLoc<N> { | ||
82 | ItemLoc { module: self.module, ast_id: self.ast_id } | ||
83 | } | ||
84 | } | ||
85 | |||
86 | #[derive(Clone, Copy)] | ||
87 | pub struct LocationCtx<DB> { | ||
88 | db: DB, | ||
89 | module: ModuleId, | ||
90 | file_id: HirFileId, | ||
91 | } | ||
92 | |||
93 | impl<'a, DB> LocationCtx<&'a DB> { | ||
94 | pub fn new(db: &'a DB, module: ModuleId, file_id: HirFileId) -> LocationCtx<&'a DB> { | ||
95 | LocationCtx { db, module, file_id } | ||
96 | } | ||
97 | } | ||
98 | |||
99 | impl<'a, DB: AstDatabase + InternDatabase> LocationCtx<&'a DB> { | ||
100 | pub fn to_def<N, DEF>(self, ast: &N) -> DEF | ||
101 | where | ||
102 | N: AstNode, | ||
103 | DEF: AstItemDef<N>, | ||
104 | { | ||
105 | DEF::from_ast(self, ast) | ||
106 | } | ||
107 | } | ||
108 | |||
109 | pub trait AstItemDef<N: AstNode>: salsa::InternKey + Clone { | ||
110 | fn intern(db: &impl InternDatabase, loc: ItemLoc<N>) -> Self; | ||
111 | fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<N>; | ||
112 | |||
113 | fn from_ast(ctx: LocationCtx<&(impl AstDatabase + InternDatabase)>, ast: &N) -> Self { | ||
114 | let items = ctx.db.ast_id_map(ctx.file_id); | ||
115 | let item_id = items.ast_id(ast); | ||
116 | Self::from_ast_id(ctx, item_id) | ||
117 | } | ||
118 | fn from_ast_id(ctx: LocationCtx<&impl InternDatabase>, ast_id: FileAstId<N>) -> Self { | ||
119 | let loc = ItemLoc { module: ctx.module, ast_id: AstId::new(ctx.file_id, ast_id) }; | ||
120 | Self::intern(ctx.db, loc) | ||
121 | } | ||
122 | fn source(self, db: &(impl AstDatabase + InternDatabase)) -> Source<N> { | ||
123 | let loc = self.lookup_intern(db); | ||
124 | let ast = loc.ast_id.to_node(db); | ||
125 | Source { file_id: loc.ast_id.file_id(), ast } | ||
126 | } | ||
127 | fn module(self, db: &impl InternDatabase) -> ModuleId { | ||
128 | let loc = self.lookup_intern(db); | ||
129 | loc.module | ||
130 | } | ||
131 | } | ||
132 | |||
133 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
134 | pub struct FunctionId(salsa::InternId); | ||
135 | impl_intern_key!(FunctionId); | ||
136 | |||
137 | impl AstItemDef<ast::FnDef> for FunctionId { | ||
138 | fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::FnDef>) -> Self { | ||
139 | db.intern_function(loc) | ||
140 | } | ||
141 | fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::FnDef> { | ||
142 | db.lookup_intern_function(self) | ||
143 | } | ||
144 | } | ||
145 | |||
146 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
147 | pub struct StructId(salsa::InternId); | ||
148 | impl_intern_key!(StructId); | ||
149 | impl AstItemDef<ast::StructDef> for StructId { | ||
150 | fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StructDef>) -> Self { | ||
151 | db.intern_struct(loc) | ||
152 | } | ||
153 | fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StructDef> { | ||
154 | db.lookup_intern_struct(self) | ||
155 | } | ||
156 | } | ||
157 | |||
158 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
159 | pub struct EnumId(salsa::InternId); | ||
160 | impl_intern_key!(EnumId); | ||
161 | impl AstItemDef<ast::EnumDef> for EnumId { | ||
162 | fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::EnumDef>) -> Self { | ||
163 | db.intern_enum(loc) | ||
164 | } | ||
165 | fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::EnumDef> { | ||
166 | db.lookup_intern_enum(self) | ||
167 | } | ||
168 | } | ||
169 | |||
170 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
171 | pub struct ConstId(salsa::InternId); | ||
172 | impl_intern_key!(ConstId); | ||
173 | impl AstItemDef<ast::ConstDef> for ConstId { | ||
174 | fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::ConstDef>) -> Self { | ||
175 | db.intern_const(loc) | ||
176 | } | ||
177 | fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::ConstDef> { | ||
178 | db.lookup_intern_const(self) | ||
179 | } | ||
180 | } | ||
181 | |||
182 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
183 | pub struct StaticId(salsa::InternId); | ||
184 | impl_intern_key!(StaticId); | ||
185 | impl AstItemDef<ast::StaticDef> for StaticId { | ||
186 | fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StaticDef>) -> Self { | ||
187 | db.intern_static(loc) | ||
188 | } | ||
189 | fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StaticDef> { | ||
190 | db.lookup_intern_static(self) | ||
191 | } | ||
192 | } | ||
193 | |||
194 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
195 | pub struct TraitId(salsa::InternId); | ||
196 | impl_intern_key!(TraitId); | ||
197 | impl AstItemDef<ast::TraitDef> for TraitId { | ||
198 | fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::TraitDef>) -> Self { | ||
199 | db.intern_trait(loc) | ||
200 | } | ||
201 | fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::TraitDef> { | ||
202 | db.lookup_intern_trait(self) | ||
203 | } | ||
204 | } | ||
205 | |||
206 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
207 | pub struct TypeAliasId(salsa::InternId); | ||
208 | impl_intern_key!(TypeAliasId); | ||
209 | impl AstItemDef<ast::TypeAliasDef> for TypeAliasId { | ||
210 | fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::TypeAliasDef>) -> Self { | ||
211 | db.intern_type_alias(loc) | ||
212 | } | ||
213 | fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::TypeAliasDef> { | ||
214 | db.lookup_intern_type_alias(self) | ||
215 | } | ||
216 | } | ||