about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs1
-rw-r--r--compiler/rustc_borrowck/src/lib.rs2
-rw-r--r--compiler/rustc_borrowck/src/places_conflict.rs13
-rw-r--r--compiler/rustc_borrowck/src/prefixes.rs1
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs17
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/src/value_and_place.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/place.rs16
-rw-r--r--compiler/rustc_const_eval/src/interpret/projection.rs10
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs1
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs1
-rw-r--r--compiler/rustc_const_eval/src/transform/promote_consts.rs2
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs8
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs7
-rw-r--r--compiler/rustc_middle/src/mir/tcx.rs4
-rw-r--r--compiler/rustc_middle/src/mir/type_foldable.rs1
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs7
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs91
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs12
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_temp.rs5
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs7
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs80
-rw-r--r--compiler/rustc_mir_build/src/build/matches/simplify.rs15
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs23
-rw-r--r--compiler/rustc_mir_build/src/build/matches/util.rs30
-rw-r--r--compiler/rustc_mir_build/src/build/scope.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs37
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs1
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs28
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs1
-rw-r--r--compiler/rustc_mir_transform/src/add_retag.rs1
-rw-r--r--src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug.rs3
-rw-r--r--src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug.stderr10
-rw-r--r--src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.rs6
-rw-r--r--src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.stderr10
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-mismatch.rs10
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-mismatch.stderr15
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-only-pattern-rpit.rs29
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-only-pattern.rs24
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-struct.rs11
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-upvar-enum.rs13
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-upvar.rs13
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-96572-unconstrained.rs11
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs1
47 files changed, 205 insertions, 396 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index ee96dbc2f60..1b3c6cac9c4 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -2155,9 +2155,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             }
                             StorageDeadOrDrop::Destructor(_) => kind,
                         },
-                        ProjectionElem::OpaqueCast { .. }
-                        | ProjectionElem::Field(..)
-                        | ProjectionElem::Downcast(..) => {
+                        ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
                             match place_ty.ty.kind() {
                                 ty::Adt(def, _) if def.has_dtor(tcx) => {
                                     // Report the outermost adt with a destructor
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index fada3d45fbe..53c07a3d481 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -226,7 +226,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 }
                 ProjectionElem::Downcast(..) if including_downcast.0 => return None,
                 ProjectionElem::Downcast(..) => (),
-                ProjectionElem::OpaqueCast(..) => (),
                 ProjectionElem::Field(field, _ty) => {
                     // FIXME(project-rfc_2229#36): print capture precisely here.
                     if let Some(field) = self.is_upvar_field_projection(PlaceRef {
@@ -287,7 +286,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)
                 }
                 ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
-                ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(*ty),
                 ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
             },
         };
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index cb7077fe621..8134e122662 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -169,7 +169,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                         ..,
                         ProjectionElem::Index(_)
                         | ProjectionElem::ConstantIndex { .. }
-                        | ProjectionElem::OpaqueCast { .. }
                         | ProjectionElem::Subslice { .. }
                         | ProjectionElem::Downcast(..),
                     ],
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 15c2a9f7aef..29f47200b80 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -1788,7 +1788,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         for (place_base, elem) in place.iter_projections().rev() {
             match elem {
                 ProjectionElem::Index(_/*operand*/) |
-                ProjectionElem::OpaqueCast(_) |
                 ProjectionElem::ConstantIndex { .. } |
                 // assigning to P[i] requires P to be valid.
                 ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) =>
@@ -2180,7 +2179,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     | ProjectionElem::Index(..)
                     | ProjectionElem::ConstantIndex { .. }
                     | ProjectionElem::Subslice { .. }
-                    | ProjectionElem::OpaqueCast { .. }
                     | ProjectionElem::Downcast(..) => {
                         let upvar_field_projection = self.is_upvar_field_projection(place);
                         if let Some(field) = upvar_field_projection {
diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs
index 5b67e6aa1cf..97335fd0dff 100644
--- a/compiler/rustc_borrowck/src/places_conflict.rs
+++ b/compiler/rustc_borrowck/src/places_conflict.rs
@@ -255,7 +255,6 @@ fn place_components_conflict<'tcx>(
                 | (ProjectionElem::Index { .. }, _, _)
                 | (ProjectionElem::ConstantIndex { .. }, _, _)
                 | (ProjectionElem::Subslice { .. }, _, _)
-                | (ProjectionElem::OpaqueCast { .. }, _, _)
                 | (ProjectionElem::Downcast { .. }, _, _) => {
                     // Recursive case. This can still be disjoint on a
                     // further iteration if this a shallow access and
@@ -323,17 +322,6 @@ fn place_projection_conflict<'tcx>(
             debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF");
             Overlap::EqualOrDisjoint
         }
-        (ProjectionElem::OpaqueCast(v1), ProjectionElem::OpaqueCast(v2)) => {
-            if v1 == v2 {
-                // same type - recur.
-                debug!("place_element_conflict: DISJOINT-OR-EQ-OPAQUE");
-                Overlap::EqualOrDisjoint
-            } else {
-                // Different types. Disjoint!
-                debug!("place_element_conflict: DISJOINT-OPAQUE");
-                Overlap::Disjoint
-            }
-        }
         (ProjectionElem::Field(f1, _), ProjectionElem::Field(f2, _)) => {
             if f1 == f2 {
                 // same field (e.g., `a.y` vs. `a.y`) - recur.
@@ -537,7 +525,6 @@ fn place_projection_conflict<'tcx>(
             | ProjectionElem::Field(..)
             | ProjectionElem::Index(..)
             | ProjectionElem::ConstantIndex { .. }
-            | ProjectionElem::OpaqueCast { .. }
             | ProjectionElem::Subslice { .. }
             | ProjectionElem::Downcast(..),
             _,
diff --git a/compiler/rustc_borrowck/src/prefixes.rs b/compiler/rustc_borrowck/src/prefixes.rs
index 2b50cbac9a0..bdf2becb711 100644
--- a/compiler/rustc_borrowck/src/prefixes.rs
+++ b/compiler/rustc_borrowck/src/prefixes.rs
@@ -81,7 +81,6 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
                         }
                         ProjectionElem::Downcast(..)
                         | ProjectionElem::Subslice { .. }
-                        | ProjectionElem::OpaqueCast { .. }
                         | ProjectionElem::ConstantIndex { .. }
                         | ProjectionElem::Index(_) => {
                             cursor = cursor_base;
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 8e763a02af3..cf2140097e6 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -790,19 +790,6 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
                 }
                 PlaceTy::from_ty(fty)
             }
-            ProjectionElem::OpaqueCast(ty) => {
-                let ty = self.sanitize_type(place, ty);
-                let ty = self.cx.normalize(ty, location);
-                self.cx
-                    .eq_types(
-                        base.ty,
-                        ty,
-                        location.to_locations(),
-                        ConstraintCategory::TypeAnnotation,
-                    )
-                    .unwrap();
-                PlaceTy::from_ty(ty)
-            }
         }
     }
 
@@ -1208,11 +1195,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 tcx,
                 self.param_env,
                 proj,
-                |this, field, _| {
+                |this, field, ()| {
                     let ty = this.field_ty(tcx, field);
                     self.normalize(ty, locations)
                 },
-                |_, _| unreachable!(),
             );
             curr_projected_ty = projected_ty;
         }
@@ -2507,7 +2493,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 }
                 ProjectionElem::Field(..)
                 | ProjectionElem::Downcast(..)
-                | ProjectionElem::OpaqueCast(..)
                 | ProjectionElem::Index(..)
                 | ProjectionElem::ConstantIndex { .. }
                 | ProjectionElem::Subslice { .. } => {
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 54652623d94..63cd4d6de4c 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -825,7 +825,6 @@ pub(crate) fn codegen_place<'tcx>(
                     cplace = cplace.place_deref(fx);
                 }
             }
