about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorb-naber <bn263@gmx.de>2022-11-21 20:56:27 +0100
committerb-naber <bn263@gmx.de>2022-11-23 20:55:15 +0100
commit4040734e44d72697dbeb35c4c1be1a70cb7b0b37 (patch)
tree64c4eaf4499cde4f82474ff9876881f6d10e77c7 /compiler
parentfd6fed3027be425c27a5a8c825575bdd7a1e63dd (diff)
downloadrust-4040734e44d72697dbeb35c4c1be1a70cb7b0b37.tar.gz
rust-4040734e44d72697dbeb35c4c1be1a70cb7b0b37.zip
get field ty during projecting
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs264
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs9
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs6
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs3
-rw-r--r--compiler/rustc_mir_build/src/build/matches/util.rs73
5 files changed, 187 insertions, 168 deletions
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index 36f08a7a48f..5c9459c97f4 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -21,21 +21,28 @@ use rustc_index::vec::Idx;
 use std::assert_matches::assert_matches;
 use std::iter;
 
-/// The "outermost" place that holds this value.
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub(crate) enum PlaceBase {
+/// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a
+/// place by pushing more and more projections onto the end, and then convert the final set into a
+/// place using the `into_place` method.
+///
+/// This is used internally when building a place for an expression like `a.b.c`. The fields `b`
+/// and `c` can be progressively pushed onto the place builder that is created when converting `a`.
+#[derive(Clone, Debug, PartialEq)]
+pub(in crate::build) enum PlaceBuilder<'tcx> {
     /// Denotes the start of a `Place`.
-    Local(Local),
+    ///
+    /// We use `PlaceElem` since this has all `Field` types available.
+    Local(Local, Vec<PlaceElem<'tcx>>),
 
     /// When building place for an expression within a closure, the place might start off a
     /// captured path. When `capture_disjoint_fields` is enabled, we might not know the capture
     /// index (within the desugared closure) of the captured path until most of the projections
-    /// are applied. We use `PlaceBase::Upvar` to keep track of the root variable off of which the
+    /// are applied. We use `PlaceBuilder::Upvar` to keep track of the root variable off of which the
     /// captured path starts, the closure the capture belongs to and the trait the closure
     /// implements.
     ///
-    /// Once we have figured out the capture index, we can convert the place builder to start from
-    /// `PlaceBase::Local`.
+    /// Once we have figured out the capture index, we can convert the place builder to
+    /// `PlaceBuilder::Local`.
     ///
     /// Consider the following example
     /// ```rust
@@ -56,24 +63,16 @@ pub(crate) enum PlaceBase {
     ///
     /// When `capture_disjoint_fields` is enabled, `t.0.0.0` is captured and we won't be able to
     /// figure out that it is captured until all the `Field` projections are applied.
-    Upvar {
-        /// HirId of the upvar
-        var_hir_id: LocalVarId,
-        /// DefId of the closure
-        closure_def_id: LocalDefId,
-    },
+    ///
+    /// Note: in contrast to `PlaceBuilder::Local` we have not yet determined all `Field` types
+    /// and will only do so once converting to `PlaceBuilder::Local`.
+    UpVar(UpVar, Vec<PlaceElem<'tcx>>),
 }
 
-/// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a
-/// place by pushing more and more projections onto the end, and then convert the final set into a
-/// place using the `to_place` method.
-///
-/// This is used internally when building a place for an expression like `a.b.c`. The fields `b`
-/// and `c` can be progressively pushed onto the place builder that is created when converting `a`.
-#[derive(Clone, Debug, PartialEq)]
-pub(in crate::build) struct PlaceBuilder<'tcx> {
-    base: PlaceBase,
-    projection: Vec<PlaceElem<'tcx>>,
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub(crate) struct UpVar {
+    var_hir_id: LocalVarId,
+    closure_def_id: LocalDefId,
 }
 
 /// Given a list of MIR projections, convert them to list of HIR ProjectionKind.
@@ -175,7 +174,7 @@ fn to_upvars_resolved_place_builder<'tcx>(
     cx: &Builder<'_, 'tcx>,
     var_hir_id: LocalVarId,
     closure_def_id: LocalDefId,
-    projection: &[PlaceElem<'tcx>],
+    projection: &[UpvarProjectionElem<'tcx>],
 ) -> Option<PlaceBuilder<'tcx>> {
     let Some((capture_index, capture)) =
         find_capture_matching_projections(
@@ -197,23 +196,31 @@ fn to_upvars_resolved_place_builder<'tcx>(
                 var_hir_id, projection,
             );
         }
+
         return None;
     };
 
     // Access the capture by accessing the field within the Closure struct.
     let capture_info = &cx.upvars[capture_index];
 
-    let mut upvar_resolved_place_builder = PlaceBuilder::from(capture_info.use_place);
+    let Place { local: upvar_resolved_local, projection: local_projection } =
+        capture_info.use_place;
 
     // We used some of the projections to build the capture itself,
     // now we apply the remaining to the upvar resolved place.
-    trace!(?capture.captured_place, ?projection);
-    let remaining_projections = strip_prefix(
+    let upvar_projection = strip_prefix(
         capture.captured_place.place.base_ty,
         projection,
         &capture.captured_place.place.projections,
+    )
+    .collect::<Vec<_>>();
+
+    let upvar_resolved_place_builder = PlaceBuilder::construct_local_place_builder(
+        cx,
+        upvar_resolved_local,
+        local_projection.to_vec(),
+        upvar_projection,
     );
-    upvar_resolved_place_builder.projection.extend(remaining_projections);
 
     Some(upvar_resolved_place_builder)
 }
@@ -235,6 +242,8 @@ fn strip_prefix<'a, 'tcx>(
         // Filter out opaque casts, they are unnecessary in the prefix.
         .filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(..)));
     for projection in prefix_projections {
+        debug!(?projection, ?projection.ty);
+
         match projection.kind {
             HirProjectionKind::Deref => {
                 assert_matches!(iter.next(), Some(ProjectionElem::Deref));
@@ -249,6 +258,7 @@ fn strip_prefix<'a, 'tcx>(
                 bug!("unexpected projection kind: {:?}", projection);
             }
         }
+
         base_ty = projection.ty;
     }
     iter
@@ -263,9 +273,9 @@ impl<'tcx> PlaceBuilder<'tcx> {
     pub(in crate::build) fn try_to_place(&self, cx: &Builder<'_, 'tcx>) -> Option<Place<'tcx>> {
         let resolved = self.resolve_upvar(cx);
         let builder = resolved.as_ref().unwrap_or(self);
-        let PlaceBase::Local(local) = builder.base else { return None };
-        let projection = cx.tcx.intern_place_elems(&builder.projection);
-        Some(Place { local, projection })
+        let PlaceBuilder::Local(local, projection) = builder else { return None };
+        let projection = cx.tcx.intern_place_elems(&projection);
+        Some(Place { local: *local, projection })
     }
 
     /// Attempts to resolve the `PlaceBuilder`.
@@ -282,22 +292,39 @@ impl<'tcx> PlaceBuilder<'tcx> {
         &self,
         cx: &Builder<'_, 'tcx>,
     ) -> Option<PlaceBuilder<'tcx>> {
-        let PlaceBase::Upvar { var_hir_id, closure_def_id } = self.base else {
+        let PlaceBuilder::Upvar( Upvar {var_hir_id, closure_def_id }, projection) = self else {
             return None;
         };
-        to_upvars_resolved_place_builder(cx, var_hir_id, closure_def_id, &self.projection)
-    }
 
-    pub(crate) fn base(&self) -> PlaceBase {
-        self.base
+        to_upvars_resolved_place_builder(cx, var_hir_id, closure_def_id, &projection)
     }
 
-    pub(crate) fn projection(&self) -> &[PlaceElem<'tcx>] {
-        &self.projection
+    pub(crate) fn get_local_projection(&self) -> &[PlaceElem<'tcx>] {
+        match self {
+            Self::Local(_, projection) => projection,
+            Self::UpVar(..) => {
+                bug!("get_local_projection_mut can only be called on PlaceBuilder::Local")
+            }
+        }
     }
 
-    pub(crate) fn field(self, f: Field, ty: Ty<'tcx>) -> Self {
-        self.project(PlaceElem::Field(f, ty))
+    #[instrument(skip(cx), level = "debug")]
+    pub(crate) fn field(
+        self,
+        cx: &Builder<'_, 'tcx>,
+        f: Field,
+        default_field_ty: Ty<'tcx>,
+    ) -> Self {
+        let field_ty = match self {
+            PlaceBuilder::Local(..) => {
+                let base_place = self.clone();
+                PlaceBuilder::try_compute_field_ty(cx, f, base_place)
+                    .unwrap_or_else(|| default_field_ty)
+            }
+            PlaceBuilder::UpVar(..) => default_field_ty,
+        };
+
+        self.project(ProjectionElem::Field(f, field_ty))
     }
 
     pub(crate) fn deref(self) -> Self {
@@ -312,16 +339,34 @@ impl<'tcx> PlaceBuilder<'tcx> {
         self.project(PlaceElem::Index(index))
     }
 
-    pub(crate) fn project(mut self, elem: PlaceElem<'tcx>) -> Self {
-        self.projection.push(elem);
-        self
+    #[instrument(level = "debug")]
+    pub(crate) fn project(self, elem: PlaceElem<'tcx>) -> Self {
+        let result = match self {
+            PlaceBuilder::Local(local, mut proj) => {
+                proj.push(elem);
+                PlaceBuilder::Local(local, proj)
+            }
+            PlaceBuilder::UpVar(upvar, mut proj) => {
+                proj.push(elem);
+                PlaceBuilder::UpVar(upvar, proj)
+            }
+        };
+
+        debug!(?result);
+        result
     }
 
     /// Same as `.clone().project(..)` but more efficient
     pub(crate) fn clone_project(&self, elem: PlaceElem<'tcx>) -> Self {
-        Self {
-            base: self.base,
-            projection: Vec::from_iter(self.projection.iter().copied().chain([elem])),
+        match self {
+            PlaceBuilder::Local(local, proj) => PlaceBuilder::Local(
+                *local,
+                Vec::from_iter(proj.iter().copied().chain([elem.into()])),
+            ),
+            PlaceBuilder::Upvar(upvar, proj) => PlaceBuilder::UpVar(
+                upvar,
+                Vec::from_iter(proj.iter().copied().chain([elem.into()])),
+            ),
         }
     }
 
@@ -332,59 +377,96 @@ impl<'tcx> PlaceBuilder<'tcx> {
     ///
     /// Fallible as the root of this place may be an upvar for
     /// which no base type can be determined.
-    pub fn try_compute_ty<D>(
-        &self,
-        local_decls: &D,
+    #[instrument(skip(cx), level = "debug")]
+    fn try_compute_field_ty(
         cx: &Builder<'_, 'tcx>,
-    ) -> Option<PlaceTy<'tcx>>
-    where
-        D: HasLocalDecls<'tcx>,
-    {
-        match self.base {
-            PlaceBase::Local(_) => Some(self.clone().into_place(cx).ty(local_decls, cx.tcx)),
-            PlaceBase::Upvar { .. } => {
-                match to_upvars_resolved_place_builder(self.clone(), cx) {
-                    Ok(resolved_place_builder) => {
-                        // `base` is guaranteed to be `PlaceBase::Local` now, so recursive call is ok
-                        resolved_place_builder.try_compute_ty(local_decls, cx)
-                    }
-                    Err(place_builder) => {
-                        match &place_builder.projection[..] {
-                            &[ProjectionElem::OpaqueCast(base_ty), ref projections @ ..] => {
-                                let place_ty = projections
-                                    .iter()
-                                    .fold(PlaceTy::from_ty(base_ty), |place_ty, &elem| {
-                                        place_ty.projection_ty(cx.tcx, elem)
-                                    });
-
-                                debug!(?place_ty);
-
-                                Some(place_ty)
-                            }
-                            _ => None, // would need a base `Ty` for these
-                        }
-                    }
+        field: Field,
+        base_place: PlaceBuilder<'tcx>,
+    ) -> Option<Ty<'tcx>> {
+        let field_idx = field.as_usize();
+        let PlaceTy { ty, variant_index } = base_place.to_place(cx).ty(&cx.local_decls, cx.tcx);
+        let base_ty = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
+        debug!(?base_ty);
+
+        let field_ty = match base_ty.kind() {
+            ty::Adt(adt_def, substs) if adt_def.is_enum() => {
+                let variant_idx = variant_index.unwrap();
+                adt_def.variant(variant_idx).fields[field_idx].ty(cx.tcx, substs)
+            }
+            ty::Adt(adt_def, substs) => adt_def
+                .all_fields()
+                .nth(field_idx)
+                .unwrap_or_else(|| {
+                    bug!("expected to take field idx {:?} of fields of {:?}", field_idx, adt_def)
+                })
+                .ty(cx.tcx, substs),
+            ty::Tuple(elems) => elems.iter().nth(field_idx).unwrap_or_else(|| {
+                bug!("expected to take field idx {:?} of {:?}", field_idx, elems)
+            }),
+            _ => return None,
+        };
+
+        Some(cx.tcx.normalize_erasing_regions(cx.param_env, field_ty))
+    }
+
+    /// Creates a `PlaceBuilder::Local` from a `PlaceBuilder::UpVar` whose upvars
+    /// are resolved. This function takes two kinds of projections: `local_projection`
+    /// contains the projections of the captured upvar and `upvar_projection` the
+    /// projections that are applied to the captured upvar. The main purpose of this
+    /// function is to figure out the `Ty`s of the field projections in `upvar_projection`.
+    #[instrument(skip(cx, local))]
+    fn construct_local_place_builder(
+        cx: &Builder<'_, 'tcx>,
+        local: Local,
+        mut local_projection: Vec<PlaceElem<'tcx>>,
+        upvar_projection: Vec<PlaceElem<'tcx>>,
+    ) -> Self {
+        // We iterate through `upvar_projection` and whenever we find a `ProjectionElem::Field` we use
+        // the ancestor projections, i.e. those projection elements that come before the field projection,
+        // to get the `Ty` for the field.
+
+        for proj in upvar_projection.iter() {
+            debug!("proj: {:?}, local_projection: {:?}", proj, local_projection);
+            match *proj {
+                ProjectionElem::Field(field, default_field_ty) => {
+                    let ancestor_proj = local_projection.to_vec();
+                    let base_place = PlaceBuilder::Local(local, ancestor_proj);
+                    let field_ty = PlaceBuilder::try_compute_field_ty(cx, field, base_place)
+                        .unwrap_or_else(|| default_field_ty);
+                    debug!(?field_ty);
+
+                    local_projection.push(ProjectionElem::Field(field, field_ty));
+                    debug!(?local_projection);
+                }
+                ProjectionElem::Deref => local_projection.push(ProjectionElem::Deref),
+                ProjectionElem::Index(idx) => local_projection.push(ProjectionElem::Index(idx)),
+                ProjectionElem::ConstantIndex { offset, min_length, from_end } => local_projection
+                    .push(ProjectionElem::ConstantIndex { offset, min_length, from_end }),
+                ProjectionElem::Subslice { from, to, from_end } => {
+                    local_projection.push(ProjectionElem::Subslice { from, to, from_end })
+                }
+                ProjectionElem::Downcast(sym, variant_idx) => {
+                    local_projection.push(ProjectionElem::Downcast(sym, variant_idx))
+                }
+                ProjectionElem::OpaqueCast(ty) => {
+                    local_projection.push(ProjectionElem::OpaqueCast(ty))
                 }
             }
         }
+
+        PlaceBuilder::Local(local, local_projection)
     }
 }
 
 impl<'tcx> From<Local> for PlaceBuilder<'tcx> {
     fn from(local: Local) -> Self {
-        Self { base: PlaceBase::Local(local), projection: Vec::new() }
-    }
-}
-
-impl<'tcx> From<PlaceBase> for PlaceBuilder<'tcx> {
-    fn from(base: PlaceBase) -> Self {
-        Self { base, projection: Vec::new() }
+        Self::Local(local, Vec::new())
     }
 }
 
 impl<'tcx> From<Place<'tcx>> for PlaceBuilder<'tcx> {
     fn from(p: Place<'tcx>) -> Self {
-        Self { base: PlaceBase::Local(p.local), projection: p.projection.to_vec() }
+        Self::Local(p.local, p.projection.to_vec())
     }
 }
 
@@ -448,6 +530,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         self.expr_as_place(block, expr, Mutability::Not, None)
     }
 
+    #[instrument(skip(self, fake_borrow_temps), level = "debug")]
     fn expr_as_place(
         &mut self,
         mut block: BasicBlock,
@@ -455,8 +538,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         mutability: Mutability,
         fake_borrow_temps: Option<&mut Vec<Local>>,
     ) -> BlockAnd<PlaceBuilder<'tcx>> {
-        debug!("expr_as_place(block={:?}, expr={:?}, mutability={:?})", block, expr, mutability);
-
         let this = self;
         let expr_span = expr.span;
         let source_info = this.source_info(expr_span);
@@ -470,12 +551,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let lhs = &this.thir[lhs];
                 let mut place_builder =
                     unpack!(block = this.expr_as_place(block, lhs, mutability, fake_borrow_temps,));
+                debug!(?place_builder);
                 if let ty::Adt(adt_def, _) = lhs.ty.kind() {
                     if adt_def.is_enum() {
                         place_builder = place_builder.downcast(*adt_def, variant_index);
                     }
                 }
-                block.and(place_builder.field(name, expr.ty))
+                block.and(place_builder.field(this, name, expr.ty))
             }
             ExprKind::Deref { arg } => {
                 let place_builder = unpack!(
@@ -617,7 +699,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     }
 
     /// Lower a captured upvar. Note we might not know the actual capture index,
-    /// so we create a place starting from `PlaceBase::Upvar`, which will be resolved
+    /// so we create a place starting from `UpVar`, which will be resolved
     /// once all projections that allow us to identify a capture have been applied.
     fn lower_captured_upvar(
         &mut self,
@@ -625,7 +707,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         closure_def_id: LocalDefId,
         var_hir_id: LocalVarId,
     ) -> BlockAnd<PlaceBuilder<'tcx>> {
-        block.and(PlaceBuilder::from(PlaceBase::Upvar { var_hir_id, closure_def_id }))
+        block.and(PlaceBuilder::UpVar(UpVar { var_hir_id, closure_def_id }, vec![]))
     }
 
     /// Lower an index expression
@@ -716,8 +798,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         source_info: SourceInfo,
     ) {
         let tcx = self.tcx;
-
         let place_ty = base_place.ty(&self.local_decls, tcx);
+
         if let ty::Slice(_) = place_ty.ty.kind() {
             // We need to create fake borrows to ensure that the bounds
             // check that we just did stays valid. Since we can't assign to
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index 0814793f277..618aa9e3109 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -4,9 +4,8 @@ use rustc_index::vec::Idx;
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_target::abi::{Abi, Primitive};
 
-use crate::build::expr::as_place::PlaceBase;
 use crate::build::expr::category::{Category, RvalueFunc};
-use crate::build::{BlockAnd, BlockAndExtension, Builder, NeedsTemporary};
+use crate::build::{BlockAnd, BlockAndExtension, Builder, NeedsTemporary, PlaceBuilder};
 use rustc_hir::lang_items::LangItem;
 use rustc_middle::middle::region;
 use rustc_middle::mir::AssertKind;
@@ -651,15 +650,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         let arg_place_builder = unpack!(block = this.as_place_builder(block, arg));
 
-        let mutability = match arg_place_builder.base() {
+        let mutability = match arg_place_builder {
             // We are capturing a path that starts off a local variable in the parent.
             // The mutability of the current capture is same as the mutability
             // of the local declaration in the parent.
-            PlaceBase::Local(local) => this.local_decls[local].mutability,
+            PlaceBuilder::Local(local, _) => this.local_decls[local].mutability,
             // Parent is a closure and we are capturing a path that is captured
             // by the parent itself. The mutability of the current capture
             // is same as that of the capture in the parent closure.
-            PlaceBase::Upvar { .. } => {
+            PlaceBuilder::UpVar(..) => {
                 let enclosing_upvars_resolved = arg_place_builder.to_place(this);
 
                 match enclosing_upvars_resolved.as_ref() {
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index 218a26e6279..12cd0e65a11 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -358,8 +358,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         .map(|(n, ty)| match fields_map.get(&n) {
                             Some(v) => v.clone(),
                             None => {
-                                let place = place_builder.clone_project(PlaceElem::Field(n, *ty));
-                                this.consume_by_copy_or_move(place.to_place(this))
+                                let place_builder = place_builder.clone();
+                                this.consume_by_copy_or_move(
+                                    place_builder.field(this, n, *ty).to_place(this),
+                                )
                             }
                         })
                         .collect()
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 58513bde2aa..7b932eda744 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -760,8 +760,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let downcast_place = match_pair.place.downcast(adt_def, variant_index); // `(x as Variant)`
         let consequent_match_pairs = subpatterns.iter().map(|subpattern| {
             // e.g., `(x as Variant).0`
-            let place = downcast_place
-                .clone_project(PlaceElem::Field(subpattern.field, subpattern.pattern.ty));
+            let place = downcast_place.clone().field(self, subpattern.field, subpattern.pattern.ty);
             // e.g., `(x as Variant).0 @ P1`
             MatchPair::new(place, &subpattern.pattern, self)
         });
diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs
index fb2a5be28a2..30f4e49d8ba 100644
--- a/compiler/rustc_mir_build/src/build/matches/util.rs
+++ b/compiler/rustc_mir_build/src/build/matches/util.rs
@@ -1,4 +1,3 @@
-use crate::build::expr::as_place::PlaceBase;
 use crate::build::expr::as_place::PlaceBuilder;
 use crate::build::matches::MatchPair;
 use crate::build::Builder;
@@ -18,70 +17,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         subpatterns
             .iter()
             .map(|fieldpat| {
-                let place =
-                    place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty));
-                MatchPair::new(place, &fieldpat.pattern, self)
-            })
-            .collect()
-    }
-
-    #[instrument(skip(self), level = "debug")]
-    pub(crate) fn field_match_pairs_tuple_struct<'pat>(
-        &mut self,
-        place_builder: PlaceBuilder<'tcx>,
-        subpatterns: &'pat [FieldPat<'tcx>],
-    ) -> Vec<MatchPair<'pat, 'tcx>> {
-        let place_ty_and_variant_idx =
-            place_builder.try_compute_ty(&self.local_decls, self).map(|place_ty| {
-                (
-                    self.tcx.normalize_erasing_regions(self.param_env, place_ty.ty),
-                    place_ty.variant_index,
-                )
-            });
-        debug!(?place_ty_and_variant_idx);
-
-        subpatterns
-            .iter()
-            .map(|fieldpat| {
-                // NOTE: With type ascriptions it can happen that we get errors
-                // during borrow-checking on higher-ranked types if we use the
-                // ascribed type as the field type, so we try to get the actual field
-                // type from the `Place`, if possible, see issue #96514
-                let field_ty = if let Some((place_ty, opt_variant_idx)) = place_ty_and_variant_idx {
-                    let field_idx = fieldpat.field.as_usize();
-                    let field_ty = match place_ty.kind() {
-                        ty::Adt(adt_def, substs) if adt_def.is_enum() => {
-                            let variant_idx = opt_variant_idx.unwrap();
-                            adt_def.variant(variant_idx).fields[field_idx].ty(self.tcx, substs)
-                        }
-                        ty::Adt(adt_def, substs) => adt_def
-                            .all_fields()
-                            .nth(field_idx)
-                            .unwrap_or_else(|| {
-                                bug!(
-                                    "expected to take field idx {:?} of fields of {:?}",
-                                    field_idx,
-                                    adt_def
-                                )
-                            })
-                            .ty(self.tcx, substs),
-                        ty::Tuple(elems) => elems.iter().nth(field_idx).unwrap_or_else(|| {
-                            bug!("expected to take field idx {:?} of {:?}", field_idx, elems)
-                        }),
-                        _ => bug!(
-                            "no field available, place_ty: {:#?}, kind: {:?}",
-                            place_ty,
-                            place_ty.kind()
-                        ),
-                    };
-
-                    self.tcx.normalize_erasing_regions(self.param_env, field_ty)
-                } else {
-                    fieldpat.pattern.ty
-                };
-
-                let place = place_builder.clone().field(fieldpat.field, field_ty);
-                debug!(?place, ?field_ty);
+                let place = place.clone().field(self, fieldpat.field, fieldpat.pattern.ty);
 
                 MatchPair::new(place, &fieldpat.pattern, self)
             })
@@ -171,9 +107,10 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
 
         // Only add the OpaqueCast projection if the given place is an opaque type and the
         // expected type from the pattern is not.
-        let may_need_cast = match place.base() {
-            PlaceBase::Local(local) => {
-                let ty = Place::ty_from(local, place.projection(), &cx.local_decls, cx.tcx).ty;
+        let may_need_cast = match place {
+            PlaceBuilder::Local(local, _) => {
+                let ty =
+                    Place::ty_from(local, place.get_local_projection(), &cx.local_decls, cx.tcx).ty;
                 ty != pattern.ty && ty.has_opaque_types()
             }
             _ => true,