about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/constant.rs5
-rw-r--r--compiler/rustc_const_eval/src/const_eval/mod.rs10
-rw-r--r--compiler/rustc_const_eval/src/const_eval/valtrees.rs16
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0158.md17
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs6
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs8
-rw-r--r--compiler/rustc_middle/src/query/erase.rs7
-rw-r--r--compiler/rustc_middle/src/thir.rs11
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs53
-rw-r--r--compiler/rustc_mir_build/Cargo.toml1
-rw-r--r--compiler/rustc_mir_build/messages.ftl2
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs45
-rw-r--r--compiler/rustc_mir_build/src/errors.rs9
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs224
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs144
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs18
-rw-r--r--compiler/rustc_trait_selection/src/solve/delegate.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_match.rs173
20 files changed, 219 insertions, 540 deletions
diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs
index 822f5c2c44a..35e9a3b7dc2 100644
--- a/compiler/rustc_codegen_ssa/src/mir/constant.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs
@@ -37,13 +37,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     pub fn eval_unevaluated_mir_constant_to_valtree(
         &self,
         constant: &mir::ConstOperand<'tcx>,
-    ) -> Result<Option<ty::ValTree<'tcx>>, ErrorHandled> {
+    ) -> Result<Result<ty::ValTree<'tcx>, Ty<'tcx>>, ErrorHandled> {
         let uv = match self.monomorphize(constant.const_) {
             mir::Const::Unevaluated(uv, _) => uv.shrink(),
             mir::Const::Ty(_, c) => match c.kind() {
                 // A constant that came from a const generic but was then used as an argument to old-style
                 // simd_shuffle (passing as argument instead of as a generic param).
-                rustc_type_ir::ConstKind::Value(_, valtree) => return Ok(Some(valtree)),
+                rustc_type_ir::ConstKind::Value(_, valtree) => return Ok(Ok(valtree)),
                 other => span_bug!(constant.span, "{other:#?}"),
             },
             // We should never encounter `Const::Val` unless MIR opts (like const prop) evaluate
@@ -70,6 +70,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         let val = self
             .eval_unevaluated_mir_constant_to_valtree(constant)
             .ok()
+            .map(|x| x.ok())
             .flatten()
             .map(|val| {
                 let field_ty = ty.builtin_index().unwrap();
diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
index 4ae4816e33a..3a6dc81eff1 100644
--- a/compiler/rustc_const_eval/src/const_eval/mod.rs
+++ b/compiler/rustc_const_eval/src/const_eval/mod.rs
@@ -27,15 +27,15 @@ pub(crate) use valtrees::{eval_to_valtree, valtree_to_const_value};
 // We forbid type-level constants that contain more than `VALTREE_MAX_NODES` nodes.
 const VALTREE_MAX_NODES: usize = 100000;
 
-pub(crate) enum ValTreeCreationError {
+pub(crate) enum ValTreeCreationError<'tcx> {
     NodesOverflow,
     /// Values of this type, or this particular value, are not supported as valtrees.
-    NonSupportedType,
+    NonSupportedType(Ty<'tcx>),
 }
-pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeCreationError>;
+pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeCreationError<'tcx>>;
 
-impl From<InterpErrorInfo<'_>> for ValTreeCreationError {
-    fn from(err: InterpErrorInfo<'_>) -> Self {
+impl<'tcx> From<InterpErrorInfo<'tcx>> for ValTreeCreationError<'tcx> {
+    fn from(err: InterpErrorInfo<'tcx>) -> Self {
         ty::tls::with(|tcx| {
             bug!(
                 "Unexpected Undefined Behavior error during valtree construction: {}",
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index 2e8ad445cf5..3bc01510730 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -120,13 +120,13 @@ fn const_to_valtree_inner<'tcx>(
             // We could allow wide raw pointers where both sides are integers in the future,
             // but for now we reject them.
             if matches!(val.layout.abi, Abi::ScalarPair(..)) {
-                return Err(ValTreeCreationError::NonSupportedType);
+                return Err(ValTreeCreationError::NonSupportedType(ty));
             }
             let val = val.to_scalar();
             // We are in the CTFE machine, so ptr-to-int casts will fail.
             // This can only be `Ok` if `val` already is an integer.
             let Ok(val) = val.try_to_scalar_int() else {
-                return Err(ValTreeCreationError::NonSupportedType);
+                return Err(ValTreeCreationError::NonSupportedType(ty));
             };
             // It's just a ScalarInt!
             Ok(ty::ValTree::Leaf(val))
@@ -134,7 +134,7 @@ fn const_to_valtree_inner<'tcx>(
 
         // Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to
         // agree with runtime equality tests.
-        ty::FnPtr(_) => Err(ValTreeCreationError::NonSupportedType),
+        ty::FnPtr(_) => Err(ValTreeCreationError::NonSupportedType(ty)),
 
         ty::Ref(_, _, _)  => {
             let derefd_place = ecx.deref_pointer(place)?;
@@ -148,7 +148,7 @@ fn const_to_valtree_inner<'tcx>(
         // resolving their backing type, even if we can do that at const eval time. We may
         // hypothetically be able to allow `dyn StructuralPartialEq` trait objects in the future,
         // but it is unclear if this is useful.
-        ty::Dynamic(..) => Err(ValTreeCreationError::NonSupportedType),
+        ty::Dynamic(..) => Err(ValTreeCreationError::NonSupportedType(ty)),
 
         ty::Tuple(elem_tys) => {
             branches(ecx, place, elem_tys.len(), None, num_nodes)
@@ -156,7 +156,7 @@ fn const_to_valtree_inner<'tcx>(
 
         ty::Adt(def, _) => {
             if def.is_union() {
-                return Err(ValTreeCreationError::NonSupportedType);
+                return Err(ValTreeCreationError::NonSupportedType(ty));
             } else if def.variants().is_empty() {
                 bug!("uninhabited types should have errored and never gotten converted to valtree")
             }
@@ -180,7 +180,7 @@ fn const_to_valtree_inner<'tcx>(
         | ty::Closure(..)
         | ty::CoroutineClosure(..)
         | ty::Coroutine(..)
-        | ty::CoroutineWitness(..) => Err(ValTreeCreationError::NonSupportedType),
+        | ty::CoroutineWitness(..) => Err(ValTreeCreationError::NonSupportedType(ty)),
     }
 }
 
@@ -251,7 +251,7 @@ pub(crate) fn eval_to_valtree<'tcx>(
     let valtree_result = const_to_valtree_inner(&ecx, &place, &mut num_nodes);
 
     match valtree_result {
-        Ok(valtree) => Ok(Some(valtree)),
+        Ok(valtree) => Ok(Ok(valtree)),
         Err(err) => {
             let did = cid.instance.def_id();
             let global_const_id = cid.display(tcx);
@@ -262,7 +262,7 @@ pub(crate) fn eval_to_valtree<'tcx>(
                         tcx.dcx().emit_err(MaxNumNodesInConstErr { span, global_const_id });
                     Err(handled.into())
                 }
-                ValTreeCreationError::NonSupportedType => Ok(None),
+                ValTreeCreationError::NonSupportedType(ty) => Ok(Err(ty)),
             }
         }
     }
diff --git a/compiler/rustc_error_codes/src/error_codes/E0158.md b/compiler/rustc_error_codes/src/error_codes/E0158.md
index 03b93d925c1..c31f1e13bee 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0158.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0158.md
@@ -1,5 +1,4 @@
-An associated `const`, `const` parameter or `static` has been referenced
-in a pattern.
+A generic parameter or `static` has been referenced in a pattern.
 
 Erroneous code example:
 
@@ -15,25 +14,25 @@ trait Bar {
 
 fn test<A: Bar>(arg: Foo) {
     match arg {
-        A::X => println!("A::X"), // error: E0158: associated consts cannot be
-                                  //        referenced in patterns
+        A::X => println!("A::X"), // error: E0158: constant pattern depends
+                                  //        on a generic parameter
         Foo::Two => println!("Two")
     }
 }
 ```
 
-Associated `const`s cannot be referenced in patterns because it is impossible
+Generic parameters cannot be referenced in patterns because it is impossible
 for the compiler to prove exhaustiveness (that some pattern will always match).
 Take the above example, because Rust does type checking in the *generic*
 method, not the *monomorphized* specific instance. So because `Bar` could have
-theoretically infinite implementations, there's no way to always be sure that
+theoretically arbitrary implementations, there's no way to always be sure that
 `A::X` is `Foo::One`. So this code must be rejected. Even if code can be
 proven exhaustive by a programmer, the compiler cannot currently prove this.
 
-The same holds true of `const` parameters and `static`s.
+The same holds true of `static`s.
 
-If you want to match against an associated `const`, `const` parameter or
-`static` consider using a guard instead:
+If you want to match against a `const` that depends on a generic parameter or a
+`static`, consider using a guard instead:
 
 ```
 trait Trait {
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index cfef1f13015..c9073d8c23e 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -1427,17 +1427,17 @@ impl<'tcx> InferCtxt<'tcx> {
         span: Span,
     ) -> Result<ty::Const<'tcx>, ErrorHandled> {
         match self.const_eval_resolve(param_env, unevaluated, span) {
-            Ok(Some(val)) => Ok(ty::Const::new_value(
+            Ok(Ok(val)) => Ok(ty::Const::new_value(
                 self.tcx,
                 val,
                 self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args),
             )),
-            Ok(None) => {
+            Ok(Err(bad_ty)) => {
                 let tcx = self.tcx;
                 let def_id = unevaluated.def;
                 span_bug!(
                     tcx.def_span(def_id),
-                    "unable to construct a constant value for the unevaluated constant {:?}",
+                    "unable to construct a valtree for the unevaluated constant {:?}: type {bad_ty} is not valtree-compatible",
                     unevaluated
                 );
             }
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 6a8498abaf9..9df19565ab3 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -90,9 +90,11 @@ TrivialTypeTraversalImpls! { ErrorHandled }
 pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
 pub type EvalStaticInitializerRawResult<'tcx> = Result<ConstAllocation<'tcx>, ErrorHandled>;
 pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
-/// `Ok(None)` indicates the constant was fine, but the valtree couldn't be constructed.
-/// This is needed in `thir::pattern::lower_inline_const`.
-pub type EvalToValTreeResult<'tcx> = Result<Option<ValTree<'tcx>>, ErrorHandled>;
+/// `Ok(Err(ty))` indicates the constant was fine, but the valtree couldn't be constructed
+/// because the value containts something of type `ty` that is not valtree-compatible.
+/// The caller can then show an appropriate error; the query does not have the
+/// necssary context to give good user-facing errors for this case.
+pub type EvalToValTreeResult<'tcx> = Result<Result<ValTree<'tcx>, Ty<'tcx>>, ErrorHandled>;
 
 #[cfg(target_pointer_width = "64")]
 rustc_data_structures::static_assert_size!(InterpErrorInfo<'_>, 8);
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index 301c9911b44..d9fa5b02f7f 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -157,9 +157,10 @@ impl EraseType for Result<mir::ConstValue<'_>, mir::interpret::ErrorHandled> {
     type Result = [u8; size_of::<Result<mir::ConstValue<'static>, mir::interpret::ErrorHandled>>()];
 }
 
-impl EraseType for Result<Option<ty::ValTree<'_>>, mir::interpret::ErrorHandled> {
-    type Result =
-        [u8; size_of::<Result<Option<ty::ValTree<'static>>, mir::interpret::ErrorHandled>>()];
+impl EraseType for Result<Result<ty::ValTree<'_>, Ty<'_>>, mir::interpret::ErrorHandled> {
+    type Result = [u8; size_of::<
+        Result<Result<ty::ValTree<'static>, Ty<'static>>, mir::interpret::ErrorHandled>,
+    >()];
 }
 
 impl EraseType for Result<&'_ ty::List<Ty<'_>>, ty::util::AlwaysRequiresDrop> {
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index c97af68c29e..b80d00719ee 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -783,16 +783,13 @@ pub enum PatKind<'tcx> {
     },
 
     /// One of the following:
-    /// * `&str` (represented as a valtree), which will be handled as a string pattern and thus
-    ///   exhaustiveness checking will detect if you use the same string twice in different
-    ///   patterns.
+    /// * `&str`/`&[u8]` (represented as a valtree), which will be handled as a string/slice pattern
+    ///   and thus exhaustiveness checking will detect if you use the same string/slice twice in
+    ///   different patterns.
     /// * integer, bool, char or float (represented as a valtree), which will be handled by
     ///   exhaustiveness to cover exactly its own value, similar to `&str`, but these values are
     ///   much simpler.
-    /// * Opaque constants (represented as `mir::ConstValue`), that must not be matched
-    ///   structurally. So anything that does not derive `PartialEq` and `Eq`.
-    ///
-    /// These are always compared with the matched place using (the semantics of) `PartialEq`.
+    /// * `String`, if `string_deref_patterns` is enabled.
     Constant {
         value: mir::Const<'tcx>,
     },
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 32d01d07c17..4d213d14af1 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -1,6 +1,7 @@
 use crate::middle::resolve_bound_vars as rbv;
 use crate::mir::interpret::{ErrorHandled, LitToConstInput, Scalar};
 use crate::ty::{self, GenericArgs, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
+use either::Either;
 use rustc_data_structures::intern::Interned;
 use rustc_error_messages::MultiSpan;
 use rustc_hir as hir;
@@ -312,14 +313,16 @@ impl<'tcx> Const<'tcx> {
         Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize))
     }
 
-    /// Returns the evaluated constant
+    /// Returns the evaluated constant as a valtree;
+    /// if that fails due to a valtree-incompatible type, indicate which type that is
+    /// by returning `Err(Left(bad_type))`.
     #[inline]
-    pub fn eval(
+    pub fn eval_valtree(
         self,
         tcx: TyCtxt<'tcx>,
         param_env: ParamEnv<'tcx>,
         span: Span,
-    ) -> Result<(Ty<'tcx>, ValTree<'tcx>), ErrorHandled> {
+    ) -> Result<(Ty<'tcx>, ValTree<'tcx>), Either<Ty<'tcx>, ErrorHandled>> {
         assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}");
         match self.kind() {
             ConstKind::Unevaluated(unevaluated) => {
@@ -328,27 +331,47 @@ impl<'tcx> Const<'tcx> {
                 let (param_env, unevaluated) = unevaluated.prepare_for_eval(tcx, param_env);
                 // try to resolve e.g. associated constants to their definition on an impl, and then
                 // evaluate the const.
-                let Some(c) = tcx.const_eval_resolve_for_typeck(param_env, unevaluated, span)?
-                else {
-                    // This can happen when we run on ill-typed code.
-                    let e = tcx.dcx().span_delayed_bug(
-                        span,
-                        "`ty::Const::eval` called on a non-valtree-compatible type",
-                    );
-                    return Err(e.into());
-                };
-                Ok((tcx.type_of(unevaluated.def).instantiate(tcx, unevaluated.args), c))
+                match tcx.const_eval_resolve_for_typeck(param_env, unevaluated, span) {
+                    Ok(Ok(c)) => {
+                        Ok((tcx.type_of(unevaluated.def).instantiate(tcx, unevaluated.args), c))
+                    }
+                    Ok(Err(bad_ty)) => Err(Either::Left(bad_ty)),
+                    Err(err) => Err(Either::Right(err.into())),
+                }
             }
             ConstKind::Value(ty, val) => Ok((ty, val)),
-            ConstKind::Error(g) => Err(g.into()),
+            ConstKind::Error(g) => Err(Either::Right(g.into())),
             ConstKind::Param(_)
             | ConstKind::Infer(_)
             | ConstKind::Bound(_, _)
             | ConstKind::Placeholder(_)
-            | ConstKind::Expr(_) => Err(ErrorHandled::TooGeneric(span)),
+            | ConstKind::Expr(_) => Err(Either::Right(ErrorHandled::TooGeneric(span))),
         }
     }
 
+    /// Returns the evaluated constant
+    #[inline]
+    pub fn eval(
+        self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ParamEnv<'tcx>,
+        span: Span,
+    ) -> Result<(Ty<'tcx>, ValTree<'tcx>), ErrorHandled> {
+        self.eval_valtree(tcx, param_env, span).map_err(|err| {
+            match err {
+                Either::Right(err) => err,
+                Either::Left(_bad_ty) => {
+                    // This can happen when we run on ill-typed code.
+                    let e = tcx.dcx().span_delayed_bug(
+                        span,
+                        "`ty::Const::eval` called on a non-valtree-compatible type",
+                    );
+                    e.into()
+                }
+            }
+        })
+    }
+
     /// Normalizes the constant to a value or an error if possible.
     #[inline]
     pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml
index 5d828d0093f..529e9cc2711 100644
--- a/compiler/rustc_mir_build/Cargo.toml
+++ b/compiler/rustc_mir_build/Cargo.toml
@@ -5,6 +5,7 @@ edition = "2021"
 
 [dependencies]
 # tidy-alphabetical-start
+either = "1.5.0"
 itertools = "0.12"
 rustc_apfloat = "0.2.0"
 rustc_arena = { path = "../rustc_arena" }
diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index 0c277811fda..281f3ef6ef3 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -4,8 +4,6 @@ mir_build_already_borrowed = cannot borrow value as mutable because it is also b
 
 mir_build_already_mut_borrowed = cannot borrow value as immutable because it is also borrowed as mutable
 
-mir_build_assoc_const_in_pattern = associated consts cannot be referenced in patterns
-
 mir_build_bindings_with_variant_name =
     pattern binding `{$name}` is named the same as one of the variants of the type `{$ty_path}`
     .suggestion = to match on the variant, qualify the path
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index d29874a5ad4..5aed2537750 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -144,7 +144,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     && tcx.is_lang_item(def.did(), LangItem::String)
                 {
                     if !tcx.features().string_deref_patterns {
-                        bug!(
+                        span_bug!(
+                            test.span,
                             "matching on `String` went through without enabling string_deref_patterns"
                         );
                     }
@@ -432,40 +433,28 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
         }
 
-        match *ty.kind() {
-            ty::Ref(_, deref_ty, _) => ty = deref_ty,
-            _ => {
-                // non_scalar_compare called on non-reference type
-                let temp = self.temp(ty, source_info.span);
-                self.cfg.push_assign(block, source_info, temp, Rvalue::Use(expect));
-                let ref_ty = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, ty);
-                let ref_temp = self.temp(ref_ty, source_info.span);
-
-                self.cfg.push_assign(
-                    block,
-                    source_info,
-                    ref_temp,
-                    Rvalue::Ref(self.tcx.lifetimes.re_erased, BorrowKind::Shared, temp),
-                );
-                expect = Operand::Move(ref_temp);
-
-                let ref_temp = self.temp(ref_ty, source_info.span);
-                self.cfg.push_assign(
-                    block,
-                    source_info,
-                    ref_temp,
-                    Rvalue::Ref(self.tcx.lifetimes.re_erased, BorrowKind::Shared, val),
-                );
-                val = ref_temp;
+        // Figure out the type on which we are calling `PartialEq`. This involves an extra wrapping
+        // reference: we can only compare two `&T`, and then compare_ty will be `T`.
+        // Make sure that we do *not* call any user-defined code here.
+        // The only types that can end up here are string and byte literals,
+        // which have their comparison defined in `core`.
+        // (Interestingly this means that exhaustiveness analysis relies, for soundness,
+        // on the `PartialEq` impls for `str` and `[u8]` to b correct!)
+        let compare_ty = match *ty.kind() {
+            ty::Ref(_, deref_ty, _)
+                if deref_ty == self.tcx.types.str_ || deref_ty != self.tcx.types.u8 =>
+            {
+                deref_ty
             }
-        }
+            _ => span_bug!(source_info.span, "invalid type for non-scalar compare: {}", ty),
+        };
 
         let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, Some(source_info.span));
         let method = trait_method(
             self.tcx,
             eq_def_id,
             sym::eq,
-            self.tcx.with_opt_host_effect_param(self.def_id, eq_def_id, [ty, ty]),
+            self.tcx.with_opt_host_effect_param(self.def_id, eq_def_id, [compare_ty, compare_ty]),
         );
 
         let bool_ty = self.tcx.types.bool;
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 7c73d8a6d47..f6f443b64a6 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -567,13 +567,6 @@ pub(crate) struct StaticInPattern {
 }
 
 #[derive(Diagnostic)]
-#[diag(mir_build_assoc_const_in_pattern, code = E0158)]
-pub(crate) struct AssocConstInPattern {
-    #[primary_span]
-    pub(crate) span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(mir_build_const_param_in_pattern, code = E0158)]
 pub(crate) struct ConstParamInPattern {
     #[primary_span]
@@ -597,7 +590,7 @@ pub(crate) struct UnreachablePattern {
 }
 
 #[derive(Diagnostic)]
-#[diag(mir_build_const_pattern_depends_on_generic_parameter)]
+#[diag(mir_build_const_pattern_depends_on_generic_parameter, code = E0158)]
 pub(crate) struct ConstPatternDependsOnGenericParameter {
     #[primary_span]
     pub(crate) span: Span,
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 5745dc0969c..0d54f332585 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -1,42 +1,45 @@
+use either::Either;
 use rustc_apfloat::Float;
 use rustc_hir as hir;
 use rustc_index::Idx;
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::Obligation;
 use rustc_middle::mir;
-use rustc_middle::span_bug;
+use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::thir::{FieldPat, Pat, PatKind};
+use rustc_middle::ty::TypeVisitableExt;
 use rustc_middle::ty::{self, Ty, TyCtxt, ValTree};
-use rustc_span::{ErrorGuaranteed, Span};
+use rustc_span::Span;
 use rustc_target::abi::{FieldIdx, VariantIdx};
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
-use rustc_trait_selection::traits::{self, ObligationCause};
+use rustc_trait_selection::traits::ObligationCause;
 use tracing::{debug, instrument, trace};
 
-use std::cell::Cell;
-
 use super::PatCtxt;
 use crate::errors::{
-    InvalidPattern, NaNPattern, PointerPattern, TypeNotPartialEq, TypeNotStructural, UnionPattern,
-    UnsizedPattern,
+    ConstPatternDependsOnGenericParameter, CouldNotEvalConstPattern, InvalidPattern, NaNPattern,
+    PointerPattern, TypeNotPartialEq, TypeNotStructural, UnionPattern, UnsizedPattern,
 };
 
 impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
-    /// Converts an evaluated constant to a pattern (if possible).
+    /// Converts a constant to a pattern (if possible).
     /// This means aggregate values (like structs and enums) are converted
     /// to a pattern that matches the value (as if you'd compared via structural equality).
     ///
-    /// `cv` must be a valtree or a `mir::ConstValue`.
+    /// Only type system constants are supported, as we are using valtrees
+    /// as an intermediate step. Unfortunately those don't carry a type
+    /// so we have to carry one ourselves.
     #[instrument(level = "debug", skip(self), ret)]
     pub(super) fn const_to_pat(
         &self,
-        cv: mir::Const<'tcx>,
+        c: ty::Const<'tcx>,
+        ty: Ty<'tcx>,
         id: hir::HirId,
         span: Span,
     ) -> Box<Pat<'tcx>> {
         let infcx = self.tcx.infer_ctxt().build();
         let mut convert = ConstToPat::new(self, id, span, infcx);
-        convert.to_pat(cv)
+        convert.to_pat(c, ty)
     }
 }
 
@@ -45,23 +48,12 @@ struct ConstToPat<'tcx> {
     span: Span,
     param_env: ty::ParamEnv<'tcx>,
 
-    // This tracks if we emitted some hard error for a given const value, so that
-    // we will not subsequently issue an irrelevant lint for the same const
-    // value.
-    saw_const_match_error: Cell<Option<ErrorGuaranteed>>,
-
     // inference context used for checking `T: Structural` bounds.
     infcx: InferCtxt<'tcx>,
 
     treat_byte_string_as_slice: bool,
 }
 
-/// This error type signals that we encountered a non-struct-eq situation.
-/// We will fall back to calling `PartialEq::eq` on such patterns,
-/// and exhaustiveness checking will consider them as matching nothing.
-#[derive(Debug)]
-struct FallbackToOpaqueConst;
-
 impl<'tcx> ConstToPat<'tcx> {
     fn new(
         pat_ctxt: &PatCtxt<'_, 'tcx>,
@@ -75,7 +67,6 @@ impl<'tcx> ConstToPat<'tcx> {
             span,
             infcx,
             param_env: pat_ctxt.param_env,
-            saw_const_match_error: Cell::new(None),
             treat_byte_string_as_slice: pat_ctxt
                 .typeck_results
                 .treat_byte_string_as_slice
@@ -91,116 +82,55 @@ impl<'tcx> ConstToPat<'tcx> {
         ty.is_structural_eq_shallow(self.infcx.tcx)
     }
 
-    fn to_pat(&mut self, cv: mir::Const<'tcx>) -> Box<Pat<'tcx>> {
+    fn to_pat(&mut self, c: ty::Const<'tcx>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> {
         trace!(self.treat_byte_string_as_slice);
-        // This method is just a wrapper handling a validity check; the heavy lifting is
-        // performed by the recursive `recur` method, which is not meant to be
-        // invoked except by this method.
-        //
-        // once indirect_structural_match is a full fledged error, this
-        // level of indirection can be eliminated
+        let pat_from_kind = |kind| Box::new(Pat { span: self.span, ty, kind });
 
-        let have_valtree =
-            matches!(cv, mir::Const::Ty(_, c) if matches!(c.kind(), ty::ConstKind::Value(_, _)));
-        let inlined_const_as_pat = match cv {
-            mir::Const::Ty(_, c) => match c.kind() {
-                ty::ConstKind::Param(_)
-                | ty::ConstKind::Infer(_)
-                | ty::ConstKind::Bound(_, _)
-                | ty::ConstKind::Placeholder(_)
-                | ty::ConstKind::Unevaluated(_)
-                | ty::ConstKind::Error(_)
-                | ty::ConstKind::Expr(_) => {
-                    span_bug!(self.span, "unexpected const in `to_pat`: {:?}", c.kind())
-                }
-                ty::ConstKind::Value(ty, valtree) => {
-                    self.recur(valtree, ty).unwrap_or_else(|_: FallbackToOpaqueConst| {
-                        Box::new(Pat {
-                            span: self.span,
-                            ty: cv.ty(),
-                            kind: PatKind::Constant { value: cv },
-                        })
-                    })
-                }
-            },
-            mir::Const::Unevaluated(_, _) => {
-                span_bug!(self.span, "unevaluated const in `to_pat`: {cv:?}")
+        // Get a valtree. If that fails, this const is definitely not valid for use as a pattern.
+        let valtree = match c.eval_valtree(self.tcx(), self.param_env, self.span) {
+            Ok((_, valtree)) => valtree,
+            Err(Either::Right(e)) => {
+                let err = match e {
+                    ErrorHandled::Reported(..) => {
+                        // Let's tell the use where this failing const occurs.
+                        self.tcx().dcx().emit_err(CouldNotEvalConstPattern { span: self.span })
+                    }
+                    ErrorHandled::TooGeneric(_) => self
+                        .tcx()
+                        .dcx()
+                        .emit_err(ConstPatternDependsOnGenericParameter { span: self.span }),
+                };
+                return pat_from_kind(PatKind::Error(err));
+            }
+            Err(Either::Left(bad_ty)) => {
+                // The pattern cannot be turned into a valtree.
+                let e = match bad_ty.kind() {
+                    ty::Adt(def, ..) => {
+                        assert!(def.is_union());
+                        self.tcx().dcx().emit_err(UnionPattern { span: self.span })
+                    }
+                    ty::FnPtr(..) | ty::RawPtr(..) => {
+                        self.tcx().dcx().emit_err(PointerPattern { span: self.span })
+                    }
+                    _ => self
+                        .tcx()
+                        .dcx()
+                        .emit_err(InvalidPattern { span: self.span, non_sm_ty: bad_ty }),
+                };
+                return pat_from_kind(PatKind::Error(e));
             }
-            mir::Const::Val(_, _) => Box::new(Pat {
-                span: self.span,
-                ty: cv.ty(),
-                kind: PatKind::Constant { value: cv },
-            }),
         };
 
-        if self.saw_const_match_error.get().is_none() {
-            // If we were able to successfully convert the const to some pat (possibly with some
-            // lints, but no errors), double-check that all types in the const implement
-            // `PartialEq`. Even if we have a valtree, we may have found something
-            // in there with non-structural-equality, meaning we match using `PartialEq`
-            // and we hence have to check if that impl exists.
-            // This is all messy but not worth cleaning up: at some point we'll emit
-            // a hard error when we don't have a valtree or when we find something in
-            // the valtree that is not structural; then this can all be made a lot simpler.
-
-            let structural = traits::search_for_structural_match_violation(self.tcx(), cv.ty());
-            debug!(
-                "search_for_structural_match_violation cv.ty: {:?} returned: {:?}",
-                cv.ty(),
-                structural
-            );
-
-            if let Some(non_sm_ty) = structural {
-                if !self.type_has_partial_eq_impl(cv.ty()) {
-                    // This is reachable and important even if we have a valtree: there might be
-                    // non-structural things in a valtree, in which case we fall back to `PartialEq`
-                    // comparison, in which case we better make sure the trait is implemented for
-                    // each inner type (and not just for the surrounding type).
-                    let e = if let ty::Adt(def, ..) = non_sm_ty.kind() {
-                        if def.is_union() {
-                            let err = UnionPattern { span: self.span };
-                            self.tcx().dcx().emit_err(err)
-                        } else {
-                            // fatal avoids ICE from resolution of nonexistent method (rare case).
-                            self.tcx()
-                                .dcx()
-                                .emit_fatal(TypeNotStructural { span: self.span, non_sm_ty })
-                        }
-                    } else {
-                        let err = InvalidPattern { span: self.span, non_sm_ty };
-                        self.tcx().dcx().emit_err(err)
-                    };
-                    // All branches above emitted an error. Don't print any more lints.
-                    // We errored. Signal that in the pattern, so that follow up errors can be silenced.
-                    let kind = PatKind::Error(e);
-                    return Box::new(Pat { span: self.span, ty: cv.ty(), kind });
-                } else if !have_valtree {
-                    // Not being structural prevented us from constructing a valtree,
-                    // so this is definitely a case we want to reject.
-                    let err = TypeNotStructural { span: self.span, non_sm_ty };
-                    let e = self.tcx().dcx().emit_err(err);
-                    let kind = PatKind::Error(e);
-                    return Box::new(Pat { span: self.span, ty: cv.ty(), kind });
-                } else {
-                    // This could be a violation in an inactive enum variant.
-                    // Since we have a valtree, we trust that we have traversed the full valtree and
-                    // complained about structural match violations there, so we don't
-                    // have to check anything any more.
-                }
-            } else if !have_valtree {
-                // The only way valtree construction can fail without the structural match
-                // checker finding a violation is if there is a pointer somewhere.
-                let e = self.tcx().dcx().emit_err(PointerPattern { span: self.span });
-                let kind = PatKind::Error(e);
-                return Box::new(Pat { span: self.span, ty: cv.ty(), kind });
-            }
+        // Convert the valtree to a const.
+        let inlined_const_as_pat = self.valtree_to_pat(valtree, ty);
 
+        if !inlined_const_as_pat.references_error() {
             // Always check for `PartialEq` if we had no other errors yet.
-            if !self.type_has_partial_eq_impl(cv.ty()) {
-                let err = TypeNotPartialEq { span: self.span, non_peq_ty: cv.ty() };
+            if !self.type_has_partial_eq_impl(ty) {
+                let err = TypeNotPartialEq { span: self.span, non_peq_ty: ty };
                 let e = self.tcx().dcx().emit_err(err);
                 let kind = PatKind::Error(e);
-                return Box::new(Pat { span: self.span, ty: cv.ty(), kind });
+                return Box::new(Pat { span: self.span, ty: ty, kind });
             }
         }
 
@@ -243,40 +173,31 @@ impl<'tcx> ConstToPat<'tcx> {
     fn field_pats(
         &self,
         vals: impl Iterator<Item = (ValTree<'tcx>, Ty<'tcx>)>,
-    ) -> Result<Vec<FieldPat<'tcx>>, FallbackToOpaqueConst> {
+    ) -> Vec<FieldPat<'tcx>> {
         vals.enumerate()
             .map(|(idx, (val, ty))| {
                 let field = FieldIdx::new(idx);
                 // Patterns can only use monomorphic types.
                 let ty = self.tcx().normalize_erasing_regions(self.param_env, ty);
-                Ok(FieldPat { field, pattern: self.recur(val, ty)? })
+                FieldPat { field, pattern: self.valtree_to_pat(val, ty) }
             })
             .collect()
     }
 
     // Recursive helper for `to_pat`; invoke that (instead of calling this directly).
     #[instrument(skip(self), level = "debug")]
-    fn recur(
-        &self,
-        cv: ValTree<'tcx>,
-        ty: Ty<'tcx>,
-    ) -> Result<Box<Pat<'tcx>>, FallbackToOpaqueConst> {
+    fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> {
         let span = self.span;
         let tcx = self.tcx();
         let param_env = self.param_env;
 
         let kind = match ty.kind() {
-            ty::FnDef(..) => {
-                let e = tcx.dcx().emit_err(InvalidPattern { span, non_sm_ty: ty });
-                self.saw_const_match_error.set(Some(e));
-                // We errored. Signal that in the pattern, so that follow up errors can be silenced.
-                PatKind::Error(e)
-            }
             ty::Adt(adt_def, _) if !self.type_marked_structural(ty) => {
+                // Extremely important check for all ADTs! Make sure they opted-in to be used in
+                // patterns.
                 debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty,);
                 let err = TypeNotStructural { span, non_sm_ty: ty };
                 let e = tcx.dcx().emit_err(err);
-                self.saw_const_match_error.set(Some(e));
                 // We errored. Signal that in the pattern, so that follow up errors can be silenced.
                 PatKind::Error(e)
             }
@@ -294,13 +215,9 @@ impl<'tcx> ConstToPat<'tcx> {
                                 .iter()
                                 .map(|field| field.ty(self.tcx(), args)),
                         ),
-                    )?,
+                    ),
                 }
             }
-            ty::Tuple(fields) => PatKind::Leaf {
-                subpatterns: self
-                    .field_pats(cv.unwrap_branch().iter().copied().zip(fields.iter()))?,
-            },
             ty::Adt(def, args) => {
                 assert!(!def.is_union()); // Valtree construction would never succeed for unions.
                 PatKind::Leaf {
@@ -311,15 +228,18 @@ impl<'tcx> ConstToPat<'tcx> {
                                 .iter()
                                 .map(|field| field.ty(self.tcx(), args)),
                         ),
-                    )?,
+                    ),
                 }
             }
+            ty::Tuple(fields) => PatKind::Leaf {
+                subpatterns: self.field_pats(cv.unwrap_branch().iter().copied().zip(fields.iter())),
+            },
             ty::Slice(elem_ty) => PatKind::Slice {
                 prefix: cv
                     .unwrap_branch()
                     .iter()
-                    .map(|val| self.recur(*val, *elem_ty))
-                    .collect::<Result<_, _>>()?,
+                    .map(|val| self.valtree_to_pat(*val, *elem_ty))
+                    .collect(),
                 slice: None,
                 suffix: Box::new([]),
             },
@@ -327,8 +247,8 @@ impl<'tcx> ConstToPat<'tcx> {
                 prefix: cv
                     .unwrap_branch()
                     .iter()
-                    .map(|val| self.recur(*val, *elem_ty))
-                    .collect::<Result<_, _>>()?,
+                    .map(|val| self.valtree_to_pat(*val, *elem_ty))
+                    .collect(),
                 slice: None,
                 suffix: Box::new([]),
             },
@@ -361,7 +281,7 @@ impl<'tcx> ConstToPat<'tcx> {
                             _ => *pointee_ty,
                         };
                         // References have the same valtree representation as their pointee.
-                        let subpattern = self.recur(cv, pointee_ty)?;
+                        let subpattern = self.valtree_to_pat(cv, pointee_ty);
                         PatKind::Deref { subpattern }
                     }
                 }
@@ -378,8 +298,7 @@ impl<'tcx> ConstToPat<'tcx> {
                     // NaNs are not ever equal to anything so they make no sense as patterns.
                     // Also see <https://github.com/rust-lang/rfcs/pull/3535>.
                     let e = tcx.dcx().emit_err(NaNPattern { span });
-                    self.saw_const_match_error.set(Some(e));
-                    return Err(FallbackToOpaqueConst);
+                    PatKind::Error(e)
                 } else {
                     PatKind::Constant {
                         value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)),
@@ -399,12 +318,11 @@ impl<'tcx> ConstToPat<'tcx> {
             _ => {
                 let err = InvalidPattern { span, non_sm_ty: ty };
                 let e = tcx.dcx().emit_err(err);
-                self.saw_const_match_error.set(Some(e));
                 // We errored. Signal that in the pattern, so that follow up errors can be silenced.
                 PatKind::Error(e)
             }
         };
 
-        Ok(Box::new(Pat { span, ty, kind }))
+        Box::new(Pat { span, ty, kind })
     }
 }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index fd778ef78a3..622651800f4 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -14,8 +14,7 @@ use rustc_hir::pat_util::EnumerateAndAdjustIterator;
 use rustc_hir::{self as hir, ByRef, Mutability, RangeEnd};
 use rustc_index::Idx;
 use rustc_lint as lint;
-use rustc_middle::mir::interpret::{ErrorHandled, GlobalId, LitToConstError, LitToConstInput};
-use rustc_middle::mir::{self, Const};
+use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
 use rustc_middle::thir::{
     Ascription, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary,
 };
@@ -549,89 +548,36 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             _ => return pat_from_kind(self.lower_variant_or_leaf(res, id, span, ty, vec![])),
         };
 
-        // Use `Reveal::All` here because patterns are always monomorphic even if their function
-        // isn't.
-        let param_env_reveal_all = self.param_env.with_reveal_all_normalized(self.tcx);
-        // N.B. There is no guarantee that args collected in typeck results are fully normalized,
-        // so they need to be normalized in order to pass to `Instance::resolve`, which will ICE
-        // if given unnormalized types.
-        let args = self
-            .tcx
-            .normalize_erasing_regions(param_env_reveal_all, self.typeck_results.node_args(id));
-        let instance = match ty::Instance::try_resolve(self.tcx, param_env_reveal_all, def_id, args)
-        {
-            Ok(Some(i)) => i,
-            Ok(None) => {
-                // It should be assoc consts if there's no error but we cannot resolve it.
-                debug_assert!(is_associated_const);
-
-                let e = self.tcx.dcx().emit_err(AssocConstInPattern { span });
-                return pat_from_kind(PatKind::Error(e));
-            }
-
-            Err(_) => {
-                let e = self.tcx.dcx().emit_err(CouldNotEvalConstPattern { span });
-                return pat_from_kind(PatKind::Error(e));
-            }
-        };
+        let args = self.typeck_results.node_args(id);
+        let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args });
+        let pattern = self.const_to_pat(c, ty, id, span);
 
-        let cid = GlobalId { instance, promoted: None };
-        // Prefer valtrees over opaque constants.
-        let const_value = self
-            .tcx
-            .const_eval_global_id_for_typeck(param_env_reveal_all, cid, span)
-            .map(|val| match val {
-                Some(valtree) => mir::Const::Ty(ty, ty::Const::new_value(self.tcx, valtree, ty)),
-                None => mir::Const::Val(
-                    self.tcx
-                        .const_eval_global_id(param_env_reveal_all, cid, span)
-                        .expect("const_eval_global_id_for_typeck should have already failed"),
-                    ty,
-                ),
-            });
-
-        match const_value {
-            Ok(const_) => {
-                let pattern = self.const_to_pat(const_, id, span);
-
-                if !is_associated_const {
-                    return pattern;
-                }
+        if !is_associated_const {
+            return pattern;
+        }
 
-                let user_provided_types = self.typeck_results().user_provided_types();
-                if let Some(&user_ty) = user_provided_types.get(id) {
-                    let annotation = CanonicalUserTypeAnnotation {
-                        user_ty: Box::new(user_ty),
-                        span,
-                        inferred_ty: self.typeck_results().node_type(id),
-                    };
-                    Box::new(Pat {
-                        span,
-                        kind: PatKind::AscribeUserType {
-                            subpattern: pattern,
-                            ascription: Ascription {
-                                annotation,
-                                // Note that use `Contravariant` here. See the
-                                // `variance` field documentation for details.
-                                variance: ty::Contravariant,
-                            },
-                        },
-                        ty: const_.ty(),
-                    })
-                } else {
-                    pattern
-                }
-            }
-            Err(ErrorHandled::TooGeneric(_)) => {
-                // While `Reported | Linted` cases will have diagnostics emitted already
-                // it is not true for TooGeneric case, so we need to give user more information.
-                let e = self.tcx.dcx().emit_err(ConstPatternDependsOnGenericParameter { span });
-                pat_from_kind(PatKind::Error(e))
-            }
-            Err(_) => {
-                let e = self.tcx.dcx().emit_err(CouldNotEvalConstPattern { span });
-                pat_from_kind(PatKind::Error(e))
-            }
+        let user_provided_types = self.typeck_results().user_provided_types();
+        if let Some(&user_ty) = user_provided_types.get(id) {
+            let annotation = CanonicalUserTypeAnnotation {
+                user_ty: Box::new(user_ty),
+                span,
+                inferred_ty: self.typeck_results().node_type(id),
+            };
+            Box::new(Pat {
+                span,
+                kind: PatKind::AscribeUserType {
+                    subpattern: pattern,
+                    ascription: Ascription {
+                        annotation,
+                        // Note that use `Contravariant` here. See the
+                        // `variance` field documentation for details.
+                        variance: ty::Contravariant,
+                    },
+                },
+                ty,
+            })
+        } else {
+            pattern
         }
     }
 
@@ -662,7 +608,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         };
         if let Some(lit_input) = lit_input {
             match tcx.at(expr.span).lit_to_const(lit_input) {
-                Ok(c) => return self.const_to_pat(Const::Ty(ty, c), id, span).kind,
+                Ok(c) => return self.const_to_pat(c, ty, id, span).kind,
                 // If an error occurred, ignore that it's a literal
                 // and leave reporting the error up to const eval of
                 // the unevaluated constant below.
@@ -675,33 +621,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             tcx.erase_regions(ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id));
         let args = ty::InlineConstArgs::new(tcx, ty::InlineConstArgsParts { parent_args, ty }).args;
 
-        let uneval = mir::UnevaluatedConst { def: def_id.to_def_id(), args, promoted: None };
         debug_assert!(!args.has_free_regions());
 
         let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args };
-        // First try using a valtree in order to destructure the constant into a pattern.
-        // FIXME: replace "try to do a thing, then fall back to another thing"
-        // but something more principled, like a trait query checking whether this can be turned into a valtree.
-        if let Ok(Some(valtree)) = self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, span)
-        {
-            let subpattern = self.const_to_pat(
-                Const::Ty(ty, ty::Const::new_value(self.tcx, valtree, ty)),
-                id,
-                span,
-            );
-            PatKind::InlineConstant { subpattern, def: def_id }
-        } else {
-            // If that fails, convert it to an opaque constant pattern.
-            match tcx.const_eval_resolve(self.param_env, uneval, span) {
-                Ok(val) => self.const_to_pat(mir::Const::Val(val, ty), id, span).kind,
-                Err(ErrorHandled::TooGeneric(_)) => {
-                    // If we land here it means the const can't be evaluated because it's `TooGeneric`.
-                    let e = self.tcx.dcx().emit_err(ConstPatternDependsOnGenericParameter { span });
-                    PatKind::Error(e)
-                }
-                Err(ErrorHandled::Reported(err, ..)) => PatKind::Error(err.into()),
-            }
-        }
+        let subpattern = self.const_to_pat(ty::Const::new_unevaluated(self.tcx, ct), ty, id, span);
+        PatKind::InlineConstant { subpattern, def: def_id }
     }
 
     /// Converts literals, paths and negation of literals to patterns.
@@ -729,9 +653,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         let ct_ty = self.typeck_results.expr_ty(expr);
         let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg };
         match self.tcx.at(expr.span).lit_to_const(lit_input) {
-            Ok(constant) => {
-                self.const_to_pat(Const::Ty(ct_ty, constant), expr.hir_id, lit.span).kind
-            }
+            Ok(constant) => self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind,
             Err(LitToConstError::Reported(e)) => PatKind::Error(e),
             Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
         }
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index d4dd4dd858c..d17ee8bff50 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -462,7 +462,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                     // This is a box pattern.
                     ty::Adt(adt, ..) if adt.is_box() => Struct,
                     ty::Ref(..) => Ref,
-                    _ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, ty),
+                    _ => span_bug!(
+                        pat.span,
+                        "pattern has unexpected type: pat: {:?}, ty: {:?}",
+                        pat.kind,
+                        ty.inner()
+                    ),
                 };
             }
             PatKind::DerefPattern { .. } => {
@@ -518,7 +523,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                             .map(|ipat| self.lower_pat(&ipat.pattern).at_index(ipat.field.index()))
                             .collect();
                     }
-                    _ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, ty),
+                    _ => span_bug!(
+                        pat.span,
+                        "pattern has unexpected type: pat: {:?}, ty: {}",
+                        pat.kind,
+                        ty.inner()
+                    ),
                 }
             }
             PatKind::Constant { value } => {
@@ -663,7 +673,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                             }
                         }
                     }
