aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src/item_tree.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def/src/item_tree.rs')
-rw-r--r--crates/hir_def/src/item_tree.rs120
1 files changed, 81 insertions, 39 deletions
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index ff62928df..3233b1957 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -21,9 +21,10 @@ use hir_expand::{
21 HirFileId, InFile, 21 HirFileId, InFile,
22}; 22};
23use la_arena::{Arena, Idx, RawIdx}; 23use la_arena::{Arena, Idx, RawIdx};
24use profile::Count;
24use rustc_hash::FxHashMap; 25use rustc_hash::FxHashMap;
25use smallvec::SmallVec; 26use smallvec::SmallVec;
26use syntax::{ast, match_ast}; 27use syntax::{ast, match_ast, SyntaxKind};
27use test_utils::mark; 28use test_utils::mark;
28 29
29use crate::{ 30use crate::{
@@ -65,22 +66,27 @@ impl GenericParamsId {
65} 66}
66 67
67/// The item tree of a source file. 68/// The item tree of a source file.
68#[derive(Debug, Eq, PartialEq)] 69#[derive(Debug, Default, Eq, PartialEq)]
69pub struct ItemTree { 70pub struct ItemTree {
71 _c: Count<Self>,
72
70 top_level: SmallVec<[ModItem; 1]>, 73 top_level: SmallVec<[ModItem; 1]>,
71 attrs: FxHashMap<AttrOwner, RawAttrs>, 74 attrs: FxHashMap<AttrOwner, RawAttrs>,
72 inner_items: FxHashMap<FileAstId<ast::Item>, SmallVec<[ModItem; 1]>>,
73 75
74 data: Option<Box<ItemTreeData>>, 76 data: Option<Box<ItemTreeData>>,
75} 77}
76 78
77impl ItemTree { 79impl ItemTree {
78 pub fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> { 80 pub(crate) fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
79 let _p = profile::span("item_tree_query").detail(|| format!("{:?}", file_id)); 81 let _p = profile::span("item_tree_query").detail(|| format!("{:?}", file_id));
80 let syntax = if let Some(node) = db.parse_or_expand(file_id) { 82 let syntax = if let Some(node) = db.parse_or_expand(file_id) {
83 if node.kind() == SyntaxKind::ERROR {
84 // FIXME: not 100% sure why these crop up, but return an empty tree to avoid a panic
85 return Default::default();
86 }
81 node 87 node
82 } else { 88 } else {
83 return Arc::new(Self::empty()); 89 return Default::default();
84 }; 90 };
85 91
86 let hygiene = Hygiene::new(db.upcast(), file_id); 92 let hygiene = Hygiene::new(db.upcast(), file_id);
@@ -96,15 +102,17 @@ impl ItemTree {
96 ctx.lower_module_items(&items) 102 ctx.lower_module_items(&items)
97 }, 103 },
98 ast::MacroStmts(stmts) => { 104 ast::MacroStmts(stmts) => {
99 ctx.lower_inner_items(stmts.syntax()) 105 // The produced statements can include items, which should be added as top-level
106 // items.
107 ctx.lower_macro_stmts(stmts)
100 }, 108 },
101 // Macros can expand to expressions. We return an empty item tree in this case, but
102 // still need to collect inner items.
103 ast::Expr(e) => { 109 ast::Expr(e) => {
110 // Macros can expand to expressions. We return an empty item tree in this case, but
111 // still need to collect inner items.
104 ctx.lower_inner_items(e.syntax()) 112 ctx.lower_inner_items(e.syntax())
105 }, 113 },
106 _ => { 114 _ => {
107 panic!("cannot create item tree from {:?}", syntax); 115 panic!("cannot create item tree from {:?} {}", syntax, syntax);
108 }, 116 },
109 } 117 }
110 }; 118 };
@@ -116,15 +124,6 @@ impl ItemTree {
116 Arc::new(item_tree) 124 Arc::new(item_tree)
117 } 125 }
118 126
119 fn empty() -> Self {
120 Self {
121 top_level: Default::default(),
122 attrs: Default::default(),
123 inner_items: Default::default(),
124 data: Default::default(),
125 }
126 }
127
128 fn shrink_to_fit(&mut self) { 127 fn shrink_to_fit(&mut self) {
129 if let Some(data) = &mut self.data { 128 if let Some(data) = &mut self.data {
130 let ItemTreeData { 129 let ItemTreeData {
@@ -147,6 +146,8 @@ impl ItemTree {
147 macro_defs, 146 macro_defs,
148 vis, 147 vis,
149 generics, 148 generics,
149 type_refs,
150 inner_items,
150 } = &mut **data; 151 } = &mut **data;
151 152
152 imports.shrink_to_fit(); 153 imports.shrink_to_fit();
@@ -169,6 +170,10 @@ impl ItemTree {
169 170
170 vis.arena.shrink_to_fit(); 171 vis.arena.shrink_to_fit();
171 generics.arena.shrink_to_fit(); 172 generics.arena.shrink_to_fit();
173 type_refs.arena.shrink_to_fit();
174 type_refs.map.shrink_to_fit();
175
176 inner_items.shrink_to_fit();
172 } 177 }
173 } 178 }
174 179
@@ -191,16 +196,18 @@ impl ItemTree {
191 self.raw_attrs(of).clone().filter(db, krate) 196 self.raw_attrs(of).clone().filter(db, krate)
192 } 197 }
193 198
194 /// Returns the lowered inner items that `ast` corresponds to. 199 pub fn all_inner_items(&self) -> impl Iterator<Item = ModItem> + '_ {
195 /// 200 match &self.data {
196 /// Most AST items are lowered to a single `ModItem`, but some (eg. `use` items) may be lowered 201 Some(data) => Some(data.inner_items.values().flatten().copied()).into_iter().flatten(),
197 /// to multiple items in the `ItemTree`. 202 None => None.into_iter().flatten(),
198 pub fn inner_items(&self, ast: FileAstId<ast::Item>) -> &[ModItem] { 203 }
199 &self.inner_items[&ast]
200 } 204 }
201 205
202 pub fn all_inner_items(&self) -> impl Iterator<Item = ModItem> + '_ { 206 pub fn inner_items_of_block(&self, block: FileAstId<ast::BlockExpr>) -> &[ModItem] {
203 self.inner_items.values().flatten().copied() 207 match &self.data {
208 Some(data) => data.inner_items.get(&block).map(|it| &**it).unwrap_or(&[]),
209 None => &[],
210 }
204 } 211 }
205 212
206 pub fn source<S: ItemTreeNode>(&self, db: &dyn DefDatabase, of: ItemTreeId<S>) -> S::Source { 213 pub fn source<S: ItemTreeNode>(&self, db: &dyn DefDatabase, of: ItemTreeId<S>) -> S::Source {
@@ -233,7 +240,7 @@ impl ItemVisibilities {
233 fn alloc(&mut self, vis: RawVisibility) -> RawVisibilityId { 240 fn alloc(&mut self, vis: RawVisibility) -> RawVisibilityId {
234 match &vis { 241 match &vis {
235 RawVisibility::Public => RawVisibilityId::PUB, 242 RawVisibility::Public => RawVisibilityId::PUB,
236 RawVisibility::Module(path) if path.segments.is_empty() => match &path.kind { 243 RawVisibility::Module(path) if path.segments().is_empty() => match &path.kind {
237 PathKind::Super(0) => RawVisibilityId::PRIV, 244 PathKind::Super(0) => RawVisibilityId::PRIV,
238 PathKind::Crate => RawVisibilityId::PUB_CRATE, 245 PathKind::Crate => RawVisibilityId::PUB_CRATE,
239 _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()), 246 _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()),
@@ -244,10 +251,8 @@ impl ItemVisibilities {
244} 251}
245 252
246static VIS_PUB: RawVisibility = RawVisibility::Public; 253static VIS_PUB: RawVisibility = RawVisibility::Public;
247static VIS_PRIV: RawVisibility = 254static VIS_PRIV: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Super(0)));
248 RawVisibility::Module(ModPath { kind: PathKind::Super(0), segments: Vec::new() }); 255static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Crate));
249static VIS_PUB_CRATE: RawVisibility =
250 RawVisibility::Module(ModPath { kind: PathKind::Crate, segments: Vec::new() });
251 256
252#[derive(Default, Debug, Eq, PartialEq)] 257#[derive(Default, Debug, Eq, PartialEq)]
253struct GenericParamsStorage { 258struct GenericParamsStorage {
@@ -275,6 +280,32 @@ static EMPTY_GENERICS: GenericParams = GenericParams {
275 where_predicates: Vec::new(), 280 where_predicates: Vec::new(),
276}; 281};
277 282
283/// `TypeRef` interner.
284#[derive(Default, Debug, Eq, PartialEq)]
285struct TypeRefStorage {
286 arena: Arena<Arc<TypeRef>>,
287 map: FxHashMap<Arc<TypeRef>, Idx<Arc<TypeRef>>>,
288}
289
290impl TypeRefStorage {
291 // Note: We lie about the `Idx<TypeRef>` to hide the interner details.
292
293 fn intern(&mut self, ty: TypeRef) -> Idx<TypeRef> {
294 if let Some(id) = self.map.get(&ty) {
295 return Idx::from_raw(id.into_raw());
296 }
297
298 let ty = Arc::new(ty);
299 let idx = self.arena.alloc(ty.clone());
300 self.map.insert(ty, idx);
301 Idx::from_raw(idx.into_raw())
302 }
303
304 fn lookup(&self, id: Idx<TypeRef>) -> &TypeRef {
305 &self.arena[Idx::from_raw(id.into_raw())]
306 }
307}
308
278#[derive(Default, Debug, Eq, PartialEq)] 309#[derive(Default, Debug, Eq, PartialEq)]
279struct ItemTreeData { 310struct ItemTreeData {
280 imports: Arena<Import>, 311 imports: Arena<Import>,
@@ -297,6 +328,9 @@ struct ItemTreeData {
297 328
298 vis: ItemVisibilities, 329 vis: ItemVisibilities,
299 generics: GenericParamsStorage, 330 generics: GenericParamsStorage,
331 type_refs: TypeRefStorage,
332
333 inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>,
300} 334}
301 335
302#[derive(Debug, Eq, PartialEq, Hash)] 336#[derive(Debug, Eq, PartialEq, Hash)]
@@ -483,6 +517,14 @@ impl Index<GenericParamsId> for ItemTree {
483 } 517 }
484} 518}
485 519
520impl Index<Idx<TypeRef>> for ItemTree {
521 type Output = TypeRef;
522
523 fn index(&self, id: Idx<TypeRef>) -> &Self::Output {
524 self.data().type_refs.lookup(id)
525 }
526}
527
486impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { 528impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
487 type Output = N; 529 type Output = N;
488 fn index(&self, id: FileItemTreeId<N>) -> &N { 530 fn index(&self, id: FileItemTreeId<N>) -> &N {
@@ -526,9 +568,9 @@ pub struct Function {
526 /// Whether the function is located in an `extern` block (*not* whether it is an 568 /// Whether the function is located in an `extern` block (*not* whether it is an
527 /// `extern "abi" fn`). 569 /// `extern "abi" fn`).
528 pub is_extern: bool, 570 pub is_extern: bool,
529 pub params: Box<[TypeRef]>, 571 pub params: Box<[Idx<TypeRef>]>,
530 pub is_varargs: bool, 572 pub is_varargs: bool,
531 pub ret_type: TypeRef, 573 pub ret_type: Idx<TypeRef>,
532 pub ast_id: FileAstId<ast::Fn>, 574 pub ast_id: FileAstId<ast::Fn>,
533} 575}
534 576
@@ -575,7 +617,7 @@ pub struct Const {
575 /// const _: () = (); 617 /// const _: () = ();
576 pub name: Option<Name>, 618 pub name: Option<Name>,
577 pub visibility: RawVisibilityId, 619 pub visibility: RawVisibilityId,
578 pub type_ref: TypeRef, 620 pub type_ref: Idx<TypeRef>,
579 pub ast_id: FileAstId<ast::Const>, 621 pub ast_id: FileAstId<ast::Const>,
580} 622}
581 623
@@ -586,7 +628,7 @@ pub struct Static {
586 pub mutable: bool, 628 pub mutable: bool,
587 /// Whether the static is in an `extern` block. 629 /// Whether the static is in an `extern` block.
588 pub is_extern: bool, 630 pub is_extern: bool,
589 pub type_ref: TypeRef, 631 pub type_ref: Idx<TypeRef>,
590 pub ast_id: FileAstId<ast::Static>, 632 pub ast_id: FileAstId<ast::Static>,
591} 633}
592 634
@@ -603,8 +645,8 @@ pub struct Trait {
603#[derive(Debug, Clone, Eq, PartialEq)] 645#[derive(Debug, Clone, Eq, PartialEq)]
604pub struct Impl { 646pub struct Impl {
605 pub generic_params: GenericParamsId, 647 pub generic_params: GenericParamsId,
606 pub target_trait: Option<TypeRef>, 648 pub target_trait: Option<Idx<TypeRef>>,
607 pub target_type: TypeRef, 649 pub target_type: Idx<TypeRef>,
608 pub is_negative: bool, 650 pub is_negative: bool,
609 pub items: Box<[AssocItem]>, 651 pub items: Box<[AssocItem]>,
610 pub ast_id: FileAstId<ast::Impl>, 652 pub ast_id: FileAstId<ast::Impl>,
@@ -617,7 +659,7 @@ pub struct TypeAlias {
617 /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. 659 /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`.
618 pub bounds: Box<[TypeBound]>, 660 pub bounds: Box<[TypeBound]>,
619 pub generic_params: GenericParamsId, 661 pub generic_params: GenericParamsId,
620 pub type_ref: Option<TypeRef>, 662 pub type_ref: Option<Idx<TypeRef>>,
621 pub is_extern: bool, 663 pub is_extern: bool,
622 pub ast_id: FileAstId<ast::TypeAlias>, 664 pub ast_id: FileAstId<ast::TypeAlias>,
623} 665}
@@ -800,6 +842,6 @@ pub enum Fields {
800#[derive(Debug, Clone, PartialEq, Eq)] 842#[derive(Debug, Clone, PartialEq, Eq)]
801pub struct Field { 843pub struct Field {
802 pub name: Name, 844 pub name: Name,
803 pub type_ref: TypeRef, 845 pub type_ref: Idx<TypeRef>,
804 pub visibility: RawVisibilityId, 846 pub visibility: RawVisibilityId,
805} 847}