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 | 337 |
1 files changed, 235 insertions, 102 deletions
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 37b27b3983..733f58e8f6 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -1,14 +1,15 @@ //! This module generates a polymorphic MIR from a hir body -use std::{iter, mem, sync::Arc}; +use std::{fmt::Write, iter, mem, sync::Arc}; +use base_db::FileId; use chalk_ir::{BoundVar, ConstData, DebruijnIndex, TyKind}; use hir_def::{ body::Body, data::adt::{StructKind, VariantData}, hir::{ - Array, BindingAnnotation, BindingId, ExprId, LabelId, Literal, MatchArm, Pat, PatId, - RecordFieldPat, RecordLitField, + ArithOp, Array, BinaryOp, BindingAnnotation, BindingId, ExprId, LabelId, Literal, MatchArm, + Pat, PatId, RecordFieldPat, RecordLitField, }, lang_item::{LangItem, LangItemTarget}, path::Path, @@ -18,6 +19,7 @@ use hir_def::{ use hir_expand::name::Name; use la_arena::ArenaMap; use rustc_hash::FxHashMap; +use syntax::TextRange; use crate::{ consteval::ConstEvalError, @@ -27,8 +29,9 @@ use crate::{ inhabitedness::is_ty_uninhabited_from, layout::{layout_of_ty, LayoutError}, mapping::ToChalk, + method_resolution::lookup_impl_const, static_lifetime, - utils::generics, + utils::{generics, ClosureSubst}, Adjust, Adjustment, AutoBorrow, CallableDefId, TyBuilder, TyExt, }; @@ -62,14 +65,14 @@ struct MirLowerCtx<'a> { #[derive(Debug, Clone, PartialEq, Eq)] pub enum MirLowerError { - ConstEvalError(Box<ConstEvalError>), + ConstEvalError(String, Box<ConstEvalError>), LayoutError(LayoutError), IncompleteExpr, /// Trying to lower a trait function, instead of an implementation TraitFunctionDefinition(TraitId, Name), UnresolvedName(String), RecordLiteralWithoutPath, - UnresolvedMethod, + UnresolvedMethod(String), UnresolvedField, MissingFunctionDefinition, TypeMismatch(TypeMismatch), @@ -88,6 +91,46 @@ pub enum MirLowerError { UnaccessableLocal, } +impl MirLowerError { + pub fn pretty_print( + &self, + f: &mut String, + db: &dyn HirDatabase, + span_formatter: impl Fn(FileId, TextRange) -> String, + ) -> std::result::Result<(), std::fmt::Error> { + match self { + MirLowerError::ConstEvalError(name, e) => { + writeln!(f, "In evaluating constant {name}")?; + match &**e { + ConstEvalError::MirLowerError(e) => e.pretty_print(f, db, span_formatter)?, + ConstEvalError::MirEvalError(e) => e.pretty_print(f, db, span_formatter)?, + } + } + MirLowerError::LayoutError(_) + | MirLowerError::IncompleteExpr + | MirLowerError::UnaccessableLocal + | MirLowerError::TraitFunctionDefinition(_, _) + | MirLowerError::UnresolvedName(_) + | MirLowerError::RecordLiteralWithoutPath + | MirLowerError::UnresolvedMethod(_) + | MirLowerError::UnresolvedField + | MirLowerError::MissingFunctionDefinition + | MirLowerError::TypeMismatch(_) + | MirLowerError::TypeError(_) + | MirLowerError::NotSupported(_) + | MirLowerError::ContinueWithoutLoop + | MirLowerError::BreakWithoutLoop + | MirLowerError::Loop + | MirLowerError::ImplementationError(_) + | MirLowerError::LangItemNotFound(_) + | MirLowerError::MutatingRvalue + | MirLowerError::UnresolvedLabel + | MirLowerError::UnresolvedUpvar(_) => writeln!(f, "{:?}", self)?, + } + Ok(()) + } +} + macro_rules! not_supported { ($x: expr) => { return Err(MirLowerError::NotSupported(format!($x))) @@ -101,15 +144,6 @@ macro_rules! implementation_error { }}; } -impl From<ConstEvalError> for MirLowerError { - fn from(value: ConstEvalError) -> Self { - match value { - ConstEvalError::MirLowerError(e) => e, - _ => MirLowerError::ConstEvalError(Box::new(value)), - } - } -} - impl From<LayoutError> for MirLowerError { fn from(value: LayoutError) -> Self { MirLowerError::LayoutError(value) @@ -177,7 +211,7 @@ impl<'ctx> MirLowerCtx<'ctx> { if !self.has_adjustments(expr_id) { match &self.body.exprs[expr_id] { Expr::Literal(l) => { - let ty = self.expr_ty(expr_id); + let ty = self.expr_ty_without_adjust(expr_id); return Ok(Some((self.lower_literal_to_operand(ty, l)?, current))); } _ => (), @@ -282,7 +316,7 @@ impl<'ctx> MirLowerCtx<'ctx> { { match assoc { hir_def::AssocItemId::ConstId(c) => { - self.lower_const(c, current, place, subst, expr_id.into())?; + self.lower_const(c, current, place, subst, expr_id.into(), self.expr_ty_without_adjust(expr_id))?; return Ok(Some(current)) }, hir_def::AssocItemId::FunctionId(_) => { @@ -309,17 +343,20 @@ impl<'ctx> MirLowerCtx<'ctx> { } }; match pr { - ValueNs::LocalBinding(pat_id) => { + ValueNs::LocalBinding(_) | ValueNs::StaticId(_) => { + let Some((temp, current)) = self.lower_expr_as_place_without_adjust(current, expr_id, false)? else { + return Ok(None); + }; self.push_assignment( current, place, - Operand::Copy(self.binding_local(pat_id)?.into()).into(), + Operand::Copy(temp).into(), expr_id.into(), ); Ok(Some(current)) } ValueNs::ConstId(const_id) => { - self.lower_const(const_id, current, place, Substitution::empty(Interner), expr_id.into())?; + self.lower_const(const_id, current, place, Substitution::empty(Interner), expr_id.into(), self.expr_ty_without_adjust(expr_id))?; Ok(Some(current)) } ValueNs::EnumVariantId(variant_id) => { @@ -343,7 +380,7 @@ impl<'ctx> MirLowerCtx<'ctx> { not_supported!("owner without generic def id"); }; let gen = generics(self.db.upcast(), def); - let ty = self.expr_ty(expr_id); + let ty = self.expr_ty_without_adjust(expr_id); self.push_assignment( current, place, @@ -388,12 +425,13 @@ impl<'ctx> MirLowerCtx<'ctx> { }; self.set_terminator( current, - Terminator::SwitchInt { + TerminatorKind::SwitchInt { discr, targets: SwitchTargets::static_if(1, start_of_then, start_of_else), }, + expr_id.into(), ); - Ok(self.merge_blocks(end_of_then, end_of_else)) + Ok(self.merge_blocks(end_of_then, end_of_else, expr_id.into())) } Expr::Let { pat, expr } => { let Some((cond_place, current)) = self.lower_expr_as_place(current, *expr, true)? else { @@ -423,32 +461,32 @@ impl<'ctx> MirLowerCtx<'ctx> { MirSpan::Unknown, )?; } - Ok(self.merge_blocks(Some(then_target), else_target)) + Ok(self.merge_blocks(Some(then_target), else_target, expr_id.into())) } Expr::Unsafe { id: _, statements, tail } => { - self.lower_block_to_place(statements, current, *tail, place) + self.lower_block_to_place(statements, current, *tail, place, expr_id.into()) } Expr::Block { id: _, statements, tail, label } => { if let Some(label) = label { - self.lower_loop(current, place.clone(), Some(*label), |this, begin| { - if let Some(block) = this.lower_block_to_place(statements, begin, *tail, place)? { + self.lower_loop(current, place.clone(), Some(*label), expr_id.into(), |this, begin| { + if let Some(block) = this.lower_block_to_place(statements, begin, *tail, place, expr_id.into())? { let end = this.current_loop_end()?; - this.set_goto(block, end); + this.set_goto(block, end, expr_id.into()); } Ok(()) }) } else { - self.lower_block_to_place(statements, current, *tail, place) + self.lower_block_to_place(statements, current, *tail, place, expr_id.into()) } } - Expr::Loop { body, label } => self.lower_loop(current, place, *label, |this, begin| { + Expr::Loop { body, label } => self.lower_loop(current, place, *label, expr_id.into(), |this, begin| { if let Some((_, block)) = this.lower_expr_as_place(begin, *body, true)? { - this.set_goto(block, begin); + this.set_goto(block, begin, expr_id.into()); } Ok(()) }), Expr::While { condition, body, label } => { - self.lower_loop(current, place, *label, |this, begin| { + self.lower_loop(current, place, *label, expr_id.into(),|this, begin| { let Some((discr, to_switch)) = this.lower_expr_to_some_operand(*condition, begin)? else { return Ok(()); }; @@ -456,13 +494,14 @@ impl<'ctx> MirLowerCtx<'ctx> { let after_cond = this.new_basic_block(); this.set_terminator( to_switch, - Terminator::SwitchInt { + TerminatorKind::SwitchInt { discr, targets: SwitchTargets::static_if(1, after_cond, end), }, + expr_id.into(), ); if let Some((_, block)) = this.lower_expr_as_place(after_cond, *body, true)? { - this.set_goto(block, begin); + this.set_goto(block, begin, expr_id.into()); } Ok(()) }) @@ -478,12 +517,12 @@ impl<'ctx> MirLowerCtx<'ctx> { let into_iter_fn_op = Operand::const_zst( TyKind::FnDef( self.db.intern_callable_def(CallableDefId::FunctionId(into_iter_fn)).into(), - Substitution::from1(Interner, self.expr_ty(iterable)) + Substitution::from1(Interner, self.expr_ty_without_adjust(iterable)) ).intern(Interner)); let iter_next_fn_op = Operand::const_zst( TyKind::FnDef( self.db.intern_callable_def(CallableDefId::FunctionId(iter_next_fn)).into(), - Substitution::from1(Interner, self.expr_ty(iterable)) + Substitution::from1(Interner, self.expr_ty_without_adjust(iterable)) ).intern(Interner)); let &Some(iterator_ty) = &self.infer.type_of_for_iterator.get(&expr_id) else { return Err(MirLowerError::TypeError("unknown for loop iterator type")); @@ -494,13 +533,13 @@ impl<'ctx> MirLowerCtx<'ctx> { let iterator_place: Place = self.temp(iterator_ty.clone())?.into(); let option_item_place: Place = self.temp(option_item_ty.clone())?.into(); let ref_mut_iterator_place: Place = self.temp(ref_mut_iterator_ty)?.into(); - let Some(current) = self.lower_call_and_args(into_iter_fn_op, Some(iterable).into_iter(), iterator_place.clone(), current, false)? + let Some(current) = self.lower_call_and_args(into_iter_fn_op, Some(iterable).into_iter(), iterator_place.clone(), current, false, expr_id.into())? else { return Ok(None); }; self.push_assignment(current, ref_mut_iterator_place.clone(), Rvalue::Ref(BorrowKind::Mut { allow_two_phase_borrow: false }, iterator_place), expr_id.into()); - self.lower_loop(current, place, label, |this, begin| { - let Some(current) = this.lower_call(iter_next_fn_op, vec![Operand::Copy(ref_mut_iterator_place)], option_item_place.clone(), begin, false)? + self.lower_loop(current, place, label, expr_id.into(), |this, begin| { + let Some(current) = this.lower_call(iter_next_fn_op, vec![Operand::Copy(ref_mut_iterator_place)], option_item_place.clone(), begin, false, expr_id.into())? else { return Ok(()); }; @@ -516,7 +555,7 @@ impl<'ctx> MirLowerCtx<'ctx> { AdtPatternShape::Tuple { args: &[pat], ellipsis: None }, )?; if let Some((_, block)) = this.lower_expr_as_place(current, body, true)? { - this.set_goto(block, begin); + this.set_goto(block, begin, expr_id.into()); } Ok(()) }) @@ -536,39 +575,36 @@ impl<'ctx> MirLowerCtx<'ctx> { place, current, self.is_uninhabited(expr_id), + expr_id.into(), ); } let callee_ty = self.expr_ty_after_adjustments(*callee); match &callee_ty.data(Interner).kind { chalk_ir::TyKind::FnDef(..) => { let func = Operand::from_bytes(vec![], callee_ty.clone()); - self.lower_call_and_args(func, args.iter().copied(), place, current, self.is_uninhabited(expr_id)) + self.lower_call_and_args(func, args.iter().copied(), place, current, self.is_uninhabited(expr_id), expr_id.into()) } chalk_ir::TyKind::Function(_) => { let Some((func, current)) = self.lower_expr_to_some_operand(*callee, current)? else { return Ok(None); }; - self.lower_call_and_args(func, args.iter().copied(), place, current, self.is_uninhabited(expr_id)) + self.lower_call_and_args(func, args.iter().copied(), place, current, self.is_uninhabited(expr_id), expr_id.into()) } TyKind::Error => return Err(MirLowerError::MissingFunctionDefinition), _ => return Err(MirLowerError::TypeError("function call on bad type")), } } - Expr::MethodCall { receiver, args, .. } => { + Expr::MethodCall { receiver, args, method_name, .. } => { let (func_id, generic_args) = - self.infer.method_resolution(expr_id).ok_or(MirLowerError::UnresolvedMethod)?; - let ty = chalk_ir::TyKind::FnDef( - CallableDefId::FunctionId(func_id).to_chalk(self.db), - generic_args, - ) - .intern(Interner); - let func = Operand::from_bytes(vec![], ty); + self.infer.method_resolution(expr_id).ok_or_else(|| MirLowerError::UnresolvedMethod(format!("{}", method_name)))?; + let func = Operand::from_fn(self.db, func_id, generic_args); self.lower_call_and_args( func, iter::once(*receiver).chain(args.iter().copied()), place, current, self.is_uninhabited(expr_id), + expr_id.into(), ) } Expr::Match { expr, arms } => { @@ -591,7 +627,7 @@ impl<'ctx> MirLowerCtx<'ctx> { let next = self.new_basic_block(); let o = otherwise.get_or_insert_with(|| self.new_basic_block()); if let Some((discr, c)) = self.lower_expr_to_some_operand(guard, then)? { - self.set_terminator(c, Terminator::SwitchInt { discr, targets: SwitchTargets::static_if(1, next, *o) }); + self.set_terminator(c, TerminatorKind::SwitchInt { discr, targets: SwitchTargets::static_if(1, next, *o) }, expr_id.into()); } next } else { @@ -599,7 +635,7 @@ impl<'ctx> MirLowerCtx<'ctx> { }; if let Some(block) = self.lower_expr_to_place(*expr, place.clone(), then)? { let r = end.get_or_insert_with(|| self.new_basic_block()); - self.set_goto(block, *r); + self.set_goto(block, *r, expr_id.into()); } match otherwise { Some(o) => current = o, @@ -611,18 +647,17 @@ impl<'ctx> MirLowerCtx<'ctx> { } } if self.is_unterminated(current) { - self.set_terminator(current, Terminator::Unreachable); + self.set_terminator(current, TerminatorKind::Unreachable, expr_id.into()); } Ok(end) } - Expr::Continue { label } => match label { - Some(_) => not_supported!("continue with label"), - None => { - let loop_data = - self.current_loop_blocks.as_ref().ok_or(MirLowerError::ContinueWithoutLoop)?; - self.set_goto(current, loop_data.begin); - Ok(None) - } + Expr::Continue { label } => { + let loop_data = match label { + Some(l) => self.labeled_loop_blocks.get(l).ok_or(MirLowerError::UnresolvedLabel)?, + None => self.current_loop_blocks.as_ref().ok_or(MirLowerError::ContinueWithoutLoop)?, + }; + self.set_goto(current, loop_data.begin, expr_id.into()); + Ok(None) }, &Expr::Break { expr, label } => { if let Some(expr) = expr { @@ -639,7 +674,7 @@ impl<'ctx> MirLowerCtx<'ctx> { Some(l) => self.labeled_loop_blocks.get(&l).ok_or(MirLowerError::UnresolvedLabel)?.end.expect("We always generate end for labeled loops"), None => self.current_loop_end()?, }; - self.set_goto(current, end); + self.set_goto(current, end, expr_id.into()); Ok(None) } Expr::Return { expr } => { @@ -650,7 +685,7 @@ impl<'ctx> MirLowerCtx<'ctx> { return Ok(None); } } - self.set_terminator(current, Terminator::Return); + self.set_terminator(current, TerminatorKind::Return, expr_id.into()); Ok(None) } Expr::Yield { .. } => not_supported!("yield"), @@ -672,7 +707,7 @@ impl<'ctx> MirLowerCtx<'ctx> { Some(p) => MirLowerError::UnresolvedName(p.display(self.db).to_string()), None => MirLowerError::RecordLiteralWithoutPath, })?; - let subst = match self.expr_ty(expr_id).kind(Interner) { + let subst = match self.expr_ty_without_adjust(expr_id).kind(Interner) { TyKind::Adt(_, s) => s.clone(), _ => not_supported!("Non ADT record literal"), }; @@ -757,7 +792,17 @@ impl<'ctx> MirLowerCtx<'ctx> { self.push_assignment(current, place, Rvalue::Ref(bk, p), expr_id.into()); Ok(Some(current)) } - Expr::Box { .. } => not_supported!("box expression"), + Expr::Box { expr } => { + let ty = self.expr_ty_after_adjustments(*expr); + self.push_assignment(current, place.clone(), Rvalue::ShallowInitBoxWithAlloc(ty), expr_id.into()); + let Some((operand, current)) = self.lower_expr_to_some_operand(*expr, current)? else { + return Ok(None); + }; + let mut p = place; + p.projection.push(ProjectionElem::Deref); + self.push_assignment(current, p, operand.into(), expr_id.into()); + Ok(Some(current)) + }, Expr::Field { .. } | Expr::Index { .. } | Expr::UnaryOp { op: hir_def::hir::UnaryOp::Deref, .. } => { let Some((p, current)) = self.lower_expr_as_place_without_adjust(current, expr_id, true)? else { return Ok(None); @@ -784,20 +829,63 @@ impl<'ctx> MirLowerCtx<'ctx> { }, Expr::BinaryOp { lhs, rhs, op } => { let op = op.ok_or(MirLowerError::IncompleteExpr)?; - if let hir_def::hir::BinaryOp::Assignment { op } = op { - if op.is_some() { - not_supported!("assignment with arith op (like +=)"); + let is_builtin = { + // Without adjust here is a hack. We assume that we know every possible adjustment + // for binary operator, and use without adjust to simplify our conditions. + let lhs_ty = self.expr_ty_without_adjust(*lhs); + let rhs_ty = self.expr_ty_without_adjust(*rhs); + let builtin_inequal_impls = matches!( + op, + BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) | BinaryOp::Assignment { op: Some(ArithOp::Shl | ArithOp::Shr) } + ); + lhs_ty.as_builtin().is_some() && rhs_ty.as_builtin().is_some() && (lhs_ty == rhs_ty || builtin_inequal_impls) + }; + if !is_builtin { + if let Some((func_id, generic_args)) = self.infer.method_resolution(expr_id) { + let func = Operand::from_fn(self.db, func_id, generic_args); + return self.lower_call_and_args( + func, + [*lhs, *rhs].into_iter(), + place, + current, + self.is_uninhabited(expr_id), + expr_id.into(), + ); } - let Some((lhs_place, current)) = + } + if let hir_def::hir::BinaryOp::Assignment { op } = op { + if let Some(op) = op { + // last adjustment is `&mut` which we don't want it. + let adjusts = self + .infer + .expr_adjustments + .get(lhs) + .and_then(|x| x.split_last()) + .map(|x| x.1) + .ok_or(MirLowerError::TypeError("adjustment of binary op was missing"))?; + let Some((lhs_place, current)) = + self.lower_expr_as_place_with_adjust(current, *lhs, false, adjusts)? + else { + return Ok(None); + }; + let Some((rhs_op, current)) = self.lower_expr_to_some_operand(*rhs, current)? else { + return Ok(None); + }; + let r_value = Rvalue::CheckedBinaryOp(op.into(), Operand::Copy(lhs_place.clone()), rhs_op); + self.push_assignment(current, lhs_place, r_value, expr_id.into()); + return Ok(Some(current)); + } else { + let Some((lhs_place, current)) = self.lower_expr_as_place(current, *lhs, false)? - else { - return Ok(None); - }; - let Some((rhs_op, current)) = self.lower_expr_to_some_operand(*rhs, current)? else { - return Ok(None); - }; - self.push_assignment(current, lhs_place, rhs_op.into(), expr_id.into()); - return Ok(Some(current)); + else { + return Ok(None); + }; + let Some((rhs_op, current)) = self.lower_expr_to_some_operand(*rhs, current)? else { + return Ok(None); + }; + self.push_assignment(current, lhs_place, rhs_op.into(), expr_id.into()); + return Ok(Some(current)); + } } let Some((lhs_op, current)) = self.lower_expr_to_some_operand(*lhs, current)? else { return Ok(None); @@ -826,7 +914,7 @@ impl<'ctx> MirLowerCtx<'ctx> { Ok(Some(current)) } &Expr::Range { lhs, rhs, range_type: _ } => { - let ty = self.expr_ty(expr_id); + let ty = self.expr_ty_without_adjust(expr_id); let Some((adt, subst)) = ty.as_adt() else { return Err(MirLowerError::TypeError("Range type is not adt")); }; @@ -869,7 +957,7 @@ impl<'ctx> MirLowerCtx<'ctx> { Ok(Some(current)) }, Expr::Closure { .. } => { - let ty = self.expr_ty(expr_id); + let ty = self.expr_ty_without_adjust(expr_id); let TyKind::Closure(id, _) = ty.kind(Interner) else { not_supported!("closure with non closure type"); }; @@ -893,7 +981,12 @@ impl<'ctx> MirLowerCtx<'ctx> { }; match &capture.kind { CaptureKind::ByRef(bk) => { - let tmp: Place = self.temp(capture.ty.clone())?.into(); + let placeholder_subst = match self.owner.as_generic_def_id() { + Some(x) => TyBuilder::placeholder_subst(self.db, x), + None => Substitution::empty(Interner), + }; + let tmp_ty = capture.ty.clone().substitute(Interner, &placeholder_subst); + let tmp: Place = self.temp(tmp_ty)?.into(); self.push_assignment( current, tmp.clone(), @@ -928,7 +1021,7 @@ impl<'ctx> MirLowerCtx<'ctx> { return Ok(None); }; let r = Rvalue::Aggregate( - AggregateKind::Tuple(self.expr_ty(expr_id)), + AggregateKind::Tuple(self.expr_ty_without_adjust(expr_id)), values, ); self.push_assignment(current, place, r, expr_id.into()); @@ -936,7 +1029,7 @@ impl<'ctx> MirLowerCtx<'ctx> { } Expr::Array(l) => match l { Array::ElementList { elements, .. } => { - let elem_ty = match &self.expr_ty(expr_id).data(Interner).kind { + let elem_ty = match &self.expr_ty_without_adjust(expr_id).data(Interner).kind { TyKind::Array(ty, _) => ty.clone(), _ => { return Err(MirLowerError::TypeError( @@ -968,7 +1061,7 @@ impl<'ctx> MirLowerCtx<'ctx> { let Some((init, current)) = self.lower_expr_to_some_operand(*initializer, current)? else { return Ok(None); }; - let len = match &self.expr_ty(expr_id).data(Interner).kind { + let len = match &self.expr_ty_without_adjust(expr_id).data(Interner).kind { TyKind::Array(_, len) => len.clone(), _ => { return Err(MirLowerError::TypeError( @@ -982,7 +1075,7 @@ impl<'ctx> MirLowerCtx<'ctx> { }, }, Expr::Literal(l) => { - let ty = self.expr_ty(expr_id); + let ty = self.expr_ty_without_adjust(expr_id); let op = self.lower_literal_to_operand(ty, l)?; self.push_assignment(current, place, op.into(), expr_id.into()); Ok(Some(current)) @@ -1057,8 +1150,30 @@ impl<'ctx> MirLowerCtx<'ctx> { place: Place, subst: Substitution, span: MirSpan, + ty: Ty, ) -> Result<()> { - let c = self.db.const_eval(const_id, subst)?; + let c = if subst.len(Interner) != 0 { + // We can't evaluate constant with substitution now, as generics are not monomorphized in lowering. + intern_const_scalar(ConstScalar::UnevaluatedConst(const_id, subst), ty) + } else { + let (const_id, subst) = lookup_impl_const( + self.db, + self.db.trait_environment_for_body(self.owner), + const_id, + subst, + ); + let name = self + .db + .const_data(const_id) + .name + .as_ref() + .and_then(|x| x.as_str()) + .unwrap_or("_") + .to_owned(); + self.db + .const_eval(const_id.into(), subst) + .map_err(|e| MirLowerError::ConstEvalError(name, Box::new(e)))? + }; self.write_const_to_place(c, prev_block, place, span) } @@ -1114,6 +1229,7 @@ impl<'ctx> MirLowerCtx<'ctx> { place: Place, mut current: BasicBlockId, is_uninhabited: bool, + span: MirSpan, ) -> Result<Option<BasicBlockId>> { let Some(args) = args .map(|arg| { @@ -1128,7 +1244,7 @@ impl<'ctx> MirLowerCtx<'ctx> { else { return Ok(None); }; - self.lower_call(func, args, place, current, is_uninhabited) + self.lower_call(func, args, place, current, is_uninhabited, span) } fn lower_call( @@ -1138,11 +1254,12 @@ impl<'ctx> MirLowerCtx<'ctx> { place: Place, current: BasicBlockId, is_uninhabited: bool, + span: MirSpan, ) -> Result<Option<BasicBlockId>> { let b = if is_uninhabited { None } else { Some(self.new_basic_block()) }; self.set_terminator( current, - Terminator::Call { + TerminatorKind::Call { func, args, destination: place, @@ -1150,6 +1267,7 @@ impl<'ctx> MirLowerCtx<'ctx> { cleanup: None, from_hir_call: true, }, + span, ); Ok(b) } @@ -1158,15 +1276,15 @@ impl<'ctx> MirLowerCtx<'ctx> { self.result.basic_blocks[source].terminator.is_none() } - fn set_terminator(&mut self, source: BasicBlockId, terminator: Terminator) { - self.result.basic_blocks[source].terminator = Some(terminator); + fn set_terminator(&mut self, source: BasicBlockId, terminator: TerminatorKind, span: MirSpan) { + self.result.basic_blocks[source].terminator = Some(Terminator { span, kind: terminator }); } - fn set_goto(&mut self, source: BasicBlockId, target: BasicBlockId) { - self.set_terminator(source, Terminator::Goto { target }); + fn set_goto(&mut self, source: BasicBlockId, target: BasicBlockId, span: MirSpan) { + self.set_terminator(source, TerminatorKind::Goto { target }, span); } - fn expr_ty(&self, e: ExprId) -> Ty { + fn expr_ty_without_adjust(&self, e: ExprId) -> Ty { self.infer[e].clone() } @@ -1177,7 +1295,7 @@ impl<'ctx> MirLowerCtx<'ctx> { ty = Some(x.target.clone()); } } - ty.unwrap_or_else(|| self.expr_ty(e)) + ty.unwrap_or_else(|| self.expr_ty_without_adjust(e)) } fn push_statement(&mut self, block: BasicBlockId, statement: Statement) { @@ -1211,6 +1329,7 @@ impl<'ctx> MirLowerCtx<'ctx> { prev_block: BasicBlockId, place: Place, label: Option<LabelId>, + span: MirSpan, f: impl FnOnce(&mut MirLowerCtx<'_>, BasicBlockId) -> Result<()>, ) -> Result<Option<BasicBlockId>> { let begin = self.new_basic_block(); @@ -1228,7 +1347,7 @@ impl<'ctx> MirLowerCtx<'ctx> { } else { None }; - self.set_goto(prev_block, begin); + self.set_goto(prev_block, begin, span); f(self, begin)?; let my = mem::replace(&mut self.current_loop_blocks, prev).ok_or( MirLowerError::ImplementationError("current_loop_blocks is corrupt".to_string()), @@ -1247,14 +1366,15 @@ impl<'ctx> MirLowerCtx<'ctx> { &mut self, b1: Option<BasicBlockId>, b2: Option<BasicBlockId>, + span: MirSpan, ) -> Option<BasicBlockId> { match (b1, b2) { (None, None) => None, (None, Some(b)) | (Some(b), None) => Some(b), (Some(b1), Some(b2)) => { let bm = self.new_basic_block(); - self.set_goto(b1, bm); - self.set_goto(b2, bm); + self.set_goto(b1, bm, span); + self.set_goto(b2, bm, span); Some(bm) } } @@ -1332,6 +1452,7 @@ impl<'ctx> MirLowerCtx<'ctx> { mut current: BasicBlockId, tail: Option<ExprId>, place: Place, + span: MirSpan, ) -> Result<Option<Idx<BasicBlock>>> { for statement in statements.iter() { match statement { @@ -1355,13 +1476,13 @@ impl<'ctx> MirLowerCtx<'ctx> { match (else_block, else_branch) { (None, _) => (), (Some(else_block), None) => { - self.set_terminator(else_block, Terminator::Unreachable); + self.set_terminator(else_block, TerminatorKind::Unreachable, span); } (Some(else_block), Some(else_branch)) => { if let Some((_, b)) = self.lower_expr_as_place(else_block, *else_branch, true)? { - self.set_terminator(b, Terminator::Unreachable); + self.set_terminator(b, TerminatorKind::Unreachable, span); } } } @@ -1438,7 +1559,7 @@ impl<'ctx> MirLowerCtx<'ctx> { BindingAnnotation::Unannotated, )?; if let Some(b) = r.1 { - self.set_terminator(b, Terminator::Unreachable); + self.set_terminator(b, TerminatorKind::Unreachable, param.into()); } current = r.0; } @@ -1456,6 +1577,18 @@ impl<'ctx> MirLowerCtx<'ctx> { } } } + + fn const_eval_discriminant(&self, variant: EnumVariantId) -> Result<i128> { + let r = self.db.const_eval_discriminant(variant); + match r { + Ok(r) => Ok(r), + Err(e) => { + let data = self.db.enum_data(variant.parent); + let name = format!("{}::{}", data.name, data.variants[variant.local_id].name); + Err(MirLowerError::ConstEvalError(name, Box::new(e))) + } + } + } } fn cast_kind(source_ty: &Ty, target_ty: &Ty) -> Result<CastKind> { @@ -1498,7 +1631,7 @@ pub fn mir_body_for_closure_query( // 0 is return local ctx.result.locals.alloc(Local { ty: infer[*root].clone() }); ctx.result.locals.alloc(Local { ty: infer[expr].clone() }); - let Some(sig) = substs.at(Interner, 0).assert_ty_ref(Interner).callable_sig(db) else { + let Some(sig) = ClosureSubst(substs).sig_ty().callable_sig(db) else { implementation_error!("closure has not callable sig"); }; let current = ctx.lower_params_and_bindings( @@ -1506,7 +1639,7 @@ pub fn mir_body_for_closure_query( |_| true, )?; if let Some(b) = ctx.lower_expr_to_place(*root, return_slot().into(), current)? { - ctx.set_terminator(b, Terminator::Return); + ctx.set_terminator(b, TerminatorKind::Return, (*root).into()); } let mut upvar_map: FxHashMap<LocalId, Vec<(&CapturedItem, usize)>> = FxHashMap::default(); for (i, capture) in captures.iter().enumerate() { @@ -1628,7 +1761,7 @@ pub fn lower_to_mir( ctx.lower_params_and_bindings([].into_iter(), binding_picker)? }; if let Some(b) = ctx.lower_expr_to_place(root_expr, return_slot().into(), current)? { - ctx.set_terminator(b, Terminator::Return); + ctx.set_terminator(b, TerminatorKind::Return, root_expr.into()); } Ok(ctx.result) } |