-            PlaceElem::OpaqueCast(ty) => cplace = cplace.place_opaque_cast(fx, ty),
             PlaceElem::Field(field, _ty) => {
                 cplace = cplace.place_field(fx, field);
             }
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index 8ff35d2f76d..a68225de58b 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -615,14 +615,6 @@ impl<'tcx> CPlace<'tcx> {
         }
     }
 
-    pub(crate) fn place_opaque_cast(
-        self,
-        fx: &mut FunctionCx<'_, '_, 'tcx>,
-        ty: Ty<'tcx>,
-    ) -> CPlace<'tcx> {
-        CPlace { inner: self.inner, layout: fx.layout_of(ty) }
-    }
-
     pub(crate) fn place_field(
         self,
         fx: &mut FunctionCx<'_, '_, 'tcx>,
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index 421d6f807ae..58cee0c8bb0 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -411,21 +411,6 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
         downcast
     }
 
-    pub fn project_type<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
-        &self,
-        bx: &mut Bx,
-        ty: Ty<'tcx>,
-    ) -> Self {
-        let mut downcast = *self;
-        downcast.layout = bx.cx().layout_of(ty);
-
-        // Cast to the appropriate type.
-        let variant_ty = bx.cx().backend_type(downcast.layout);
-        downcast.llval = bx.pointercast(downcast.llval, bx.cx().type_ptr_to(variant_ty));
-
-        downcast
-    }
-
     pub fn storage_live<Bx: BuilderMethods<'a, 'tcx, Value = V>>(&self, bx: &mut Bx) {
         bx.lifetime_start(self.llval, self.layout.size);
     }
@@ -474,7 +459,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 mir::ProjectionElem::Field(ref field, _) => {
                     cg_base.project_field(bx, field.index())
                 }
