Auto merge of #14408 - Veykril:intern-block, r=Veykril

internal: Only intern blocks that declare items

We only used `BlockId` for the block defmap, so this is wasted memory. Lowering for non item declaring blocks is also cheaper now as we no longer have to fully lower a block that defines not items.
This commit is contained in:
bors 2023-03-25 19:48:04 +00:00
commit 82ec4586f1
5 changed files with 57 additions and 17 deletions

View File

@ -37,6 +37,7 @@ use crate::{
RecordFieldPat, RecordLitField, Statement,
},
item_scope::BuiltinShadowMode,
item_tree::ItemTree,
lang_item::LangItem,
path::{GenericArgs, Path},
type_ref::{Mutability, Rawness, TypeRef},
@ -888,16 +889,24 @@ impl ExprCollector<'_> {
fn collect_block_(
&mut self,
block: ast::BlockExpr,
mk_block: impl FnOnce(BlockId, Box<[Statement]>, Option<ExprId>) -> Expr,
mk_block: impl FnOnce(Option<BlockId>, Box<[Statement]>, Option<ExprId>) -> Expr,
) -> ExprId {
let file_local_id = self.ast_id_map.ast_id(&block);
let ast_id = AstId::new(self.expander.current_file_id, file_local_id);
let block_loc =
BlockLoc { ast_id, module: self.expander.def_map.module_id(self.expander.module) };
let block_id = self.db.intern_block(block_loc);
let (module, def_map) = match self.db.block_def_map(block_id) {
Some(def_map) => {
let block_id = if ItemTree::block_has_items(self.db, ast_id.file_id, &block) {
Some(self.db.intern_block(BlockLoc {
ast_id,
module: self.expander.def_map.module_id(self.expander.module),
}))
} else {
None
};
let (module, def_map) = match block_id
.and_then(|block_id| self.db.block_def_map(block_id).zip(Some(block_id)))
{
Some((def_map, block_id)) => {
self.body.block_scopes.push(block_id);
(def_map.root(), def_map)
}

View File

@ -115,15 +115,10 @@ impl ExprScopes {
fn new_block_scope(
&mut self,
parent: ScopeId,
block: BlockId,
block: Option<BlockId>,
label: Option<(LabelId, Name)>,
) -> ScopeId {
self.scopes.alloc(ScopeData {
parent: Some(parent),
block: Some(block),
label,
entries: vec![],
})
self.scopes.alloc(ScopeData { parent: Some(parent), block, label, entries: vec![] })
}
fn add_bindings(&mut self, body: &Body, scope: ScopeId, binding: BindingId) {

View File

@ -117,23 +117,23 @@ pub enum Expr {
expr: ExprId,
},
Block {
id: BlockId,
id: Option<BlockId>,
statements: Box<[Statement]>,
tail: Option<ExprId>,
label: Option<LabelId>,
},
Async {
id: BlockId,
id: Option<BlockId>,
statements: Box<[Statement]>,
tail: Option<ExprId>,
},
Const {
id: BlockId,
id: Option<BlockId>,
statements: Box<[Statement]>,
tail: Option<ExprId>,
},
Unsafe {
id: BlockId,
id: Option<BlockId>,
statements: Box<[Statement]>,
tail: Option<ExprId>,
},

View File

@ -152,6 +152,14 @@ impl ItemTree {
&self.top_level
}
pub fn block_has_items(
db: &dyn DefDatabase,
file_id: HirFileId,
block: &ast::BlockExpr,
) -> bool {
lower::Ctx::new(db, file_id).block_has_items(block)
}
/// Returns the inner attributes of the source file.
pub fn top_level_attrs(&self, db: &dyn DefDatabase, krate: CrateId) -> Attrs {
Attrs::filter(

View File

@ -101,6 +101,34 @@ impl<'a> Ctx<'a> {
self.tree
}
pub(super) fn block_has_items(mut self, block: &ast::BlockExpr) -> bool {
let statement_has_item = block
.statements()
.find_map(|stmt| match stmt {
ast::Stmt::Item(item) => self.lower_mod_item(&item),
// Macro calls can be both items and expressions. The syntax library always treats
// them as expressions here, so we undo that.
ast::Stmt::ExprStmt(es) => match es.expr()? {
ast::Expr::MacroExpr(expr) => self.lower_mod_item(&expr.macro_call()?.into()),
_ => None,
},
_ => None,
})
.is_some();
if statement_has_item {
return true;
}
if let Some(ast::Expr::MacroExpr(expr)) = block.tail_expr() {
if let Some(call) = expr.macro_call() {
if let Some(_) = self.lower_mod_item(&call.into()) {
return true;
}
}
}
false
}
fn data(&mut self) -> &mut ItemTreeData {
self.tree.data_mut()
}