Unnamed repository; edit this file 'description' to name the repository.
BodyCollector
Lukas Wirth 2025-01-25
parent 6012e96 · commit 724455b
-rw-r--r--crates/hir-def/src/body.rs112
-rw-r--r--crates/hir-def/src/body/lower.rs49
-rw-r--r--crates/hir-def/src/hir.rs7
3 files changed, 91 insertions, 77 deletions
diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs
index 139e1ba896..334177751e 100644
--- a/crates/hir-def/src/body.rs
+++ b/crates/hir-def/src/body.rs
@@ -25,8 +25,8 @@ use crate::{
db::DefDatabase,
expander::Expander,
hir::{
- dummy_expr_id, Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, Label,
- LabelId, Pat, PatId, RecordFieldPat, Statement,
+ Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, Label, LabelId, Pat,
+ PatId, RecordFieldPat, Statement,
},
item_tree::AttrOwner,
nameres::DefMap,
@@ -81,7 +81,7 @@ pub struct Body {
pub body_expr: ExprId,
pub types: TypesMap,
/// Block expressions in this body that may contain inner items.
- block_scopes: Vec<BlockId>,
+ block_scopes: Box<[BlockId]>,
/// A map from binding to its hygiene ID.
///
@@ -98,6 +98,64 @@ pub struct Body {
ident_hygiene: FxHashMap<ExprOrPatId, HygieneId>,
}
+/// The body of an item (function, const etc.).
+#[derive(Debug, Eq, PartialEq, Default)]
+pub struct BodyCollector {
+ pub exprs: Arena<Expr>,
+ pub pats: Arena<Pat>,
+ pub bindings: Arena<Binding>,
+ pub labels: Arena<Label>,
+ pub binding_owners: FxHashMap<BindingId, ExprId>,
+ pub types: TypesMap,
+ block_scopes: Vec<BlockId>,
+ binding_hygiene: FxHashMap<BindingId, HygieneId>,
+ ident_hygiene: FxHashMap<ExprOrPatId, HygieneId>,
+}
+
+impl BodyCollector {
+ fn finish(
+ self,
+ body_expr: ExprId,
+ self_param: Option<BindingId>,
+ params: Box<[PatId]>,
+ ) -> Body {
+ let Self {
+ block_scopes,
+ mut exprs,
+ mut labels,
+ mut pats,
+ mut bindings,
+ mut binding_owners,
+ mut binding_hygiene,
+ mut ident_hygiene,
+ mut types,
+ } = self;
+ exprs.shrink_to_fit();
+ labels.shrink_to_fit();
+ pats.shrink_to_fit();
+ bindings.shrink_to_fit();
+ binding_owners.shrink_to_fit();
+ binding_hygiene.shrink_to_fit();
+ ident_hygiene.shrink_to_fit();
+ types.shrink_to_fit();
+
+ Body {
+ exprs,
+ pats,
+ bindings,
+ labels,
+ binding_owners,
+ params,
+ self_param,
+ body_expr,
+ types,
+ block_scopes: block_scopes.into_boxed_slice(),
+ binding_hygiene,
+ ident_hygiene,
+ }
+ }
+}
+
pub type ExprPtr = AstPtr<ast::Expr>;
pub type ExprSource = InFile<ExprPtr>;
@@ -242,9 +300,8 @@ impl Body {
};
let module = def.module(db);
let expander = Expander::new(db, file_id, module);
- let (mut body, mut source_map) =
+ let (body, mut source_map) =
Body::new(db, def, expander, params, body, module.krate, is_async_fn);
- body.shrink_to_fit();
source_map.shrink_to_fit();
(Arc::new(body), Arc::new(source_map))
@@ -304,32 +361,6 @@ impl Body {
lower::lower(db, owner, expander, params, body, krate, is_async_fn)
}
- fn shrink_to_fit(&mut self) {
- let Self {
- body_expr: _,
- params: _,
- self_param: _,
- block_scopes,
- exprs,
- labels,
- pats,
- bindings,
- binding_owners,
- binding_hygiene,
- ident_hygiene,
- types,
- } = self;
- block_scopes.shrink_to_fit();
- exprs.shrink_to_fit();
- labels.shrink_to_fit();
- pats.shrink_to_fit();
- bindings.shrink_to_fit();
- binding_owners.shrink_to_fit();
- binding_hygiene.shrink_to_fit();
- ident_hygiene.shrink_to_fit();
- types.shrink_to_fit();
- }
-
pub fn walk_bindings_in_pat(&self, pat_id: PatId, mut f: impl FnMut(BindingId)) {
self.walk_pats(pat_id, &mut |pat| {
if let Pat::Bind { id, .. } = &self[pat] {
@@ -670,25 +701,6 @@ impl Body {
}
}
-impl Default for Body {
- fn default() -> Self {
- Self {
- body_expr: dummy_expr_id(),
- exprs: Default::default(),
- pats: Default::default(),
- bindings: Default::default(),
- labels: Default::default(),
- params: Default::default(),
- block_scopes: Default::default(),
- binding_owners: Default::default(),
- self_param: Default::default(),
- binding_hygiene: Default::default(),
- ident_hygiene: Default::default(),
- types: Default::default(),
- }
- }
-}
-
impl Index<ExprId> for Body {
type Output = Expr;
diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs
index 583c6ac5e8..2b25dbdd7f 100644
--- a/crates/hir-def/src/body/lower.rs
+++ b/crates/hir-def/src/body/lower.rs
@@ -29,7 +29,9 @@ use triomphe::Arc;
use crate::{
attr::Attrs,
- body::{Body, BodyDiagnostic, BodySourceMap, ExprPtr, HygieneId, LabelPtr, PatPtr},
+ body::{
+ Body, BodyCollector, BodyDiagnostic, BodySourceMap, ExprPtr, HygieneId, LabelPtr, PatPtr,
+ },
builtin_type::BuiltinUint,
data::adt::StructKind,
db::DefDatabase,
@@ -82,7 +84,7 @@ pub(super) fn lower(
def_map: expander.module.def_map(db),
source_map: BodySourceMap::default(),
ast_id_map: db.ast_id_map(expander.current_file_id()),
- body: Body::default(),
+ body: BodyCollector::default(),
expander,
current_try_block_label: None,
is_lowering_coroutine: false,
@@ -102,7 +104,7 @@ struct ExprCollector<'a> {
def_map: Arc<DefMap>,
ast_id_map: Arc<AstIdMap>,
krate: CrateId,
- body: Body,
+ body: BodyCollector,
source_map: BodySourceMap,
is_lowering_coroutine: bool,
@@ -214,6 +216,9 @@ impl ExprCollector<'_> {
body: Option<ast::Expr>,
is_async_fn: bool,
) -> (Body, BodySourceMap) {
+ let mut self_param = None;
+ let mut params = vec![];
+
let skip_body = match self.owner {
DefWithBodyId::FunctionId(it) => self.db.attrs(it.into()),
DefWithBodyId::StaticId(it) => self.db.attrs(it.into()),
@@ -226,29 +231,32 @@ impl ExprCollector<'_> {
// If #[rust_analyzer::skip] annotated, only construct enough information for the signature
// and skip the body.
if skip_body {
- self.body.body_expr = self.missing_expr();
if let Some((param_list, mut attr_enabled)) = param_list {
- if let Some(self_param) =
+ if let Some(self_param_syn) =
param_list.self_param().filter(|_| attr_enabled.next().unwrap_or(false))
{
- let is_mutable =
- self_param.mut_token().is_some() && self_param.amp_token().is_none();
+ let is_mutable = self_param_syn.mut_token().is_some()
+ && self_param_syn.amp_token().is_none();
let binding_id: la_arena::Idx<Binding> = self.alloc_binding(
Name::new_symbol_root(sym::self_.clone()),
BindingAnnotation::new(is_mutable, false),
);
- self.body.self_param = Some(binding_id);
+ self_param = Some(binding_id);
self.source_map.self_param =
- Some(self.expander.in_file(AstPtr::new(&self_param)));
+ Some(self.expander.in_file(AstPtr::new(&self_param_syn)));
}
- self.body.params = param_list
+ params = param_list
.params()
.zip(attr_enabled)
.filter(|(_, enabled)| *enabled)
.map(|_| self.missing_pat())
.collect();
};
- return (self.body, self.source_map);
+ let body_expr = self.missing_expr();
+ return (
+ self.body.finish(body_expr, self_param, params.into_boxed_slice()),
+ self.source_map,
+ );
}
self.awaitable_context.replace(if is_async_fn {
@@ -264,25 +272,25 @@ impl ExprCollector<'_> {
}
});
if let Some((param_list, mut attr_enabled)) = param_list {
- let mut params = vec![];
- if let Some(self_param) =
+ if let Some(self_param_syn) =
param_list.self_param().filter(|_| attr_enabled.next().unwrap_or(false))
{
let is_mutable =
- self_param.mut_token().is_some() && self_param.amp_token().is_none();
+ self_param_syn.mut_token().is_some() && self_param_syn.amp_token().is_none();
let binding_id: la_arena::Idx<Binding> = self.alloc_binding(
Name::new_symbol_root(sym::self_.clone()),
BindingAnnotation::new(is_mutable, false),
);
- let hygiene = self_param
+ let hygiene = self_param_syn
.name()
.map(|name| self.hygiene_id_for(name.syntax().text_range().start()))
.unwrap_or(HygieneId::ROOT);
if !hygiene.is_root() {
self.body.binding_hygiene.insert(binding_id, hygiene);
}
- self.body.self_param = Some(binding_id);
- self.source_map.self_param = Some(self.expander.in_file(AstPtr::new(&self_param)));
+ self_param = Some(binding_id);
+ self.source_map.self_param =
+ Some(self.expander.in_file(AstPtr::new(&self_param_syn)));
}
for (param, _) in param_list.params().zip(attr_enabled).filter(|(_, enabled)| *enabled)
@@ -290,9 +298,8 @@ impl ExprCollector<'_> {
let param_pat = self.collect_pat_top(param.pat());
params.push(param_pat);
}
- self.body.params = params.into_boxed_slice();
};
- self.body.body_expr = self.with_label_rib(RibKind::Closure, |this| {
+ let body_expr = self.with_label_rib(RibKind::Closure, |this| {
if is_async_fn {
match body {
Some(e) => {
@@ -310,7 +317,7 @@ impl ExprCollector<'_> {
}
});
- (self.body, self.source_map)
+ (self.body.finish(body_expr, self_param, params.into_boxed_slice()), self.source_map)
}
fn ctx(&mut self) -> LowerCtx<'_> {
@@ -1934,7 +1941,7 @@ impl ExprCollector<'_> {
f: impl FnOnce(&mut Self) -> T,
) -> T {
self.label_ribs.push(LabelRib::new(RibKind::Normal(
- self.body[label].name.clone(),
+ self.body.labels[label].name.clone(),
label,
hygiene,
)));
diff --git a/crates/hir-def/src/hir.rs b/crates/hir-def/src/hir.rs
index 9392e8d12d..0dcddf162b 100644
--- a/crates/hir-def/src/hir.rs
+++ b/crates/hir-def/src/hir.rs
@@ -19,7 +19,7 @@ use std::fmt;
use hir_expand::{name::Name, MacroDefId};
use intern::Symbol;
-use la_arena::{Idx, RawIdx};
+use la_arena::Idx;
use rustc_apfloat::ieee::{Half as f16, Quad as f128};
use syntax::ast;
use type_ref::TypeRefId;
@@ -37,11 +37,6 @@ pub type BindingId = Idx<Binding>;
pub type ExprId = Idx<Expr>;
-/// FIXME: this is a hacky function which should be removed
-pub(crate) fn dummy_expr_id() -> ExprId {
- ExprId::from_raw(RawIdx::from(u32::MAX))
-}
-
pub type PatId = Idx<Pat>;
// FIXME: Encode this as a single u32, we won't ever reach all 32 bits especially given these counts