-                    _ => bug!("invalid type for range pattern: {}", ty.inner()),
+                    _ => span_bug!(pat.span, "invalid type for range pattern: {}", ty.inner()),
                 };
                 fields = vec![];
                 arity = 0;
@@ -674,7 +684,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                         Some(length.eval_target_usize(cx.tcx, cx.param_env) as usize)
                     }
                     ty::Slice(_) => None,
-                    _ => span_bug!(pat.span, "bad ty {:?} for slice pattern", ty),
+                    _ => span_bug!(pat.span, "bad ty {} for slice pattern", ty.inner()),
                 };
                 let kind = if slice.is_some() {
                     SliceKind::VarLen(prefix.len(), suffix.len())
diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs
index f67518a577e..ade26a40920 100644
--- a/compiler/rustc_trait_selection/src/solve/delegate.rs
+++ b/compiler/rustc_trait_selection/src/solve/delegate.rs
@@ -87,12 +87,12 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
     ) -> Option<ty::Const<'tcx>> {
         use rustc_middle::mir::interpret::ErrorHandled;
         match self.const_eval_resolve(param_env, unevaluated, DUMMY_SP) {
-            Ok(Some(val)) => Some(ty::Const::new_value(
+            Ok(Ok(val)) => Some(ty::Const::new_value(
                 self.tcx,
                 val,
                 self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args),
             )),
-            Ok(None) | Err(ErrorHandled::TooGeneric(_)) => None,
+            Ok(Err(_)) | Err(ErrorHandled::TooGeneric(_)) => None,
             Err(ErrorHandled::Reported(e, _)) => Some(ty::Const::new_error(self.tcx, e.into())),
         }
     }
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 1d32ef2ccd9..796f7fd5a54 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -765,8 +765,8 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                                 unevaluated,
                                 obligation.cause.span,
                             ) {
-                                Ok(Some(valtree)) => Ok(ty::Const::new_value(selcx.tcx(),valtree, self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args))),
-                                Ok(None) => {
+                                Ok(Ok(valtree)) => Ok(ty::Const::new_value(selcx.tcx(),valtree, self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args))),
+                                Ok(Err(_)) => {
                                     let tcx = self.tcx;
                                     let reported =
                                         tcx.dcx().emit_err(UnableToConstructConstantValue {
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index d28982ed849..f7eb1730582 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -16,7 +16,6 @@ pub mod query;
 #[allow(hidden_glob_reexports)]
 mod select;
 mod specialize;
-mod structural_match;
 mod structural_normalize;
 #[allow(hidden_glob_reexports)]
 mod util;
@@ -60,7 +59,6 @@ pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
 pub use self::specialize::{
     specialization_graph, translate_args, translate_args_with_cause, OverlapError,
 };
-pub use self::structural_match::search_for_structural_match_violation;
 pub use self::structural_normalize::StructurallyNormalizeExt;
 pub use self::util::elaborate;
 pub use self::util::{expand_trait_aliases, TraitAliasExpander, TraitAliasExpansionInfo};
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
deleted file mode 100644
index d4535db951e..00000000000
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ /dev/null
@@ -1,173 +0,0 @@
-use rustc_data_structures::fx::FxHashSet;
-use rustc_hir as hir;
-use rustc_middle::bug;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
-use std::ops::ControlFlow;
-
-/// This method traverses the structure of `ty`, trying to find an
-/// instance of an ADT (i.e. struct or enum) that doesn't implement
-/// the structural-match traits, or a generic type parameter
-/// (which cannot be determined to be structural-match).
-///
-/// The "structure of a type" includes all components that would be
-/// considered when doing a pattern match on a constant of that
-/// type.
-///
-///  * This means this method descends into fields of structs/enums,
-///    and also descends into the inner type `T` of `&T` and `&mut T`
-///
-///  * The traversal doesn't dereference unsafe pointers (`*const T`,
-///    `*mut T`), and it does not visit the type arguments of an
-///    instantiated generic like `PhantomData<T>`.
-///
-/// The reason we do this search is Rust currently require all ADTs
-/// reachable from a constant's type to implement the
-/// structural-match traits, which essentially say that
-/// the implementation of `PartialEq::eq` behaves *equivalently* to a
-/// comparison against the unfolded structure.
-///
-/// For more background on why Rust has this requirement, and issues
-/// that arose when the requirement was not enforced completely, see
-/// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
-pub fn search_for_structural_match_violation<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    ty: Ty<'tcx>,
-) -> Option<Ty<'tcx>> {
-    ty.visit_with(&mut Search { tcx, seen: FxHashSet::default() }).break_value()
-}
-
-/// This implements the traversal over the structure of a given type to try to
-/// find instances of ADTs (specifically structs or enums) that do not implement
-/// `StructuralPartialEq`.
-struct Search<'tcx> {
-    tcx: TyCtxt<'tcx>,
-
-    /// Tracks ADTs previously encountered during search, so that
-    /// we will not recur on them again.
-    seen: FxHashSet<hir::def_id::DefId>,
-}
-
-impl<'tcx> Search<'tcx> {
-    fn type_marked_structural(&self, adt_ty: Ty<'tcx>) -> bool {
-        adt_ty.is_structural_eq_shallow(self.tcx)
-    }
-}
-
-impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Search<'tcx> {
-    type Result = ControlFlow<Ty<'tcx>>;
-
-    fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
-        debug!("Search visiting ty: {:?}", ty);
-
-        let (adt_def, args) = match *ty.kind() {
-            ty::Adt(adt_def, args) => (adt_def, args),
-            ty::Param(_) => {
-                return ControlFlow::Break(ty);
-            }
-            ty::Dynamic(..) => {
-                return ControlFlow::Break(ty);
-            }
-            ty::Foreign(_) => {
-                return ControlFlow::Break(ty);
-            }
-            ty::Alias(..) => {
-                return ControlFlow::Break(ty);
-            }
-            ty::Closure(..) => {
-                return ControlFlow::Break(ty);
-            }
-            ty::CoroutineClosure(..) => {
-                return ControlFlow::Break(ty);
-            }
-            ty::Coroutine(..) | ty::CoroutineWitness(..) => {
-                return ControlFlow::Break(ty);
-            }
-            ty::FnDef(..) => {
-                // Types of formals and return in `fn(_) -> _` are also irrelevant;
-                // so we do not recur into them via `super_visit_with`
-                return ControlFlow::Continue(());
-            }
-            ty::Array(_, n)
-                if { n.try_eval_target_usize(self.tcx, ty::ParamEnv::reveal_all()) == Some(0) } =>
-            {
-                // rust-lang/rust#62336: ignore type of contents
-                // for empty array.
-                return ControlFlow::Continue(());
-            }
-            ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Str | ty::Never => {
-                // These primitive types are always structural match.
-                //
-                // `Never` is kind of special here, but as it is not inhabitable, this should be fine.
-                return ControlFlow::Continue(());
-            }
-
-            ty::FnPtr(..) => {
-                return ControlFlow::Continue(());
-            }
-
-            ty::RawPtr(..) => {
-                // structural-match ignores substructure of
-                // `*const _`/`*mut _`, so skip `super_visit_with`.
-                //
-                // For example, if you have:
-                // ```
-                // struct NonStructural;
-                // #[derive(PartialEq, Eq)]
-                // struct T(*const NonStructural);
-                // const C: T = T(std::ptr::null());
-                // ```
-                //
-                // Even though `NonStructural` does not implement `PartialEq`,
-                // structural equality on `T` does not recur into the raw
-                // pointer. Therefore, one can still use `C` in a pattern.
-                return ControlFlow::Continue(());
-            }
-
-            ty::Float(_) => {
-                return ControlFlow::Continue(());
-            }
-
-            ty::Pat(..) | ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => {
-                // First check all contained types and then tell the caller to continue searching.
-                return ty.super_visit_with(self);
-            }
-            ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => {
-                bug!("unexpected type during structural-match checking: {:?}", ty);
-            }
-            ty::Error(_) => {
-                // We still want to check other types after encountering an error,
-                // as this may still emit relevant errors.
-                return ControlFlow::Continue(());
-            }
-        };
-
-        if !self.seen.insert(adt_def.did()) {
-            debug!("Search already seen adt_def: {:?}", adt_def);
-            return ControlFlow::Continue(());
-        }
-
-        if !self.type_marked_structural(ty) {
-            debug!("Search found ty: {:?}", ty);
-            return ControlFlow::Break(ty);
-        }
-
-        // structural-match does not care about the
-        // instantiation of the generics in an ADT (it
-        // instead looks directly at its fields outside
-        // this match), so we skip super_visit_with.
-        //
-        // (Must not recur on args for `PhantomData<T>` cf
-        // rust-lang/rust#55028 and rust-lang/rust#55837; but also
-        // want to skip args when only uses of generic are
-        // behind unsafe pointers `*const T`/`*mut T`.)
-
-        // even though we skip super_visit_with, we must recur on
-        // fields of ADT.
-        let tcx = self.tcx;
-        adt_def.all_fields().map(|field| field.ty(tcx, args)).try_for_each(|field_ty| {
-            let ty = self.tcx.normalize_erasing_regions(ty::ParamEnv::empty(), field_ty);
-            debug!("structural-match ADT: field_ty={:?}, ty={:?}", field_ty, ty);
-            ty.visit_with(self)
-        })
-    }
-}