about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-06-03 13:55:40 +0000
committerbors <bors@rust-lang.org>2023-06-03 13:55:40 +0000
commite5c56cd9a03c8cb032a9aa139cf8084b08d73dde (patch)
treea6d73a266a6e31a4a2d796d9f4d97519f40063f7
parentdd0c29c934467ecc121ae73039381ae34fa3caf2 (diff)
parentf44fc271d459d280c733f39b8af8747875eecfa9 (diff)
downloadrust-e5c56cd9a03c8cb032a9aa139cf8084b08d73dde.tar.gz
rust-e5c56cd9a03c8cb032a9aa139cf8084b08d73dde.zip
Auto merge of #14955 - HKalbasi:mir-fix, r=HKalbasi
Remove unnecessary `StorageDead`

I hope this reduces MIR memory usage.
-rw-r--r--crates/hir-ty/src/infer/closure.rs105
-rw-r--r--crates/hir-ty/src/mir/lower.rs27
-rw-r--r--crates/hir-ty/src/mir/lower/pattern_matching.rs385
-rw-r--r--crates/hir-ty/src/utils.rs22
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 662f2e5fa16..754ac88bb50 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::<Vec<_>>()
+            .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 ebd41998355..ef94b3650bc 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 ee2a0306d5e..5cd1be68424 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
@@ -30,19 +50,49 @@ impl MirLowerCtx<'_> {
     /// so it should be an empty block.
     pub(super) fn pattern_match(
         &mut self,
+        current: BasicBlockId,
+        current_else: Option<BasicBlockId>,
+        cond_place: Place,
+        pattern: PatId,
+    ) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
+        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<BasicBlockId>,
         mut cond_place: Place,
-        mut cond_ty: Ty,
         pattern: PatId,
-        mut binding_mode: BindingAnnotation,
+        mode: MatchingMode,
     ) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
+        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::<Vec<_>>()
+            .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<BasicBlockId>,
     ) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
         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<BasicBlockId>,
+        mut current_else: Option<BasicBlockId>,
         shape: AdtPatternShape<'_>,
+        mode: MatchingMode,
     ) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
-        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<BasicBlockId>,
         cond_place: &Place,
-        binding_mode: BindingAnnotation,
+        mode: MatchingMode,
     ) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
-        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::<Result<Vec<_>>>()?;
-                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<BasicBlockId>,
-        args: impl Iterator<Item = (PlaceElem, PatId, Ty)>,
+        args: impl Iterator<Item = (PlaceElem, PatId)>,
         cond_place: &Place,
-        binding_mode: BindingAnnotation,
+        mode: MatchingMode,
     ) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
-        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<BasicBlockId>,
         args: &[PatId],
         ellipsis: Option<usize>,
-        fields: impl DoubleEndedIterator<Item = (PlaceElem, Ty)> + Clone,
+        fields: impl DoubleEndedIterator<Item = PlaceElem> + Clone,
         cond_place: &Place,
-        binding_mode: BindingAnnotation,
+        mode: MatchingMode,
     ) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
         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::<Vec<_>>()
-        .into();
-}
diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs
index 8f36188b78a..681d087ede6 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,
 }