From f44fc271d459d280c733f39b8af8747875eecfa9 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Sat, 3 Jun 2023 17:24:10 +0330 Subject: [PATCH] Remove unnecessary `StorageDead` --- crates/hir-ty/src/infer/closure.rs | 105 ++--- crates/hir-ty/src/mir/lower.rs | 27 +- .../hir-ty/src/mir/lower/pattern_matching.rs | 385 +++++++++--------- crates/hir-ty/src/utils.rs | 22 +- 4 files changed, 238 insertions(+), 301 deletions(-) diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs index 662f2e5fa1..754ac88bb5 100644 --- a/crates/hir-ty/src/infer/closure.rs +++ b/crates/hir-ty/src/infer/closure.rs @@ -9,10 +9,7 @@ use chalk_ir::{ }; use hir_def::{ data::adt::VariantData, - hir::{ - Array, BinaryOp, BindingAnnotation, BindingId, CaptureBy, Expr, ExprId, Pat, PatId, - Statement, UnaryOp, - }, + hir::{Array, BinaryOp, BindingId, CaptureBy, Expr, ExprId, Pat, PatId, Statement, UnaryOp}, lang_item::LangItem, resolver::{resolver_for_expr, ResolveValueResult, ValueNs}, DefWithBodyId, FieldId, HasModule, VariantId, @@ -28,9 +25,9 @@ use crate::{ mir::{BorrowKind, MirSpan, ProjectionElem}, static_lifetime, to_chalk_trait_id, traits::FnTrait, - utils::{self, generics, pattern_matching_dereference_count, Generics}, - Adjust, Adjustment, Binders, ChalkTraitId, ClosureId, ConstValue, DynTy, FnPointer, FnSig, - Interner, Substitution, Ty, TyExt, + utils::{self, generics, Generics}, + Adjust, Adjustment, Binders, BindingMode, ChalkTraitId, ClosureId, ConstValue, DynTy, + FnPointer, FnSig, Interner, Substitution, Ty, TyExt, }; use super::{Expectation, InferenceContext}; @@ -488,13 +485,7 @@ impl InferenceContext<'_> { if let Some(initializer) = initializer { self.walk_expr(*initializer); if let Some(place) = self.place_of_expr(*initializer) { - let ty = self.expr_ty(*initializer); - self.consume_with_pat( - place, - ty, - BindingAnnotation::Unannotated, - *pat, - ); + self.consume_with_pat(place, *pat); } } } @@ -799,41 +790,37 @@ impl InferenceContext<'_> { } } - fn consume_with_pat( - &mut self, - mut place: HirPlace, - mut ty: Ty, - mut bm: BindingAnnotation, - pat: PatId, - ) { + fn consume_with_pat(&mut self, mut place: HirPlace, pat: PatId) { + let cnt = self.result.pat_adjustments.get(&pat).map(|x| x.len()).unwrap_or_default(); + place.projections = place + .projections + .iter() + .cloned() + .chain((0..cnt).map(|_| ProjectionElem::Deref)) + .collect::>() + .into(); match &self.body[pat] { Pat::Missing | Pat::Wild => (), Pat::Tuple { args, ellipsis } => { - pattern_matching_dereference(&mut ty, &mut bm, &mut place); let (al, ar) = args.split_at(ellipsis.unwrap_or(args.len())); - let subst = match ty.kind(Interner) { - TyKind::Tuple(_, s) => s, + let field_count = match self.result[pat].kind(Interner) { + TyKind::Tuple(_, s) => s.len(Interner), _ => return, }; - let fields = subst.iter(Interner).map(|x| x.assert_ty_ref(Interner)).enumerate(); + let fields = 0..field_count; let it = al.iter().zip(fields.clone()).chain(ar.iter().rev().zip(fields.rev())); - for (arg, (i, ty)) in it { + for (arg, i) in it { let mut p = place.clone(); p.projections.push(ProjectionElem::TupleOrClosureField(i)); - self.consume_with_pat(p, ty.clone(), bm, *arg); + self.consume_with_pat(p, *arg); } } Pat::Or(pats) => { for pat in pats.iter() { - self.consume_with_pat(place.clone(), ty.clone(), bm, *pat); + self.consume_with_pat(place.clone(), *pat); } } Pat::Record { args, .. } => { - pattern_matching_dereference(&mut ty, &mut bm, &mut place); - let subst = match ty.kind(Interner) { - TyKind::Adt(_, s) => s, - _ => return, - }; let Some(variant) = self.result.variant_resolution_for_pat(pat) else { return; }; @@ -843,7 +830,6 @@ impl InferenceContext<'_> { } VariantId::StructId(s) => { let vd = &*self.db.struct_data(s).variant_data; - let field_types = self.db.field_types(variant); for field_pat in args.iter() { let arg = field_pat.pat; let Some(local_id) = vd.field(&field_pat.name) else { @@ -854,12 +840,7 @@ impl InferenceContext<'_> { parent: variant.into(), local_id, })); - self.consume_with_pat( - p, - field_types[local_id].clone().substitute(Interner, subst), - bm, - arg, - ); + self.consume_with_pat(p, arg); } } } @@ -870,26 +851,20 @@ impl InferenceContext<'_> { | Pat::Path(_) | Pat::Lit(_) => self.consume_place(place, pat.into()), Pat::Bind { id, subpat: _ } => { - let mode = self.body.bindings[*id].mode; - if matches!(mode, BindingAnnotation::Ref | BindingAnnotation::RefMut) { - bm = mode; - } - let capture_kind = match bm { - BindingAnnotation::Unannotated | BindingAnnotation::Mutable => { + let mode = self.result.binding_modes[*id]; + let capture_kind = match mode { + BindingMode::Move => { self.consume_place(place, pat.into()); return; } - BindingAnnotation::Ref => BorrowKind::Shared, - BindingAnnotation::RefMut => BorrowKind::Mut { allow_two_phase_borrow: false }, + BindingMode::Ref(Mutability::Not) => BorrowKind::Shared, + BindingMode::Ref(Mutability::Mut) => { + BorrowKind::Mut { allow_two_phase_borrow: false } + } }; self.add_capture(place, CaptureKind::ByRef(capture_kind), pat.into()); } Pat::TupleStruct { path: _, args, ellipsis } => { - pattern_matching_dereference(&mut ty, &mut bm, &mut place); - let subst = match ty.kind(Interner) { - TyKind::Adt(_, s) => s, - _ => return, - }; let Some(variant) = self.result.variant_resolution_for_pat(pat) else { return; }; @@ -903,29 +878,20 @@ impl InferenceContext<'_> { let fields = vd.fields().iter(); let it = al.iter().zip(fields.clone()).chain(ar.iter().rev().zip(fields.rev())); - let field_types = self.db.field_types(variant); for (arg, (i, _)) in it { let mut p = place.clone(); p.projections.push(ProjectionElem::Field(FieldId { parent: variant.into(), local_id: i, })); - self.consume_with_pat( - p, - field_types[i].clone().substitute(Interner, subst), - bm, - *arg, - ); + self.consume_with_pat(p, *arg); } } } } Pat::Ref { pat, mutability: _ } => { - if let Some((inner, _, _)) = ty.as_reference() { - ty = inner.clone(); - place.projections.push(ProjectionElem::Deref); - self.consume_with_pat(place, ty, bm, *pat) - } + place.projections.push(ProjectionElem::Deref); + self.consume_with_pat(place, *pat) } Pat::Box { .. } => (), // not supported } @@ -1054,12 +1020,3 @@ fn apply_adjusts_to_place(mut r: HirPlace, adjustments: &[Adjustment]) -> Option } Some(r) } - -fn pattern_matching_dereference( - cond_ty: &mut Ty, - binding_mode: &mut BindingAnnotation, - cond_place: &mut HirPlace, -) { - let cnt = pattern_matching_dereference_count(cond_ty, binding_mode); - cond_place.projections.extend((0..cnt).map(|_| ProjectionElem::Deref)); -} diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index ebd4199835..ef94b3650b 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -478,9 +478,7 @@ impl<'ctx> MirLowerCtx<'ctx> { current, None, cond_place, - self.expr_ty_after_adjustments(*expr), *pat, - BindingAnnotation::Unannotated, )?; self.write_bytes_to_place( then_target, @@ -598,16 +596,13 @@ impl<'ctx> MirLowerCtx<'ctx> { else { return Ok(None); }; - let cond_ty = self.expr_ty_after_adjustments(*expr); let mut end = None; for MatchArm { pat, guard, expr } in arms.iter() { let (then, mut otherwise) = self.pattern_match( current, None, cond_place.clone(), - cond_ty.clone(), *pat, - BindingAnnotation::Unannotated, )?; let then = if let &Some(guard) = guard { let next = self.new_basic_block(); @@ -1477,9 +1472,6 @@ impl<'ctx> MirLowerCtx<'ctx> { span: MirSpan, ) -> Result<()> { self.drop_scopes.last_mut().unwrap().locals.push(l); - // FIXME: this storage dead is not neccessary, but since drop scope handling is broken, we need - // it to avoid falso positives in mutability errors - self.push_statement(current, StatementKind::StorageDead(l).with_span(span)); self.push_statement(current, StatementKind::StorageLive(l).with_span(span)); Ok(()) } @@ -1508,14 +1500,8 @@ impl<'ctx> MirLowerCtx<'ctx> { return Ok(None); }; current = c; - (current, else_block) = self.pattern_match( - current, - None, - init_place, - self.expr_ty_after_adjustments(*expr_id), - *pat, - BindingAnnotation::Unannotated, - )?; + (current, else_block) = + self.pattern_match(current, None, init_place, *pat)?; match (else_block, else_branch) { (None, _) => (), (Some(else_block), None) => { @@ -1595,14 +1581,7 @@ impl<'ctx> MirLowerCtx<'ctx> { continue; } } - let r = self.pattern_match( - current, - None, - local.into(), - self.result.locals[local].ty.clone(), - param, - BindingAnnotation::Unannotated, - )?; + let r = self.pattern_match(current, None, local.into(), param)?; if let Some(b) = r.1 { self.set_terminator(b, TerminatorKind::Unreachable, param.into()); } diff --git a/crates/hir-ty/src/mir/lower/pattern_matching.rs b/crates/hir-ty/src/mir/lower/pattern_matching.rs index ee2a0306d5..5cd1be6842 100644 --- a/crates/hir-ty/src/mir/lower/pattern_matching.rs +++ b/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -2,7 +2,7 @@ use hir_def::{hir::LiteralOrConst, resolver::HasResolver, AssocItemId}; -use crate::utils::pattern_matching_dereference_count; +use crate::BindingMode; use super::*; @@ -18,6 +18,26 @@ pub(super) enum AdtPatternShape<'a> { Unit, } +/// We need to do pattern matching in two phases: One to check if the pattern matches, and one to fill the bindings +/// of patterns. This is necessary to prevent double moves and similar problems. For example: +/// ```ignore +/// struct X; +/// match (X, 3) { +/// (b, 2) | (b, 3) => {}, +/// _ => {} +/// } +/// ``` +/// If we do everything in one pass, we will move `X` to the first `b`, then we see that the second field of tuple +/// doesn't match and we should move the `X` to the second `b` (which here is the same thing, but doesn't need to be) and +/// it might even doesn't match the second pattern and we may want to not move `X` at all. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum MatchingMode { + /// Check that if this pattern matches + Check, + /// Assume that this pattern matches, fill bindings + Bind, +} + impl MirLowerCtx<'_> { /// It gets a `current` unterminated block, appends some statements and possibly a terminator to it to check if /// the pattern matches and write bindings, and returns two unterminated blocks, one for the matched path (which @@ -29,20 +49,50 @@ impl MirLowerCtx<'_> { /// wouldn't be `None` as well. Note that this function will add jumps to the beginning of the `current_else` block, /// so it should be an empty block. pub(super) fn pattern_match( + &mut self, + current: BasicBlockId, + current_else: Option, + cond_place: Place, + pattern: PatId, + ) -> Result<(BasicBlockId, Option)> { + let (current, current_else) = self.pattern_match_inner( + current, + current_else, + cond_place.clone(), + pattern, + MatchingMode::Check, + )?; + let (current, current_else) = self.pattern_match_inner( + current, + current_else, + cond_place, + pattern, + MatchingMode::Bind, + )?; + Ok((current, current_else)) + } + + fn pattern_match_inner( &mut self, mut current: BasicBlockId, mut current_else: Option, mut cond_place: Place, - mut cond_ty: Ty, pattern: PatId, - mut binding_mode: BindingAnnotation, + mode: MatchingMode, ) -> Result<(BasicBlockId, Option)> { + let cnt = self.infer.pat_adjustments.get(&pattern).map(|x| x.len()).unwrap_or_default(); + cond_place.projection = cond_place + .projection + .iter() + .cloned() + .chain((0..cnt).map(|_| ProjectionElem::Deref)) + .collect::>() + .into(); Ok(match &self.body.pats[pattern] { Pat::Missing => return Err(MirLowerError::IncompletePattern), Pat::Wild => (current, current_else), Pat::Tuple { args, ellipsis } => { - pattern_matching_dereference(&mut cond_ty, &mut binding_mode, &mut cond_place); - let subst = match cond_ty.kind(Interner) { + let subst = match self.infer[pattern].kind(Interner) { TyKind::Tuple(_, s) => s, _ => { return Err(MirLowerError::TypeError( @@ -55,25 +105,31 @@ impl MirLowerCtx<'_> { current_else, args, *ellipsis, - subst.iter(Interner).enumerate().map(|(i, x)| { - (PlaceElem::TupleOrClosureField(i), x.assert_ty_ref(Interner).clone()) - }), - &cond_place, - binding_mode, + (0..subst.len(Interner)).map(|i| PlaceElem::TupleOrClosureField(i)), + &(&mut cond_place), + mode, )? } Pat::Or(pats) => { let then_target = self.new_basic_block(); let mut finished = false; for pat in &**pats { - let (next, next_else) = self.pattern_match( + let (mut next, next_else) = self.pattern_match_inner( current, None, - cond_place.clone(), - cond_ty.clone(), + (&mut cond_place).clone(), *pat, - binding_mode, + MatchingMode::Check, )?; + if mode == MatchingMode::Bind { + (next, _) = self.pattern_match_inner( + next, + None, + (&mut cond_place).clone(), + *pat, + MatchingMode::Bind, + )?; + } self.set_goto(next, then_target, pattern.into()); match next_else { Some(t) => { @@ -86,8 +142,12 @@ impl MirLowerCtx<'_> { } } if !finished { - let ce = *current_else.get_or_insert_with(|| self.new_basic_block()); - self.set_goto(current, ce, pattern.into()); + if mode == MatchingMode::Bind { + self.set_terminator(current, TerminatorKind::Unreachable, pattern.into()); + } else { + let ce = *current_else.get_or_insert_with(|| self.new_basic_block()); + self.set_goto(current, ce, pattern.into()); + } } (then_target, current_else) } @@ -96,19 +156,19 @@ impl MirLowerCtx<'_> { not_supported!("unresolved variant for record"); }; self.pattern_matching_variant( - cond_ty, - binding_mode, cond_place, variant, current, pattern.into(), current_else, AdtPatternShape::Record { args: &*args }, + mode, )? } Pat::Range { start, end } => { let mut add_check = |l: &LiteralOrConst, binop| -> Result<()> { - let lv = self.lower_literal_or_const_to_operand(cond_ty.clone(), l)?; + let lv = + self.lower_literal_or_const_to_operand(self.infer[pattern].clone(), l)?; let else_target = *current_else.get_or_insert_with(|| self.new_basic_block()); let next = self.new_basic_block(); let discr: Place = @@ -116,7 +176,11 @@ impl MirLowerCtx<'_> { self.push_assignment( current, discr.clone(), - Rvalue::CheckedBinaryOp(binop, lv, Operand::Copy(cond_place.clone())), + Rvalue::CheckedBinaryOp( + binop, + lv, + Operand::Copy((&mut cond_place).clone()), + ), pattern.into(), ); let discr = Operand::Copy(discr); @@ -131,24 +195,25 @@ impl MirLowerCtx<'_> { current = next; Ok(()) }; - if let Some(start) = start { - add_check(start, BinOp::Le)?; - } - if let Some(end) = end { - add_check(end, BinOp::Ge)?; + if mode == MatchingMode::Check { + if let Some(start) = start { + add_check(start, BinOp::Le)?; + } + if let Some(end) = end { + add_check(end, BinOp::Ge)?; + } } (current, current_else) } Pat::Slice { prefix, slice, suffix } => { - pattern_matching_dereference(&mut cond_ty, &mut binding_mode, &mut cond_place); - if let TyKind::Slice(_) = cond_ty.kind(Interner) { + if let TyKind::Slice(_) = self.infer[pattern].kind(Interner) { let pattern_len = prefix.len() + suffix.len(); let place_len: Place = self.temp(TyBuilder::usize(), current, pattern.into())?.into(); self.push_assignment( current, place_len.clone(), - Rvalue::Len(cond_place.clone()), + Rvalue::Len((&mut cond_place).clone()), pattern.into(), ); let else_target = *current_else.get_or_insert_with(|| self.new_basic_block()); @@ -193,63 +258,49 @@ impl MirLowerCtx<'_> { current = next; } for (i, &pat) in prefix.iter().enumerate() { - let next_place = cond_place.project(ProjectionElem::ConstantIndex { + let next_place = (&mut cond_place).project(ProjectionElem::ConstantIndex { offset: i as u64, from_end: false, }); - let cond_ty = self.infer[pat].clone(); - (current, current_else) = self.pattern_match( - current, - current_else, - next_place, - cond_ty, - pat, - binding_mode, - )?; + (current, current_else) = + self.pattern_match_inner(current, current_else, next_place, pat, mode)?; } if let Some(slice) = slice { - if let Pat::Bind { id, subpat: _ } = self.body[*slice] { - let next_place = cond_place.project(ProjectionElem::Subslice { - from: prefix.len() as u64, - to: suffix.len() as u64, - }); - (current, current_else) = self.pattern_match_binding( - id, - &mut binding_mode, - next_place, - (*slice).into(), - current, - current_else, - )?; + if mode == MatchingMode::Bind { + if let Pat::Bind { id, subpat: _ } = self.body[*slice] { + let next_place = (&mut cond_place).project(ProjectionElem::Subslice { + from: prefix.len() as u64, + to: suffix.len() as u64, + }); + (current, current_else) = self.pattern_match_binding( + id, + next_place, + (*slice).into(), + current, + current_else, + )?; + } } } for (i, &pat) in suffix.iter().enumerate() { - let next_place = cond_place.project(ProjectionElem::ConstantIndex { + let next_place = (&mut cond_place).project(ProjectionElem::ConstantIndex { offset: i as u64, from_end: true, }); - let cond_ty = self.infer[pat].clone(); - (current, current_else) = self.pattern_match( - current, - current_else, - next_place, - cond_ty, - pat, - binding_mode, - )?; + (current, current_else) = + self.pattern_match_inner(current, current_else, next_place, pat, mode)?; } (current, current_else) } Pat::Path(p) => match self.infer.variant_resolution_for_pat(pattern) { Some(variant) => self.pattern_matching_variant( - cond_ty, - binding_mode, cond_place, variant, current, pattern.into(), current_else, AdtPatternShape::Unit, + mode, )?, None => { let unresolved_name = || MirLowerError::unresolved_path(self.db, p); @@ -270,9 +321,17 @@ impl MirLowerCtx<'_> { } not_supported!("path in pattern position that is not const or variant") }; - let tmp: Place = self.temp(cond_ty.clone(), current, pattern.into())?.into(); + let tmp: Place = + self.temp(self.infer[pattern].clone(), current, pattern.into())?.into(); let span = pattern.into(); - self.lower_const(c.into(), current, tmp.clone(), subst, span, cond_ty.clone())?; + self.lower_const( + c.into(), + current, + tmp.clone(), + subst, + span, + self.infer[pattern].clone(), + )?; let tmp2: Place = self.temp(TyBuilder::bool(), current, pattern.into())?.into(); self.push_assignment( current, @@ -299,61 +358,58 @@ impl MirLowerCtx<'_> { }, Pat::Lit(l) => match &self.body.exprs[*l] { Expr::Literal(l) => { - let c = self.lower_literal_to_operand(cond_ty, l)?; - self.pattern_match_const(current_else, current, c, cond_place, pattern)? + let c = self.lower_literal_to_operand(self.infer[pattern].clone(), l)?; + if mode == MatchingMode::Check { + self.pattern_match_const(current_else, current, c, cond_place, pattern)? + } else { + (current, current_else) + } } _ => not_supported!("expression path literal"), }, Pat::Bind { id, subpat } => { if let Some(subpat) = subpat { - (current, current_else) = self.pattern_match( + (current, current_else) = self.pattern_match_inner( current, current_else, - cond_place.clone(), - cond_ty, + (&mut cond_place).clone(), *subpat, - binding_mode, + mode, )? } - self.pattern_match_binding( - *id, - &mut binding_mode, - cond_place, - pattern.into(), - current, - current_else, - )? + if mode == MatchingMode::Bind { + self.pattern_match_binding( + *id, + cond_place, + pattern.into(), + current, + current_else, + )? + } else { + (current, current_else) + } } Pat::TupleStruct { path: _, args, ellipsis } => { let Some(variant) = self.infer.variant_resolution_for_pat(pattern) else { not_supported!("unresolved variant"); }; self.pattern_matching_variant( - cond_ty, - binding_mode, cond_place, variant, current, pattern.into(), current_else, AdtPatternShape::Tuple { args, ellipsis: *ellipsis }, + mode, )? } - Pat::Ref { pat, mutability: _ } => { - if let Some((ty, _, _)) = cond_ty.as_reference() { - cond_ty = ty.clone(); - self.pattern_match( - current, - current_else, - cond_place.project(ProjectionElem::Deref), - cond_ty, - *pat, - binding_mode, - )? - } else { - return Err(MirLowerError::TypeError("& pattern for non reference")); - } - } + Pat::Ref { pat, mutability: _ } => self.pattern_match_inner( + current, + current_else, + cond_place.project(ProjectionElem::Deref), + *pat, + mode, + )?, Pat::Box { .. } => not_supported!("box pattern"), Pat::ConstBlock(_) => not_supported!("const block pattern"), }) @@ -362,27 +418,21 @@ impl MirLowerCtx<'_> { fn pattern_match_binding( &mut self, id: BindingId, - binding_mode: &mut BindingAnnotation, cond_place: Place, span: MirSpan, current: BasicBlockId, current_else: Option, ) -> Result<(BasicBlockId, Option)> { let target_place = self.binding_local(id)?; - let mode = self.body.bindings[id].mode; - if matches!(mode, BindingAnnotation::Ref | BindingAnnotation::RefMut) { - *binding_mode = mode; - } + let mode = self.infer.binding_modes[id]; self.push_storage_live(id, current)?; self.push_assignment( current, target_place.into(), - match *binding_mode { - BindingAnnotation::Unannotated | BindingAnnotation::Mutable => { - Operand::Copy(cond_place).into() - } - BindingAnnotation::Ref => Rvalue::Ref(BorrowKind::Shared, cond_place), - BindingAnnotation::RefMut => { + match mode { + BindingMode::Move => Operand::Copy(cond_place).into(), + BindingMode::Ref(Mutability::Not) => Rvalue::Ref(BorrowKind::Shared, cond_place), + BindingMode::Ref(Mutability::Mut) => { Rvalue::Ref(BorrowKind::Mut { allow_two_phase_borrow: false }, cond_place) } }, @@ -420,52 +470,48 @@ impl MirLowerCtx<'_> { Ok((then_target, Some(else_target))) } - pub(super) fn pattern_matching_variant( + fn pattern_matching_variant( &mut self, - mut cond_ty: Ty, - mut binding_mode: BindingAnnotation, - mut cond_place: Place, + cond_place: Place, variant: VariantId, - current: BasicBlockId, + mut current: BasicBlockId, span: MirSpan, - current_else: Option, + mut current_else: Option, shape: AdtPatternShape<'_>, + mode: MatchingMode, ) -> Result<(BasicBlockId, Option)> { - pattern_matching_dereference(&mut cond_ty, &mut binding_mode, &mut cond_place); - let subst = match cond_ty.kind(Interner) { - TyKind::Adt(_, s) => s, - _ => return Err(MirLowerError::TypeError("non adt type matched with tuple struct")), - }; Ok(match variant { VariantId::EnumVariantId(v) => { - let e = self.const_eval_discriminant(v)? as u128; - let tmp = self.discr_temp_place(current); - self.push_assignment( - current, - tmp.clone(), - Rvalue::Discriminant(cond_place.clone()), - span, - ); - let next = self.new_basic_block(); - let else_target = current_else.unwrap_or_else(|| self.new_basic_block()); - self.set_terminator( - current, - TerminatorKind::SwitchInt { - discr: Operand::Copy(tmp), - targets: SwitchTargets::static_if(e, next, else_target), - }, - span, - ); + if mode == MatchingMode::Check { + let e = self.const_eval_discriminant(v)? as u128; + let tmp = self.discr_temp_place(current); + self.push_assignment( + current, + tmp.clone(), + Rvalue::Discriminant(cond_place.clone()), + span, + ); + let next = self.new_basic_block(); + let else_target = current_else.get_or_insert_with(|| self.new_basic_block()); + self.set_terminator( + current, + TerminatorKind::SwitchInt { + discr: Operand::Copy(tmp), + targets: SwitchTargets::static_if(e, next, *else_target), + }, + span, + ); + current = next; + } let enum_data = self.db.enum_data(v.parent); self.pattern_matching_variant_fields( shape, &enum_data.variants[v.local_id].variant_data, variant, - subst, - next, - Some(else_target), + current, + current_else, &cond_place, - binding_mode, + mode, )? } VariantId::StructId(s) => { @@ -474,11 +520,10 @@ impl MirLowerCtx<'_> { shape, &struct_data.variant_data, variant, - subst, current, current_else, &cond_place, - binding_mode, + mode, )? } VariantId::UnionId(_) => { @@ -492,13 +537,11 @@ impl MirLowerCtx<'_> { shape: AdtPatternShape<'_>, variant_data: &VariantData, v: VariantId, - subst: &Substitution, current: BasicBlockId, current_else: Option, cond_place: &Place, - binding_mode: BindingAnnotation, + mode: MatchingMode, ) -> Result<(BasicBlockId, Option)> { - let fields_type = self.db.field_types(v); Ok(match shape { AdtPatternShape::Record { args } => { let it = args @@ -509,25 +552,16 @@ impl MirLowerCtx<'_> { Ok(( PlaceElem::Field(FieldId { parent: v.into(), local_id: field_id }), x.pat, - fields_type[field_id].clone().substitute(Interner, subst), )) }) .collect::>>()?; - self.pattern_match_adt( - current, - current_else, - it.into_iter(), - cond_place, - binding_mode, - )? + self.pattern_match_adt(current, current_else, it.into_iter(), cond_place, mode)? } AdtPatternShape::Tuple { args, ellipsis } => { - let fields = variant_data.fields().iter().map(|(x, _)| { - ( - PlaceElem::Field(FieldId { parent: v.into(), local_id: x }), - fields_type[x].clone().substitute(Interner, subst), - ) - }); + let fields = variant_data + .fields() + .iter() + .map(|(x, _)| PlaceElem::Field(FieldId { parent: v.into(), local_id: x })); self.pattern_match_tuple_like( current, current_else, @@ -535,7 +569,7 @@ impl MirLowerCtx<'_> { ellipsis, fields, cond_place, - binding_mode, + mode, )? } AdtPatternShape::Unit => (current, current_else), @@ -546,14 +580,14 @@ impl MirLowerCtx<'_> { &mut self, mut current: BasicBlockId, mut current_else: Option, - args: impl Iterator, + args: impl Iterator, cond_place: &Place, - binding_mode: BindingAnnotation, + mode: MatchingMode, ) -> Result<(BasicBlockId, Option)> { - for (proj, arg, ty) in args { + for (proj, arg) in args { let cond_place = cond_place.project(proj); (current, current_else) = - self.pattern_match(current, current_else, cond_place, ty, arg, binding_mode)?; + self.pattern_match_inner(current, current_else, cond_place, arg, mode)?; } Ok((current, current_else)) } @@ -564,31 +598,16 @@ impl MirLowerCtx<'_> { current_else: Option, args: &[PatId], ellipsis: Option, - fields: impl DoubleEndedIterator + Clone, + fields: impl DoubleEndedIterator + Clone, cond_place: &Place, - binding_mode: BindingAnnotation, + mode: MatchingMode, ) -> Result<(BasicBlockId, Option)> { let (al, ar) = args.split_at(ellipsis.unwrap_or(args.len())); let it = al .iter() .zip(fields.clone()) .chain(ar.iter().rev().zip(fields.rev())) - .map(|(x, y)| (y.0, *x, y.1)); - self.pattern_match_adt(current, current_else, it, cond_place, binding_mode) + .map(|(x, y)| (y, *x)); + self.pattern_match_adt(current, current_else, it, cond_place, mode) } } - -fn pattern_matching_dereference( - cond_ty: &mut Ty, - binding_mode: &mut BindingAnnotation, - cond_place: &mut Place, -) { - let cnt = pattern_matching_dereference_count(cond_ty, binding_mode); - cond_place.projection = cond_place - .projection - .iter() - .cloned() - .chain((0..cnt).map(|_| ProjectionElem::Deref)) - .collect::>() - .into(); -} diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs index 8f36188b78..681d087ede 100644 --- a/crates/hir-ty/src/utils.rs +++ b/crates/hir-ty/src/utils.rs @@ -7,7 +7,7 @@ use base_db::CrateId; use chalk_ir::{ cast::Cast, fold::{FallibleTypeFolder, Shift}, - BoundVar, DebruijnIndex, Mutability, + BoundVar, DebruijnIndex, }; use either::Either; use hir_def::{ @@ -16,7 +16,6 @@ use hir_def::{ GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget, }, - hir::BindingAnnotation, lang_item::LangItem, resolver::{HasResolver, TypeNs}, type_ref::{TraitBoundModifier, TypeRef}, @@ -35,7 +34,7 @@ use crate::{ layout::{Layout, TagEncoding}, mir::pad16, ChalkTraitId, Const, ConstScalar, GenericArg, Interner, Substitution, TraitRef, TraitRefExt, - Ty, TyExt, WhereClause, + Ty, WhereClause, }; pub(crate) fn fn_traits( @@ -395,23 +394,6 @@ pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool { } } -pub(crate) fn pattern_matching_dereference_count( - cond_ty: &mut Ty, - binding_mode: &mut BindingAnnotation, -) -> usize { - let mut r = 0; - while let Some((ty, _, mu)) = cond_ty.as_reference() { - if mu == Mutability::Mut && *binding_mode != BindingAnnotation::Ref { - *binding_mode = BindingAnnotation::RefMut; - } else { - *binding_mode = BindingAnnotation::Ref; - } - *cond_ty = ty.clone(); - r += 1; - } - r -} - pub(crate) struct UnevaluatedConstEvaluatorFolder<'a> { pub(crate) db: &'a dyn HirDatabase, }