diff options
Diffstat (limited to 'crates/ra_hir_def/src/lib.rs')
-rw-r--r-- | crates/ra_hir_def/src/lib.rs | 362 |
1 files changed, 362 insertions, 0 deletions
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs new file mode 100644 index 000000000..93ad40005 --- /dev/null +++ b/crates/ra_hir_def/src/lib.rs | |||
@@ -0,0 +1,362 @@ | |||
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 | pub mod attr; | ||
12 | pub mod path; | ||
13 | pub mod type_ref; | ||
14 | pub mod builtin_type; | ||
15 | |||
16 | // FIXME: this should be private | ||
17 | pub mod nameres; | ||
18 | |||
19 | use std::hash::{Hash, Hasher}; | ||
20 | |||
21 | use hir_expand::{ast_id_map::FileAstId, db::AstDatabase, AstId, HirFileId}; | ||
22 | use ra_arena::{impl_arena_id, RawId}; | ||
23 | use ra_db::{salsa, CrateId, FileId}; | ||
24 | use ra_syntax::{ast, AstNode, SyntaxNode}; | ||
25 | |||
26 | use crate::{builtin_type::BuiltinType, db::InternDatabase}; | ||
27 | |||
28 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||
29 | pub struct Source<T> { | ||
30 | pub file_id: HirFileId, | ||
31 | pub ast: T, | ||
32 | } | ||
33 | |||
34 | pub enum ModuleSource { | ||
35 | SourceFile(ast::SourceFile), | ||
36 | Module(ast::Module), | ||
37 | } | ||
38 | |||
39 | impl ModuleSource { | ||
40 | pub fn new( | ||
41 | db: &impl db::DefDatabase2, | ||
42 | file_id: Option<FileId>, | ||
43 | decl_id: Option<AstId<ast::Module>>, | ||
44 | ) -> ModuleSource { | ||
45 | match (file_id, decl_id) { | ||
46 | (Some(file_id), _) => { | ||
47 | let source_file = db.parse(file_id).tree(); | ||
48 | ModuleSource::SourceFile(source_file) | ||
49 | } | ||
50 | (None, Some(item_id)) => { | ||
51 | let module = item_id.to_node(db); | ||
52 | assert!(module.item_list().is_some(), "expected inline module"); | ||
53 | ModuleSource::Module(module) | ||
54 | } | ||
55 | (None, None) => panic!(), | ||
56 | } | ||
57 | } | ||
58 | |||
59 | // FIXME: this methods do not belong here | ||
60 | pub fn from_position( | ||
61 | db: &impl db::DefDatabase2, | ||
62 | position: ra_db::FilePosition, | ||
63 | ) -> ModuleSource { | ||
64 | let parse = db.parse(position.file_id); | ||
65 | match &ra_syntax::algo::find_node_at_offset::<ast::Module>( | ||
66 | parse.tree().syntax(), | ||
67 | position.offset, | ||
68 | ) { | ||
69 | Some(m) if !m.has_semi() => ModuleSource::Module(m.clone()), | ||
70 | _ => { | ||
71 | let source_file = parse.tree(); | ||
72 | ModuleSource::SourceFile(source_file) | ||
73 | } | ||
74 | } | ||
75 | } | ||
76 | |||
77 | pub fn from_child_node( | ||
78 | db: &impl db::DefDatabase2, | ||
79 | file_id: FileId, | ||
80 | child: &SyntaxNode, | ||
81 | ) -> ModuleSource { | ||
82 | if let Some(m) = child.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi()) { | ||
83 | ModuleSource::Module(m) | ||
84 | } else { | ||
85 | let source_file = db.parse(file_id).tree(); | ||
86 | ModuleSource::SourceFile(source_file) | ||
87 | } | ||
88 | } | ||
89 | |||
90 | pub fn from_file_id(db: &impl db::DefDatabase2, file_id: FileId) -> ModuleSource { | ||
91 | let source_file = db.parse(file_id).tree(); | ||
92 | ModuleSource::SourceFile(source_file) | ||
93 | } | ||
94 | } | ||
95 | |||
96 | impl<T> Source<T> { | ||
97 | pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> { | ||
98 | Source { file_id: self.file_id, ast: f(self.ast) } | ||
99 | } | ||
100 | pub fn file_syntax(&self, db: &impl AstDatabase) -> SyntaxNode { | ||
101 | db.parse_or_expand(self.file_id).expect("source created from invalid file") | ||
102 | } | ||
103 | } | ||
104 | |||
105 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
106 | pub struct ModuleId { | ||
107 | pub krate: CrateId, | ||
108 | pub module_id: CrateModuleId, | ||
109 | } | ||
110 | |||
111 | /// An ID of a module, **local** to a specific crate | ||
112 | // FIXME: rename to `LocalModuleId`. | ||
113 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
114 | pub struct CrateModuleId(RawId); | ||
115 | impl_arena_id!(CrateModuleId); | ||
116 | |||
117 | macro_rules! impl_intern_key { | ||
118 | ($name:ident) => { | ||
119 | impl salsa::InternKey for $name { | ||
120 | fn from_intern_id(v: salsa::InternId) -> Self { | ||
121 | $name(v) | ||
122 | } | ||
123 | fn as_intern_id(&self) -> salsa::InternId { | ||
124 | self.0 | ||
125 | } | ||
126 | } | ||
127 | }; | ||
128 | } | ||
129 | |||
130 | #[derive(Debug)] | ||
131 | pub struct ItemLoc<N: AstNode> { | ||
132 | pub(crate) module: ModuleId, | ||
133 | ast_id: AstId<N>, | ||
134 | } | ||
135 | |||
136 | impl<N: AstNode> PartialEq for ItemLoc<N> { | ||
137 | fn eq(&self, other: &Self) -> bool { | ||
138 | self.module == other.module && self.ast_id == other.ast_id | ||
139 | } | ||
140 | } | ||
141 | impl<N: AstNode> Eq for ItemLoc<N> {} | ||
142 | impl<N: AstNode> Hash for ItemLoc<N> { | ||
143 | fn hash<H: Hasher>(&self, hasher: &mut H) { | ||
144 | self.module.hash(hasher); | ||
145 | self.ast_id.hash(hasher); | ||
146 | } | ||
147 | } | ||
148 | |||
149 | impl<N: AstNode> Clone for ItemLoc<N> { | ||
150 | fn clone(&self) -> ItemLoc<N> { | ||
151 | ItemLoc { module: self.module, ast_id: self.ast_id } | ||
152 | } | ||
153 | } | ||
154 | |||
155 | #[derive(Clone, Copy)] | ||
156 | pub struct LocationCtx<DB> { | ||
157 | db: DB, | ||
158 | module: ModuleId, | ||
159 | file_id: HirFileId, | ||
160 | } | ||
161 | |||
162 | impl<'a, DB> LocationCtx<&'a DB> { | ||
163 | pub fn new(db: &'a DB, module: ModuleId, file_id: HirFileId) -> LocationCtx<&'a DB> { | ||
164 | LocationCtx { db, module, file_id } | ||
165 | } | ||
166 | } | ||
167 | |||
168 | impl<'a, DB: AstDatabase + InternDatabase> LocationCtx<&'a DB> { | ||
169 | pub fn to_def<N, DEF>(self, ast: &N) -> DEF | ||
170 | where | ||
171 | N: AstNode, | ||
172 | DEF: AstItemDef<N>, | ||
173 | { | ||
174 | DEF::from_ast(self, ast) | ||
175 | } | ||
176 | } | ||
177 | |||
178 | pub trait AstItemDef<N: AstNode>: salsa::InternKey + Clone { | ||
179 | fn intern(db: &impl InternDatabase, loc: ItemLoc<N>) -> Self; | ||
180 | fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<N>; | ||
181 | |||
182 | fn from_ast(ctx: LocationCtx<&(impl AstDatabase + InternDatabase)>, ast: &N) -> Self { | ||
183 | let items = ctx.db.ast_id_map(ctx.file_id); | ||
184 | let item_id = items.ast_id(ast); | ||
185 | Self::from_ast_id(ctx, item_id) | ||
186 | } | ||
187 | fn from_ast_id(ctx: LocationCtx<&impl InternDatabase>, ast_id: FileAstId<N>) -> Self { | ||
188 | let loc = ItemLoc { module: ctx.module, ast_id: AstId::new(ctx.file_id, ast_id) }; | ||
189 | Self::intern(ctx.db, loc) | ||
190 | } | ||
191 | fn source(self, db: &(impl AstDatabase + InternDatabase)) -> Source<N> { | ||
192 | let loc = self.lookup_intern(db); | ||
193 | let ast = loc.ast_id.to_node(db); | ||
194 | Source { file_id: loc.ast_id.file_id(), ast } | ||
195 | } | ||
196 | fn module(self, db: &impl InternDatabase) -> ModuleId { | ||
197 | let loc = self.lookup_intern(db); | ||
198 | loc.module | ||
199 | } | ||
200 | } | ||
201 | |||
202 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
203 | pub struct FunctionId(salsa::InternId); | ||
204 | impl_intern_key!(FunctionId); | ||
205 | |||
206 | impl AstItemDef<ast::FnDef> for FunctionId { | ||
207 | fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::FnDef>) -> Self { | ||
208 | db.intern_function(loc) | ||
209 | } | ||
210 | fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::FnDef> { | ||
211 | db.lookup_intern_function(self) | ||
212 | } | ||
213 | } | ||
214 | |||
215 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
216 | pub struct StructId(salsa::InternId); | ||
217 | impl_intern_key!(StructId); | ||
218 | impl AstItemDef<ast::StructDef> for StructId { | ||
219 | fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StructDef>) -> Self { | ||
220 | db.intern_struct(loc) | ||
221 | } | ||
222 | fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StructDef> { | ||
223 | db.lookup_intern_struct(self) | ||
224 | } | ||
225 | } | ||
226 | |||
227 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
228 | pub struct UnionId(salsa::InternId); | ||
229 | impl_intern_key!(UnionId); | ||
230 | impl AstItemDef<ast::StructDef> for UnionId { | ||
231 | fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StructDef>) -> Self { | ||
232 | db.intern_union(loc) | ||
233 | } | ||
234 | fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StructDef> { | ||
235 | db.lookup_intern_union(self) | ||
236 | } | ||
237 | } | ||
238 | |||
239 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
240 | pub struct EnumId(salsa::InternId); | ||
241 | impl_intern_key!(EnumId); | ||
242 | impl AstItemDef<ast::EnumDef> for EnumId { | ||
243 | fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::EnumDef>) -> Self { | ||
244 | db.intern_enum(loc) | ||
245 | } | ||
246 | fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::EnumDef> { | ||
247 | db.lookup_intern_enum(self) | ||
248 | } | ||
249 | } | ||
250 | |||
251 | // FIXME: rename to `VariantId`, only enums can ave variants | ||
252 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
253 | pub struct EnumVariantId { | ||
254 | parent: EnumId, | ||
255 | local_id: LocalEnumVariantId, | ||
256 | } | ||
257 | |||
258 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
259 | pub struct LocalEnumVariantId(RawId); | ||
260 | impl_arena_id!(LocalEnumVariantId); | ||
261 | |||
262 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
263 | pub struct ConstId(salsa::InternId); | ||
264 | impl_intern_key!(ConstId); | ||
265 | impl AstItemDef<ast::ConstDef> for ConstId { | ||
266 | fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::ConstDef>) -> Self { | ||
267 | db.intern_const(loc) | ||
268 | } | ||
269 | fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::ConstDef> { | ||
270 | db.lookup_intern_const(self) | ||
271 | } | ||
272 | } | ||
273 | |||
274 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
275 | pub struct StaticId(salsa::InternId); | ||
276 | impl_intern_key!(StaticId); | ||
277 | impl AstItemDef<ast::StaticDef> for StaticId { | ||
278 | fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StaticDef>) -> Self { | ||
279 | db.intern_static(loc) | ||
280 | } | ||
281 | fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StaticDef> { | ||
282 | db.lookup_intern_static(self) | ||
283 | } | ||
284 | } | ||
285 | |||
286 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
287 | pub struct TraitId(salsa::InternId); | ||
288 | impl_intern_key!(TraitId); | ||
289 | impl AstItemDef<ast::TraitDef> for TraitId { | ||
290 | fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::TraitDef>) -> Self { | ||
291 | db.intern_trait(loc) | ||
292 | } | ||
293 | fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::TraitDef> { | ||
294 | db.lookup_intern_trait(self) | ||
295 | } | ||
296 | } | ||
297 | |||
298 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
299 | pub struct TypeAliasId(salsa::InternId); | ||
300 | impl_intern_key!(TypeAliasId); | ||
301 | impl AstItemDef<ast::TypeAliasDef> for TypeAliasId { | ||
302 | fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::TypeAliasDef>) -> Self { | ||
303 | db.intern_type_alias(loc) | ||
304 | } | ||
305 | fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::TypeAliasDef> { | ||
306 | db.lookup_intern_type_alias(self) | ||
307 | } | ||
308 | } | ||
309 | |||
310 | macro_rules! impl_froms { | ||
311 | ($e:ident: $($v:ident $(($($sv:ident),*))?),*) => { | ||
312 | $( | ||
313 | impl From<$v> for $e { | ||
314 | fn from(it: $v) -> $e { | ||
315 | $e::$v(it) | ||
316 | } | ||
317 | } | ||
318 | $($( | ||
319 | impl From<$sv> for $e { | ||
320 | fn from(it: $sv) -> $e { | ||
321 | $e::$v($v::$sv(it)) | ||
322 | } | ||
323 | } | ||
324 | )*)? | ||
325 | )* | ||
326 | } | ||
327 | } | ||
328 | |||
329 | /// A Data Type | ||
330 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
331 | pub enum AdtId { | ||
332 | StructId(StructId), | ||
333 | UnionId(UnionId), | ||
334 | EnumId(EnumId), | ||
335 | } | ||
336 | impl_froms!(AdtId: StructId, UnionId, EnumId); | ||
337 | |||
338 | /// The defs which can be visible in the module. | ||
339 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
340 | pub enum ModuleDefId { | ||
341 | ModuleId(ModuleId), | ||
342 | FunctionId(FunctionId), | ||
343 | AdtId(AdtId), | ||
344 | // Can't be directly declared, but can be imported. | ||
345 | EnumVariantId(EnumVariantId), | ||
346 | ConstId(ConstId), | ||
347 | StaticId(StaticId), | ||
348 | TraitId(TraitId), | ||
349 | TypeAliasId(TypeAliasId), | ||
350 | BuiltinType(BuiltinType), | ||
351 | } | ||
352 | impl_froms!( | ||
353 | ModuleDefId: ModuleId, | ||
354 | FunctionId, | ||
355 | AdtId(StructId, EnumId, UnionId), | ||
356 | EnumVariantId, | ||
357 | ConstId, | ||
358 | StaticId, | ||
359 | TraitId, | ||
360 | TypeAliasId, | ||
361 | BuiltinType | ||
362 | ); | ||