]> git.lizzy.rs Git - rust.git/blob - crates/hir_def/src/item_tree.rs
Merge #10863
[rust.git] / crates / hir_def / src / item_tree.rs
1 //! A simplified AST that only contains items.
2 //!
3 //! This is the primary IR used throughout `hir_def`. It is the input to the name resolution
4 //! algorithm, as well as to the queries defined in `adt.rs`, `data.rs`, and most things in
5 //! `attr.rs`.
6 //!
7 //! `ItemTree`s are built per `HirFileId`, from the syntax tree of the parsed file. This means that
8 //! they are crate-independent: they don't know which `#[cfg]`s are active or which module they
9 //! belong to, since those concepts don't exist at this level (a single `ItemTree` might be part of
10 //! multiple crates, or might be included into the same crate twice via `#[path]`).
11 //!
12 //! One important purpose of this layer is to provide an "invalidation barrier" for incremental
13 //! computations: when typing inside an item body, the `ItemTree` of the modified file is typically
14 //! unaffected, so we don't have to recompute name resolution results or item data (see `data.rs`).
15 //!
16 //! The `ItemTree` for the currently open file can be displayed by using the VS Code command
17 //! "Rust Analyzer: Debug ItemTree".
18 //!
19 //! Compared to rustc's architecture, `ItemTree` has properties from both rustc's AST and HIR: many
20 //! syntax-level Rust features are already desugared to simpler forms in the `ItemTree`, but name
21 //! resolution has not yet been performed. `ItemTree`s are per-file, while rustc's AST and HIR are
22 //! per-crate, because we are interested in incrementally computing it.
23 //!
24 //! The representation of items in the `ItemTree` should generally mirror the surface syntax: it is
25 //! usually a bad idea to desugar a syntax-level construct to something that is structurally
26 //! different here. Name resolution needs to be able to process attributes and expand macros
27 //! (including attribute macros), and having a 1-to-1 mapping between syntax and the `ItemTree`
28 //! avoids introducing subtle bugs.
29 //!
30 //! In general, any item in the `ItemTree` stores its `AstId`, which allows mapping it back to its
31 //! surface syntax.
32
33 mod lower;
34 mod pretty;
35 #[cfg(test)]
36 mod tests;
37
38 use std::{
39     fmt::{self, Debug},
40     hash::{Hash, Hasher},
41     marker::PhantomData,
42     ops::Index,
43     sync::Arc,
44 };
45
46 use ast::{AstNode, HasName, StructKind};
47 use base_db::CrateId;
48 use either::Either;
49 use hir_expand::{
50     ast_id_map::FileAstId,
51     hygiene::Hygiene,
52     name::{name, AsName, Name},
53     ExpandTo, HirFileId, InFile,
54 };
55 use la_arena::{Arena, Idx, IdxRange, RawIdx};
56 use profile::Count;
57 use rustc_hash::FxHashMap;
58 use smallvec::SmallVec;
59 use syntax::{ast, match_ast, SyntaxKind};
60
61 use crate::{
62     attr::{Attrs, RawAttrs},
63     db::DefDatabase,
64     generics::GenericParams,
65     intern::Interned,
66     path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind},
67     type_ref::{Mutability, TraitRef, TypeBound, TypeRef},
68     visibility::RawVisibility,
69     BlockId,
70 };
71
72 #[derive(Copy, Clone, Eq, PartialEq)]
73 pub struct RawVisibilityId(u32);
74
75 impl RawVisibilityId {
76     pub const PUB: Self = RawVisibilityId(u32::max_value());
77     pub const PRIV: Self = RawVisibilityId(u32::max_value() - 1);
78     pub const PUB_CRATE: Self = RawVisibilityId(u32::max_value() - 2);
79 }
80
81 impl fmt::Debug for RawVisibilityId {
82     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83         let mut f = f.debug_tuple("RawVisibilityId");
84         match *self {
85             Self::PUB => f.field(&"pub"),
86             Self::PRIV => f.field(&"pub(self)"),
87             Self::PUB_CRATE => f.field(&"pub(crate)"),
88             _ => f.field(&self.0),
89         };
90         f.finish()
91     }
92 }
93
94 /// The item tree of a source file.
95 #[derive(Debug, Default, Eq, PartialEq)]
96 pub struct ItemTree {
97     _c: Count<Self>,
98
99     top_level: SmallVec<[ModItem; 1]>,
100     attrs: FxHashMap<AttrOwner, RawAttrs>,
101
102     data: Option<Box<ItemTreeData>>,
103 }
104
105 impl ItemTree {
106     pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
107         let _p = profile::span("item_tree_query").detail(|| format!("{:?}", file_id));
108         let syntax = if let Some(node) = db.parse_or_expand(file_id) {
109             if node.kind() == SyntaxKind::ERROR {
110                 // FIXME: not 100% sure why these crop up, but return an empty tree to avoid a panic
111                 return Default::default();
112             }
113             node
114         } else {
115             return Default::default();
116         };
117
118         let hygiene = Hygiene::new(db.upcast(), file_id);
119         let ctx = lower::Ctx::new(db, hygiene.clone(), file_id);
120         let mut top_attrs = None;
121         let mut item_tree = match_ast! {
122             match syntax {
123                 ast::SourceFile(file) => {
124                     top_attrs = Some(RawAttrs::new(db, &file, &hygiene));
125                     ctx.lower_module_items(&file)
126                 },
127                 ast::MacroItems(items) => {
128                     ctx.lower_module_items(&items)
129                 },
130                 ast::MacroStmts(stmts) => {
131                     // The produced statements can include items, which should be added as top-level
132                     // items.
133                     ctx.lower_macro_stmts(stmts)
134                 },
135                 _ => {
136                     panic!("cannot create item tree from {:?} {}", syntax, syntax);
137                 },
138             }
139         };
140
141         if let Some(attrs) = top_attrs {
142             item_tree.attrs.insert(AttrOwner::TopLevel, attrs);
143         }
144         item_tree.shrink_to_fit();
145         Arc::new(item_tree)
146     }
147
148     fn block_item_tree(db: &dyn DefDatabase, block: BlockId) -> Arc<ItemTree> {
149         let loc = db.lookup_intern_block(block);
150         let block = loc.ast_id.to_node(db.upcast());
151         let hygiene = Hygiene::new(db.upcast(), loc.ast_id.file_id);
152         let ctx = lower::Ctx::new(db, hygiene.clone(), loc.ast_id.file_id);
153         Arc::new(ctx.lower_block(&block))
154     }
155
156     fn shrink_to_fit(&mut self) {
157         if let Some(data) = &mut self.data {
158             let ItemTreeData {
159                 imports,
160                 extern_crates,
161                 extern_blocks,
162                 functions,
163                 params,
164                 structs,
165                 fields,
166                 unions,
167                 enums,
168                 variants,
169                 consts,
170                 statics,
171                 traits,
172                 impls,
173                 type_aliases,
174                 mods,
175                 macro_calls,
176                 macro_rules,
177                 macro_defs,
178                 vis,
179             } = &mut **data;
180
181             imports.shrink_to_fit();
182             extern_crates.shrink_to_fit();
183             extern_blocks.shrink_to_fit();
184             functions.shrink_to_fit();
185             params.shrink_to_fit();
186             structs.shrink_to_fit();
187             fields.shrink_to_fit();
188             unions.shrink_to_fit();
189             enums.shrink_to_fit();
190             variants.shrink_to_fit();
191             consts.shrink_to_fit();
192             statics.shrink_to_fit();
193             traits.shrink_to_fit();
194             impls.shrink_to_fit();
195             type_aliases.shrink_to_fit();
196             mods.shrink_to_fit();
197             macro_calls.shrink_to_fit();
198             macro_rules.shrink_to_fit();
199             macro_defs.shrink_to_fit();
200
201             vis.arena.shrink_to_fit();
202         }
203     }
204
205     /// Returns an iterator over all items located at the top level of the `HirFileId` this
206     /// `ItemTree` was created from.
207     pub fn top_level_items(&self) -> &[ModItem] {
208         &self.top_level
209     }
210
211     /// Returns the inner attributes of the source file.
212     pub fn top_level_attrs(&self, db: &dyn DefDatabase, krate: CrateId) -> Attrs {
213         self.attrs.get(&AttrOwner::TopLevel).unwrap_or(&RawAttrs::EMPTY).clone().filter(db, krate)
214     }
215
216     pub(crate) fn raw_attrs(&self, of: AttrOwner) -> &RawAttrs {
217         self.attrs.get(&of).unwrap_or(&RawAttrs::EMPTY)
218     }
219
220     pub fn attrs(&self, db: &dyn DefDatabase, krate: CrateId, of: AttrOwner) -> Attrs {
221         self.raw_attrs(of).clone().filter(db, krate)
222     }
223
224     pub fn pretty_print(&self) -> String {
225         pretty::print_item_tree(self)
226     }
227
228     fn data(&self) -> &ItemTreeData {
229         self.data.as_ref().expect("attempted to access data of empty ItemTree")
230     }
231
232     fn data_mut(&mut self) -> &mut ItemTreeData {
233         self.data.get_or_insert_with(Box::default)
234     }
235 }
236
237 #[derive(Default, Debug, Eq, PartialEq)]
238 struct ItemVisibilities {
239     arena: Arena<RawVisibility>,
240 }
241
242 impl ItemVisibilities {
243     fn alloc(&mut self, vis: RawVisibility) -> RawVisibilityId {
244         match &vis {
245             RawVisibility::Public => RawVisibilityId::PUB,
246             RawVisibility::Module(path) if path.segments().is_empty() => match &path.kind {
247                 PathKind::Super(0) => RawVisibilityId::PRIV,
248                 PathKind::Crate => RawVisibilityId::PUB_CRATE,
249                 _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()),
250             },
251             _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()),
252         }
253     }
254 }
255
256 static VIS_PUB: RawVisibility = RawVisibility::Public;
257 static VIS_PRIV: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Super(0)));
258 static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Crate));
259
260 #[derive(Default, Debug, Eq, PartialEq)]
261 struct ItemTreeData {
262     imports: Arena<Import>,
263     extern_crates: Arena<ExternCrate>,
264     extern_blocks: Arena<ExternBlock>,
265     functions: Arena<Function>,
266     params: Arena<Param>,
267     structs: Arena<Struct>,
268     fields: Arena<Field>,
269     unions: Arena<Union>,
270     enums: Arena<Enum>,
271     variants: Arena<Variant>,
272     consts: Arena<Const>,
273     statics: Arena<Static>,
274     traits: Arena<Trait>,
275     impls: Arena<Impl>,
276     type_aliases: Arena<TypeAlias>,
277     mods: Arena<Mod>,
278     macro_calls: Arena<MacroCall>,
279     macro_rules: Arena<MacroRules>,
280     macro_defs: Arena<MacroDef>,
281
282     vis: ItemVisibilities,
283 }
284
285 #[derive(Debug, Eq, PartialEq, Hash)]
286 pub enum AttrOwner {
287     /// Attributes on an item.
288     ModItem(ModItem),
289     /// Inner attributes of the source file.
290     TopLevel,
291
292     Variant(Idx<Variant>),
293     Field(Idx<Field>),
294     Param(Idx<Param>),
295 }
296
297 macro_rules! from_attrs {
298     ( $( $var:ident($t:ty) ),+ ) => {
299         $(
300             impl From<$t> for AttrOwner {
301                 fn from(t: $t) -> AttrOwner {
302                     AttrOwner::$var(t)
303                 }
304             }
305         )+
306     };
307 }
308
309 from_attrs!(ModItem(ModItem), Variant(Idx<Variant>), Field(Idx<Field>), Param(Idx<Param>));
310
311 /// Trait implemented by all item nodes in the item tree.
312 pub trait ItemTreeNode: Clone {
313     type Source: AstNode + Into<ast::Item>;
314
315     fn ast_id(&self) -> FileAstId<Self::Source>;
316
317     /// Looks up an instance of `Self` in an item tree.
318     fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self;
319
320     /// Downcasts a `ModItem` to a `FileItemTreeId` specific to this type.
321     fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>>;
322
323     /// Upcasts a `FileItemTreeId` to a generic `ModItem`.
324     fn id_to_mod_item(id: FileItemTreeId<Self>) -> ModItem;
325 }
326
327 pub struct FileItemTreeId<N: ItemTreeNode> {
328     index: Idx<N>,
329     _p: PhantomData<N>,
330 }
331
332 impl<N: ItemTreeNode> Clone for FileItemTreeId<N> {
333     fn clone(&self) -> Self {
334         Self { index: self.index, _p: PhantomData }
335     }
336 }
337 impl<N: ItemTreeNode> Copy for FileItemTreeId<N> {}
338
339 impl<N: ItemTreeNode> PartialEq for FileItemTreeId<N> {
340     fn eq(&self, other: &FileItemTreeId<N>) -> bool {
341         self.index == other.index
342     }
343 }
344 impl<N: ItemTreeNode> Eq for FileItemTreeId<N> {}
345
346 impl<N: ItemTreeNode> Hash for FileItemTreeId<N> {
347     fn hash<H: Hasher>(&self, state: &mut H) {
348         self.index.hash(state)
349     }
350 }
351
352 impl<N: ItemTreeNode> fmt::Debug for FileItemTreeId<N> {
353     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
354         self.index.fmt(f)
355     }
356 }
357
358 /// Identifies a particular [`ItemTree`].
359 #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
360 pub struct TreeId {
361     file: HirFileId,
362     block: Option<BlockId>,
363 }
364
365 impl TreeId {
366     pub(crate) fn new(file: HirFileId, block: Option<BlockId>) -> Self {
367         Self { file, block }
368     }
369
370     pub(crate) fn item_tree(&self, db: &dyn DefDatabase) -> Arc<ItemTree> {
371         match self.block {
372             Some(block) => ItemTree::block_item_tree(db, block),
373             None => db.file_item_tree(self.file),
374         }
375     }
376
377     pub(crate) fn file_id(self) -> HirFileId {
378         self.file
379     }
380
381     pub(crate) fn is_block(self) -> bool {
382         self.block.is_some()
383     }
384 }
385
386 #[derive(Debug)]
387 pub struct ItemTreeId<N: ItemTreeNode> {
388     tree: TreeId,
389     pub value: FileItemTreeId<N>,
390 }
391
392 impl<N: ItemTreeNode> ItemTreeId<N> {
393     pub fn new(tree: TreeId, idx: FileItemTreeId<N>) -> Self {
394         Self { tree, value: idx }
395     }
396
397     pub fn file_id(self) -> HirFileId {
398         self.tree.file
399     }
400
401     pub fn tree_id(self) -> TreeId {
402         self.tree
403     }
404
405     pub fn item_tree(self, db: &dyn DefDatabase) -> Arc<ItemTree> {
406         self.tree.item_tree(db)
407     }
408 }
409
410 impl<N: ItemTreeNode> Copy for ItemTreeId<N> {}
411 impl<N: ItemTreeNode> Clone for ItemTreeId<N> {
412     fn clone(&self) -> Self {
413         *self
414     }
415 }
416
417 impl<N: ItemTreeNode> PartialEq for ItemTreeId<N> {
418     fn eq(&self, other: &Self) -> bool {
419         self.tree == other.tree && self.value == other.value
420     }
421 }
422
423 impl<N: ItemTreeNode> Eq for ItemTreeId<N> {}
424
425 impl<N: ItemTreeNode> Hash for ItemTreeId<N> {
426     fn hash<H: Hasher>(&self, state: &mut H) {
427         self.tree.hash(state);
428         self.value.hash(state);
429     }
430 }
431
432 macro_rules! mod_items {
433     ( $( $typ:ident in $fld:ident -> $ast:ty ),+ $(,)? ) => {
434         #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
435         pub enum ModItem {
436             $(
437                 $typ(FileItemTreeId<$typ>),
438             )+
439         }
440
441         $(
442             impl From<FileItemTreeId<$typ>> for ModItem {
443                 fn from(id: FileItemTreeId<$typ>) -> ModItem {
444                     ModItem::$typ(id)
445                 }
446             }
447         )+
448
449         $(
450             impl ItemTreeNode for $typ {
451                 type Source = $ast;
452
453                 fn ast_id(&self) -> FileAstId<Self::Source> {
454                     self.ast_id
455                 }
456
457                 fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self {
458                     &tree.data().$fld[index]
459                 }
460
461                 fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>> {
462                     match mod_item {
463                         ModItem::$typ(id) => Some(id),
464                         _ => None,
465                     }
466                 }
467
468                 fn id_to_mod_item(id: FileItemTreeId<Self>) -> ModItem {
469                     ModItem::$typ(id)
470                 }
471             }
472
473             impl Index<Idx<$typ>> for ItemTree {
474                 type Output = $typ;
475
476                 fn index(&self, index: Idx<$typ>) -> &Self::Output {
477                     &self.data().$fld[index]
478                 }
479             }
480         )+
481     };
482 }
483
484 mod_items! {
485     Import in imports -> ast::Use,
486     ExternCrate in extern_crates -> ast::ExternCrate,
487     ExternBlock in extern_blocks -> ast::ExternBlock,
488     Function in functions -> ast::Fn,
489     Struct in structs -> ast::Struct,
490     Union in unions -> ast::Union,
491     Enum in enums -> ast::Enum,
492     Const in consts -> ast::Const,
493     Static in statics -> ast::Static,
494     Trait in traits -> ast::Trait,
495     Impl in impls -> ast::Impl,
496     TypeAlias in type_aliases -> ast::TypeAlias,
497     Mod in mods -> ast::Module,
498     MacroCall in macro_calls -> ast::MacroCall,
499     MacroRules in macro_rules -> ast::MacroRules,
500     MacroDef in macro_defs -> ast::MacroDef,
501 }
502
503 macro_rules! impl_index {
504     ( $($fld:ident: $t:ty),+ $(,)? ) => {
505         $(
506             impl Index<Idx<$t>> for ItemTree {
507                 type Output = $t;
508
509                 fn index(&self, index: Idx<$t>) -> &Self::Output {
510                     &self.data().$fld[index]
511                 }
512             }
513         )+
514     };
515 }
516
517 impl_index!(fields: Field, variants: Variant, params: Param);
518
519 impl Index<RawVisibilityId> for ItemTree {
520     type Output = RawVisibility;
521     fn index(&self, index: RawVisibilityId) -> &Self::Output {
522         match index {
523             RawVisibilityId::PRIV => &VIS_PRIV,
524             RawVisibilityId::PUB => &VIS_PUB,
525             RawVisibilityId::PUB_CRATE => &VIS_PUB_CRATE,
526             _ => &self.data().vis.arena[Idx::from_raw(index.0.into())],
527         }
528     }
529 }
530
531 impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
532     type Output = N;
533     fn index(&self, id: FileItemTreeId<N>) -> &N {
534         N::lookup(self, id.index)
535     }
536 }
537
538 #[derive(Debug, Clone, Eq, PartialEq)]
539 pub struct Import {
540     pub visibility: RawVisibilityId,
541     pub ast_id: FileAstId<ast::Use>,
542     pub use_tree: UseTree,
543 }
544
545 #[derive(Debug, Clone, Eq, PartialEq)]
546 pub struct UseTree {
547     pub index: Idx<ast::UseTree>,
548     kind: UseTreeKind,
549 }
550
551 #[derive(Debug, Clone, Eq, PartialEq)]
552 pub enum UseTreeKind {
553     /// ```
554     /// use path::to::Item;
555     /// use path::to::Item as Renamed;
556     /// use path::to::Trait as _;
557     /// ```
558     Single { path: Interned<ModPath>, alias: Option<ImportAlias> },
559
560     /// ```
561     /// use *;  // (invalid, but can occur in nested tree)
562     /// use path::*;
563     /// ```
564     Glob { path: Option<Interned<ModPath>> },
565
566     /// ```
567     /// use prefix::{self, Item, ...};
568     /// ```
569     Prefixed { prefix: Option<Interned<ModPath>>, list: Box<[UseTree]> },
570 }
571
572 #[derive(Debug, Clone, Eq, PartialEq)]
573 pub struct ExternCrate {
574     pub name: Name,
575     pub alias: Option<ImportAlias>,
576     pub visibility: RawVisibilityId,
577     pub ast_id: FileAstId<ast::ExternCrate>,
578 }
579
580 #[derive(Debug, Clone, Eq, PartialEq)]
581 pub struct ExternBlock {
582     pub abi: Option<Interned<str>>,
583     pub ast_id: FileAstId<ast::ExternBlock>,
584     pub children: Box<[ModItem]>,
585 }
586
587 #[derive(Debug, Clone, Eq, PartialEq)]
588 pub struct Function {
589     pub name: Name,
590     pub visibility: RawVisibilityId,
591     pub explicit_generic_params: Interned<GenericParams>,
592     pub abi: Option<Interned<str>>,
593     pub params: IdxRange<Param>,
594     pub ret_type: Interned<TypeRef>,
595     pub async_ret_type: Option<Interned<TypeRef>>,
596     pub ast_id: FileAstId<ast::Fn>,
597     pub(crate) flags: FnFlags,
598 }
599
600 #[derive(Debug, Clone, Eq, PartialEq)]
601 pub enum Param {
602     Normal(Interned<TypeRef>),
603     Varargs,
604 }
605
606 #[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
607 pub(crate) struct FnFlags {
608     pub(crate) bits: u8,
609 }
610 impl FnFlags {
611     pub(crate) const HAS_SELF_PARAM: u8 = 1 << 0;
612     pub(crate) const HAS_BODY: u8 = 1 << 1;
613     pub(crate) const IS_DEFAULT: u8 = 1 << 2;
614     pub(crate) const IS_CONST: u8 = 1 << 3;
615     pub(crate) const IS_ASYNC: u8 = 1 << 4;
616     pub(crate) const IS_UNSAFE: u8 = 1 << 5;
617     /// Whether the function is located in an `extern` block (*not* whether it is an
618     /// `extern "abi" fn`).
619     pub(crate) const IS_IN_EXTERN_BLOCK: u8 = 1 << 6;
620     pub(crate) const IS_VARARGS: u8 = 1 << 7;
621 }
622
623 #[derive(Debug, Clone, Eq, PartialEq)]
624 pub struct Struct {
625     pub name: Name,
626     pub visibility: RawVisibilityId,
627     pub generic_params: Interned<GenericParams>,
628     pub fields: Fields,
629     pub ast_id: FileAstId<ast::Struct>,
630 }
631
632 #[derive(Debug, Clone, Eq, PartialEq)]
633 pub struct Union {
634     pub name: Name,
635     pub visibility: RawVisibilityId,
636     pub generic_params: Interned<GenericParams>,
637     pub fields: Fields,
638     pub ast_id: FileAstId<ast::Union>,
639 }
640
641 #[derive(Debug, Clone, Eq, PartialEq)]
642 pub struct Enum {
643     pub name: Name,
644     pub visibility: RawVisibilityId,
645     pub generic_params: Interned<GenericParams>,
646     pub variants: IdxRange<Variant>,
647     pub ast_id: FileAstId<ast::Enum>,
648 }
649
650 #[derive(Debug, Clone, Eq, PartialEq)]
651 pub struct Const {
652     /// const _: () = ();
653     pub name: Option<Name>,
654     pub visibility: RawVisibilityId,
655     pub type_ref: Interned<TypeRef>,
656     pub ast_id: FileAstId<ast::Const>,
657 }
658
659 #[derive(Debug, Clone, Eq, PartialEq)]
660 pub struct Static {
661     pub name: Name,
662     pub visibility: RawVisibilityId,
663     pub mutable: bool,
664     /// Whether the static is in an `extern` block.
665     pub is_extern: bool,
666     pub type_ref: Interned<TypeRef>,
667     pub ast_id: FileAstId<ast::Static>,
668 }
669
670 #[derive(Debug, Clone, Eq, PartialEq)]
671 pub struct Trait {
672     pub name: Name,
673     pub visibility: RawVisibilityId,
674     pub generic_params: Interned<GenericParams>,
675     pub is_auto: bool,
676     pub is_unsafe: bool,
677     pub items: Box<[AssocItem]>,
678     pub ast_id: FileAstId<ast::Trait>,
679 }
680
681 #[derive(Debug, Clone, Eq, PartialEq)]
682 pub struct Impl {
683     pub generic_params: Interned<GenericParams>,
684     pub target_trait: Option<Interned<TraitRef>>,
685     pub self_ty: Interned<TypeRef>,
686     pub is_negative: bool,
687     pub items: Box<[AssocItem]>,
688     pub ast_id: FileAstId<ast::Impl>,
689 }
690
691 #[derive(Debug, Clone, PartialEq, Eq)]
692 pub struct TypeAlias {
693     pub name: Name,
694     pub visibility: RawVisibilityId,
695     /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`.
696     pub bounds: Box<[Interned<TypeBound>]>,
697     pub generic_params: Interned<GenericParams>,
698     pub type_ref: Option<Interned<TypeRef>>,
699     pub is_extern: bool,
700     pub ast_id: FileAstId<ast::TypeAlias>,
701 }
702
703 #[derive(Debug, Clone, Eq, PartialEq)]
704 pub struct Mod {
705     pub name: Name,
706     pub visibility: RawVisibilityId,
707     pub kind: ModKind,
708     pub ast_id: FileAstId<ast::Module>,
709 }
710
711 #[derive(Debug, Clone, Eq, PartialEq)]
712 pub enum ModKind {
713     /// `mod m { ... }`
714     Inline { items: Box<[ModItem]> },
715
716     /// `mod m;`
717     Outline {},
718 }
719
720 #[derive(Debug, Clone, Eq, PartialEq)]
721 pub struct MacroCall {
722     /// Path to the called macro.
723     pub path: Interned<ModPath>,
724     pub ast_id: FileAstId<ast::MacroCall>,
725     pub expand_to: ExpandTo,
726 }
727
728 #[derive(Debug, Clone, Eq, PartialEq)]
729 pub struct MacroRules {
730     /// The name of the declared macro.
731     pub name: Name,
732     pub ast_id: FileAstId<ast::MacroRules>,
733 }
734
735 /// "Macros 2.0" macro definition.
736 #[derive(Debug, Clone, Eq, PartialEq)]
737 pub struct MacroDef {
738     pub name: Name,
739     pub visibility: RawVisibilityId,
740     pub ast_id: FileAstId<ast::MacroDef>,
741 }
742
743 impl Import {
744     /// Maps a `UseTree` contained in this import back to its AST node.
745     pub fn use_tree_to_ast(
746         &self,
747         db: &dyn DefDatabase,
748         file_id: HirFileId,
749         index: Idx<ast::UseTree>,
750     ) -> ast::UseTree {
751         // Re-lower the AST item and get the source map.
752         // Note: The AST unwraps are fine, since if they fail we should have never obtained `index`.
753         let ast = InFile::new(file_id, self.ast_id).to_node(db.upcast());
754         let ast_use_tree = ast.use_tree().expect("missing `use_tree`");
755         let hygiene = Hygiene::new(db.upcast(), file_id);
756         let (_, source_map) =
757             lower::lower_use_tree(db, &hygiene, ast_use_tree).expect("failed to lower use tree");
758         source_map[index].clone()
759     }
760 }
761
762 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
763 pub enum ImportKind {
764     /// The `ModPath` is imported normally.
765     Plain,
766     /// This is a glob-import of all names in the `ModPath`.
767     Glob,
768     /// This is a `some::path::self` import, which imports `some::path` only in type namespace.
769     TypeOnly,
770 }
771
772 impl UseTree {
773     /// Expands the `UseTree` into individually imported `ModPath`s.
774     pub fn expand(
775         &self,
776         mut cb: impl FnMut(Idx<ast::UseTree>, ModPath, ImportKind, Option<ImportAlias>),
777     ) {
778         self.expand_impl(None, &mut cb)
779     }
780
781     fn expand_impl(
782         &self,
783         prefix: Option<ModPath>,
784         cb: &mut dyn FnMut(Idx<ast::UseTree>, ModPath, ImportKind, Option<ImportAlias>),
785     ) {
786         fn concat_mod_paths(
787             prefix: Option<ModPath>,
788             path: &ModPath,
789         ) -> Option<(ModPath, ImportKind)> {
790             match (prefix, &path.kind) {
791                 (None, _) => Some((path.clone(), ImportKind::Plain)),
792                 (Some(mut prefix), PathKind::Plain) => {
793                     for segment in path.segments() {
794                         prefix.push_segment(segment.clone());
795                     }
796                     Some((prefix, ImportKind::Plain))
797                 }
798                 (Some(prefix), PathKind::Super(0)) => {
799                     // `some::path::self` == `some::path`
800                     if path.segments().is_empty() {
801                         Some((prefix, ImportKind::TypeOnly))
802                     } else {
803                         None
804                     }
805                 }
806                 (Some(_), _) => None,
807             }
808         }
809
810         match &self.kind {
811             UseTreeKind::Single { path, alias } => {
812                 if let Some((path, kind)) = concat_mod_paths(prefix, path) {
813                     cb(self.index, path, kind, alias.clone());
814                 }
815             }
816             UseTreeKind::Glob { path: Some(path) } => {
817                 if let Some((path, _)) = concat_mod_paths(prefix, path) {
818                     cb(self.index, path, ImportKind::Glob, None);
819                 }
820             }
821             UseTreeKind::Glob { path: None } => {
822                 if let Some(prefix) = prefix {
823                     cb(self.index, prefix, ImportKind::Glob, None);
824                 }
825             }
826             UseTreeKind::Prefixed { prefix: additional_prefix, list } => {
827                 let prefix = match additional_prefix {
828                     Some(path) => match concat_mod_paths(prefix, path) {
829                         Some((path, ImportKind::Plain)) => Some(path),
830                         _ => return,
831                     },
832                     None => prefix,
833                 };
834                 for tree in &**list {
835                     tree.expand_impl(prefix.clone(), cb);
836                 }
837             }
838         }
839     }
840 }
841
842 macro_rules! impl_froms {
843     ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => {
844         $(
845             impl From<$t> for $e {
846                 fn from(it: $t) -> $e {
847                     $e::$v(it)
848                 }
849             }
850         )*
851     }
852 }
853
854 impl ModItem {
855     pub fn as_assoc_item(&self) -> Option<AssocItem> {
856         match self {
857             ModItem::Import(_)
858             | ModItem::ExternCrate(_)
859             | ModItem::ExternBlock(_)
860             | ModItem::Struct(_)
861             | ModItem::Union(_)
862             | ModItem::Enum(_)
863             | ModItem::Static(_)
864             | ModItem::Trait(_)
865             | ModItem::Impl(_)
866             | ModItem::Mod(_)
867             | ModItem::MacroRules(_)
868             | ModItem::MacroDef(_) => None,
869             ModItem::MacroCall(call) => Some(AssocItem::MacroCall(*call)),
870             ModItem::Const(konst) => Some(AssocItem::Const(*konst)),
871             ModItem::TypeAlias(alias) => Some(AssocItem::TypeAlias(*alias)),
872             ModItem::Function(func) => Some(AssocItem::Function(*func)),
873         }
874     }
875
876     pub fn downcast<N: ItemTreeNode>(self) -> Option<FileItemTreeId<N>> {
877         N::id_from_mod_item(self)
878     }
879
880     pub fn ast_id(&self, tree: &ItemTree) -> FileAstId<ast::Item> {
881         match self {
882             ModItem::Import(it) => tree[it.index].ast_id().upcast(),
883             ModItem::ExternCrate(it) => tree[it.index].ast_id().upcast(),
884             ModItem::ExternBlock(it) => tree[it.index].ast_id().upcast(),
885             ModItem::Function(it) => tree[it.index].ast_id().upcast(),
886             ModItem::Struct(it) => tree[it.index].ast_id().upcast(),
887             ModItem::Union(it) => tree[it.index].ast_id().upcast(),
888             ModItem::Enum(it) => tree[it.index].ast_id().upcast(),
889             ModItem::Const(it) => tree[it.index].ast_id().upcast(),
890             ModItem::Static(it) => tree[it.index].ast_id().upcast(),
891             ModItem::Trait(it) => tree[it.index].ast_id().upcast(),
892             ModItem::Impl(it) => tree[it.index].ast_id().upcast(),
893             ModItem::TypeAlias(it) => tree[it.index].ast_id().upcast(),
894             ModItem::Mod(it) => tree[it.index].ast_id().upcast(),
895             ModItem::MacroCall(it) => tree[it.index].ast_id().upcast(),
896             ModItem::MacroRules(it) => tree[it.index].ast_id().upcast(),
897             ModItem::MacroDef(it) => tree[it.index].ast_id().upcast(),
898         }
899     }
900 }
901
902 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
903 pub enum AssocItem {
904     Function(FileItemTreeId<Function>),
905     TypeAlias(FileItemTreeId<TypeAlias>),
906     Const(FileItemTreeId<Const>),
907     MacroCall(FileItemTreeId<MacroCall>),
908 }
909
910 impl_froms!(AssocItem {
911     Function(FileItemTreeId<Function>),
912     TypeAlias(FileItemTreeId<TypeAlias>),
913     Const(FileItemTreeId<Const>),
914     MacroCall(FileItemTreeId<MacroCall>),
915 });
916
917 impl From<AssocItem> for ModItem {
918     fn from(item: AssocItem) -> Self {
919         match item {
920             AssocItem::Function(it) => it.into(),
921             AssocItem::TypeAlias(it) => it.into(),
922             AssocItem::Const(it) => it.into(),
923             AssocItem::MacroCall(it) => it.into(),
924         }
925     }
926 }
927
928 #[derive(Debug, Eq, PartialEq)]
929 pub struct Variant {
930     pub name: Name,
931     pub fields: Fields,
932 }
933
934 #[derive(Debug, Clone, PartialEq, Eq)]
935 pub enum Fields {
936     Record(IdxRange<Field>),
937     Tuple(IdxRange<Field>),
938     Unit,
939 }
940
941 /// A single field of an enum variant or struct
942 #[derive(Debug, Clone, PartialEq, Eq)]
943 pub struct Field {
944     pub name: Name,
945     pub type_ref: Interned<TypeRef>,
946     pub visibility: RawVisibilityId,
947 }