-                mir::ProjectionElem::OpaqueCast(ty) => cg_base.project_type(bx, ty),
                 mir::ProjectionElem::Index(index) => {
                     let index = &mir::Operand::Copy(mir::Place::from(index));
                     let index = self.codegen_operand(bx, index);
diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs
index 4e69d71dc00..61d58232dc2 100644
--- a/compiler/rustc_const_eval/src/interpret/projection.rs
+++ b/compiler/rustc_const_eval/src/interpret/projection.rs
@@ -349,11 +349,6 @@ where
     ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
         use rustc_middle::mir::ProjectionElem::*;
         Ok(match proj_elem {
-            OpaqueCast(ty) => {
-                let mut place = base.clone();
-                place.layout = self.layout_of(ty)?;
-                place
-            }
             Field(field, _) => self.place_field(base, field.index())?,
             Downcast(_, variant) => self.place_downcast(base, variant)?,
             Deref => self.deref_operand(&self.place_to_op(base)?)?.into(),
@@ -378,11 +373,6 @@ where
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
         use rustc_middle::mir::ProjectionElem::*;
         Ok(match proj_elem {
-            OpaqueCast(ty) => {
-                let mut op = base.clone();
-                op.layout = self.layout_of(ty)?;
-                op
-            }
             Field(field, _) => self.operand_field(base, field.index())?,
             Downcast(_, variant) => self.operand_downcast(base, variant)?,
             Deref => self.deref_operand(base)?.into(),
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 0581f491978..628298df473 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -652,7 +652,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
 
             ProjectionElem::ConstantIndex { .. }
             | ProjectionElem::Downcast(..)
-            | ProjectionElem::OpaqueCast(..)
             | ProjectionElem::Subslice { .. }
             | ProjectionElem::Field(..)
             | ProjectionElem::Index(_) => {}
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index c2b4f6eca5c..29464cf8c4e 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -316,7 +316,6 @@ where
 
             ProjectionElem::Deref
             | ProjectionElem::Field(_, _)
-            | ProjectionElem::OpaqueCast(_)
             | ProjectionElem::ConstantIndex { .. }
             | ProjectionElem::Subslice { .. }
             | ProjectionElem::Downcast(_, _)
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index daa154576ae..ed4d8c95d1e 100644
--- a/compiler/rustc_const_eval/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -361,7 +361,7 @@ impl<'tcx> Validator<'_, 'tcx> {
                             return Err(Unpromotable);
                         }
                     }
-                    ProjectionElem::OpaqueCast(..) | ProjectionElem::Downcast(..) => {
+                    ProjectionElem::Downcast(..) => {
                         return Err(Unpromotable);
                     }
 
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 0b5d23be58d..f61cb7e8c47 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -1397,7 +1397,6 @@ impl<V, T> ProjectionElem<V, T> {
 
             Self::Field(_, _)
             | Self::Index(_)
-            | Self::OpaqueCast(_)
             | Self::ConstantIndex { .. }
             | Self::Subslice { .. }
             | Self::Downcast(_, _) => false,
@@ -1575,9 +1574,7 @@ impl Debug for Place<'_> {
     fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
         for elem in self.projection.iter().rev() {
             match elem {
-                ProjectionElem::OpaqueCast(_)
-                | ProjectionElem::Downcast(_, _)
-                | ProjectionElem::Field(_, _) => {
+                ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => {
                     write!(fmt, "(").unwrap();
                 }
                 ProjectionElem::Deref => {
@@ -1593,9 +1590,6 @@ impl Debug for Place<'_> {
 
         for elem in self.projection.iter() {
             match elem {
-                ProjectionElem::OpaqueCast(ty) => {
-                    write!(fmt, " as {})", ty)?;
-                }
                 ProjectionElem::Downcast(Some(name), _index) => {
                     write!(fmt, " as {})", name)?;
                 }
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 263c2ca3c70..510316c778b 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -754,9 +754,6 @@ pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>;
 ///    generator has more than one variant, the parent place's variant index must be set, indicating
 ///    which variant is being used. If it has just one variant, the variant index may or may not be
 ///    included - the single possible variant is inferred if it is not included.
-///  - [`OpaqueCast`](ProjectionElem::OpaqueCast): This projection changes the place's type to the
-///    given one, and makes no other changes. A `OpaqueCast` projection on any type other than an
-///    opaque type from the current crate is not well-formed.
 ///  - [`ConstantIndex`](ProjectionElem::ConstantIndex): Computes an offset in units of `T` into the
 ///    place as described in the documentation for the `ProjectionElem`. The resulting address is
 ///    the parent's address plus that offset, and the type is `T`. This is only legal if the parent
@@ -859,10 +856,6 @@ pub enum ProjectionElem<V, T> {
     ///
     /// The included Symbol is the name of the variant, used for printing MIR.
     Downcast(Option<Symbol>, VariantIdx),
-
-    /// Like an explicit cast from an opaque type to a concrete type, but without
-    /// requiring an intermediate variable.
-    OpaqueCast(T),
 }
 
 /// Alias for projections as they appear in places, where the base is a place
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index c6975df45ef..fd3359ea80f 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -57,7 +57,7 @@ impl<'tcx> PlaceTy<'tcx> {
     /// `PlaceElem`, where we can just use the `Ty` that is already
     /// stored inline on field projection elems.
     pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> {
-        self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, ty| ty, |_, ty| ty)
+        self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, ty| ty)
     }
 
     /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })`
@@ -71,7 +71,6 @@ impl<'tcx> PlaceTy<'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         elem: &ProjectionElem<V, T>,
         mut handle_field: impl FnMut(&Self, Field, T) -> Ty<'tcx>,
-        mut handle_opaque_cast: impl FnMut(&Self, T) -> Ty<'tcx>,
     ) -> PlaceTy<'tcx>
     where
         V: ::std::fmt::Debug,
@@ -110,7 +109,6 @@ impl<'tcx> PlaceTy<'tcx> {
                 PlaceTy { ty: self.ty, variant_index: Some(index) }
             }
             ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)),
-            ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(handle_opaque_cast(&self, ty)),
         };
         debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
         answer
diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs
index a73ef23e281..82a6b0c506f 100644
--- a/compiler/rustc_middle/src/mir/type_foldable.rs
+++ b/compiler/rustc_middle/src/mir/type_foldable.rs
@@ -182,7 +182,6 @@ impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
         Ok(match self {
             Deref => Deref,
             Field(f, ty) => Field(f, ty.try_fold_with(folder)?),
-            OpaqueCast(ty) => OpaqueCast(ty.try_fold_with(folder)?),
             Index(v) => Index(v.try_fold_with(folder)?),
             Downcast(symbol, variantidx) => Downcast(symbol, variantidx),
             ConstantIndex { offset, min_length, from_end } => {
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index e5599fb15ad..d285728ec07 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -1064,11 +1064,6 @@ macro_rules! visit_place_fns {
                     self.visit_ty(&mut new_ty, TyContext::Location(location));
                     if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None }
                 }
-                PlaceElem::OpaqueCast(ty) => {
-                    let mut new_ty = ty;
-                    self.visit_ty(&mut new_ty, TyContext::Location(location));
-                    if ty != new_ty { Some(PlaceElem::OpaqueCast(new_ty)) } else { None }
-                }
                 PlaceElem::Deref
                 | PlaceElem::ConstantIndex { .. }
                 | PlaceElem::Subslice { .. }
@@ -1138,7 +1133,7 @@ macro_rules! visit_place_fns {
             location: Location,
         ) {
             match elem {
-                ProjectionElem::OpaqueCast(ty) | ProjectionElem::Field(_, ty) => {
+                ProjectionElem::Field(_field, ty) => {
                     self.visit_ty(ty, TyContext::Location(location));
                 }
                 ProjectionElem::Index(local) => {
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 6abf419dd49..e88f9dc1f08 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -7,7 +7,6 @@ use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::hir::place::Projection as HirProjection;
 use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
 use rustc_middle::middle::region;
-use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::AssertKind::BoundsCheck;
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
@@ -72,7 +71,7 @@ pub(crate) enum PlaceBase {
 /// 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> {
+pub(crate) struct PlaceBuilder<'tcx> {
     base: PlaceBase,
     projection: Vec<PlaceElem<'tcx>>,
 }
@@ -105,8 +104,6 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>(
                 variant = Some(*idx);
                 continue;
             }
-            // These do not affect anything, they just make sure we know the right type.
-            ProjectionElem::OpaqueCast(_) => continue,
             ProjectionElem::Index(..)
             | ProjectionElem::ConstantIndex { .. }
             | ProjectionElem::Subslice { .. } => {
@@ -204,10 +201,10 @@ fn find_capture_matching_projections<'a, 'tcx>(
 /// `PlaceBuilder` now starts from `PlaceBase::Local`.
 ///
 /// Returns a Result with the error being the PlaceBuilder (`from_builder`) that was not found.
-#[instrument(level = "trace", skip(cx))]
-fn to_upvars_resolved_place_builder<'tcx>(
+fn to_upvars_resolved_place_builder<'a, 'tcx>(
     from_builder: PlaceBuilder<'tcx>,
-    cx: &Builder<'_, 'tcx>,
+    tcx: TyCtxt<'tcx>,
+    typeck_results: &'a ty::TypeckResults<'tcx>,
 ) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> {
     match from_builder.base {
         PlaceBase::Local(_) => Ok(from_builder),
@@ -222,13 +219,13 @@ fn to_upvars_resolved_place_builder<'tcx>(
 
             let Some((capture_index, capture)) =
                 find_capture_matching_projections(
-                    cx.typeck_results,
+                    typeck_results,
                     var_hir_id,
                     closure_def_id,
                     &from_builder.projection,
                 ) else {
-                let closure_span = cx.tcx.def_span(closure_def_id);
-                if !enable_precise_capture(cx.tcx, closure_span) {
+                let closure_span = tcx.def_span(closure_def_id);
+                if !enable_precise_capture(tcx, closure_span) {
                     bug!(
                         "No associated capture found for {:?}[{:#?}] even though \
                             capture_disjoint_fields isn't enabled",
@@ -245,8 +242,8 @@ fn to_upvars_resolved_place_builder<'tcx>(
             };
 
             // We won't be building MIR if the closure wasn't local
-            let closure_hir_id = cx.tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local());
-            let closure_ty = cx.typeck_results.node_type(closure_hir_id);
+            let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local());
+            let closure_ty = typeck_results.node_type(closure_hir_id);
 
             let substs = match closure_ty.kind() {
                 ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs),
@@ -273,14 +270,12 @@ fn to_upvars_resolved_place_builder<'tcx>(
 
             // We used some of the projections to build the capture itself,
             // now we apply the remaining to the upvar resolved place.
-            trace!(?capture.place, ?from_builder.projection);
             let remaining_projections = strip_prefix(
                 capture.place.base_ty,
                 from_builder.projection,
                 &capture.place.projections,
             );
             upvar_resolved_place_builder.projection.extend(remaining_projections);
-            trace!(?upvar_resolved_place_builder);
 
             Ok(upvar_resolved_place_builder)
         }
@@ -299,21 +294,16 @@ fn strip_prefix<'tcx>(
     prefix_projections: &[HirProjection<'tcx>],
 ) -> impl Iterator<Item = PlaceElem<'tcx>> {
     let mut iter = projections.into_iter();
-    let mut next = || match iter.next()? {
-        // Filter out opaque casts, they are unnecessary in the prefix.
-        ProjectionElem::OpaqueCast(..) => iter.next(),
-        other => Some(other),
-    };
     for projection in prefix_projections {
         match projection.kind {
             HirProjectionKind::Deref => {
-                assert!(matches!(next(), Some(ProjectionElem::Deref)));
+                assert!(matches!(iter.next(), Some(ProjectionElem::Deref)));
             }
             HirProjectionKind::Field(..) => {
                 if base_ty.is_enum() {
-                    assert!(matches!(next(), Some(ProjectionElem::Downcast(..))));
+                    assert!(matches!(iter.next(), Some(ProjectionElem::Downcast(..))));
                 }
-                assert!(matches!(next(), Some(ProjectionElem::Field(..))));
+                assert!(matches!(iter.next(), Some(ProjectionElem::Field(..))));
             }
             HirProjectionKind::Index | HirProjectionKind::Subslice => {
                 bug!("unexpected projection kind: {:?}", projection);
@@ -325,32 +315,24 @@ fn strip_prefix<'tcx>(
 }
 
 impl<'tcx> PlaceBuilder<'tcx> {
-    pub(crate) fn into_place(self, cx: &Builder<'_, 'tcx>) -> Place<'tcx> {
+    pub(crate) fn into_place<'a>(
+        self,
+        tcx: TyCtxt<'tcx>,
+        typeck_results: &'a ty::TypeckResults<'tcx>,
+    ) -> Place<'tcx> {
         if let PlaceBase::Local(local) = self.base {
-            let mut projections = vec![];
-            let mut ty = PlaceTy::from_ty(cx.local_decls[local].ty);
-            for projection in self.projection {
-                // Only preserve those opaque casts that actually go from an opaque type
-                // to another type.
-                if let ProjectionElem::OpaqueCast(t) = projection {
-                    if let ty::Opaque(..) = ty.ty.kind() {
-                        if t != ty.ty {
-                            projections.push(ProjectionElem::OpaqueCast(t));
-                        }
-                    }
-                } else {
-                    projections.push(projection);
-                }
-                ty = ty.projection_ty(cx.tcx, projection);
-            }
-            Place { local, projection: cx.tcx.intern_place_elems(&projections) }
+            Place { local, projection: tcx.intern_place_elems(&self.projection) }
         } else {
-            self.expect_upvars_resolved(cx).into_place(cx)
+            self.expect_upvars_resolved(tcx, typeck_results).into_place(tcx, typeck_results)
         }
     }
 
-    fn expect_upvars_resolved(self, cx: &Builder<'_, 'tcx>) -> PlaceBuilder<'tcx> {
-        to_upvars_resolved_place_builder(self, cx).unwrap()
+    fn expect_upvars_resolved<'a>(
+        self,
+        tcx: TyCtxt<'tcx>,
+        typeck_results: &'a ty::TypeckResults<'tcx>,
+    ) -> PlaceBuilder<'tcx> {
+        to_upvars_resolved_place_builder(self, tcx, typeck_results).unwrap()
     }
 
     /// Attempts to resolve the `PlaceBuilder`.
@@ -364,11 +346,12 @@ impl<'tcx> PlaceBuilder<'tcx> {
     /// not captured. This can happen because the final mir that will be
     /// generated doesn't require a read for this place. Failures will only
     /// happen inside closures.
-    pub(crate) fn try_upvars_resolved(
+    pub(crate) fn try_upvars_resolved<'a>(
         self,
-        cx: &Builder<'_, 'tcx>,
+        tcx: TyCtxt<'tcx>,
+        typeck_results: &'a ty::TypeckResults<'tcx>,
     ) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> {
-        to_upvars_resolved_place_builder(self, cx)
+        to_upvars_resolved_place_builder(self, tcx, typeck_results)
     }
 
     pub(crate) fn base(&self) -> PlaceBase {
@@ -428,7 +411,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         expr: &Expr<'tcx>,
     ) -> BlockAnd<Place<'tcx>> {
         let place_builder = unpack!(block = self.as_place_builder(block, expr));
-        block.and(place_builder.into_place(self))
+        block.and(place_builder.into_place(self.tcx, self.typeck_results))
     }
 
     /// This is used when constructing a compound `Place`, so that we can avoid creating
@@ -452,7 +435,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         expr: &Expr<'tcx>,
     ) -> BlockAnd<Place<'tcx>> {
         let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr));
-        block.and(place_builder.into_place(self))
+        block.and(place_builder.into_place(self.tcx, self.typeck_results))
     }
 
     /// This is used when constructing a compound `Place`, so that we can avoid creating
@@ -547,7 +530,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                             inferred_ty: expr.ty,
                         });
 
-                    let place = place_builder.clone().into_place(this);
+                    let place = place_builder.clone().into_place(this.tcx, this.typeck_results);
                     this.cfg.push(
                         block,
                         Statement {
@@ -699,7 +682,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         if is_outermost_index {
             self.read_fake_borrows(block, fake_borrow_temps, source_info)
         } else {
-            base_place = base_place.expect_upvars_resolved(self);
+            base_place = base_place.expect_upvars_resolved(self.tcx, self.typeck_results);
             self.add_fake_borrows_of_base(
                 &base_place,
                 block,
@@ -727,7 +710,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let lt = self.temp(bool_ty, expr_span);
 
         // len = len(slice)
-        self.cfg.push_assign(block, source_info, len, Rvalue::Len(slice.into_place(self)));
+        self.cfg.push_assign(
+            block,
+            source_info,
+            len,
+            Rvalue::Len(slice.into_place(self.tcx, self.typeck_results)),
+        );
         // lt = idx < len
         self.cfg.push_assign(
             block,
@@ -807,7 +795,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     }
                     ProjectionElem::Field(..)
                     | ProjectionElem::Downcast(..)
-                    | ProjectionElem::OpaqueCast(..)
                     | ProjectionElem::ConstantIndex { .. }
                     | ProjectionElem::Subslice { .. } => (),
                 }
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 93f76333165..15f2d17c4e0 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -321,8 +321,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     let place_builder =
                         unpack!(block = this.as_place_builder(block, &this.thir[*thir_place]));
 
-                    if let Ok(place_builder_resolved) = place_builder.try_upvars_resolved(this) {
-                        let mir_place = place_builder_resolved.into_place(this);
+                    if let Ok(place_builder_resolved) =
+                        place_builder.try_upvars_resolved(this.tcx, this.typeck_results)
+                    {
+                        let mir_place =
+                            place_builder_resolved.into_place(this.tcx, this.typeck_results);
                         this.cfg.push_fake_read(
                             block,
                             this.source_info(this.tcx.hir().span(*hir_id)),
@@ -613,7 +616,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             // by the parent itself. The mutability of the current capture
             // is same as that of the capture in the parent closure.
             PlaceBase::Upvar { .. } => {
-                let enclosing_upvars_resolved = arg_place_builder.clone().into_place(this);
+                let enclosing_upvars_resolved =
+                    arg_place_builder.clone().into_place(this.tcx, this.typeck_results);
 
                 match enclosing_upvars_resolved.as_ref() {
                     PlaceRef {
@@ -650,7 +654,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false },
         };
 
-        let arg_place = arg_place_builder.into_place(this);
+        let arg_place = arg_place_builder.into_place(this.tcx, this.typeck_results);
 
         this.cfg.push_assign(
             block,
diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs
index dac8862647a..724b72f8769 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs
@@ -23,7 +23,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         ensure_sufficient_stack(|| self.as_temp_inner(block, temp_lifetime, expr, mutability))
     }
 
-    #[instrument(skip(self), level = "debug")]
     fn as_temp_inner(
         &mut self,
         mut block: BasicBlock,
@@ -31,6 +30,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         expr: &Expr<'tcx>,
         mutability: Mutability,
     ) -> BlockAnd<Local> {
+        debug!(
+            "as_temp(block={:?}, temp_lifetime={:?}, expr={:?}, mutability={:?})",
+            block, temp_lifetime, expr, mutability
+        );
         let this = self;
 
         let expr_span = expr.span;
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index d1ef515b3d2..017d43d10a9 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -15,13 +15,14 @@ use std::iter;
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Compile `expr`, storing the result into `destination`, which
     /// is assumed to be uninitialized.
-    #[instrument(level = "debug", skip(self))]
     pub(crate) fn expr_into_dest(
         &mut self,
         destination: Place<'tcx>,
         mut block: BasicBlock,
         expr: &Expr<'tcx>,
     ) -> BlockAnd<()> {
+        debug!("expr_into_dest(destination={:?}, block={:?}, expr={:?})", destination, block, expr);
+
         // since we frequently have to reference `self` from within a
         // closure, where `self` would be shadowed, it's easier to
         // just use the name `this` uniformly
@@ -365,7 +366,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                             None => {
                                 let place_builder = place_builder.clone();
                                 this.consume_by_copy_or_move(
-                                    place_builder.field(n, *ty).into_place(this),
+                                    place_builder
+                                        .field(n, *ty)
+                                        .into_place(this.tcx, this.typeck_results),
                                 )
                             }
                         })
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 86ef666eac8..7067a48b783 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -220,8 +220,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let cause_matched_place = FakeReadCause::ForMatchedPlace(None);
         let source_info = self.source_info(scrutinee_span);
 
-        if let Ok(scrutinee_builder) = scrutinee_place_builder.clone().try_upvars_resolved(self) {
-            let scrutinee_place = scrutinee_builder.into_place(self);
+        if let Ok(scrutinee_builder) =
+            scrutinee_place_builder.clone().try_upvars_resolved(self.tcx, self.typeck_results)
+        {
+            let scrutinee_place = scrutinee_builder.into_place(self.tcx, self.typeck_results);
             self.cfg.push_fake_read(block, source_info, cause_matched_place, scrutinee_place);
         }
 
@@ -346,10 +348,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     // ```
                     let mut opt_scrutinee_place: Option<(Option<&Place<'tcx>>, Span)> = None;
                     let scrutinee_place: Place<'tcx>;
-                    if let Ok(scrutinee_builder) =
-                        scrutinee_place_builder.clone().try_upvars_resolved(this)
+                    if let Ok(scrutinee_builder) = scrutinee_place_builder
+                        .clone()
+                        .try_upvars_resolved(this.tcx, this.typeck_results)
                     {
-                        scrutinee_place = scrutinee_builder.into_place(this);
+                        scrutinee_place =
+                            scrutinee_builder.into_place(this.tcx, this.typeck_results);
                         opt_scrutinee_place = Some((Some(&scrutinee_place), scrutinee_span));
                     }
                     let scope = this.declare_bindings(
@@ -598,6 +602,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             while let Some(next) = {
                 for binding in &candidate_ref.bindings {
                     let local = self.var_local_id(binding.var_id, OutsideGuard);
+
+                    let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
+                        VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. },
+                    )))) = self.local_decls[local].local_info else {
+                        bug!("Let binding to non-user variable.")
+                    };
                     // `try_upvars_resolved` may fail if it is unable to resolve the given
                     // `PlaceBuilder` inside a closure. In this case, we don't want to include
                     // a scrutinee place. `scrutinee_place_builder` will fail for destructured
@@ -612,15 +622,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     //    let (v1, v2) = foo;
                     // };
                     // ```
-                    if let Ok(match_pair_resolved) = initializer.clone().try_upvars_resolved(self) {
-                        let place = match_pair_resolved.into_place(self);
-
-                        let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
-                            VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. },
-                        )))) = self.local_decls[local].local_info else {
-                            bug!("Let binding to non-user variable.")
-                        };
-
+                    if let Ok(match_pair_resolved) =
+                        initializer.clone().try_upvars_resolved(self.tcx, self.typeck_results)
+                    {
+                        let place = match_pair_resolved.into_place(self.tcx, self.typeck_results);
                         *match_place = Some(place);
                     }
                 }
@@ -649,7 +654,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// scope for the bindings in these patterns, if such a scope had to be
     /// created. NOTE: Declaring the bindings should always be done in their
     /// drop scope.
-    #[instrument(skip(self), level = "debug")]
     pub(crate) fn declare_bindings(
         &mut self,
         mut visibility_scope: Option<SourceScope>,
@@ -658,6 +662,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         has_guard: ArmHasGuard,
         opt_match_place: Option<(Option<&Place<'tcx>>, Span)>,
     ) -> Option<SourceScope> {
+        debug!("declare_bindings: pattern={:?}", pattern);
         self.visit_primary_bindings(
             &pattern,
             UserTypeProjections::none(),
@@ -867,7 +872,7 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
         Candidate {
             span: pattern.span,
             has_guard,
-            match_pairs: smallvec![MatchPair::new(place, pattern)],
+            match_pairs: smallvec![MatchPair { place, pattern }],
             bindings: Vec::new(),
             ascriptions: Vec::new(),
             subcandidates: Vec::new(),
@@ -1043,7 +1048,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// if `x.0` matches `false` (for the third arm). In the (impossible at
     /// runtime) case when `x.0` is now `true`, we branch to
     /// `otherwise_block`.
-    #[instrument(skip(self, fake_borrows), level = "debug")]
     fn match_candidates<'pat>(
         &mut self,
         span: Span,
@@ -1053,6 +1057,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         candidates: &mut [&mut Candidate<'pat, 'tcx>],
         fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
     ) {
+        debug!(
+            "matched_candidate(span={:?}, candidates={:?}, start_block={:?}, otherwise_block={:?})",
+            span, candidates, start_block, otherwise_block,
+        );
+
         // Start by simplifying candidates. Once this process is complete, all
         // the match pairs which remain require some form of test, whether it
         // be a switch or pattern comparison.
@@ -1371,10 +1380,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         )
     }
 
-    #[instrument(
-        skip(self, otherwise, or_span, place, fake_borrows, candidate, pats),
-        level = "debug"
-    )]
     fn test_or_pattern<'pat>(
         &mut self,
         candidate: &mut Candidate<'pat, 'tcx>,
@@ -1384,7 +1389,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         place: PlaceBuilder<'tcx>,
         fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
     ) {
-        debug!("candidate={:#?}\npats={:#?}", candidate, pats);
+        debug!("test_or_pattern:\ncandidate={:#?}\npats={:#?}", candidate, pats);
         let mut or_candidates: Vec<_> = pats
             .iter()
             .map(|pat| Candidate::new(place.clone(), pat, candidate.has_guard))
@@ -1600,9 +1605,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         // Insert a Shallow borrow of any places that is switched on.
         if let Some(fb) = fake_borrows && let Ok(match_place_resolved) =
-            match_place.clone().try_upvars_resolved(self)
+            match_place.clone().try_upvars_resolved(self.tcx, self.typeck_results)
         {
-            let resolved_place = match_place_resolved.into_place(self);
+            let resolved_place = match_place_resolved.into_place(self.tcx, self.typeck_results);
             fb.insert(resolved_place);
         }
 
@@ -1629,14 +1634,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             candidates = rest;
         }
         // at least the first candidate ought to be tested
-        assert!(
-            total_candidate_count > candidates.len(),
-            "{}, {:#?}",
-            total_candidate_count,
-            candidates
-        );
-        debug!("tested_candidates: {}", total_candidate_count - candidates.len());
-        debug!("untested_candidates: {}", candidates.len());
+        assert!(total_candidate_count > candidates.len());
+        debug!("test_candidates: tested_candidates: {}", total_candidate_count - candidates.len());
+        debug!("test_candidates: untested_candidates: {}", candidates.len());
 
         // HACK(matthewjasper) This is a closure so that we can let the test
         // create its blocks before the rest of the match. This currently
@@ -1794,8 +1794,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         );
         let mut opt_expr_place: Option<(Option<&Place<'tcx>>, Span)> = None;
         let expr_place: Place<'tcx>;
-        if let Ok(expr_builder) = expr_place_builder.try_upvars_resolved(self) {
-            expr_place = expr_builder.into_place(self);
+        if let Ok(expr_builder) =
+            expr_place_builder.try_upvars_resolved(self.tcx, self.typeck_results)
+        {
+            expr_place = expr_builder.into_place(self.tcx, self.typeck_results);
             opt_expr_place = Some((Some(&expr_place), expr_span));
         }
         let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap();
@@ -2193,7 +2195,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// first local is a binding for occurrences of `var` in the guard, which
     /// will have type `&T`. The second local is a binding for occurrences of
     /// `var` in the arm body, which will have type `T`.
-    #[instrument(skip(self), level = "debug")]
     fn declare_binding(
         &mut self,
         source_info: SourceInfo,
@@ -2208,12 +2209,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
         pat_span: Span,
     ) {
+        debug!(
+            "declare_binding(var_id={:?}, name={:?}, mode={:?}, var_ty={:?}, \
+             visibility_scope={:?}, source_info={:?})",
+            var_id, name, mode, var_ty, visibility_scope, source_info
+        );
+
         let tcx = self.tcx;
         let debug_source_info = SourceInfo { span: source_info.span, scope: visibility_scope };
         let binding_mode = match mode {
             BindingMode::ByValue => ty::BindingMode::BindByValue(mutability),
             BindingMode::ByRef(_) => ty::BindingMode::BindByReference(mutability),
         };
+        debug!("declare_binding: user_ty={:?}", user_ty);
         let local = LocalDecl::<'tcx> {
             mutability,
             ty: var_ty,
@@ -2263,7 +2271,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         } else {
             LocalsForNode::One(for_arm_body)
         };
-        debug!(?locals);
+        debug!("declare_binding: vars={:?}", locals);
         self.var_indices.insert(var_id, locals);
     }
 
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index 6fa817da28a..c6298904140 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -37,13 +37,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     ///
     /// only generates a single switch. If this happens this method returns
     /// `true`.
-    #[instrument(skip(self, candidate), level = "debug")]
     pub(super) fn simplify_candidate<'pat>(
         &mut self,
         candidate: &mut Candidate<'pat, 'tcx>,
     ) -> bool {
         // repeatedly simplify match pairs until fixed point is reached
-        debug!("{:#?}", candidate);
+        debug!(?candidate, "simplify_candidate");
 
         // existing_bindings and new_bindings exists to keep the semantics in order.
         // Reversing the binding order for bindings after `@` changes the binding order in places
@@ -156,10 +155,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 ascription: thir::Ascription { ref annotation, variance },
             } => {
                 // Apply the type ascription to the value at `match_pair.place`, which is the
-                if let Ok(place_resolved) = match_pair.place.clone().try_upvars_resolved(self) {
+                if let Ok(place_resolved) =
+                    match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results)
+                {
                     candidate.ascriptions.push(Ascription {
                         annotation: annotation.clone(),
-                        source: place_resolved.into_place(self),
+                        source: place_resolved.into_place(self.tcx, self.typeck_results),
                         variance,
                     });
                 }
@@ -183,10 +184,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 ref subpattern,
                 is_primary: _,
             } => {
-                if let Ok(place_resolved) = match_pair.place.clone().try_upvars_resolved(self) {
+                if let Ok(place_resolved) =
+                    match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results)
+                {
                     candidate.bindings.push(Binding {
                         span: match_pair.pattern.span,
-                        source: place_resolved.into_place(self),
+                        source: place_resolved.into_place(self.tcx, self.typeck_results),
                         var_id: var,
                         binding_mode: mode,
                     });
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 63acd731db7..598da80c574 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -144,7 +144,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         }
     }
 
