Skip to content

Commit 3bb6f50

Browse files
Build per-block ItemTrees
1 parent 91cb422 commit 3bb6f50

File tree

5 files changed

+57
-177
lines changed

5 files changed

+57
-177
lines changed

crates/hir_def/src/body/tests/block.rs

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,11 @@ fn f() {
148148
}
149149
"#,
150150
expect![[r#"
151-
BlockId(1) in ModuleId { krate: CrateId(0), block: Some(BlockId(0)), local_id: Idx::<ModuleData>(0) }
151+
BlockId(1) in ModuleId { krate: CrateId(0), block: Some(BlockId(0)), local_id: Idx::<ModuleData>(1) }
152152
BlockId(0) in ModuleId { krate: CrateId(0), block: None, local_id: Idx::<ModuleData>(0) }
153153
crate scope
154154
"#]],
155155
);
156-
// FIXME: The module nesting here is wrong!
157-
// The first block map should be located in module #1 (`mod module`), not #0 (BlockId(0) root module)
158156
}
159157

160158
#[test]
@@ -352,25 +350,18 @@ fn is_visible_from_same_def_map() {
352350
check_at(
353351
r#"
354352
fn outer() {
355-
mod command {
356-
use crate::name;
357-
}
358-
359353
mod tests {
360354
use super::*;
361355
}
356+
use crate::name;
362357
$0
363358
}
364359
"#,
365360
expect![[r#"
366361
block scope
367-
command: t
368362
name: _
369363
tests: t
370364
371-
block scope::command
372-
name: _
373-
374365
block scope::tests
375366
name: _
376367
outer: v
@@ -379,6 +370,4 @@ fn outer() {
379370
outer: v
380371
"#]],
381372
);
382-
// FIXME: `name` should not be visible in the block scope. This happens because ItemTrees store
383-
// inner items incorrectly.
384373
}

crates/hir_def/src/item_tree.rs

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -132,21 +132,6 @@ impl ItemTree {
132132
// items.
133133
ctx.lower_macro_stmts(stmts)
134134
},
135-
ast::Pat(_pat) => {
136-
// FIXME: This occurs because macros in pattern position are treated as inner
137-
// items and expanded during block DefMap computation
138-
return Default::default();
139-
},
140-
ast::Type(ty) => {
141-
// Types can contain inner items. We return an empty item tree in this case, but
142-
// still need to collect inner items.
143-
ctx.lower_inner_items(ty.syntax())
144-
},
145-
ast::Expr(e) => {
146-
// Macros can expand to expressions. We return an empty item tree in this case, but
147-
// still need to collect inner items.
148-
ctx.lower_inner_items(e.syntax())
149-
},
150135
_ => {
151136
panic!("cannot create item tree from {:?} {}", syntax, syntax);
152137
},
@@ -160,6 +145,14 @@ impl ItemTree {
160145
Arc::new(item_tree)
161146
}
162147

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+
163156
fn shrink_to_fit(&mut self) {
164157
if let Some(data) = &mut self.data {
165158
let ItemTreeData {
@@ -183,7 +176,6 @@ impl ItemTree {
183176
macro_rules,
184177
macro_defs,
185178
vis,
186-
inner_items,
187179
} = &mut **data;
188180

189181
imports.shrink_to_fit();
@@ -207,8 +199,6 @@ impl ItemTree {
207199
macro_defs.shrink_to_fit();
208200

209201
vis.arena.shrink_to_fit();
210-
211-
inner_items.shrink_to_fit();
212202
}
213203
}
214204

@@ -231,13 +221,6 @@ impl ItemTree {
231221
self.raw_attrs(of).clone().filter(db, krate)
232222
}
233223

234-
pub fn inner_items_of_block(&self, block: FileAstId<ast::BlockExpr>) -> &[ModItem] {
235-
match &self.data {
236-
Some(data) => data.inner_items.get(&block).map(|it| &**it).unwrap_or(&[]),
237-
None => &[],
238-
}
239-
}
240-
241224
pub fn pretty_print(&self) -> String {
242225
pretty::print_item_tree(self)
243226
}
@@ -297,8 +280,6 @@ struct ItemTreeData {
297280
macro_defs: Arena<MacroDef>,
298281

299282
vis: ItemVisibilities,
300-
301-
inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>,
302283
}
303284

304285
#[derive(Debug, Eq, PartialEq, Hash)]
@@ -388,14 +369,18 @@ impl TreeId {
388369

389370
pub(crate) fn item_tree(&self, db: &dyn DefDatabase) -> Arc<ItemTree> {
390371
match self.block {
391-
Some(_) => unreachable!("per-block ItemTrees are not yet implemented"),
372+
Some(block) => ItemTree::block_item_tree(db, block),
392373
None => db.file_item_tree(self.file),
393374
}
394375
}
395376

396377
pub(crate) fn file_id(self) -> HirFileId {
397378
self.file
398379
}
380+
381+
pub(crate) fn is_block(self) -> bool {
382+
self.block.is_some()
383+
}
399384
}
400385

401386
#[derive(Debug)]

crates/hir_def/src/item_tree/lower.rs

Lines changed: 22 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@
33
use std::{collections::hash_map::Entry, mem, sync::Arc};
44

55
use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, name::known, HirFileId};
6-
use syntax::{
7-
ast::{self, HasModuleItem},
8-
SyntaxNode, WalkEvent,
9-
};
6+
use syntax::ast::{self, HasModuleItem};
107

118
use crate::{
129
generics::{GenericParams, TypeParamData, TypeParamProvenance},
@@ -42,7 +39,7 @@ impl<'a> Ctx<'a> {
4239

4340
pub(super) fn lower_module_items(mut self, item_owner: &dyn HasModuleItem) -> ItemTree {
4441
self.tree.top_level =
45-
item_owner.items().flat_map(|item| self.lower_mod_item(&item, false)).collect();
42+
item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect();
4643
self.tree
4744
}
4845

@@ -62,63 +59,35 @@ impl<'a> Ctx<'a> {
6259
},
6360
_ => None,
6461
})
65-
.flat_map(|item| self.lower_mod_item(&item, false))
62+
.flat_map(|item| self.lower_mod_item(&item))
6663
.collect();
6764

68-
// Non-items need to have their inner items collected.
69-
for stmt in stmts.statements() {
70-
match stmt {
71-
ast::Stmt::ExprStmt(_) | ast::Stmt::LetStmt(_) => {
72-
self.collect_inner_items(stmt.syntax())
73-
}
74-
_ => {}
75-
}
76-
}
77-
if let Some(expr) = stmts.expr() {
78-
self.collect_inner_items(expr.syntax());
79-
}
8065
self.tree
8166
}
8267

83-
pub(super) fn lower_inner_items(mut self, within: &SyntaxNode) -> ItemTree {
84-
self.collect_inner_items(within);
68+
pub(super) fn lower_block(mut self, block: &ast::BlockExpr) -> ItemTree {
69+
self.tree.top_level = block
70+
.statements()
71+
.filter_map(|stmt| match stmt {
72+
ast::Stmt::Item(item) => self.lower_mod_item(&item),
73+
// Macro calls can be both items and expressions. The syntax library always treats
74+
// them as expressions here, so we undo that.
75+
ast::Stmt::ExprStmt(es) => match es.expr()? {
76+
ast::Expr::MacroCall(call) => self.lower_mod_item(&call.into()),
77+
_ => None,
78+
},
79+
_ => None,
80+
})
81+
.collect();
82+
8583
self.tree
8684
}
8785

8886
fn data(&mut self) -> &mut ItemTreeData {
8987
self.tree.data_mut()
9088
}
9189

92-
fn lower_mod_item(&mut self, item: &ast::Item, inner: bool) -> Option<ModItem> {
93-
// Collect inner items for 1-to-1-lowered items.
94-
match item {
95-
ast::Item::Struct(_)
96-
| ast::Item::Union(_)
97-
| ast::Item::Enum(_)
98-
| ast::Item::Fn(_)
99-
| ast::Item::TypeAlias(_)
100-
| ast::Item::Const(_)
101-
| ast::Item::Static(_) => {
102-
// Skip this if we're already collecting inner items. We'll descend into all nodes
103-
// already.
104-
if !inner {
105-
self.collect_inner_items(item.syntax());
106-
}
107-
}
108-
109-
// These are handled in their respective `lower_X` method (since we can't just blindly
110-
// walk them).
111-
ast::Item::Trait(_) | ast::Item::Impl(_) | ast::Item::ExternBlock(_) => {}
112-
113-
// These don't have inner items.
114-
ast::Item::Module(_)
115-
| ast::Item::ExternCrate(_)
116-
| ast::Item::Use(_)
117-
| ast::Item::MacroCall(_)
118-
| ast::Item::MacroRules(_)
119-
| ast::Item::MacroDef(_) => {}
120-
};
121-
90+
fn lower_mod_item(&mut self, item: &ast::Item) -> Option<ModItem> {
12291
let attrs = RawAttrs::new(self.db, item, &self.hygiene);
12392
let item: ModItem = match item {
12493
ast::Item::Struct(ast) => self.lower_struct(ast)?.into(),
@@ -155,47 +124,6 @@ impl<'a> Ctx<'a> {
155124
}
156125
}
157126

158-
fn collect_inner_items(&mut self, container: &SyntaxNode) {
159-
let forced_vis = self.forced_visibility.take();
160-
161-
let mut block_stack = Vec::new();
162-
163-
// if container itself is block, add it to the stack
164-
if let Some(block) = ast::BlockExpr::cast(container.clone()) {
165-
block_stack.push(self.source_ast_id_map.ast_id(&block));
166-
}
167-
168-
for event in container.preorder().skip(1) {
169-
match event {
170-
WalkEvent::Enter(node) => {
171-
match_ast! {
172-
match node {
173-
ast::BlockExpr(block) => {
174-
block_stack.push(self.source_ast_id_map.ast_id(&block));
175-
},
176-
ast::Item(item) => {
177-
// FIXME: This triggers for macro calls in expression/pattern/type position
178-
let mod_item = self.lower_mod_item(&item, true);
179-
let current_block = block_stack.last();
180-
if let (Some(mod_item), Some(block)) = (mod_item, current_block) {
181-
self.data().inner_items.entry(*block).or_default().push(mod_item);
182-
}
183-
},
184-
_ => {}
185-
}
186-
}
187-
}
188-
WalkEvent::Leave(node) => {
189-
if ast::BlockExpr::cast(node).is_some() {
190-
block_stack.pop();
191-
}
192-
}
193-
}
194-
}
195-
196-
self.forced_visibility = forced_vis;
197-
}
198-
199127
fn lower_assoc_item(&mut self, item: &ast::AssocItem) -> Option<AssocItem> {
200128
match item {
201129
ast::AssocItem::Fn(ast) => self.lower_function(ast).map(Into::into),
@@ -470,9 +398,7 @@ impl<'a> Ctx<'a> {
470398
ModKind::Inline {
471399
items: module
472400
.item_list()
473-
.map(|list| {
474-
list.items().flat_map(|item| self.lower_mod_item(&item, false)).collect()
475-
})
401+
.map(|list| list.items().flat_map(|item| self.lower_mod_item(&item)).collect())
476402
.unwrap_or_else(|| {
477403
cov_mark::hit!(name_res_works_for_broken_modules);
478404
Box::new([]) as Box<[_]>
@@ -487,8 +413,7 @@ impl<'a> Ctx<'a> {
487413
fn lower_trait(&mut self, trait_def: &ast::Trait) -> Option<FileItemTreeId<Trait>> {
488414
let name = trait_def.name()?.as_name();
489415
let visibility = self.lower_visibility(trait_def);
490-
let generic_params =
491-
self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def);
416+
let generic_params = self.lower_generic_params(GenericsOwner::Trait(trait_def), trait_def);
492417
let is_auto = trait_def.auto_token().is_some();
493418
let is_unsafe = trait_def.unsafe_token().is_some();
494419
let items = trait_def.assoc_item_list().map(|list| {
@@ -497,7 +422,6 @@ impl<'a> Ctx<'a> {
497422
list.assoc_items()
498423
.filter_map(|item| {
499424
let attrs = RawAttrs::new(db, &item, &this.hygiene);
500-
this.collect_inner_items(item.syntax());
501425
this.lower_assoc_item(&item).map(|item| {
502426
this.add_attrs(ModItem::from(item).into(), attrs);
503427
item
@@ -520,8 +444,7 @@ impl<'a> Ctx<'a> {
520444
}
521445

522446
fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option<FileItemTreeId<Impl>> {
523-
let generic_params =
524-
self.lower_generic_params_and_inner_items(GenericsOwner::Impl, impl_def);
447+
let generic_params = self.lower_generic_params(GenericsOwner::Impl, impl_def);
525448
// FIXME: If trait lowering fails, due to a non PathType for example, we treat this impl
526449
// as if it was an non-trait impl. Ideally we want to create a unique missing ref that only
527450
// equals itself.
@@ -535,7 +458,6 @@ impl<'a> Ctx<'a> {
535458
.into_iter()
536459
.flat_map(|it| it.assoc_items())
537460
.filter_map(|item| {
538-
self.collect_inner_items(item.syntax());
539461
let assoc = self.lower_assoc_item(&item)?;
540462
let attrs = RawAttrs::new(self.db, &item, &self.hygiene);
541463
self.add_attrs(ModItem::from(assoc).into(), attrs);
@@ -603,7 +525,6 @@ impl<'a> Ctx<'a> {
603525
let children: Box<[_]> = block.extern_item_list().map_or(Box::new([]), |list| {
604526
list.extern_items()
605527
.filter_map(|item| {
606-
self.collect_inner_items(item.syntax());
607528
let attrs = RawAttrs::new(self.db, &item, &self.hygiene);
608529
let id: ModItem = match item {
609530
ast::ExternItem::Fn(ast) => {
@@ -641,23 +562,6 @@ impl<'a> Ctx<'a> {
641562
id(self.data().extern_blocks.alloc(res))
642563
}
643564

644-
/// Lowers generics defined on `node` and collects inner items defined within.
645-
fn lower_generic_params_and_inner_items(
646-
&mut self,
647-
owner: GenericsOwner<'_>,
648-
node: &dyn ast::HasGenericParams,
649-
) -> Interned<GenericParams> {
650-
// Generics are part of item headers and may contain inner items we need to collect.
651-
if let Some(params) = node.generic_param_list() {
652-
self.collect_inner_items(params.syntax());
653-
}
654-
if let Some(clause) = node.where_clause() {
655-
self.collect_inner_items(clause.syntax());
656-
}
657-
658-
self.lower_generic_params(owner, node)
659-
}
660-
661565
fn lower_generic_params(
662566
&mut self,
663567
owner: GenericsOwner<'_>,

0 commit comments

Comments
 (0)