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 | 431 |
1 files changed, 308 insertions, 123 deletions
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 1821796be3..78a2d90f7f 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -4,9 +4,9 @@ use std::{iter, mem, sync::Arc}; use chalk_ir::{BoundVar, ConstData, DebruijnIndex, TyKind}; use hir_def::{ - adt::{StructKind, VariantData}, body::Body, - expr::{ + data::adt::{StructKind, VariantData}, + hir::{ Array, BindingAnnotation, BindingId, ExprId, LabelId, Literal, MatchArm, Pat, PatId, RecordFieldPat, RecordLitField, }, @@ -21,9 +21,16 @@ use la_arena::ArenaMap; use rustc_hash::FxHashMap; use crate::{ - consteval::ConstEvalError, db::HirDatabase, display::HirDisplay, infer::TypeMismatch, - inhabitedness::is_ty_uninhabited_from, layout::layout_of_ty, mapping::ToChalk, static_lifetime, - utils::generics, Adjust, Adjustment, AutoBorrow, CallableDefId, TyBuilder, TyExt, + consteval::ConstEvalError, + db::HirDatabase, + display::HirDisplay, + infer::{CaptureKind, CapturedItem, TypeMismatch}, + inhabitedness::is_ty_uninhabited_from, + layout::layout_of_ty, + mapping::ToChalk, + static_lifetime, + utils::generics, + Adjust, Adjustment, AutoBorrow, CallableDefId, TyBuilder, TyExt, }; use super::*; @@ -47,7 +54,7 @@ struct MirLowerCtx<'a> { current_loop_blocks: Option<LoopBlocks>, // FIXME: we should resolve labels in HIR lowering and always work with label id here, not // with raw names. - labeled_loop_blocks: FxHashMap<Name, LoopBlocks>, + labeled_loop_blocks: FxHashMap<LabelId, LoopBlocks>, discr_temp: Option<Place>, db: &'a dyn HirDatabase, body: &'a Body, @@ -74,10 +81,12 @@ pub enum MirLowerError { BreakWithoutLoop, Loop, /// Something that should never happen and is definitely a bug, but we don't want to panic if it happened - ImplementationError(&'static str), + ImplementationError(String), LangItemNotFound(LangItem), MutatingRvalue, UnresolvedLabel, + UnresolvedUpvar(Place), + UnaccessableLocal, } macro_rules! not_supported { @@ -88,8 +97,8 @@ macro_rules! not_supported { macro_rules! implementation_error { ($x: expr) => {{ - ::stdx::never!("MIR lower implementation bug: {}", $x); - return Err(MirLowerError::ImplementationError($x)); + ::stdx::never!("MIR lower implementation bug: {}", format!($x)); + return Err(MirLowerError::ImplementationError(format!($x))); }}; } @@ -116,7 +125,44 @@ impl MirLowerError { type Result<T> = std::result::Result<T, MirLowerError>; -impl MirLowerCtx<'_> { +impl<'ctx> MirLowerCtx<'ctx> { + fn new( + db: &'ctx dyn HirDatabase, + owner: DefWithBodyId, + body: &'ctx Body, + infer: &'ctx InferenceResult, + ) -> Self { + let mut basic_blocks = Arena::new(); + let start_block = basic_blocks.alloc(BasicBlock { + statements: vec![], + terminator: None, + is_cleanup: false, + }); + let locals = Arena::new(); + let binding_locals: ArenaMap<BindingId, LocalId> = ArenaMap::new(); + let mir = MirBody { + basic_blocks, + locals, + start_block, + binding_locals, + param_locals: vec![], + owner, + arg_count: body.params.len(), + closures: vec![], + }; + let ctx = MirLowerCtx { + result: mir, + db, + infer, + body, + owner, + current_loop_blocks: None, + labeled_loop_blocks: Default::default(), + discr_temp: None, + }; + ctx + } + fn temp(&mut self, ty: Ty) -> Result<LocalId> { if matches!(ty.kind(Interner), TyKind::Slice(_) | TyKind::Dyn(_)) { implementation_error!("unsized temporaries"); @@ -268,7 +314,7 @@ impl MirLowerCtx<'_> { self.push_assignment( current, place, - Operand::Copy(self.result.binding_locals[pat_id].into()).into(), + Operand::Copy(self.binding_local(pat_id)?.into()).into(), expr_id.into(), ); Ok(Some(current)) @@ -579,19 +625,19 @@ impl MirLowerCtx<'_> { Ok(None) } }, - Expr::Break { expr, label } => { + &Expr::Break { expr, label } => { if let Some(expr) = expr { let loop_data = match label { - Some(l) => self.labeled_loop_blocks.get(l).ok_or(MirLowerError::UnresolvedLabel)?, + Some(l) => self.labeled_loop_blocks.get(&l).ok_or(MirLowerError::UnresolvedLabel)?, None => self.current_loop_blocks.as_ref().ok_or(MirLowerError::BreakWithoutLoop)?, }; - let Some(c) = self.lower_expr_to_place(*expr, loop_data.place.clone(), current)? else { + let Some(c) = self.lower_expr_to_place(expr, loop_data.place.clone(), current)? else { return Ok(None); }; current = c; } let end = match label { - Some(l) => self.labeled_loop_blocks.get(l).ok_or(MirLowerError::UnresolvedLabel)?.end.expect("We always generate end for labeled loops"), + 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); @@ -713,20 +759,20 @@ impl MirLowerCtx<'_> { Ok(Some(current)) } Expr::Box { .. } => not_supported!("box expression"), - Expr::Field { .. } | Expr::Index { .. } | Expr::UnaryOp { op: hir_def::expr::UnaryOp::Deref, .. } => { + 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); }; self.push_assignment(current, place, Operand::Copy(p).into(), expr_id.into()); Ok(Some(current)) } - Expr::UnaryOp { expr, op: op @ (hir_def::expr::UnaryOp::Not | hir_def::expr::UnaryOp::Neg) } => { + Expr::UnaryOp { expr, op: op @ (hir_def::hir::UnaryOp::Not | hir_def::hir::UnaryOp::Neg) } => { let Some((operand, current)) = self.lower_expr_to_some_operand(*expr, current)? else { return Ok(None); }; let operation = match op { - hir_def::expr::UnaryOp::Not => UnOp::Not, - hir_def::expr::UnaryOp::Neg => UnOp::Neg, + hir_def::hir::UnaryOp::Not => UnOp::Not, + hir_def::hir::UnaryOp::Neg => UnOp::Neg, _ => unreachable!(), }; self.push_assignment( @@ -739,7 +785,7 @@ impl MirLowerCtx<'_> { }, Expr::BinaryOp { lhs, rhs, op } => { let op = op.ok_or(MirLowerError::IncompleteExpr)?; - if let hir_def::expr::BinaryOp::Assignment { op } = op { + if let hir_def::hir::BinaryOp::Assignment { op } = op { if op.is_some() { not_supported!("assignment with arith op (like +=)"); } @@ -765,13 +811,13 @@ impl MirLowerCtx<'_> { place, Rvalue::CheckedBinaryOp( match op { - hir_def::expr::BinaryOp::LogicOp(op) => match op { - hir_def::expr::LogicOp::And => BinOp::BitAnd, // FIXME: make these short circuit - hir_def::expr::LogicOp::Or => BinOp::BitOr, + hir_def::hir::BinaryOp::LogicOp(op) => match op { + hir_def::hir::LogicOp::And => BinOp::BitAnd, // FIXME: make these short circuit + hir_def::hir::LogicOp::Or => BinOp::BitOr, }, - hir_def::expr::BinaryOp::ArithOp(op) => BinOp::from(op), - hir_def::expr::BinaryOp::CmpOp(op) => BinOp::from(op), - hir_def::expr::BinaryOp::Assignment { .. } => unreachable!(), // handled above + hir_def::hir::BinaryOp::ArithOp(op) => BinOp::from(op), + hir_def::hir::BinaryOp::CmpOp(op) => BinOp::from(op), + hir_def::hir::BinaryOp::Assignment { .. } => unreachable!(), // handled above }, lhs_op, rhs_op, @@ -823,7 +869,51 @@ impl MirLowerCtx<'_> { ); Ok(Some(current)) }, - Expr::Closure { .. } => not_supported!("closure"), + Expr::Closure { .. } => { + let ty = self.expr_ty(expr_id); + let TyKind::Closure(id, _) = ty.kind(Interner) else { + not_supported!("closure with non closure type"); + }; + self.result.closures.push(*id); + let (captures, _) = self.infer.closure_info(id); + let mut operands = vec![]; + for capture in captures.iter() { + let p = Place { + local: self.binding_local(capture.place.local)?, + projection: capture.place.projections.clone().into_iter().map(|x| { + match x { + ProjectionElem::Deref => ProjectionElem::Deref, + ProjectionElem::Field(x) => ProjectionElem::Field(x), + ProjectionElem::TupleOrClosureField(x) => ProjectionElem::TupleOrClosureField(x), + ProjectionElem::ConstantIndex { offset, min_length, from_end } => ProjectionElem::ConstantIndex { offset, min_length, from_end }, + ProjectionElem::Subslice { from, to, from_end } => ProjectionElem::Subslice { from, to, from_end }, + ProjectionElem::OpaqueCast(x) => ProjectionElem::OpaqueCast(x), + ProjectionElem::Index(x) => match x { }, + } + }).collect(), + }; + match &capture.kind { + CaptureKind::ByRef(bk) => { + let tmp: Place = self.temp(capture.ty.clone())?.into(); + self.push_assignment( + current, + tmp.clone(), + Rvalue::Ref(bk.clone(), p), + expr_id.into(), + ); + operands.push(Operand::Move(tmp)); + }, + CaptureKind::ByValue => operands.push(Operand::Move(p)), + } + } + self.push_assignment( + current, + place, + Rvalue::Aggregate(AggregateKind::Closure(ty), operands), + expr_id.into(), + ); + Ok(Some(current)) + }, Expr::Tuple { exprs, is_assignee_expr: _ } => { let Some(values) = exprs .iter() @@ -893,7 +983,7 @@ impl MirLowerCtx<'_> { let index = name .as_tuple_index() .ok_or(MirLowerError::TypeError("named field on tuple"))?; - place.projection.push(ProjectionElem::TupleField(index)) + place.projection.push(ProjectionElem::TupleOrClosureField(index)) } else { let field = self.infer.field_resolution(expr_id).ok_or(MirLowerError::UnresolvedField)?; @@ -910,7 +1000,7 @@ impl MirLowerCtx<'_> { .size .bytes_usize(); let bytes = match l { - hir_def::expr::Literal::String(b) => { + hir_def::hir::Literal::String(b) => { let b = b.as_bytes(); let mut data = vec![]; data.extend(0usize.to_le_bytes()); @@ -919,7 +1009,7 @@ impl MirLowerCtx<'_> { mm.insert(0, b.to_vec()); return Ok(Operand::from_concrete_const(data, mm, ty)); } - hir_def::expr::Literal::ByteString(b) => { + hir_def::hir::Literal::ByteString(b) => { let mut data = vec![]; data.extend(0usize.to_le_bytes()); data.extend(b.len().to_le_bytes()); @@ -927,11 +1017,11 @@ impl MirLowerCtx<'_> { mm.insert(0, b.to_vec()); return Ok(Operand::from_concrete_const(data, mm, ty)); } - hir_def::expr::Literal::Char(c) => u32::from(*c).to_le_bytes().into(), - hir_def::expr::Literal::Bool(b) => vec![*b as u8], - hir_def::expr::Literal::Int(x, _) => x.to_le_bytes()[0..size].into(), - hir_def::expr::Literal::Uint(x, _) => x.to_le_bytes()[0..size].into(), - hir_def::expr::Literal::Float(f, _) => match size { + hir_def::hir::Literal::Char(c) => u32::from(*c).to_le_bytes().into(), + hir_def::hir::Literal::Bool(b) => vec![*b as u8], + hir_def::hir::Literal::Int(x, _) => x.to_le_bytes()[0..size].into(), + hir_def::hir::Literal::Uint(x, _) => x.to_le_bytes()[0..size].into(), + hir_def::hir::Literal::Float(f, _) => match size { 8 => f.into_f64().to_le_bytes().into(), 4 => f.into_f32().to_le_bytes().into(), _ => { @@ -1119,19 +1209,18 @@ impl MirLowerCtx<'_> { // bad as we may emit end (unneccessary unreachable block) for unterminating loop, but // it should not affect correctness. self.current_loop_end()?; - self.labeled_loop_blocks.insert( - self.body.labels[label].name.clone(), - self.current_loop_blocks.as_ref().unwrap().clone(), - ) + self.labeled_loop_blocks + .insert(label, self.current_loop_blocks.as_ref().unwrap().clone()) } else { None }; self.set_goto(prev_block, begin); f(self, begin)?; - let my = mem::replace(&mut self.current_loop_blocks, prev) - .ok_or(MirLowerError::ImplementationError("current_loop_blocks is corrupt"))?; + let my = mem::replace(&mut self.current_loop_blocks, prev).ok_or( + MirLowerError::ImplementationError("current_loop_blocks is corrupt".to_string()), + )?; if let Some(prev) = prev_label { - self.labeled_loop_blocks.insert(self.body.labels[label.unwrap()].name.clone(), prev); + self.labeled_loop_blocks.insert(label.unwrap(), prev); } Ok(my.end) } @@ -1161,7 +1250,9 @@ impl MirLowerCtx<'_> { let r = match self .current_loop_blocks .as_mut() - .ok_or(MirLowerError::ImplementationError("Current loop access out of loop"))? + .ok_or(MirLowerError::ImplementationError( + "Current loop access out of loop".to_string(), + ))? .end { Some(x) => x, @@ -1169,7 +1260,9 @@ impl MirLowerCtx<'_> { let s = self.new_basic_block(); self.current_loop_blocks .as_mut() - .ok_or(MirLowerError::ImplementationError("Current loop access out of loop"))? + .ok_or(MirLowerError::ImplementationError( + "Current loop access out of loop".to_string(), + ))? .end = Some(s); s } @@ -1183,7 +1276,7 @@ impl MirLowerCtx<'_> { /// This function push `StorageLive` statement for the binding, and applies changes to add `StorageDead` in /// the appropriated places. - fn push_storage_live(&mut self, b: BindingId, current: BasicBlockId) { + fn push_storage_live(&mut self, b: BindingId, current: BasicBlockId) -> Result<()> { // Current implementation is wrong. It adds no `StorageDead` at the end of scope, and before each break // and continue. It just add a `StorageDead` before the `StorageLive`, which is not wrong, but unneeeded in // the proper implementation. Due this limitation, implementing a borrow checker on top of this mir will falsely @@ -1208,9 +1301,10 @@ impl MirLowerCtx<'_> { .copied() .map(MirSpan::PatId) .unwrap_or(MirSpan::Unknown); - let l = self.result.binding_locals[b]; + let l = self.binding_local(b)?; self.push_statement(current, StatementKind::StorageDead(l).with_span(span)); self.push_statement(current, StatementKind::StorageLive(l).with_span(span)); + Ok(()) } fn resolve_lang_item(&self, item: LangItem) -> Result<LangItemTarget> { @@ -1220,14 +1314,14 @@ impl MirLowerCtx<'_> { fn lower_block_to_place( &mut self, - statements: &[hir_def::expr::Statement], + statements: &[hir_def::hir::Statement], mut current: BasicBlockId, tail: Option<ExprId>, place: Place, ) -> Result<Option<Idx<BasicBlock>>> { for statement in statements.iter() { match statement { - hir_def::expr::Statement::Let { pat, initializer, else_branch, type_ref: _ } => { + hir_def::hir::Statement::Let { pat, initializer, else_branch, type_ref: _ } => { if let Some(expr_id) = initializer { let else_block; let Some((init_place, c)) = @@ -1258,12 +1352,18 @@ impl MirLowerCtx<'_> { } } } else { + let mut err = None; self.body.walk_bindings_in_pat(*pat, |b| { - self.push_storage_live(b, current); + if let Err(e) = self.push_storage_live(b, current) { + err = Some(e); + } }); + if let Some(e) = err { + return Err(e); + } } } - hir_def::expr::Statement::Expr { expr, has_semi: _ } => { + hir_def::hir::Statement::Expr { expr, has_semi: _ } => { let Some((_, c)) = self.lower_expr_as_place(current, *expr, true)? else { return Ok(None); }; @@ -1276,6 +1376,67 @@ impl MirLowerCtx<'_> { None => Ok(Some(current)), } } + + fn lower_params_and_bindings( + &mut self, + params: impl Iterator<Item = (PatId, Ty)> + Clone, + pick_binding: impl Fn(BindingId) -> bool, + ) -> Result<BasicBlockId> { + let base_param_count = self.result.param_locals.len(); + self.result.param_locals.extend(params.clone().map(|(x, ty)| { + let local_id = self.result.locals.alloc(Local { ty }); + if let Pat::Bind { id, subpat: None } = self.body[x] { + if matches!( + self.body.bindings[id].mode, + BindingAnnotation::Unannotated | BindingAnnotation::Mutable + ) { + self.result.binding_locals.insert(id, local_id); + } + } + local_id + })); + // and then rest of bindings + for (id, _) in self.body.bindings.iter() { + if !pick_binding(id) { + continue; + } + if !self.result.binding_locals.contains_idx(id) { + self.result + .binding_locals + .insert(id, self.result.locals.alloc(Local { ty: self.infer[id].clone() })); + } + } + let mut current = self.result.start_block; + for ((param, _), local) in + params.zip(self.result.param_locals.clone().into_iter().skip(base_param_count)) + { + if let Pat::Bind { id, .. } = self.body[param] { + if local == self.binding_local(id)? { + continue; + } + } + let r = self.pattern_match( + current, + None, + local.into(), + self.result.locals[local].ty.clone(), + param, + BindingAnnotation::Unannotated, + )?; + if let Some(b) = r.1 { + self.set_terminator(b, Terminator::Unreachable); + } + current = r.0; + } + Ok(current) + } + + fn binding_local(&self, b: BindingId) -> Result<LocalId> { + match self.result.binding_locals.get(b) { + Some(x) => Ok(*x), + None => Err(MirLowerError::UnaccessableLocal), + } + } } fn cast_kind(source_ty: &Ty, target_ty: &Ty) -> Result<CastKind> { @@ -1299,6 +1460,87 @@ fn cast_kind(source_ty: &Ty, target_ty: &Ty) -> Result<CastKind> { }) } +pub fn mir_body_for_closure_query( + db: &dyn HirDatabase, + closure: ClosureId, +) -> Result<Arc<MirBody>> { + let (owner, expr) = db.lookup_intern_closure(closure.into()); + let body = db.body(owner); + let infer = db.infer(owner); + let Expr::Closure { args, body: root, .. } = &body[expr] else { + implementation_error!("closure expression is not closure"); + }; + let TyKind::Closure(_, substs) = &infer[expr].kind(Interner) else { + implementation_error!("closure expression is not closure"); + }; + let (captures, _) = infer.closure_info(&closure); + let mut ctx = MirLowerCtx::new(db, owner, &body, &infer); + ctx.result.arg_count = args.len() + 1; + // 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 { + implementation_error!("closure has not callable sig"); + }; + let current = ctx.lower_params_and_bindings( + args.iter().zip(sig.params().iter()).map(|(x, y)| (*x, y.clone())), + |_| true, + )?; + if let Some(b) = ctx.lower_expr_to_place(*root, return_slot().into(), current)? { + ctx.set_terminator(b, Terminator::Return); + } + let mut upvar_map: FxHashMap<LocalId, Vec<(&CapturedItem, usize)>> = FxHashMap::default(); + for (i, capture) in captures.iter().enumerate() { + let local = ctx.binding_local(capture.place.local)?; + upvar_map.entry(local).or_default().push((capture, i)); + } + let mut err = None; + let closure_local = ctx.result.locals.iter().nth(1).unwrap().0; + ctx.result.walk_places(|p| { + if let Some(x) = upvar_map.get(&p.local) { + let r = x.iter().find(|x| { + if p.projection.len() < x.0.place.projections.len() { + return false; + } + for (x, y) in p.projection.iter().zip(x.0.place.projections.iter()) { + match (x, y) { + (ProjectionElem::Deref, ProjectionElem::Deref) => (), + (ProjectionElem::Field(x), ProjectionElem::Field(y)) if x == y => (), + ( + ProjectionElem::TupleOrClosureField(x), + ProjectionElem::TupleOrClosureField(y), + ) if x == y => (), + _ => return false, + } + } + true + }); + match r { + Some(x) => { + p.local = closure_local; + let prev_projs = + mem::replace(&mut p.projection, vec![PlaceElem::TupleOrClosureField(x.1)]); + if x.0.kind != CaptureKind::ByValue { + p.projection.push(ProjectionElem::Deref); + } + p.projection.extend(prev_projs.into_iter().skip(x.0.place.projections.len())); + } + None => err = Some(p.clone()), + } + } + }); + ctx.result.binding_locals = ctx + .result + .binding_locals + .into_iter() + .filter(|x| ctx.body[x.0].owner == Some(expr)) + .collect(); + if let Some(err) = err { + return Err(MirLowerError::UnresolvedUpvar(err)); + } + Ok(Arc::new(ctx.result)) +} + pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result<Arc<MirBody>> { let _p = profile::span("mir_body_query").detail(|| match def { DefWithBodyId::FunctionId(it) => db.function_data(it).name.to_string(), @@ -1336,86 +1578,29 @@ pub fn lower_to_mir( if let Some((_, x)) = infer.type_mismatches().next() { return Err(MirLowerError::TypeMismatch(x.clone())); } - let mut basic_blocks = Arena::new(); - let start_block = - basic_blocks.alloc(BasicBlock { statements: vec![], terminator: None, is_cleanup: false }); - let mut locals = Arena::new(); + let mut ctx = MirLowerCtx::new(db, owner, body, infer); // 0 is return local - locals.alloc(Local { ty: infer[root_expr].clone() }); - let mut binding_locals: ArenaMap<BindingId, LocalId> = ArenaMap::new(); + ctx.result.locals.alloc(Local { ty: infer[root_expr].clone() }); + let binding_picker = |b: BindingId| { + if root_expr == body.body_expr { + body[b].owner.is_none() + } else { + body[b].owner == Some(root_expr) + } + }; // 1 to param_len is for params - let param_locals: Vec<LocalId> = if let DefWithBodyId::FunctionId(fid) = owner { + let current = if let DefWithBodyId::FunctionId(fid) = owner { let substs = TyBuilder::placeholder_subst(db, fid); let callable_sig = db.callable_item_signature(fid.into()).substitute(Interner, &substs); - body.params - .iter() - .zip(callable_sig.params().iter()) - .map(|(&x, ty)| { - let local_id = locals.alloc(Local { ty: ty.clone() }); - if let Pat::Bind { id, subpat: None } = body[x] { - if matches!( - body.bindings[id].mode, - BindingAnnotation::Unannotated | BindingAnnotation::Mutable - ) { - binding_locals.insert(id, local_id); - } - } - local_id - }) - .collect() + ctx.lower_params_and_bindings( + body.params.iter().zip(callable_sig.params().iter()).map(|(x, y)| (*x, y.clone())), + binding_picker, + )? } else { - if !body.params.is_empty() { - return Err(MirLowerError::TypeError("Unexpected parameter for non function body")); - } - vec![] + ctx.lower_params_and_bindings([].into_iter(), binding_picker)? }; - // and then rest of bindings - for (id, _) in body.bindings.iter() { - if !binding_locals.contains_idx(id) { - binding_locals.insert(id, locals.alloc(Local { ty: infer[id].clone() })); - } - } - let mir = MirBody { - basic_blocks, - locals, - start_block, - binding_locals, - param_locals, - owner, - arg_count: body.params.len(), - }; - let mut ctx = MirLowerCtx { - result: mir, - db, - infer, - body, - owner, - current_loop_blocks: None, - labeled_loop_blocks: Default::default(), - discr_temp: None, - }; - let mut current = start_block; - for (¶m, local) in body.params.iter().zip(ctx.result.param_locals.clone().into_iter()) { - if let Pat::Bind { id, .. } = body[param] { - if local == ctx.result.binding_locals[id] { - continue; - } - } - let r = ctx.pattern_match( - current, - None, - local.into(), - ctx.result.locals[local].ty.clone(), - param, - BindingAnnotation::Unannotated, - )?; - if let Some(b) = r.1 { - ctx.set_terminator(b, Terminator::Unreachable); - } - current = r.0; - } if let Some(b) = ctx.lower_expr_to_place(root_expr, return_slot().into(), current)? { - ctx.result.basic_blocks[b].terminator = Some(Terminator::Return); + ctx.set_terminator(b, Terminator::Return); } Ok(ctx.result) } |