-    #[instrument(skip(self, make_target_blocks, place_builder), level = "debug")]
     pub(super) fn perform_test(
         &mut self,
         match_start_span: Span,
@@ -154,9 +153,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         test: &Test<'tcx>,
         make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
     ) {
-        let place = place_builder.into_place(self);
-        let place_ty = place.ty(&self.local_decls, self.tcx);
-        debug!(?place, ?place_ty,);
+        let place: Place<'tcx>;
+        if let Ok(test_place_builder) =
+            place_builder.try_upvars_resolved(self.tcx, self.typeck_results)
+        {
+            place = test_place_builder.into_place(self.tcx, self.typeck_results);
+        } else {
+            return;
+        }
+        debug!(
+            "perform_test({:?}, {:?}: {:?}, {:?})",
+            block,
+            place,
+            place.ty(&self.local_decls, self.tcx),
+            test
+        );
 
         let source_info = self.source_info(test.span);
         match test.kind {
@@ -724,7 +735,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         // So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`,
         // we want to create a set of derived match-patterns like
         // `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`.
-        let downcast_place = match_pair.place.downcast(adt_def, variant_index); // `(x as Variant)`
+        let elem =
+            ProjectionElem::Downcast(Some(adt_def.variant(variant_index).name), variant_index);
+        let downcast_place = match_pair.place.project(elem); // `(x as Variant)`
         let consequent_match_pairs = subpatterns.iter().map(|subpattern| {
             // e.g., `(x as Variant).0`
             let place = downcast_place.clone().field(subpattern.field, subpattern.pattern.ty);
diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs
index 4a7edc517f4..9a1e98d3bb1 100644
--- a/compiler/rustc_mir_build/src/build/matches/util.rs
+++ b/compiler/rustc_mir_build/src/build/matches/util.rs
@@ -31,15 +31,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         suffix: &'pat [Pat<'tcx>],
     ) {
         let tcx = self.tcx;
-        let (min_length, exact_size) =
-            if let Ok(place_resolved) = place.clone().try_upvars_resolved(self) {
-                match place_resolved.into_place(self).ty(&self.local_decls, tcx).ty.kind() {
-                    ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true),
-                    _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
-                }
-            } else {
-                ((prefix.len() + suffix.len()).try_into().unwrap(), false)
-            };
+        let (min_length, exact_size) = if let Ok(place_resolved) =
+            place.clone().try_upvars_resolved(tcx, self.typeck_results)
+        {
+            match place_resolved
+                .into_place(tcx, self.typeck_results)
+                .ty(&self.local_decls, tcx)
+                .ty
+                .kind()
+            {
+                ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true),
+                _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
+            }
+        } else {
+            ((prefix.len() + suffix.len()).try_into().unwrap(), false)
+        };
 
         match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
             let elem =
@@ -94,14 +100,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 }
 
 impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
