aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-01-20 16:09:22 +0000
committerGitHub <[email protected]>2021-01-20 16:09:22 +0000
commite62533c3ec74358d3488e8e4b7967c78459b238f (patch)
treecd1fe4ad8f6a19b44678e1389c0c7553a6d11036 /crates
parent9d10aa09726f38d184d499c0a04f8ba4bc1c2bba (diff)
parentc5ed2284b5733dcaf8b57b1771c441afc39fa5e7 (diff)
Merge #7359
7359: ItemTree: store a mapping from blocks to inner items r=jonas-schievink a=jonas-schievink To do name resolution within block expressions, we need to know which inner items are located inside each block expression. This adds such a mapping to `ItemTree`, replacing the previous one, which was seemingly unused other than to access all the inner items. This also assigns `AstId`s to block expressions, which is needed to store the mapping in salsa. Co-authored-by: Jonas Schievink <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r--crates/hir_def/src/item_tree.rs28
-rw-r--r--crates/hir_def/src/item_tree/lower.rs33
-rw-r--r--crates/hir_expand/src/ast_id_map.rs20
3 files changed, 49 insertions, 32 deletions
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index ff62928df..6494cebd3 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -69,13 +69,12 @@ impl GenericParamsId {
69pub struct ItemTree { 69pub struct ItemTree {
70 top_level: SmallVec<[ModItem; 1]>, 70 top_level: SmallVec<[ModItem; 1]>,
71 attrs: FxHashMap<AttrOwner, RawAttrs>, 71 attrs: FxHashMap<AttrOwner, RawAttrs>,
72 inner_items: FxHashMap<FileAstId<ast::Item>, SmallVec<[ModItem; 1]>>,
73 72
74 data: Option<Box<ItemTreeData>>, 73 data: Option<Box<ItemTreeData>>,
75} 74}
76 75
77impl ItemTree { 76impl ItemTree {
78 pub fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> { 77 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)); 78 let _p = profile::span("item_tree_query").detail(|| format!("{:?}", file_id));
80 let syntax = if let Some(node) = db.parse_or_expand(file_id) { 79 let syntax = if let Some(node) = db.parse_or_expand(file_id) {
81 node 80 node
@@ -117,12 +116,7 @@ impl ItemTree {
117 } 116 }
118 117
119 fn empty() -> Self { 118 fn empty() -> Self {
120 Self { 119 Self { top_level: Default::default(), attrs: Default::default(), data: Default::default() }
121 top_level: Default::default(),
122 attrs: Default::default(),
123 inner_items: Default::default(),
124 data: Default::default(),
125 }
126 } 120 }
127 121
128 fn shrink_to_fit(&mut self) { 122 fn shrink_to_fit(&mut self) {
@@ -147,6 +141,7 @@ impl ItemTree {
147 macro_defs, 141 macro_defs,
148 vis, 142 vis,
149 generics, 143 generics,
144 inner_items,
150 } = &mut **data; 145 } = &mut **data;
151 146
152 imports.shrink_to_fit(); 147 imports.shrink_to_fit();
@@ -169,6 +164,8 @@ impl ItemTree {
169 164
170 vis.arena.shrink_to_fit(); 165 vis.arena.shrink_to_fit();
171 generics.arena.shrink_to_fit(); 166 generics.arena.shrink_to_fit();
167
168 inner_items.shrink_to_fit();
172 } 169 }
173 } 170 }
174 171
@@ -191,16 +188,11 @@ impl ItemTree {
191 self.raw_attrs(of).clone().filter(db, krate) 188 self.raw_attrs(of).clone().filter(db, krate)
192 } 189 }
193 190
194 /// Returns the lowered inner items that `ast` corresponds to.
195 ///
196 /// Most AST items are lowered to a single `ModItem`, but some (eg. `use` items) may be lowered
197 /// to multiple items in the `ItemTree`.
198 pub fn inner_items(&self, ast: FileAstId<ast::Item>) -> &[ModItem] {
199 &self.inner_items[&ast]
200 }
201
202 pub fn all_inner_items(&self) -> impl Iterator<Item = ModItem> + '_ { 191 pub fn all_inner_items(&self) -> impl Iterator<Item = ModItem> + '_ {
203 self.inner_items.values().flatten().copied() 192 match &self.data {
193 Some(data) => Some(data.inner_items.values().flatten().copied()).into_iter().flatten(),
194 None => None.into_iter().flatten(),
195 }
204 } 196 }
205 197
206 pub fn source<S: ItemTreeNode>(&self, db: &dyn DefDatabase, of: ItemTreeId<S>) -> S::Source { 198 pub fn source<S: ItemTreeNode>(&self, db: &dyn DefDatabase, of: ItemTreeId<S>) -> S::Source {
@@ -297,6 +289,8 @@ struct ItemTreeData {
297 289
298 vis: ItemVisibilities, 290 vis: ItemVisibilities,
299 generics: GenericParamsStorage, 291 generics: GenericParamsStorage,
292
293 inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>,
300} 294}
301 295
302#[derive(Debug, Eq, PartialEq, Hash)] 296#[derive(Debug, Eq, PartialEq, Hash)]
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 5e71ca42c..56fe569ff 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -6,7 +6,7 @@ use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, name::known, HirFileId}
6use smallvec::SmallVec; 6use smallvec::SmallVec;
7use syntax::{ 7use syntax::{
8 ast::{self, ModuleItemOwner}, 8 ast::{self, ModuleItemOwner},
9 SyntaxNode, 9 SyntaxNode, WalkEvent,
10}; 10};
11 11
12use crate::{ 12use crate::{
@@ -150,14 +150,29 @@ impl Ctx {
150 150
151 fn collect_inner_items(&mut self, container: &SyntaxNode) { 151 fn collect_inner_items(&mut self, container: &SyntaxNode) {
152 let forced_vis = self.forced_visibility.take(); 152 let forced_vis = self.forced_visibility.take();
153 let mut inner_items = mem::take(&mut self.tree.inner_items); 153
154 inner_items.extend(container.descendants().skip(1).filter_map(ast::Item::cast).filter_map( 154 let mut current_block = None;
155 |item| { 155 for event in container.preorder().skip(1) {
156 let ast_id = self.source_ast_id_map.ast_id(&item); 156 if let WalkEvent::Enter(node) = event {
157 Some((ast_id, self.lower_mod_item(&item, true)?.0)) 157 match_ast! {
158 }, 158 match node {
159 )); 159 ast::BlockExpr(block) => {
160 self.tree.inner_items = inner_items; 160 current_block = Some(self.source_ast_id_map.ast_id(&block));
161 },
162 ast::Item(item) => {
163 let mod_items = self.lower_mod_item(&item, true);
164 if let (Some(mod_items), Some(block)) = (mod_items, current_block) {
165 if !mod_items.0.is_empty() {
166 self.data().inner_items.entry(block).or_default().extend(mod_items.0.iter().copied());
167 }
168 }
169 },
170 _ => {}
171 }
172 }
173 }
174 }
175
161 self.forced_visibility = forced_vis; 176 self.forced_visibility = forced_vis;
162 } 177 }
163 178
diff --git a/crates/hir_expand/src/ast_id_map.rs b/crates/hir_expand/src/ast_id_map.rs
index 2401b0cc5..0991fffd8 100644
--- a/crates/hir_expand/src/ast_id_map.rs
+++ b/crates/hir_expand/src/ast_id_map.rs
@@ -13,7 +13,7 @@ use std::{
13}; 13};
14 14
15use la_arena::{Arena, Idx}; 15use la_arena::{Arena, Idx};
16use syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr}; 16use syntax::{ast, match_ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr};
17 17
18/// `AstId` points to an AST node in a specific file. 18/// `AstId` points to an AST node in a specific file.
19pub struct FileAstId<N: AstNode> { 19pub struct FileAstId<N: AstNode> {
@@ -72,12 +72,20 @@ impl AstIdMap {
72 // get lower ids then children. That is, adding a new child does not 72 // get lower ids then children. That is, adding a new child does not
73 // change parent's id. This means that, say, adding a new function to a 73 // change parent's id. This means that, say, adding a new function to a
74 // trait does not change ids of top-level items, which helps caching. 74 // trait does not change ids of top-level items, which helps caching.
75 bdfs(node, |it| match ast::Item::cast(it) { 75 bdfs(node, |it| {
76 Some(module_item) => { 76 match_ast! {
77 res.alloc(module_item.syntax()); 77 match it {
78 true 78 ast::Item(module_item) => {
79 res.alloc(module_item.syntax());
80 true
81 },
82 ast::BlockExpr(block) => {
83 res.alloc(block.syntax());
84 true
85 },
86 _ => false,
87 }
79 } 88 }
80 None => false,
81 }); 89 });
82 res 90 res
83 } 91 }