aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def/src/lib.rs')
-rw-r--r--crates/hir_def/src/lib.rs541
1 files changed, 541 insertions, 0 deletions
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
new file mode 100644
index 000000000..f24a1dd77
--- /dev/null
+++ b/crates/hir_def/src/lib.rs
@@ -0,0 +1,541 @@
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#[allow(unused)]
11macro_rules! eprintln {
12 ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
13}
14
15pub mod db;
16
17pub mod attr;
18pub mod path;
19pub mod type_ref;
20pub mod builtin_type;
21pub mod diagnostics;
22pub mod per_ns;
23pub mod item_scope;
24
25pub mod dyn_map;
26pub mod keys;
27
28pub mod item_tree;
29
30pub mod adt;
31pub mod data;
32pub mod generics;
33pub mod lang_item;
34pub mod docs;
35
36pub mod expr;
37pub mod body;
38pub mod resolver;
39
40mod trace;
41pub mod nameres;
42
43pub mod src;
44pub mod child_by_source;
45
46pub mod visibility;
47pub mod find_path;
48pub mod import_map;
49
50#[cfg(test)]
51mod test_db;
52
53use std::hash::{Hash, Hasher};
54
55use arena::Idx;
56use base_db::{impl_intern_key, salsa, CrateId};
57use hir_expand::{
58 ast_id_map::FileAstId, eager::expand_eager_macro, hygiene::Hygiene, AstId, HirFileId, InFile,
59 MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
60};
61use syntax::ast;
62
63use crate::builtin_type::BuiltinType;
64use item_tree::{
65 Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, ModItem, Static, Struct, Trait,
66 TypeAlias, Union,
67};
68use stdx::impl_from;
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
71pub struct ModuleId {
72 pub krate: CrateId,
73 pub local_id: LocalModuleId,
74}
75
76/// An ID of a module, **local** to a specific crate
77pub type LocalModuleId = Idx<nameres::ModuleData>;
78
79#[derive(Debug)]
80pub struct ItemLoc<N: ItemTreeNode> {
81 pub container: ContainerId,
82 pub id: ItemTreeId<N>,
83}
84
85impl<N: ItemTreeNode> Clone for ItemLoc<N> {
86 fn clone(&self) -> Self {
87 Self { container: self.container, id: self.id }
88 }
89}
90
91impl<N: ItemTreeNode> Copy for ItemLoc<N> {}
92
93impl<N: ItemTreeNode> PartialEq for ItemLoc<N> {
94 fn eq(&self, other: &Self) -> bool {
95 self.container == other.container && self.id == other.id
96 }
97}
98
99impl<N: ItemTreeNode> Eq for ItemLoc<N> {}
100
101impl<N: ItemTreeNode> Hash for ItemLoc<N> {
102 fn hash<H: Hasher>(&self, state: &mut H) {
103 self.container.hash(state);
104 self.id.hash(state);
105 }
106}
107
108#[derive(Debug)]
109pub struct AssocItemLoc<N: ItemTreeNode> {
110 pub container: AssocContainerId,
111 pub id: ItemTreeId<N>,
112}
113
114impl<N: ItemTreeNode> Clone for AssocItemLoc<N> {
115 fn clone(&self) -> Self {
116 Self { container: self.container, id: self.id }
117 }
118}
119
120impl<N: ItemTreeNode> Copy for AssocItemLoc<N> {}
121
122impl<N: ItemTreeNode> PartialEq for AssocItemLoc<N> {
123 fn eq(&self, other: &Self) -> bool {
124 self.container == other.container && self.id == other.id
125 }
126}
127
128impl<N: ItemTreeNode> Eq for AssocItemLoc<N> {}
129
130impl<N: ItemTreeNode> Hash for AssocItemLoc<N> {
131 fn hash<H: Hasher>(&self, state: &mut H) {
132 self.container.hash(state);
133 self.id.hash(state);
134 }
135}
136
137macro_rules! impl_intern {
138 ($id:ident, $loc:ident, $intern:ident, $lookup:ident) => {
139 impl_intern_key!($id);
140
141 impl Intern for $loc {
142 type ID = $id;
143 fn intern(self, db: &dyn db::DefDatabase) -> $id {
144 db.$intern(self)
145 }
146 }
147
148 impl Lookup for $id {
149 type Data = $loc;
150 fn lookup(&self, db: &dyn db::DefDatabase) -> $loc {
151 db.$lookup(*self)
152 }
153 }
154 };
155}
156
157#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
158pub struct FunctionId(salsa::InternId);
159type FunctionLoc = AssocItemLoc<Function>;
160impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function);
161
162#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
163pub struct StructId(salsa::InternId);
164type StructLoc = ItemLoc<Struct>;
165impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct);
166
167#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
168pub struct UnionId(salsa::InternId);
169pub type UnionLoc = ItemLoc<Union>;
170impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union);
171
172#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
173pub struct EnumId(salsa::InternId);
174pub type EnumLoc = ItemLoc<Enum>;
175impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum);
176
177// FIXME: rename to `VariantId`, only enums can ave variants
178#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
179pub struct EnumVariantId {
180 pub parent: EnumId,
181 pub local_id: LocalEnumVariantId,
182}
183
184pub type LocalEnumVariantId = Idx<adt::EnumVariantData>;
185
186#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
187pub struct FieldId {
188 pub parent: VariantId,
189 pub local_id: LocalFieldId,
190}
191
192pub type LocalFieldId = Idx<adt::FieldData>;
193
194#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
195pub struct ConstId(salsa::InternId);
196type ConstLoc = AssocItemLoc<Const>;
197impl_intern!(ConstId, ConstLoc, intern_const, lookup_intern_const);
198
199#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
200pub struct StaticId(salsa::InternId);
201pub type StaticLoc = ItemLoc<Static>;
202impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static);
203
204#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
205pub struct TraitId(salsa::InternId);
206pub type TraitLoc = ItemLoc<Trait>;
207impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait);
208
209#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
210pub struct TypeAliasId(salsa::InternId);
211type TypeAliasLoc = AssocItemLoc<TypeAlias>;
212impl_intern!(TypeAliasId, TypeAliasLoc, intern_type_alias, lookup_intern_type_alias);
213
214#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
215pub struct ImplId(salsa::InternId);
216type ImplLoc = ItemLoc<Impl>;
217impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl);
218
219#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
220pub struct TypeParamId {
221 pub parent: GenericDefId,
222 pub local_id: LocalTypeParamId,
223}
224
225pub type LocalTypeParamId = Idx<generics::TypeParamData>;
226
227#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
228pub enum ContainerId {
229 ModuleId(ModuleId),
230 DefWithBodyId(DefWithBodyId),
231}
232
233#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
234pub enum AssocContainerId {
235 ContainerId(ContainerId),
236 ImplId(ImplId),
237 TraitId(TraitId),
238}
239impl_from!(ContainerId for AssocContainerId);
240
241/// A Data Type
242#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
243pub enum AdtId {
244 StructId(StructId),
245 UnionId(UnionId),
246 EnumId(EnumId),
247}
248impl_from!(StructId, UnionId, EnumId for AdtId);
249
250/// The defs which can be visible in the module.
251#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
252pub enum ModuleDefId {
253 ModuleId(ModuleId),
254 FunctionId(FunctionId),
255 AdtId(AdtId),
256 // Can't be directly declared, but can be imported.
257 EnumVariantId(EnumVariantId),
258 ConstId(ConstId),
259 StaticId(StaticId),
260 TraitId(TraitId),
261 TypeAliasId(TypeAliasId),
262 BuiltinType(BuiltinType),
263}
264impl_from!(
265 ModuleId,
266 FunctionId,
267 AdtId(StructId, EnumId, UnionId),
268 EnumVariantId,
269 ConstId,
270 StaticId,
271 TraitId,
272 TypeAliasId,
273 BuiltinType
274 for ModuleDefId
275);
276
277/// The defs which have a body.
278#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
279pub enum DefWithBodyId {
280 FunctionId(FunctionId),
281 StaticId(StaticId),
282 ConstId(ConstId),
283}
284
285impl_from!(FunctionId, ConstId, StaticId for DefWithBodyId);
286
287#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
288pub enum AssocItemId {
289 FunctionId(FunctionId),
290 ConstId(ConstId),
291 TypeAliasId(TypeAliasId),
292}
293// FIXME: not every function, ... is actually an assoc item. maybe we should make
294// sure that you can only turn actual assoc items into AssocItemIds. This would
295// require not implementing From, and instead having some checked way of
296// casting them, and somehow making the constructors private, which would be annoying.
297impl_from!(FunctionId, ConstId, TypeAliasId for AssocItemId);
298
299#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
300pub enum GenericDefId {
301 FunctionId(FunctionId),
302 AdtId(AdtId),
303 TraitId(TraitId),
304 TypeAliasId(TypeAliasId),
305 ImplId(ImplId),
306 // enum variants cannot have generics themselves, but their parent enums
307 // can, and this makes some code easier to write
308 EnumVariantId(EnumVariantId),
309 // consts can have type parameters from their parents (i.e. associated consts of traits)
310 ConstId(ConstId),
311}
312impl_from!(
313 FunctionId,
314 AdtId(StructId, EnumId, UnionId),
315 TraitId,
316 TypeAliasId,
317 ImplId,
318 EnumVariantId,
319 ConstId
320 for GenericDefId
321);
322
323impl From<AssocItemId> for GenericDefId {
324 fn from(item: AssocItemId) -> Self {
325 match item {
326 AssocItemId::FunctionId(f) => f.into(),
327 AssocItemId::ConstId(c) => c.into(),
328 AssocItemId::TypeAliasId(t) => t.into(),
329 }
330 }
331}
332
333#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
334pub enum AttrDefId {
335 ModuleId(ModuleId),
336 FieldId(FieldId),
337 AdtId(AdtId),
338 FunctionId(FunctionId),
339 EnumVariantId(EnumVariantId),
340 StaticId(StaticId),
341 ConstId(ConstId),
342 TraitId(TraitId),
343 TypeAliasId(TypeAliasId),
344 MacroDefId(MacroDefId),
345 ImplId(ImplId),
346}
347
348impl_from!(
349 ModuleId,
350 FieldId,
351 AdtId(StructId, EnumId, UnionId),
352 EnumVariantId,
353 StaticId,
354 ConstId,
355 FunctionId,
356 TraitId,
357 TypeAliasId,
358 MacroDefId,
359 ImplId
360 for AttrDefId
361);
362
363#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
364pub enum VariantId {
365 EnumVariantId(EnumVariantId),
366 StructId(StructId),
367 UnionId(UnionId),
368}
369impl_from!(EnumVariantId, StructId, UnionId for VariantId);
370
371trait Intern {
372 type ID;
373 fn intern(self, db: &dyn db::DefDatabase) -> Self::ID;
374}
375
376pub trait Lookup {
377 type Data;
378 fn lookup(&self, db: &dyn db::DefDatabase) -> Self::Data;
379}
380
381pub trait HasModule {
382 fn module(&self, db: &dyn db::DefDatabase) -> ModuleId;
383}
384
385impl HasModule for ContainerId {
386 fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
387 match *self {
388 ContainerId::ModuleId(it) => it,
389 ContainerId::DefWithBodyId(it) => it.module(db),
390 }
391 }
392}
393
394impl HasModule for AssocContainerId {
395 fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
396 match *self {
397 AssocContainerId::ContainerId(it) => it.module(db),
398 AssocContainerId::ImplId(it) => it.lookup(db).container.module(db),
399 AssocContainerId::TraitId(it) => it.lookup(db).container.module(db),
400 }
401 }
402}
403
404impl<N: ItemTreeNode> HasModule for AssocItemLoc<N> {
405 fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
406 self.container.module(db)
407 }
408}
409
410impl HasModule for AdtId {
411 fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
412 match self {
413 AdtId::StructId(it) => it.lookup(db).container,
414 AdtId::UnionId(it) => it.lookup(db).container,
415 AdtId::EnumId(it) => it.lookup(db).container,
416 }
417 .module(db)
418 }
419}
420
421impl HasModule for DefWithBodyId {
422 fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
423 match self {
424 DefWithBodyId::FunctionId(it) => it.lookup(db).module(db),
425 DefWithBodyId::StaticId(it) => it.lookup(db).module(db),
426 DefWithBodyId::ConstId(it) => it.lookup(db).module(db),
427 }
428 }
429}
430
431impl DefWithBodyId {
432 pub fn as_mod_item(self, db: &dyn db::DefDatabase) -> ModItem {
433 match self {
434 DefWithBodyId::FunctionId(it) => it.lookup(db).id.value.into(),
435 DefWithBodyId::StaticId(it) => it.lookup(db).id.value.into(),
436 DefWithBodyId::ConstId(it) => it.lookup(db).id.value.into(),
437 }
438 }
439}
440
441impl HasModule for GenericDefId {
442 fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
443 match self {
444 GenericDefId::FunctionId(it) => it.lookup(db).module(db),
445 GenericDefId::AdtId(it) => it.module(db),
446 GenericDefId::TraitId(it) => it.lookup(db).container.module(db),
447 GenericDefId::TypeAliasId(it) => it.lookup(db).module(db),
448 GenericDefId::ImplId(it) => it.lookup(db).container.module(db),
449 GenericDefId::EnumVariantId(it) => it.parent.lookup(db).container.module(db),
450 GenericDefId::ConstId(it) => it.lookup(db).module(db),
451 }
452 }
453}
454
455impl HasModule for StaticLoc {
456 fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
457 self.container.module(db)
458 }
459}
460
461/// A helper trait for converting to MacroCallId
462pub trait AsMacroCall {
463 fn as_call_id(
464 &self,
465 db: &dyn db::DefDatabase,
466 krate: CrateId,
467 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
468 ) -> Option<MacroCallId>;
469}
470
471impl AsMacroCall for InFile<&ast::MacroCall> {
472 fn as_call_id(
473 &self,
474 db: &dyn db::DefDatabase,
475 krate: CrateId,
476 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
477 ) -> Option<MacroCallId> {
478 let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value));
479 let h = Hygiene::new(db.upcast(), self.file_id);
480 let path = path::ModPath::from_src(self.value.path()?, &h)?;
481
482 AstIdWithPath::new(ast_id.file_id, ast_id.value, path).as_call_id(db, krate, resolver)
483 }
484}
485
486/// Helper wrapper for `AstId` with `ModPath`
487#[derive(Clone, Debug, Eq, PartialEq)]
488struct AstIdWithPath<T: ast::AstNode> {
489 pub ast_id: AstId<T>,
490 pub path: path::ModPath,
491}
492
493impl<T: ast::AstNode> AstIdWithPath<T> {
494 pub fn new(file_id: HirFileId, ast_id: FileAstId<T>, path: path::ModPath) -> AstIdWithPath<T> {
495 AstIdWithPath { ast_id: AstId::new(file_id, ast_id), path }
496 }
497}
498
499impl AsMacroCall for AstIdWithPath<ast::MacroCall> {
500 fn as_call_id(
501 &self,
502 db: &dyn db::DefDatabase,
503 krate: CrateId,
504 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
505 ) -> Option<MacroCallId> {
506 let def: MacroDefId = resolver(self.path.clone())?;
507
508 if let MacroDefKind::BuiltInEager(_) = def.kind {
509 let macro_call = InFile::new(self.ast_id.file_id, self.ast_id.to_node(db.upcast()));
510 let hygiene = Hygiene::new(db.upcast(), self.ast_id.file_id);
511
512 Some(
513 expand_eager_macro(db.upcast(), krate, macro_call, def, &|path: ast::Path| {
514 resolver(path::ModPath::from_src(path, &hygiene)?)
515 })?
516 .into(),
517 )
518 } else {
519 Some(def.as_lazy_macro(db.upcast(), krate, MacroCallKind::FnLike(self.ast_id)).into())
520 }
521 }
522}
523
524impl AsMacroCall for AstIdWithPath<ast::Item> {
525 fn as_call_id(
526 &self,
527 db: &dyn db::DefDatabase,
528 krate: CrateId,
529 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
530 ) -> Option<MacroCallId> {
531 let def = resolver(self.path.clone())?;
532 Some(
533 def.as_lazy_macro(
534 db.upcast(),
535 krate,
536 MacroCallKind::Attr(self.ast_id, self.path.segments.last()?.to_string()),
537 )
538 .into(),
539 )
540 }
541}