-    pub(in crate::build) fn new(
+    pub(crate) fn new(
         place: PlaceBuilder<'tcx>,
         pattern: &'pat Pat<'tcx>,
     ) -> MatchPair<'pat, 'tcx> {
-        // Force the place type to the pattern's type.
-        // FIXME(oli-obk): only do this when we don't already know the place type.
-        // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
-        let place = place.project(ProjectionElem::OpaqueCast(pattern.ty));
         MatchPair { place, pattern }
     }
 }
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index ab37c480285..b9fd8c50e6a 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -553,7 +553,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
     /// Convenience wrapper that pushes a scope and then executes `f`
     /// to build its contents, popping the scope afterwards.
-    #[instrument(skip(self, f), level = "debug")]
     pub(crate) fn in_scope<F, R>(
         &mut self,
         region_scope: (region::Scope, SourceInfo),
@@ -563,6 +562,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     where
         F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R>,
     {
+        debug!("in_scope(region_scope={:?})", region_scope);
         let source_scope = self.source_scope;
         let tcx = self.tcx;
         if let LintLevel::Explicit(current_hir_id) = lint_level {
@@ -589,7 +589,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let rv = unpack!(block = f(self));
         unpack!(block = self.pop_scope(region_scope, block));
         self.source_scope = source_scope;
-        debug!(?block);
+        debug!("in_scope: exiting region_scope={:?} block={:?}", region_scope, block);
         block.and(rv)
     }
 
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 05da33caa91..4eb3607e9cc 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -48,8 +48,6 @@ impl<'tcx> Cx<'tcx> {
             _ => None,
         };
 
-        trace!(?expr.ty);
-
         // Now apply adjustments, if any.
         for adjustment in self.typeck_results.expr_adjustments(hir_expr) {
             trace!(?expr, ?adjustment);
@@ -58,8 +56,6 @@ impl<'tcx> Cx<'tcx> {
                 self.apply_adjustment(hir_expr, expr, adjustment, adjustment_span.unwrap_or(span));
         }
 
-        trace!(?expr.ty, "after adjustments");
-
         // Next, wrap this up in the expr's scope.
         expr = Expr {
             temp_lifetime,
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index c0fd19cf71c..60db98073a3 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -1202,32 +1202,35 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
 
     /// Creates a new list of wildcard fields for a given constructor. The result must have a
     /// length of `constructor.arity()`.
-    #[instrument(level = "trace")]
-    pub(super) fn wildcards(pcx: PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'tcx>) -> Self {
+    pub(super) fn wildcards(
+        cx: &MatchCheckCtxt<'p, 'tcx>,
+        ty: Ty<'tcx>,
+        constructor: &Constructor<'tcx>,
+    ) -> Self {
         let ret = match constructor {
-            Single | Variant(_) => match pcx.ty.kind() {
-                ty::Tuple(fs) => Fields::wildcards_from_tys(pcx.cx, fs.iter()),
-                ty::Ref(_, rty, _) => Fields::wildcards_from_tys(pcx.cx, once(*rty)),
+            Single | Variant(_) => match ty.kind() {
+                ty::Tuple(fs) => Fields::wildcards_from_tys(cx, fs.iter()),
+                ty::Ref(_, rty, _) => Fields::wildcards_from_tys(cx, once(*rty)),
                 ty::Adt(adt, substs) => {
                     if adt.is_box() {
                         // The only legal patterns of type `Box` (outside `std`) are `_` and box
                         // patterns. If we're here we can assume this is a box pattern.
-                        Fields::wildcards_from_tys(pcx.cx, once(substs.type_at(0)))
+                        Fields::wildcards_from_tys(cx, once(substs.type_at(0)))
                     } else {
                         let variant = &adt.variant(constructor.variant_index_for_adt(*adt));
-                        let tys = Fields::list_variant_nonhidden_fields(pcx.cx, pcx.ty, variant)
+                        let tys = Fields::list_variant_nonhidden_fields(cx, ty, variant)
                             .map(|(_, ty)| ty);
-                        Fields::wildcards_from_tys(pcx.cx, tys)
+                        Fields::wildcards_from_tys(cx, tys)
                     }
                 }
-                _ => bug!("Unexpected type for `Single` constructor: {:?}", pcx),
+                _ => bug!("Unexpected type for `Single` constructor: {:?}", ty),
             },
-            Slice(slice) => match *pcx.ty.kind() {
+            Slice(slice) => match *ty.kind() {
                 ty::Slice(ty) | ty::Array(ty, _) => {
                     let arity = slice.arity();
-                    Fields::wildcards_from_tys(pcx.cx, (0..arity).map(|_| ty))
+                    Fields::wildcards_from_tys(cx, (0..arity).map(|_| ty))
                 }
-                _ => bug!("bad slice pattern {:?} {:?}", constructor, pcx),
+                _ => bug!("bad slice pattern {:?} {:?}", constructor, ty),
             },
             Str(..)
             | FloatRange(..)
@@ -1240,7 +1243,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
                 bug!("called `Fields::wildcards` on an `Or` ctor")
             }
         };
-        debug!(?ret);
+        debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret);
         ret
     }
 
@@ -1283,7 +1286,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
     /// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
     /// `Some(_)`.
     pub(super) fn wild_from_ctor(pcx: PatCtxt<'_, 'p, 'tcx>, ctor: Constructor<'tcx>) -> Self {
-        let fields = Fields::wildcards(pcx, &ctor);
+        let fields = Fields::wildcards(pcx.cx, pcx.ty, &ctor);
         DeconstructedPat::new(ctor, fields, pcx.ty, DUMMY_SP)
     }
 
@@ -1550,13 +1553,13 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
     /// `other_ctor` can be different from `self.ctor`, but must be covered by it.
     pub(super) fn specialize<'a>(
         &'a self,
-        pcx: PatCtxt<'_, 'p, 'tcx>,
+        cx: &MatchCheckCtxt<'p, 'tcx>,
         other_ctor: &Constructor<'tcx>,
     ) -> SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]> {
         match (&self.ctor, other_ctor) {
             (Wildcard, _) => {
                 // We return a wildcard for each field of `other_ctor`.
-                Fields::wildcards(pcx, other_ctor).iter_patterns().collect()
+                Fields::wildcards(cx, self.ty, other_ctor).iter_patterns().collect()
             }
             (Slice(self_slice), Slice(other_slice))
                 if self_slice.arity() != other_slice.arity() =>
@@ -1575,7 +1578,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
                         let prefix = &self.fields.fields[..prefix];
                         let suffix = &self.fields.fields[self_slice.arity() - suffix..];
                         let wildcard: &_ =
-                            pcx.cx.pattern_arena.alloc(DeconstructedPat::wildcard(inner_ty));
+                            cx.pattern_arena.alloc(DeconstructedPat::wildcard(inner_ty));
                         let extra_wildcards = other_slice.arity() - self_slice.arity();
                         let extra_wildcards = (0..extra_wildcards).map(|_| wildcard);
                         prefix.iter().chain(extra_wildcards).chain(suffix).collect()
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 7d22f7b69d8..a13748a2d47 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -196,7 +196,6 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         }
     }
 
-    #[instrument(skip(self), level = "debug")]
     fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
         let mut ty = self.typeck_results.node_type(pat.hir_id);
 
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index f27ec22a8de..9e7a267ecbd 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -411,12 +411,12 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
     /// This is roughly the inverse of `Constructor::apply`.
     fn pop_head_constructor(
         &self,
-        pcx: PatCtxt<'_, 'p, 'tcx>,
+        cx: &MatchCheckCtxt<'p, 'tcx>,
         ctor: &Constructor<'tcx>,
     ) -> PatStack<'p, 'tcx> {
         // We pop the head pattern and push the new fields extracted from the arguments of
         // `self.head()`.
-        let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(pcx, ctor);
+        let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(cx, ctor);
         new_fields.extend_from_slice(&self.pats[1..]);
         PatStack::from_vec(new_fields)
     }
@@ -475,7 +475,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
         let mut matrix = Matrix::empty();
         for row in &self.patterns {
             if ctor.is_covered_by(pcx, row.head().ctor()) {
-                let new_row = row.pop_head_constructor(pcx, ctor);
+                let new_row = row.pop_head_constructor(pcx.cx, ctor);
                 matrix.push(new_row);
             }
         }
@@ -786,7 +786,7 @@ fn is_useful<'p, 'tcx>(
     is_under_guard: bool,
     is_top_level: bool,
 ) -> Usefulness<'p, 'tcx> {
-    debug!(?matrix, ?v);
+    debug!("matrix,v={:?}{:?}", matrix, v);
     let Matrix { patterns: rows, .. } = matrix;
 
     // The base case. We are pattern-matching on () and the return value is
@@ -806,6 +806,11 @@ fn is_useful<'p, 'tcx>(
 
     debug_assert!(rows.iter().all(|r| r.len() == v.len()));
 
+    let ty = v.head().ty();
+    let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
+    debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span());
+    let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive };
+
     // If the first pattern is an or-pattern, expand it.
     let mut ret = Usefulness::new_not_useful(witness_preference);
     if v.head().is_or_pat() {
@@ -827,19 +832,6 @@ fn is_useful<'p, 'tcx>(
             }
         }
     } else {
-        let mut ty = v.head().ty();
-
-        // Opaque types can't get destructured/split, but the patterns can
-        // actually hint at hidden types, so we use the patterns' types instead.
-        if let ty::Opaque(..) = v.head().ty().kind() {
-            if let Some(row) = rows.first() {
-                ty = row.head().ty();
-            }
-        }
-        let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
-        debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span());
-        let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive };
-
         let v_ctor = v.head().ctor();
         debug!(?v_ctor);
         if let Constructor::IntRange(ctor_range) = &v_ctor {
@@ -861,7 +853,7 @@ fn is_useful<'p, 'tcx>(
             debug!("specialize({:?})", ctor);
             // We cache the result of `Fields::wildcards` because it is used a lot.
             let spec_matrix = start_matrix.specialize_constructor(pcx, &ctor);
-            let v = v.pop_head_constructor(pcx, &ctor);
+            let v = v.pop_head_constructor(cx, &ctor);
             let usefulness = ensure_sufficient_stack(|| {
                 is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false)
             });
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs b/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs
index 7806e8f45d3..28936274baa 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs
@@ -48,7 +48,6 @@ impl<'tcx> Lift for PlaceElem<'tcx> {
         match *self {
             ProjectionElem::Deref => ProjectionElem::Deref,
             ProjectionElem::Field(f, ty) => ProjectionElem::Field(f, ty.lift()),
-            ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty.lift()),
             ProjectionElem::Index(ref i) => ProjectionElem::Index(i.lift()),
             ProjectionElem::Subslice { from, to, from_end } => {
                 ProjectionElem::Subslice { from, to, from_end }
diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs
index 86327ade94b..b91ae083cf5 100644
--- a/compiler/rustc_mir_transform/src/add_retag.rs
+++ b/compiler/rustc_mir_transform/src/add_retag.rs
@@ -28,7 +28,6 @@ fn is_stable(place: PlaceRef<'_>) -> bool {
             ProjectionElem::Field { .. } |
             ProjectionElem::ConstantIndex { .. } |
             ProjectionElem::Subslice { .. } |
-            ProjectionElem::OpaqueCast { .. } |
             ProjectionElem::Downcast { .. } => true,
         }
     })
diff --git a/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug.rs b/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug.rs
index 9a50c0f988a..811832848d9 100644
--- a/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug.rs
+++ b/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug.rs
@@ -1,9 +1,8 @@
 // compile-flags: --edition=2021
-// check-pass
 #![feature(type_alias_impl_trait)]
 
 fn main() {
-    type T = impl Copy;
+    type T = impl Copy; //~ ERROR unconstrained opaque type
     let foo: T = (1u32, 2u32);
     let (a, b): (u32, u32) = foo;
 }
diff --git a/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug.stderr b/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug.stderr
new file mode 100644
index 00000000000..03b172e6de5
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug.stderr
@@ -0,0 +1,10 @@
+error: unconstrained opaque type
+  --> $DIR/cross_inference_pattern_bug.rs:5:14
+   |
+LL |     type T = impl Copy;
+   |              ^^^^^^^^^
+   |
+   = note: `T` must be used in combination with a concrete type within the same module
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.rs b/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.rs
index b929122a6c2..328096d44b4 100644
--- a/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.rs
+++ b/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.rs
@@ -1,13 +1,13 @@
+// known-bug: #96572
 // compile-flags: --edition=2021 --crate-type=lib
 // rustc-env:RUST_BACKTRACE=0
-// check-pass
 
 // tracked in https://github.com/rust-lang/rust/issues/96572
 
 #![feature(type_alias_impl_trait)]
 
 fn main() {
-    type T = impl Copy;
+    type T = impl Copy;  // error: unconstrained opaque type
     let foo: T = (1u32, 2u32);
-    let (a, b) = foo; // this line used to make the code fail
+    let (a, b) = foo; // removing this line makes the code compile
 }
diff --git a/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.stderr b/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.stderr
new file mode 100644
index 00000000000..8aa1f495639
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.stderr
@@ -0,0 +1,10 @@
+error: unconstrained opaque type
+  --> $DIR/cross_inference_pattern_bug_no_type.rs:10:14
+   |
+LL |     type T = impl Copy;  // error: unconstrained opaque type
+   |              ^^^^^^^^^
+   |
+   = note: `T` must be used in combination with a concrete type within the same module
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-mismatch.rs b/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-mismatch.rs
deleted file mode 100644
index 825710851b0..00000000000
--- a/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-mismatch.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-#![feature(type_alias_impl_trait)]
-
-fn main() {
-    type T = impl Copy;
-    let foo: T = Some((1u32, 2u32));
-    match foo {
-        None => (),
-        Some((a, b, c)) => (), //~ ERROR mismatched types
-    }
-}
diff --git a/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-mismatch.stderr b/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-mismatch.stderr
deleted file mode 100644
index 728244a1844..00000000000
--- a/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-mismatch.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/issue-96572-unconstrained-mismatch.rs:8:14
-   |
-LL |     match foo {
-   |           --- this expression has type `T`
-LL |         None => (),
-LL |         Some((a, b, c)) => (),
-   |              ^^^^^^^^^ expected a tuple with 2 elements, found one with 3 elements
-   |
-   = note: expected tuple `(u32, u32)`
-              found tuple `(_, _, _)`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-only-pattern-rpit.rs b/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-only-pattern-rpit.rs
deleted file mode 100644
index c0a371eca1c..00000000000
--- a/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-only-pattern-rpit.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-// check-pass
-
-#[allow(unconditional_recursion)]
-fn foo(b: bool) -> impl Copy {
-    let (mut x, mut y) = foo(false);
-    x = 42;
-    y = "foo";
-    if b {
-        panic!()
-    } else {
-        foo(true)
-    }
-}
-
-fn bar(b: bool) -> Option<impl Copy> {
-    if b {
-        return None;
-    }
-    match bar(!b) {
-        Some((mut x, mut y)) => {
-            x = 42;
-            y = "foo";
-        }
-        None => {}
-    }
-    None
-}
-
-fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-only-pattern.rs b/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-only-pattern.rs
deleted file mode 100644
index ec249958590..00000000000
--- a/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-only-pattern.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-#![feature(type_alias_impl_trait)]
-// check-pass
-
-type T = impl Copy;
-
-fn foo(foo: T) {
-    let (mut x, mut y) = foo;
-    x = 42;
-    y = "foo";
-}
-
-type U = impl Copy;
-
-fn bar(bar: Option<U>) {
-    match bar {
-        Some((mut x, mut y)) => {
-            x = 42;
-            y = "foo";
-        }
-        None => {}
-    }
-}
-
-fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-struct.rs b/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-struct.rs
deleted file mode 100644
index 3351d9bcff1..00000000000
--- a/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-struct.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-#![feature(type_alias_impl_trait)]
-// check-pass
-
-#[derive(Copy, Clone)]
-struct Foo((u32, u32));
-
-fn main() {
-    type U = impl Copy;
-    let foo: U = Foo((1u32, 2u32));
-    let Foo((a, b)) = foo;
-}
diff --git a/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-upvar-enum.rs b/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-upvar-enum.rs
deleted file mode 100644
index ef3279a98d1..00000000000
--- a/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-upvar-enum.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-#![feature(type_alias_impl_trait)]
-// check-pass
-
-fn main() {
-    type T = impl Copy;
-    let foo: T = Some((1u32, 2u32));
-    let x = move || {
-        match foo {
-            None => (),
-            Some((a, b)) => (),
-        }
-    };
-}
diff --git a/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-upvar.rs b/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-upvar.rs
deleted file mode 100644
index bb0fc7c7534..00000000000
--- a/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-upvar.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-#![feature(type_alias_impl_trait)]
-// check-pass
-
-#[derive(Copy, Clone)]
-struct Foo((u32, u32));
-
-fn main() {
-    type T = impl Copy;
-    let foo: T = Foo((1u32, 2u32));
-    let x = move || {
-        let Foo((a, b)) = foo;
-    };
-}
diff --git a/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained.rs b/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained.rs
deleted file mode 100644
index 4b9ed7f28eb..00000000000
--- a/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-#![feature(type_alias_impl_trait)]
-// check-pass
-
-fn main() {
-    type T = impl Copy;
-    let foo: T = Some((1u32, 2u32));
-    match foo {
-        None => (),
-        Some((a, b)) => (),
-    }
-}
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 9690ad27771..3bf75bcbee8 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -252,7 +252,6 @@ fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &B
                 }
             },
             ProjectionElem::ConstantIndex { .. }
-            | ProjectionElem::OpaqueCast(..)
             | ProjectionElem::Downcast(..)
             | ProjectionElem::Subslice { .. }
             | ProjectionElem::Deref