diff options
Diffstat (limited to 'crates/hir_def/src/item_tree.rs')
-rw-r--r-- | crates/hir_def/src/item_tree.rs | 120 |
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 | }; |
23 | use la_arena::{Arena, Idx, RawIdx}; | 23 | use la_arena::{Arena, Idx, RawIdx}; |
24 | use profile::Count; | ||
24 | use rustc_hash::FxHashMap; | 25 | use rustc_hash::FxHashMap; |
25 | use smallvec::SmallVec; | 26 | use smallvec::SmallVec; |
26 | use syntax::{ast, match_ast}; | 27 | use syntax::{ast, match_ast, SyntaxKind}; |
27 | use test_utils::mark; | 28 | use test_utils::mark; |
28 | 29 | ||
29 | use crate::{ | 30 | use 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)] |
69 | pub struct ItemTree { | 70 | pub 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 | ||
77 | impl ItemTree { | 79 | impl 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 | ||
246 | static VIS_PUB: RawVisibility = RawVisibility::Public; | 253 | static VIS_PUB: RawVisibility = RawVisibility::Public; |
247 | static VIS_PRIV: RawVisibility = | 254 | static VIS_PRIV: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Super(0))); |
248 | RawVisibility::Module(ModPath { kind: PathKind::Super(0), segments: Vec::new() }); | 255 | static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Crate)); |
249 | static 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)] |
253 | struct GenericParamsStorage { | 258 | struct 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)] | ||
285 | struct TypeRefStorage { | ||
286 | arena: Arena<Arc<TypeRef>>, | ||
287 | map: FxHashMap<Arc<TypeRef>, Idx<Arc<TypeRef>>>, | ||
288 | } | ||
289 | |||
290 | impl 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)] |
279 | struct ItemTreeData { | 310 | struct 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 | ||
520 | impl 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 | |||
486 | impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { | 528 | impl<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)] |
604 | pub struct Impl { | 646 | pub 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)] |
801 | pub struct Field { | 843 | pub 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 | } |