Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/mir/lower.rs')
-rw-r--r--crates/hir-ty/src/mir/lower.rs166
1 files changed, 101 insertions, 65 deletions
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index 199db7a3e7..44785d948a 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -4,16 +4,17 @@ use std::{fmt::Write, iter, mem};
use base_db::Crate;
use hir_def::{
- AdtId, DefWithBodyId, EnumVariantId, GeneralConstId, GenericParamId, HasModule,
- ItemContainerId, LocalFieldId, Lookup, TraitId, TupleId,
+ AdtId, DefWithBodyId, EnumVariantId, ExpressionStoreOwnerId, GeneralConstId, GenericParamId,
+ HasModule, ItemContainerId, LocalFieldId, Lookup, TraitId, TupleId,
expr_store::{Body, ExpressionStore, HygieneId, path::Path},
hir::{
ArithOp, Array, BinaryOp, BindingAnnotation, BindingId, ExprId, LabelId, Literal, MatchArm,
- Pat, PatId, RecordFieldPat, RecordLitField, RecordSpread,
+ Pat, PatId, RecordFieldPat, RecordLitField, RecordSpread, generics::GenericParams,
},
item_tree::FieldsShape,
lang_item::LangItems,
resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs},
+ signatures::{ConstSignature, EnumSignature, FunctionSignature, StaticSignature},
};
use hir_expand::name::Name;
use la_arena::ArenaMap;
@@ -82,7 +83,7 @@ struct MirLowerCtx<'a, 'db> {
labeled_loop_blocks: FxHashMap<LabelId, LoopBlocks>,
discr_temp: Option<Place>,
db: &'db dyn HirDatabase,
- body: &'a Body,
+ store: &'a ExpressionStore,
infer: &'a InferenceResult,
types: &'db crate::next_solver::DefaultAny<'db>,
resolver: Resolver<'db>,
@@ -185,7 +186,7 @@ impl MirLowerError {
}
}
MirLowerError::MissingFunctionDefinition(owner, it) => {
- let body = db.body(*owner);
+ let body = Body::of(db, *owner);
writeln!(
f,
"Missing function definition for {}",
@@ -202,13 +203,13 @@ impl MirLowerError {
MirLowerError::GenericArgNotProvided(id, subst) => {
let param_name = match *id {
GenericParamId::TypeParamId(id) => {
- db.generic_params(id.parent())[id.local_id()].name().cloned()
+ GenericParams::of(db, id.parent())[id.local_id()].name().cloned()
}
GenericParamId::ConstParamId(id) => {
- db.generic_params(id.parent())[id.local_id()].name().cloned()
+ GenericParams::of(db, id.parent())[id.local_id()].name().cloned()
}
GenericParamId::LifetimeParamId(id) => {
- Some(db.generic_params(id.parent)[id.local_id].name.clone())
+ Some(GenericParams::of(db, id.parent)[id.local_id].name.clone())
}
};
writeln!(
@@ -285,7 +286,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
fn new(
db: &'db dyn HirDatabase,
owner: DefWithBodyId,
- body: &'a Body,
+ store: &'a ExpressionStore,
infer: &'a InferenceResult,
) -> Self {
let mut basic_blocks = Arena::new();
@@ -307,7 +308,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
closures: vec![],
};
let resolver = owner.resolver(db);
- let env = db.trait_environment_for_body(owner);
+ let env = db.trait_environment(ExpressionStoreOwnerId::from(owner));
let interner = DbInterner::new_with(db, resolver.krate());
// FIXME(next-solver): Is `non_body_analysis()` correct here? Don't we want to reveal opaque types defined by this body?
let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis());
@@ -316,7 +317,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
result: mir,
db,
infer,
- body,
+ store,
types: crate::next_solver::default_types(db),
owner,
resolver,
@@ -354,7 +355,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
current: BasicBlockId,
) -> Result<'db, Option<(Operand, BasicBlockId)>> {
if !self.has_adjustments(expr_id)
- && let Expr::Literal(l) = &self.body[expr_id]
+ && let Expr::Literal(l) = &self.store[expr_id]
{
let ty = self.expr_ty_without_adjust(expr_id);
return Ok(Some((self.lower_literal_to_operand(ty, l)?, current)));
@@ -461,7 +462,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
place: Place,
mut current: BasicBlockId,
) -> Result<'db, Option<BasicBlockId>> {
- match &self.body[expr_id] {
+ match &self.store[expr_id] {
Expr::OffsetOf(_) => {
not_supported!("builtin#offset_of")
}
@@ -472,7 +473,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
if let DefWithBodyId::FunctionId(f) = self.owner {
let assoc = f.lookup(self.db);
if let ItemContainerId::TraitId(t) = assoc.container {
- let name = &self.db.function_signature(f).name;
+ let name = &FunctionSignature::of(self.db, f).name;
return Err(MirLowerError::TraitFunctionDefinition(t, name.clone()));
}
}
@@ -500,7 +501,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
} else {
let resolver_guard =
self.resolver.update_to_inner_scope(self.db, self.owner, expr_id);
- let hygiene = self.body.expr_path_hygiene(expr_id);
+ let hygiene = self.store.expr_path_hygiene(expr_id);
let result = self
.resolver
.resolve_path_in_value_ns_fully(self.db, p, hygiene)
@@ -509,7 +510,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
self.db,
p,
DisplayTarget::from_crate(self.db, self.krate()),
- self.body,
+ self.store,
)
})?;
self.resolver.reset_to_guard(resolver_guard);
@@ -882,7 +883,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
let variant_id =
self.infer.variant_resolution_for_expr(expr_id).ok_or_else(|| match path {
Some(p) => MirLowerError::UnresolvedName(
- hir_display_with_store(&**p, self.body)
+ hir_display_with_store(&**p, self.store)
.display(self.db, self.display_target())
.to_string(),
),
@@ -1382,7 +1383,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
}
fn push_field_projection(&mut self, place: &mut Place, expr_id: ExprId) -> Result<'db, ()> {
- if let Expr::Field { expr, name } = &self.body[expr_id] {
+ if let Expr::Field { expr, name } = &self.store[expr_id] {
if let TyKind::Tuple(..) = self.expr_ty_after_adjustments(*expr).kind() {
let index =
name.as_tuple_index().ok_or(MirLowerError::TypeError("named field on tuple"))?
@@ -1411,7 +1412,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
ty: Ty<'db>,
loc: &ExprId,
) -> Result<'db, Operand> {
- match &self.body[*loc] {
+ match &self.store[*loc] {
Expr::Literal(l) => self.lower_literal_to_operand(ty, l),
Expr::Path(c) => {
let owner = self.owner;
@@ -1421,7 +1422,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
self.db,
c,
DisplayTarget::from_crate(db, owner.krate(db)),
- self.body,
+ self.store,
)
};
let pr = self
@@ -1429,7 +1430,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
.resolve_path_in_value_ns(self.db, c, HygieneId::ROOT)
.ok_or_else(unresolved_name)?;
match pr {
- ResolveValueResult::ValueNs(v, _) => {
+ ResolveValueResult::ValueNs(v) => {
if let ValueNs::ConstId(c) = v {
self.lower_const_to_operand(
GenericArgs::empty(self.interner()),
@@ -1439,7 +1440,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
not_supported!("bad path in range pattern");
}
}
- ResolveValueResult::Partial(_, _, _) => {
+ ResolveValueResult::Partial(_, _) => {
not_supported!("associated constants in range pattern")
}
}
@@ -1546,6 +1547,9 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
MirLowerError::ConstEvalError(name.into(), Box::new(e))
})?
}
+ GeneralConstId::AnonConstId(_) => {
+ return Err(MirLowerError::IncompleteExpr);
+ }
}
};
let ty = self
@@ -1553,6 +1557,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
.value_ty(match const_id {
GeneralConstId::ConstId(id) => id.into(),
GeneralConstId::StaticId(id) => id.into(),
+ GeneralConstId::AnonConstId(_) => unreachable!("handled above"),
})
.unwrap()
.instantiate(self.interner(), subst);
@@ -1859,7 +1864,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
}
} else {
let mut err = None;
- self.body.walk_bindings_in_pat(*pat, |b| {
+ self.store.walk_bindings_in_pat(*pat, |b| {
if let Err(e) = self.push_storage_live(b, current) {
err = Some(e);
}
@@ -1913,9 +1918,9 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
self.result.param_locals.extend(params.clone().map(|(it, ty)| {
let local_id = self.result.locals.alloc(Local { ty: ty.store() });
self.drop_scopes.last_mut().unwrap().locals.push(local_id);
- if let Pat::Bind { id, subpat: None } = self.body[it]
+ if let Pat::Bind { id, subpat: None } = self.store[it]
&& matches!(
- self.body[id].mode,
+ self.store[id].mode,
BindingAnnotation::Unannotated | BindingAnnotation::Mutable
)
{
@@ -1924,7 +1929,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
local_id
}));
// and then rest of bindings
- for (id, _) in self.body.bindings() {
+ for (id, _) in self.store.bindings() {
if !pick_binding(id) {
continue;
}
@@ -1953,7 +1958,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
.into_iter()
.skip(base_param_count + self_binding.is_some() as usize);
for ((param, _), local) in params.zip(local_params) {
- if let Pat::Bind { id, .. } = self.body[param]
+ if let Pat::Bind { id, .. } = self.store[param]
&& local == self.binding_local(id)?
{
continue;
@@ -1989,7 +1994,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
let loc = variant.lookup(db);
let name = format!(
"{}::{}",
- self.db.enum_signature(loc.parent).name.display(db, edition),
+ EnumSignature::of(db, loc.parent).name.display(db, edition),
loc.parent
.enum_variants(self.db)
.variant_name_by_id(variant)
@@ -2106,8 +2111,10 @@ pub fn mir_body_for_closure_query<'db>(
closure: InternedClosureId,
) -> Result<'db, Arc<MirBody>> {
let InternedClosure(owner, expr) = db.lookup_intern_closure(closure);
- let body = db.body(owner);
- let infer = InferenceResult::for_body(db, owner);
+ let body_owner =
+ owner.as_def_with_body().expect("MIR lowering should only happen for body-owned closures");
+ let body = Body::of(db, body_owner);
+ let infer = InferenceResult::of(db, body_owner);
let Expr::Closure { args, body: root, .. } = &body[expr] else {
implementation_error!("closure expression is not closure");
};
@@ -2115,7 +2122,7 @@ pub fn mir_body_for_closure_query<'db>(
implementation_error!("closure expression is not closure");
};
let (captures, kind) = infer.closure_info(closure);
- let mut ctx = MirLowerCtx::new(db, owner, &body, infer);
+ let mut ctx = MirLowerCtx::new(db, body_owner, &body.store, infer);
// 0 is return local
ctx.result.locals.alloc(Local { ty: infer.expr_ty(*root).store() });
let closure_local = ctx.result.locals.alloc(Local {
@@ -2138,7 +2145,7 @@ pub fn mir_body_for_closure_query<'db>(
});
ctx.result.param_locals.push(closure_local);
let sig = ctx.interner().signature_unclosure(substs.as_closure().sig(), Safety::Safe);
- let resolver_guard = ctx.resolver.update_to_inner_scope(db, owner, expr);
+ let resolver_guard = ctx.resolver.update_to_inner_scope(db, body_owner, expr);
let current = ctx.lower_params_and_bindings(
args.iter().zip(sig.skip_binder().inputs().iter()).map(|(it, y)| (*it, *y)),
None,
@@ -2205,7 +2212,7 @@ pub fn mir_body_for_closure_query<'db>(
.result
.binding_locals
.into_iter()
- .filter(|it| ctx.body.binding_owner(it.0) == Some(expr))
+ .filter(|it| ctx.store.binding_owner(it.0) == Some(expr))
.collect();
if let Some(err) = err {
return Err(MirLowerError::UnresolvedUpvar(err));
@@ -2222,13 +2229,12 @@ pub fn mir_body_query<'db>(
let edition = krate.data(db).edition;
let detail = match def {
DefWithBodyId::FunctionId(it) => {
- db.function_signature(it).name.display(db, edition).to_string()
+ FunctionSignature::of(db, it).name.display(db, edition).to_string()
}
DefWithBodyId::StaticId(it) => {
- db.static_signature(it).name.display(db, edition).to_string()
+ StaticSignature::of(db, it).name.display(db, edition).to_string()
}
- DefWithBodyId::ConstId(it) => db
- .const_signature(it)
+ DefWithBodyId::ConstId(it) => ConstSignature::of(db, it)
.name
.clone()
.unwrap_or_else(Name::missing)
@@ -2243,9 +2249,9 @@ pub fn mir_body_query<'db>(
}
};
let _p = tracing::info_span!("mir_body_query", ?detail).entered();
- let body = db.body(def);
- let infer = InferenceResult::for_body(db, def);
- let mut result = lower_to_mir(db, def, &body, infer, body.body_expr)?;
+ let body = Body::of(db, def);
+ let infer = InferenceResult::of(db, def);
+ let mut result = lower_body_to_mir(db, def, body, infer, body.root_expr())?;
result.shrink_to_fit();
Ok(Arc::new(result))
}
@@ -2258,44 +2264,74 @@ pub(crate) fn mir_body_cycle_result<'db>(
Err(MirLowerError::Loop)
}
-pub fn lower_to_mir<'db>(
+/// Extracts params from `body.params`/`body.self_param` and the callable signature,
+/// then delegates to [`lower_to_mir_with_store`].
+pub fn lower_body_to_mir<'db>(
db: &'db dyn HirDatabase,
owner: DefWithBodyId,
body: &Body,
infer: &InferenceResult,
- // FIXME: root_expr should always be the body.body_expr, but since `X` in `[(); X]` doesn't have its own specific body yet, we
- // need to take this input explicitly.
+ // FIXME: root_expr should always be the body.body_expr,
+ // but this is currently also used for `X` in `[(); X]` which live in the same expression store
root_expr: ExprId,
) -> Result<'db, MirBody> {
+ let is_root = root_expr == body.root_expr();
+ // Extract params and self_param only when lowering the body's root expression for a function.
+ if is_root && let DefWithBodyId::FunctionId(fid) = owner {
+ let callable_sig =
+ db.callable_item_signature(fid.into()).instantiate_identity().skip_binder();
+ let mut param_tys = callable_sig.inputs().iter().copied();
+ let self_param = body.self_param.and_then(|id| Some((id, param_tys.next()?)));
+
+ lower_to_mir_with_store(
+ db,
+ owner,
+ &body.store,
+ infer,
+ root_expr,
+ body.params.iter().copied().zip(param_tys),
+ self_param,
+ is_root,
+ )
+ } else {
+ lower_to_mir_with_store(
+ db,
+ owner,
+ &body.store,
+ infer,
+ root_expr,
+ iter::empty(),
+ None,
+ is_root,
+ )
+ }
+}
+
+/// # Parameters
+/// - `is_root`: `true` when `root_expr` is the body's top-level expression (picks
+/// bindings with no owner); `false` when lowering an inline const or anonymous
+/// const (picks bindings owned by `root_expr`).
+pub fn lower_to_mir_with_store<'db>(
+ db: &'db dyn HirDatabase,
+ owner: DefWithBodyId,
+ store: &ExpressionStore,
+ infer: &InferenceResult,
+ root_expr: ExprId,
+ params: impl Iterator<Item = (PatId, Ty<'db>)> + Clone,
+ self_param: Option<(BindingId, Ty<'db>)>,
+ is_root: bool,
+) -> Result<'db, MirBody> {
if infer.type_mismatches().next().is_some() || infer.is_erroneous() {
return Err(MirLowerError::HasErrors);
}
- let mut ctx = MirLowerCtx::new(db, owner, body, infer);
+ let mut ctx = MirLowerCtx::new(db, owner, store, infer);
// 0 is return local
ctx.result.locals.alloc(Local { ty: ctx.expr_ty_after_adjustments(root_expr).store() });
let binding_picker = |b: BindingId| {
- let owner = ctx.body.binding_owner(b);
- if root_expr == body.body_expr { owner.is_none() } else { owner == Some(root_expr) }
- };
- // 1 to param_len is for params
- // FIXME: replace with let chain once it becomes stable
- let current = 'b: {
- if body.body_expr == root_expr {
- // otherwise it's an inline const, and has no parameter
- if let DefWithBodyId::FunctionId(fid) = owner {
- let callable_sig =
- db.callable_item_signature(fid.into()).instantiate_identity().skip_binder();
- let mut params = callable_sig.inputs().iter().copied();
- let self_param = body.self_param.and_then(|id| Some((id, params.next()?)));
- break 'b ctx.lower_params_and_bindings(
- body.params.iter().zip(params).map(|(it, y)| (*it, y)),
- self_param,
- binding_picker,
- )?;
- }
- }
- ctx.lower_params_and_bindings([].into_iter(), None, binding_picker)?
+ let owner = ctx.store.binding_owner(b);
+ if is_root { owner.is_none() } else { owner == Some(root_expr) }
};
+ let current = ctx.lower_params_and_bindings(params, self_param, binding_picker)?;
if let Some(current) = ctx.lower_expr_to_place(root_expr, return_slot().into(), current)? {
let current = ctx.pop_drop_scope_assert_finished(current, root_expr.into())?;
ctx.set_terminator(current, TerminatorKind::Return, root_expr.into());