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.rs | 166 |
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()); |