about summary refs log tree commit diff
path: root/compiler/rustc_trait_selection/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_trait_selection/src')
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs8
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs8
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs140
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs63
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs6
-rw-r--r--compiler/rustc_trait_selection/src/errors/note_and_explain.rs4
-rw-r--r--compiler/rustc_trait_selection/src/regions.rs14
-rw-r--r--compiler/rustc_trait_selection/src/solve/delegate.rs12
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/outlives_bounds.rs18
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs21
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs198
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs48
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs93
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs10
20 files changed, 278 insertions, 393 deletions
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index a618bae269f..42d37418fb8 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -65,7 +65,9 @@ use rustc_middle::bug;
 use rustc_middle::dep_graph::DepContext;
 use rustc_middle::traits::PatternOriginExpr;
 use rustc_middle::ty::error::{ExpectedFound, TypeError, TypeErrorToStringExt};
-use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, with_forced_trimmed_paths};
+use rustc_middle::ty::print::{
+    PrintError, PrintTraitRefExt as _, WrapBinderMode, with_forced_trimmed_paths,
+};
 use rustc_middle::ty::{
     self, List, ParamEnv, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable,
     TypeVisitableExt,
@@ -835,7 +837,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         let get_lifetimes = |sig| {
             use rustc_hir::def::Namespace;
             let (sig, reg) = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS)
-                .name_all_regions(sig)
+                .name_all_regions(sig, WrapBinderMode::ForAll)
                 .unwrap();
             let lts: Vec<String> =
                 reg.into_items().map(|(_, kind)| kind.to_string()).into_sorted_stable_ord();
@@ -2418,7 +2420,7 @@ impl<'tcx> ObligationCause<'tcx> {
 pub struct ObligationCauseAsDiagArg<'tcx>(pub ObligationCause<'tcx>);
 
 impl IntoDiagArg for ObligationCauseAsDiagArg<'_> {
-    fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
         let kind = match self.0.code() {
             ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => "method_compat",
             ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => "type_compat",
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
index bed9734f389..a6d8eb6add7 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
@@ -137,7 +137,7 @@ impl InferenceDiagnosticsParentData {
 }
 
 impl IntoDiagArg for UnderspecifiedArgKind {
-    fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
         let kind = match self {
             Self::Type { .. } => "type",
             Self::Const { is_parameter: true } => "const_with_param",
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs
index aaaefd81d19..5056161e117 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs
@@ -31,7 +31,7 @@ impl<'tcx, T> IntoDiagArg for Highlighted<'tcx, T>
 where
     T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>>,
 {
-    fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
         rustc_errors::DiagArgValue::Str(self.to_string().into())
     }
 }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
index f15f1b78b52..d673e5672a0 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
@@ -1,8 +1,6 @@
 use std::ops::ControlFlow;
 
-use rustc_errors::{
-    Applicability, Diag, E0283, E0284, E0790, MultiSpan, StashKey, struct_span_code_err,
-};
+use rustc_errors::{Applicability, Diag, E0283, E0284, E0790, MultiSpan, struct_span_code_err};
 use rustc_hir as hir;
 use rustc_hir::LangItem;
 use rustc_hir::def::{DefKind, Res};
@@ -197,7 +195,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 // be ignoring the fact that we don't KNOW the type works
                 // out. Though even that would probably be harmless, given that
                 // we're only talking about builtin traits, which are known to be
-                // inhabited. We used to check for `self.tcx.sess.has_errors()` to
+                // inhabited. We used to check for `self.tainted_by_errors()` to
                 // avoid inundating the user with unnecessary errors, but we now
                 // check upstream for type errors and don't add the obligations to
                 // begin with in those cases.
@@ -211,7 +209,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                                 TypeAnnotationNeeded::E0282,
                                 false,
                             );
-                            return err.stash(span, StashKey::MaybeForgetReturn).unwrap();
+                            return err.emit();
                         }
                         Some(e) => return e,
                     }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 596f794568c..e2bdd52ba7c 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -829,7 +829,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 && let ty::Closure(closure_def_id, _) | ty::CoroutineClosure(closure_def_id, _) =
                     *typeck_results.node_type(arg_hir_id).kind()
             {
-                // Otherwise, extract the closure kind from the obligation.
+                // Otherwise, extract the closure kind from the obligation,
+                // but only if we actually have an argument to deduce the
+                // closure type from...
                 let mut err = self.report_closure_error(
                     &obligation,
                     closure_def_id,
@@ -844,63 +846,72 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
         let self_ty = trait_pred.self_ty().skip_binder();
 
-        if let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_pred.def_id()) {
-            let (closure_def_id, found_args, by_ref_captures) = match *self_ty.kind() {
-                ty::Closure(def_id, args) => {
-                    (def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), None)
-                }
-                ty::CoroutineClosure(def_id, args) => (
-                    def_id,
-                    args.as_coroutine_closure()
-                        .coroutine_closure_sig()
-                        .map_bound(|sig| sig.tupled_inputs_ty),
-                    Some(args.as_coroutine_closure().coroutine_captures_by_ref_ty()),
-                ),
-                _ => return None,
+        let (expected_kind, trait_prefix) =
+            if let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_pred.def_id()) {
+                (expected_kind, "")
+            } else if let Some(expected_kind) =
+                self.tcx.async_fn_trait_kind_from_def_id(trait_pred.def_id())
+            {
+                (expected_kind, "Async")
+            } else {
+                return None;
             };
 
-            let expected_args =
-                trait_pred.map_bound(|trait_pred| trait_pred.trait_ref.args.type_at(1));
-
-            // Verify that the arguments are compatible. If the signature is
-            // mismatched, then we have a totally different error to report.
-            if self.enter_forall(found_args, |found_args| {
-                self.enter_forall(expected_args, |expected_args| {
-                    !self.can_eq(obligation.param_env, expected_args, found_args)
-                })
-            }) {
-                return None;
+        let (closure_def_id, found_args, by_ref_captures) = match *self_ty.kind() {
+            ty::Closure(def_id, args) => {
+                (def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), None)
             }
+            ty::CoroutineClosure(def_id, args) => (
+                def_id,
+                args.as_coroutine_closure()
+                    .coroutine_closure_sig()
+                    .map_bound(|sig| sig.tupled_inputs_ty),
+                Some(args.as_coroutine_closure().coroutine_captures_by_ref_ty()),
+            ),
+            _ => return None,
+        };
 
-            if let Some(found_kind) = self.closure_kind(self_ty)
-                && !found_kind.extends(expected_kind)
-            {
-                let mut err = self.report_closure_error(
-                    &obligation,
-                    closure_def_id,
-                    found_kind,
-                    expected_kind,
-                    "",
-                );
-                self.note_obligation_cause(&mut err, &obligation);
-                return Some(err.emit());
-            }
+        let expected_args = trait_pred.map_bound(|trait_pred| trait_pred.trait_ref.args.type_at(1));
 
-            // If the closure has captures, then perhaps the reason that the trait
-            // is unimplemented is because async closures don't implement `Fn`/`FnMut`
-            // if they have captures.
-            if let Some(by_ref_captures) = by_ref_captures
-                && let ty::FnPtr(sig_tys, _) = by_ref_captures.kind()
-                && !sig_tys.skip_binder().output().is_unit()
-            {
-                let mut err = self.dcx().create_err(AsyncClosureNotFn {
-                    span: self.tcx.def_span(closure_def_id),
-                    kind: expected_kind.as_str(),
-                });
-                self.note_obligation_cause(&mut err, &obligation);
-                return Some(err.emit());
-            }
+        // Verify that the arguments are compatible. If the signature is
+        // mismatched, then we have a totally different error to report.
+        if self.enter_forall(found_args, |found_args| {
+            self.enter_forall(expected_args, |expected_args| {
+                !self.can_eq(obligation.param_env, expected_args, found_args)
+            })
+        }) {
+            return None;
+        }
+
+        if let Some(found_kind) = self.closure_kind(self_ty)
+            && !found_kind.extends(expected_kind)
+        {
+            let mut err = self.report_closure_error(
+                &obligation,
+                closure_def_id,
+                found_kind,
+                expected_kind,
+                trait_prefix,
+            );
+            self.note_obligation_cause(&mut err, &obligation);
+            return Some(err.emit());
+        }
+
+        // If the closure has captures, then perhaps the reason that the trait
+        // is unimplemented is because async closures don't implement `Fn`/`FnMut`
+        // if they have captures.
+        if let Some(by_ref_captures) = by_ref_captures
+            && let ty::FnPtr(sig_tys, _) = by_ref_captures.kind()
+            && !sig_tys.skip_binder().output().is_unit()
+        {
+            let mut err = self.dcx().create_err(AsyncClosureNotFn {
+                span: self.tcx.def_span(closure_def_id),
+                kind: expected_kind.as_str(),
+            });
+            self.note_obligation_cause(&mut err, &obligation);
+            return Some(err.emit());
         }
+
         None
     }
 
@@ -1189,9 +1200,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         let span = obligation.cause.span;
 
         let mut diag = match ty.kind() {
-            _ if ty.has_param() => {
-                span_bug!(span, "const param tys cannot mention other generic parameters");
-            }
             ty::Float(_) => {
                 struct_span_code_err!(
                     self.dcx(),
@@ -2419,6 +2427,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 &mut vec![],
                 &mut Default::default(),
             );
+            self.suggest_swapping_lhs_and_rhs(
+                err,
+                obligation.predicate,
+                obligation.param_env,
+                obligation.cause.code(),
+            );
             self.suggest_unsized_bound_if_applicable(err, obligation);
             if let Some(span) = err.span.primary_span()
                 && let Some(mut diag) =
@@ -2530,9 +2544,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 return GetSafeTransmuteErrorAndReason::Silent;
             };
 
-            let Some(assume) =
-                rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, assume)
-            else {
+            let Some(assume) = rustc_transmute::Assume::from_const(self.infcx.tcx, assume) else {
                 self.dcx().span_delayed_bug(
                     span,
                     "Unable to construct rustc_transmute::Assume where it was previously possible",
@@ -2544,11 +2556,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             let src = trait_pred.trait_ref.args.type_at(1);
             let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`");
 
-            match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
-                obligation.cause,
-                src_and_dst,
-                assume,
-            ) {
+            match rustc_transmute::TransmuteTypeEnv::new(self.infcx.tcx)
+                .is_transmutable(src_and_dst, assume)
+            {
                 Answer::No(reason) => {
                     let safe_transmute_explanation = match reason {
                         rustc_transmute::Reason::SrcIsNotYetSupported => {
@@ -3251,7 +3261,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         obligation: &PredicateObligation<'tcx>,
         span: Span,
     ) -> Result<Diag<'a>, ErrorGuaranteed> {
-        if !self.tcx.features().generic_const_exprs() {
+        if !self.tcx.features().generic_const_exprs()
+            && !self.tcx.features().min_generic_const_args()
+        {
             let guar = self
                 .dcx()
                 .struct_span_err(span, "constant expression depends on a generic parameter")
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index c7e71a626dc..ad46a15a5ac 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -136,7 +136,10 @@ pub fn suggest_restriction<'tcx, G: EmissionGuarantee>(
 ) {
     if hir_generics.where_clause_span.from_expansion()
         || hir_generics.where_clause_span.desugaring_kind().is_some()
-        || projection.is_some_and(|projection| tcx.is_impl_trait_in_trait(projection.def_id))
+        || projection.is_some_and(|projection| {
+            tcx.is_impl_trait_in_trait(projection.def_id)
+                || tcx.lookup_stability(projection.def_id).is_some_and(|stab| stab.is_unstable())
+        })
     {
         return;
     }
@@ -2692,7 +2695,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             | ObligationCauseCode::LetElse
             | ObligationCauseCode::BinOp { .. }
             | ObligationCauseCode::AscribeUserTypeProvePredicate(..)
-            | ObligationCauseCode::DropImpl
+            | ObligationCauseCode::AlwaysApplicableImpl
             | ObligationCauseCode::ConstParam(_)
             | ObligationCauseCode::ReferenceOutlivesReferent(..)
             | ObligationCauseCode::ObjectTypeBound(..) => {}
@@ -3123,8 +3126,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     Applicability::MachineApplicable,
                 );
             }
-            ObligationCauseCode::ConstSized => {
-                err.note("constant expressions must have a statically known size");
+            ObligationCauseCode::SizedConstOrStatic => {
+                err.note("statics and constants must have a statically known size");
             }
             ObligationCauseCode::InlineAsmSized => {
                 err.note("all inline asm arguments must have a statically known size");
@@ -3188,7 +3191,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     false
                 };
 
-                if !is_upvar_tys_infer_tuple {
+                let is_builtin_async_fn_trait =
+                    tcx.async_fn_trait_kind_from_def_id(data.parent_trait_pred.def_id()).is_some();
+
+                if !is_upvar_tys_infer_tuple && !is_builtin_async_fn_trait {
                     let ty_str = tcx.short_string(ty, err.long_ty_path());
                     let msg = format!("required because it appears within the type `{ty_str}`");
                     match ty.kind() {
@@ -4911,6 +4917,53 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         );
         true
     }
+    pub(crate) fn suggest_swapping_lhs_and_rhs<T>(
+        &self,
+        err: &mut Diag<'_>,
+        predicate: T,
+        param_env: ty::ParamEnv<'tcx>,
+        cause_code: &ObligationCauseCode<'tcx>,
+    ) where
+        T: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>,
+    {
+        let tcx = self.tcx;
+        let predicate = predicate.upcast(tcx);
+        match *cause_code {
+            ObligationCauseCode::BinOp {
+                lhs_hir_id,
+                rhs_hir_id: Some(rhs_hir_id),
+                rhs_span: Some(rhs_span),
+                ..
+            } if let Some(typeck_results) = &self.typeck_results
+                && let hir::Node::Expr(lhs) = tcx.hir_node(lhs_hir_id)
+                && let hir::Node::Expr(rhs) = tcx.hir_node(rhs_hir_id)
+                && let Some(lhs_ty) = typeck_results.expr_ty_opt(lhs)
+                && let Some(rhs_ty) = typeck_results.expr_ty_opt(rhs) =>
+            {
+                if let Some(pred) = predicate.as_trait_clause()
+                    && tcx.is_lang_item(pred.def_id(), LangItem::PartialEq)
+                    && self
+                        .infcx
+                        .type_implements_trait(pred.def_id(), [rhs_ty, lhs_ty], param_env)
+                        .must_apply_modulo_regions()
+                {
+                    let lhs_span = tcx.hir().span(lhs_hir_id);
+                    let sm = tcx.sess.source_map();
+                    if let Ok(rhs_snippet) = sm.span_to_snippet(rhs_span)
+                        && let Ok(lhs_snippet) = sm.span_to_snippet(lhs_span)
+                    {
+                        err.note(format!("`{rhs_ty}` implements `PartialEq<{lhs_ty}>`"));
+                        err.multipart_suggestion(
+                            "consider swapping the equality",
+                            vec![(lhs_span, rhs_snippet), (rhs_span, lhs_snippet)],
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                }
+            }
+            _ => {}
+        }
+    }
 }
 
 /// Add a hint to add a missing borrow or remove an unnecessary one.
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index 23aa3800660..fe859eb53cd 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -784,10 +784,10 @@ pub enum TyOrSig<'tcx> {
 }
 
 impl IntoDiagArg for TyOrSig<'_> {
-    fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
+    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
         match self {
-            TyOrSig::Ty(ty) => ty.into_diag_arg(),
-            TyOrSig::ClosureSig(sig) => sig.into_diag_arg(),
+            TyOrSig::Ty(ty) => ty.into_diag_arg(path),
+            TyOrSig::ClosureSig(sig) => sig.into_diag_arg(path),
         }
     }
 }
diff --git a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs
index 4601ddf678a..46622246a17 100644
--- a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs
+++ b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs
@@ -105,7 +105,7 @@ pub enum SuffixKind {
 }
 
 impl IntoDiagArg for PrefixKind {
-    fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
         let kind = match self {
             Self::Empty => "empty",
             Self::RefValidFor => "ref_valid_for",
@@ -127,7 +127,7 @@ impl IntoDiagArg for PrefixKind {
 }
 
 impl IntoDiagArg for SuffixKind {
-    fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
         let kind = match self {
             Self::Empty => "empty",
             Self::Continues => "continues",
diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs
index 55171754618..068e90b00b8 100644
--- a/compiler/rustc_trait_selection/src/regions.rs
+++ b/compiler/rustc_trait_selection/src/regions.rs
@@ -17,13 +17,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>,
     ) -> Self {
-        Self::new_with_implied_bounds_compat(
-            infcx,
-            body_id,
-            param_env,
-            assumed_wf_tys,
-            !infcx.tcx.sess.opts.unstable_opts.no_implied_bounds_compat,
-        )
+        Self::new_with_implied_bounds_compat(infcx, body_id, param_env, assumed_wf_tys, false)
     }
 
     fn new_with_implied_bounds_compat(
@@ -31,7 +25,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
         body_id: LocalDefId,
         param_env: ty::ParamEnv<'tcx>,
         assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>,
-        implied_bounds_compat: bool,
+        disable_implied_bounds_hack: bool,
     ) -> Self {
         let mut bounds = vec![];
 
@@ -59,11 +53,11 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
         OutlivesEnvironment::from_normalized_bounds(
             param_env,
             bounds,
-            infcx.implied_bounds_tys_with_compat(
+            infcx.implied_bounds_tys(
                 body_id,
                 param_env,
                 assumed_wf_tys,
-                implied_bounds_compat,
+                disable_implied_bounds_hack,
             ),
         )
     }
diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs
index 58d8a3a6254..e69bad095e3 100644
--- a/compiler/rustc_trait_selection/src/solve/delegate.rs
+++ b/compiler/rustc_trait_selection/src/solve/delegate.rs
@@ -7,7 +7,6 @@ use rustc_infer::infer::canonical::{
     Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarInfo, CanonicalVarValues,
 };
 use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, TyCtxtInferExt};
-use rustc_infer::traits::ObligationCause;
 use rustc_infer::traits::solve::Goal;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _};
@@ -222,7 +221,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
     // register candidates. We probably need to register >1 since we may have an OR of ANDs.
     fn is_transmutable(
         &self,
-        param_env: ty::ParamEnv<'tcx>,
         dst: Ty<'tcx>,
         src: Ty<'tcx>,
         assume: ty::Const<'tcx>,
@@ -231,16 +229,14 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
         // which will ICE for region vars.
         let (dst, src) = self.tcx.erase_regions((dst, src));
 
-        let Some(assume) = rustc_transmute::Assume::from_const(self.tcx, param_env, assume) else {
+        let Some(assume) = rustc_transmute::Assume::from_const(self.tcx, assume) else {
             return Err(NoSolution);
         };
 
         // FIXME(transmutability): This really should be returning nested goals for `Answer::If*`
-        match rustc_transmute::TransmuteTypeEnv::new(&self.0).is_transmutable(
-            ObligationCause::dummy(),
-            rustc_transmute::Types { src, dst },
-            assume,
-        ) {
+        match rustc_transmute::TransmuteTypeEnv::new(self.0.tcx)
+            .is_transmutable(rustc_transmute::Types { src, dst }, assume)
+        {
             rustc_transmute::Answer::Yes => Ok(Certainty::Yes),
             rustc_transmute::Answer::No(_) | rustc_transmute::Answer::If(_) => Err(NoSolution),
         }
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
index 982782bc57c..4f177df89e2 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
@@ -438,7 +438,10 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
 
             let obligation;
             match (child_mode, nested_goal.source()) {
-                (ChildMode::Trait(_) | ChildMode::Host(_), GoalSource::Misc) => {
+                (
+                    ChildMode::Trait(_) | ChildMode::Host(_),
+                    GoalSource::Misc | GoalSource::NormalizeGoal(_),
+                ) => {
                     continue;
                 }
                 (ChildMode::Trait(parent_trait_pred), GoalSource::ImplWhereBound) => {
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index bdee6ca2afe..75f53b063d1 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -85,6 +85,12 @@ pub fn is_const_evaluatable<'tcx>(
             }
             _ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"),
         }
+    } else if tcx.features().min_generic_const_args() {
+        // This is a sanity check to make sure that non-generics consts are checked to
+        // be evaluatable in case they aren't cchecked elsewhere. This will NOT error
+        // if the const uses generics, as desired.
+        crate::traits::evaluate_const(infcx, unexpanded_ct, param_env);
+        Ok(())
     } else {
         let uv = match unexpanded_ct.kind() {
             ty::ConstKind::Unevaluated(uv) => uv,
diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
index 18932695807..68983ef80fa 100644
--- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
@@ -36,7 +36,7 @@ fn implied_outlives_bounds<'a, 'tcx>(
     param_env: ty::ParamEnv<'tcx>,
     body_id: LocalDefId,
     ty: Ty<'tcx>,
-    compat: bool,
+    disable_implied_bounds_hack: bool,
 ) -> Vec<OutlivesBound<'tcx>> {
     let ty = infcx.resolve_vars_if_possible(ty);
     let ty = OpportunisticRegionResolver::new(infcx).fold_ty(ty);
@@ -52,11 +52,8 @@ fn implied_outlives_bounds<'a, 'tcx>(
     let mut canonical_var_values = OriginalQueryValues::default();
     let input = ImpliedOutlivesBounds { ty };
     let canonical = infcx.canonicalize_query(param_env.and(input), &mut canonical_var_values);
-    let implied_bounds_result = if compat {
-        infcx.tcx.implied_outlives_bounds_compat(canonical)
-    } else {
-        infcx.tcx.implied_outlives_bounds(canonical)
-    };
+    let implied_bounds_result =
+        infcx.tcx.implied_outlives_bounds((canonical, disable_implied_bounds_hack));
     let Ok(canonical_result) = implied_bounds_result else {
         return vec![];
     };
@@ -110,14 +107,15 @@ fn implied_outlives_bounds<'a, 'tcx>(
 impl<'tcx> InferCtxt<'tcx> {
     /// Do *NOT* call this directly. You probably want to construct a `OutlivesEnvironment`
     /// instead if you're interested in the implied bounds for a given signature.
-    fn implied_bounds_tys_with_compat<Tys: IntoIterator<Item = Ty<'tcx>>>(
+    fn implied_bounds_tys<Tys: IntoIterator<Item = Ty<'tcx>>>(
         &self,
         body_id: LocalDefId,
         param_env: ParamEnv<'tcx>,
         tys: Tys,
-        compat: bool,
+        disable_implied_bounds_hack: bool,
     ) -> impl Iterator<Item = OutlivesBound<'tcx>> {
-        tys.into_iter()
-            .flat_map(move |ty| implied_outlives_bounds(self, param_env, body_id, ty, compat))
+        tys.into_iter().flat_map(move |ty| {
+            implied_outlives_bounds(self, param_env, body_id, ty, disable_implied_bounds_hack)
+        })
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index de5aaa5bd97..4d9cf6620d6 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1232,8 +1232,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                 // why we special case object types.
                 false
             }
-            ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _)
-            | ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => {
+            ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _) => {
                 // These traits have no associated types.
                 selcx.tcx().dcx().span_delayed_bug(
                     obligation.cause.span,
@@ -1325,8 +1324,7 @@ fn confirm_select_candidate<'cx, 'tcx>(
         }
         ImplSource::Builtin(BuiltinImplSource::Object { .. }, _)
         | ImplSource::Param(..)
-        | ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _)
-        | ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => {
+        | ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _) => {
             // we don't create Select candidates with this kind of resolution
             span_bug!(
                 obligation.cause.span,
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 2ef9d5421ba..6bf76eaee5c 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -31,20 +31,19 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     /// normalized. If you don't care about regions, you should prefer
     /// `normalize_erasing_regions`, which is more efficient.
     ///
-    /// If the normalization succeeds and is unambiguous, returns back
-    /// the normalized value along with various outlives relations (in
-    /// the form of obligations that must be discharged).
+    /// If the normalization succeeds, returns back the normalized
+    /// value along with various outlives relations (in the form of
+    /// obligations that must be discharged).
     ///
-    /// N.B., this will *eventually* be the main means of
-    /// normalizing, but for now should be used only when we actually
-    /// know that normalization will succeed, since error reporting
-    /// and other details are still "under development".
-    ///
-    /// This normalization should *only* be used when the projection does not
-    /// have possible ambiguity or may not be well-formed.
+    /// This normalization should *only* be used when the projection is well-formed and
+    /// does not have possible ambiguity (contains inference variables).
     ///
     /// After codegen, when lifetimes do not matter, it is preferable to instead
     /// use [`TyCtxt::normalize_erasing_regions`], which wraps this procedure.
+    ///
+    /// N.B. Once the new solver is stabilized this method of normalization will
+    /// likely be removed as trait solver operations are already cached by the query
+    /// system making this redundant.
     fn query_normalize<T>(self, value: T) -> Result<Normalized<'tcx, T>, NoSolution>
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
@@ -210,8 +209,6 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
 
         // See note in `rustc_trait_selection::traits::project` about why we
         // wait to fold the args.
-
-        // Wrap this in a closure so we don't accidentally return from the outer function
         let res = match kind {
             ty::Opaque => {
                 // Only normalize `impl Trait` outside of type inference, usually in codegen.
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
index ec0b7903396..f98529860ff 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
@@ -1,15 +1,16 @@
+use std::ops::ControlFlow;
+
+use rustc_infer::infer::RegionObligation;
 use rustc_infer::infer::canonical::CanonicalQueryInput;
-use rustc_infer::infer::resolve::OpportunisticRegionResolver;
 use rustc_infer::traits::query::OutlivesBound;
 use rustc_infer::traits::query::type_op::ImpliedOutlivesBounds;
 use rustc_middle::infer::canonical::CanonicalQueryResponse;
 use rustc_middle::traits::ObligationCause;
-use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFolder, TypeVisitableExt};
+use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitable, TypeVisitor};
 use rustc_span::def_id::CRATE_DEF_ID;
-use rustc_span::{DUMMY_SP, Span};
+use rustc_span::{DUMMY_SP, Span, sym};
 use rustc_type_ir::outlives::{Component, push_outlives_components};
 use smallvec::{SmallVec, smallvec};
-use tracing::debug;
 
 use crate::traits::query::NoSolution;
 use crate::traits::{ObligationCtxt, wf};
@@ -35,11 +36,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> {
         tcx: TyCtxt<'tcx>,
         canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Self>>,
     ) -> Result<CanonicalQueryResponse<'tcx, Self::QueryResponse>, NoSolution> {
-        if tcx.sess.opts.unstable_opts.no_implied_bounds_compat {
-            tcx.implied_outlives_bounds(canonicalized)
-        } else {
-            tcx.implied_outlives_bounds_compat(canonicalized)
-        }
+        tcx.implied_outlives_bounds((canonicalized, false))
     }
 
     fn perform_locally_with_next_solver(
@@ -47,11 +44,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> {
         key: ParamEnvAnd<'tcx, Self>,
         span: Span,
     ) -> Result<Self::QueryResponse, NoSolution> {
-        if ocx.infcx.tcx.sess.opts.unstable_opts.no_implied_bounds_compat {
-            compute_implied_outlives_bounds_inner(ocx, key.param_env, key.value.ty, span)
-        } else {
-            compute_implied_outlives_bounds_compat_inner(ocx, key.param_env, key.value.ty, span)
-        }
+        compute_implied_outlives_bounds_inner(ocx, key.param_env, key.value.ty, span, false)
     }
 }
 
@@ -60,18 +53,15 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
     param_env: ty::ParamEnv<'tcx>,
     ty: Ty<'tcx>,
     span: Span,
+    disable_implied_bounds_hack: bool,
 ) -> Result<Vec<OutlivesBound<'tcx>>, NoSolution> {
-    let normalize_op = |ty| -> Result<_, NoSolution> {
+    let normalize_ty = |ty| -> Result<_, NoSolution> {
         // We must normalize the type so we can compute the right outlives components.
         // for example, if we have some constrained param type like `T: Trait<Out = U>`,
         // and we know that `&'a T::Out` is WF, then we want to imply `U: 'a`.
         let ty = ocx
             .deeply_normalize(&ObligationCause::dummy_with_span(span), param_env, ty)
             .map_err(|_| NoSolution)?;
-        if !ocx.select_all_or_error().is_empty() {
-            return Err(NoSolution);
-        }
-        let ty = OpportunisticRegionResolver::new(&ocx.infcx).fold_ty(ty);
         Ok(ty)
     };
 
@@ -81,7 +71,7 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
     // guaranteed to be a subset of the original type, so we need to store the
     // WF args we've computed in a set.
     let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default();
-    let mut wf_args = vec![ty.into(), normalize_op(ty)?.into()];
+    let mut wf_args = vec![ty.into(), normalize_ty(ty)?.into()];
 
     let mut outlives_bounds: Vec<OutlivesBound<'tcx>> = vec![];
 
@@ -96,8 +86,14 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
                 .into_iter()
                 .flatten()
         {
-            assert!(!obligation.has_escaping_bound_vars());
-            let Some(pred) = obligation.predicate.kind().no_bound_vars() else {
+            let pred = ocx
+                .deeply_normalize(
+                    &ObligationCause::dummy_with_span(span),
+                    param_env,
+                    obligation.predicate,
+                )
+                .map_err(|_| NoSolution)?;
+            let Some(pred) = pred.kind().no_bound_vars() else {
                 continue;
             };
             match pred {
@@ -130,7 +126,6 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
                     ty_a,
                     r_b,
                 ))) => {
-                    let ty_a = normalize_op(ty_a)?;
                     let mut components = smallvec![];
                     push_outlives_components(ocx.infcx.tcx, ty_a, &mut components);
                     outlives_bounds.extend(implied_bounds_from_components(r_b, components))
@@ -139,141 +134,48 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
         }
     }
 
-    Ok(outlives_bounds)
-}
-
-pub fn compute_implied_outlives_bounds_compat_inner<'tcx>(
-    ocx: &ObligationCtxt<'_, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    ty: Ty<'tcx>,
-    span: Span,
-) -> Result<Vec<OutlivesBound<'tcx>>, NoSolution> {
-    let tcx = ocx.infcx.tcx;
-
-    // Sometimes when we ask what it takes for T: WF, we get back that
-    // U: WF is required; in that case, we push U onto this stack and
-    // process it next. Because the resulting predicates aren't always
-    // guaranteed to be a subset of the original type, so we need to store the
-    // WF args we've computed in a set.
-    let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default();
-    let mut wf_args = vec![ty.into()];
-
-    let mut outlives_bounds: Vec<ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>> = vec![];
-
-    while let Some(arg) = wf_args.pop() {
-        if !checked_wf_args.insert(arg) {
-            continue;
+    // If we detect `bevy_ecs::*::ParamSet` in the WF args list (and `disable_implied_bounds_hack`
+    // or `-Zno-implied-bounds-compat` are not set), then use the registered outlives obligations
+    // as implied bounds.
+    if !disable_implied_bounds_hack
+        && !ocx.infcx.tcx.sess.opts.unstable_opts.no_implied_bounds_compat
+        && ty.visit_with(&mut ContainsBevyParamSet { tcx: ocx.infcx.tcx }).is_break()
+    {
+        for RegionObligation { sup_type, sub_region, .. } in
+            ocx.infcx.take_registered_region_obligations()
+        {
+            let mut components = smallvec![];
+            push_outlives_components(ocx.infcx.tcx, sup_type, &mut components);
+            outlives_bounds.extend(implied_bounds_from_components(sub_region, components));
         }
+    }
 
-        // Compute the obligations for `arg` to be well-formed. If `arg` is
-        // an unresolved inference variable, just instantiated an empty set
-        // -- because the return type here is going to be things we *add*
-        // to the environment, it's always ok for this set to be smaller
-        // than the ultimate set. (Note: normally there won't be
-        // unresolved inference variables here anyway, but there might be
-        // during typeck under some circumstances.)
-        //
-        // FIXME(@lcnr): It's not really "always fine", having fewer implied
-        // bounds can be backward incompatible, e.g. #101951 was caused by
-        // us not dealing with inference vars in `TypeOutlives` predicates.
-        let obligations =
-            wf::obligations(ocx.infcx, param_env, CRATE_DEF_ID, 0, arg, span).unwrap_or_default();
+    Ok(outlives_bounds)
+}
 
-        for obligation in obligations {
-            debug!(?obligation);
-            assert!(!obligation.has_escaping_bound_vars());
+struct ContainsBevyParamSet<'tcx> {
+    tcx: TyCtxt<'tcx>,
+}
 
-            // While these predicates should all be implied by other parts of
-            // the program, they are still relevant as they may constrain
-            // inference variables, which is necessary to add the correct
-            // implied bounds in some cases, mostly when dealing with projections.
-            //
-            // Another important point here: we only register `Projection`
-            // predicates, since otherwise we might register outlives
-            // predicates containing inference variables, and we don't
-            // learn anything new from those.
-            if obligation.predicate.has_non_region_infer() {
-                match obligation.predicate.kind().skip_binder() {
-                    ty::PredicateKind::Clause(ty::ClauseKind::Projection(..))
-                    | ty::PredicateKind::AliasRelate(..) => {
-                        ocx.register_obligation(obligation.clone());
-                    }
-                    _ => {}
-                }
-            }
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ContainsBevyParamSet<'tcx> {
+    type Result = ControlFlow<()>;
 
-            let pred = match obligation.predicate.kind().no_bound_vars() {
-                None => continue,
-                Some(pred) => pred,
-            };
-            match pred {
-                // FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound
-                // if we ever support that
-                ty::PredicateKind::Clause(ty::ClauseKind::Trait(..))
-                | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..))
-                | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
-                | ty::PredicateKind::Subtype(..)
-                | ty::PredicateKind::Coerce(..)
-                | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..))
-                | ty::PredicateKind::DynCompatible(..)
-                | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
-                | ty::PredicateKind::ConstEquate(..)
-                | ty::PredicateKind::Ambiguous
-                | ty::PredicateKind::NormalizesTo(..)
-                | ty::PredicateKind::AliasRelate(..) => {}
-
-                // We need to search through *all* WellFormed predicates
-                ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
-                    wf_args.push(arg);
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
+        // We only care to match `ParamSet<T>` or `&ParamSet<T>`.
+        match t.kind() {
+            ty::Adt(def, _) => {
+                if self.tcx.item_name(def.did()) == sym::ParamSet
+                    && self.tcx.crate_name(def.did().krate) == sym::bevy_ecs
+                {
+                    return ControlFlow::Break(());
                 }
-
-                // We need to register region relationships
-                ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(
-                    ty::OutlivesPredicate(r_a, r_b),
-                )) => outlives_bounds.push(ty::OutlivesPredicate(r_a.into(), r_b)),
-
-                ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
-                    ty_a,
-                    r_b,
-                ))) => outlives_bounds.push(ty::OutlivesPredicate(ty_a.into(), r_b)),
             }
+            ty::Ref(_, ty, _) => ty.visit_with(self)?,
+            _ => {}
         }
-    }
 
-    // This call to `select_all_or_error` is necessary to constrain inference variables, which we
-    // use further down when computing the implied bounds.
-    match ocx.select_all_or_error().as_slice() {
-        [] => (),
-        _ => return Err(NoSolution),
+        ControlFlow::Continue(())
     }
-
-    // We lazily compute the outlives components as
-    // `select_all_or_error` constrains inference variables.
-    let mut implied_bounds = Vec::new();
-    for ty::OutlivesPredicate(a, r_b) in outlives_bounds {
-        match a.unpack() {
-            ty::GenericArgKind::Lifetime(r_a) => {
-                implied_bounds.push(OutlivesBound::RegionSubRegion(r_b, r_a))
-            }
-            ty::GenericArgKind::Type(ty_a) => {
-                let mut ty_a = ocx.infcx.resolve_vars_if_possible(ty_a);
-                // Need to manually normalize in the new solver as `wf::obligations` does not.
-                if ocx.infcx.next_trait_solver() {
-                    ty_a = ocx
-                        .deeply_normalize(&ObligationCause::dummy_with_span(span), param_env, ty_a)
-                        .map_err(|_| NoSolution)?;
-                }
-                let mut components = smallvec![];
-                push_outlives_components(tcx, ty_a, &mut components);
-                implied_bounds.extend(implied_bounds_from_components(r_b, components))
-            }
-            ty::GenericArgKind::Const(_) => {
-                unreachable!("consts do not participate in outlives bounds")
-            }
-        }
-    }
-
-    Ok(implied_bounds)
 }
 
 /// When we have an implied bound that `T: 'a`, we can further break
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 11b6b826efe..a8d8003ead6 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -1017,13 +1017,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 }
             }
 
-            // `(.., T)` -> `(.., U)`
-            (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => {
-                if tys_a.len() == tys_b.len() {
-                    candidates.vec.push(BuiltinUnsizeCandidate);
-                }
-            }
-
             _ => {}
         };
     }
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 32cbb97e314..6db97fc321a 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -7,7 +7,6 @@
 //! [rustc dev guide]:
 //! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation
 
-use std::iter;
 use std::ops::ControlFlow;
 
 use rustc_ast::Mutability;
@@ -410,13 +409,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let predicate = obligation.predicate.skip_binder();
 
         let mut assume = predicate.trait_ref.args.const_at(2);
-        // FIXME(min_generic_const_exprs): We should shallowly normalize this.
+        // FIXME(mgca): We should shallowly normalize this.
         if self.tcx().features().generic_const_exprs() {
             assume = crate::traits::evaluate_const(self.infcx, assume, obligation.param_env)
         }
-        let Some(assume) =
-            rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, assume)
-        else {
+        let Some(assume) = rustc_transmute::Assume::from_const(self.infcx.tcx, assume) else {
             return Err(Unimplemented);
         };
 
@@ -424,12 +421,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let src = predicate.trait_ref.args.type_at(1);
 
         debug!(?src, ?dst);
-        let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx);
-        let maybe_transmutable = transmute_env.is_transmutable(
-            obligation.cause.clone(),
-            rustc_transmute::Types { dst, src },
-            assume,
-        );
+        let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx.tcx);
+        let maybe_transmutable =
+            transmute_env.is_transmutable(rustc_transmute::Types { dst, src }, assume);
 
         let fully_flattened = match maybe_transmutable {
             Answer::No(_) => Err(Unimplemented)?,
@@ -989,8 +983,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 return Err(SelectionError::Unimplemented);
             }
         } else {
-            nested.push(obligation.with(
+            nested.push(Obligation::new(
                 self.tcx(),
+                obligation.derived_cause(ObligationCauseCode::BuiltinDerived),
+                obligation.param_env,
                 ty::TraitRef::new(
                     self.tcx(),
                     self.tcx().require_lang_item(
@@ -1320,34 +1316,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 ImplSource::Builtin(BuiltinImplSource::Misc, nested)
             }
 
-            // `(.., T)` -> `(.., U)`
-            (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => {
-                assert_eq!(tys_a.len(), tys_b.len());
-
-                // The last field of the tuple has to exist.
-                let (&a_last, a_mid) = tys_a.split_last().ok_or(Unimplemented)?;
-                let &b_last = tys_b.last().unwrap();
-
-                // Check that the source tuple with the target's
-                // last element is equal to the target.
-                let new_tuple =
-                    Ty::new_tup_from_iter(tcx, a_mid.iter().copied().chain(iter::once(b_last)));
-                let InferOk { mut obligations, .. } = self
-                    .infcx
-                    .at(&obligation.cause, obligation.param_env)
-                    .eq(DefineOpaqueTypes::Yes, target, new_tuple)
-                    .map_err(|_| Unimplemented)?;
-
-                // Add a nested `T: Unsize<U>` predicate.
-                let last_unsize_obligation = obligation.with(
-                    tcx,
-                    ty::TraitRef::new(tcx, obligation.predicate.def_id(), [a_last, b_last]),
-                );
-                obligations.push(last_unsize_obligation);
-
-                ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, obligations)
-            }
-
             _ => bug!("source: {source}, target: {target}"),
         })
     }
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 436ce3dddd9..77dbb43465e 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -9,7 +9,7 @@ use std::ops::ControlFlow;
 use std::{cmp, iter};
 
 use hir::def::DefKind;
-use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::{Diag, EmissionGuarantee};
 use rustc_hir as hir;
@@ -25,7 +25,6 @@ use rustc_middle::dep_graph::{DepNodeIndex, dep_kinds};
 pub use rustc_middle::traits::select::*;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::TypeErrorToStringExt;
-use rustc_middle::ty::fold::fold_regions;
 use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths};
 use rustc_middle::ty::{
     self, GenericArgsRef, PolyProjectionPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitableExt,
@@ -1008,7 +1007,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             // depend on its particular value in order to work, so we can clear
             // out the param env and get better caching.
             debug!("in global");
-            obligation.param_env = obligation.param_env.without_caller_bounds();
+            obligation.param_env = ty::ParamEnv::empty();
         }
 
         let stack = self.push_stack(previous_stack, &obligation);
@@ -1225,15 +1224,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     /// that recursion is ok. This routine returns `true` if the top of the
     /// stack (`cycle[0]`):
     ///
-    /// - is a defaulted trait,
+    /// - is a coinductive trait: an auto-trait or `Sized`,
     /// - it also appears in the backtrace at some position `X`,
     /// - all the predicates at positions `X..` between `X` and the top are
-    ///   also defaulted traits.
+    ///   also coinductive traits.
     pub(crate) fn coinductive_match<I>(&mut self, mut cycle: I) -> bool
     where
         I: Iterator<Item = ty::Predicate<'tcx>>,
     {
-        cycle.all(|predicate| predicate.is_coinductive(self.tcx()))
+        cycle.all(|p| match p.kind().skip_binder() {
+            ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
+                self.infcx.tcx.trait_is_coinductive(data.def_id())
+            }
+            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => true,
+            _ => false,
+        })
     }
 
     /// Further evaluates `candidate` to decide whether all type parameters match and whether nested
@@ -2199,8 +2204,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             }
 
             ty::CoroutineWitness(def_id, args) => {
-                let hidden_types = bind_coroutine_hidden_types_above(
-                    self.infcx,
+                let hidden_types = rebind_coroutine_witness_types(
+                    self.infcx.tcx,
                     def_id,
                     args,
                     obligation.predicate.bound_vars(),
@@ -2348,7 +2353,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             }
 
             ty::CoroutineWitness(def_id, args) => {
-                bind_coroutine_hidden_types_above(self.infcx, def_id, args, t.bound_vars())
+                rebind_coroutine_witness_types(self.infcx.tcx, def_id, args, t.bound_vars())
             }
 
             // For `PhantomData<T>`, we pass `T`.
@@ -2843,6 +2848,23 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
     }
 }
 
+fn rebind_coroutine_witness_types<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: DefId,
+    args: ty::GenericArgsRef<'tcx>,
+    bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
+) -> ty::Binder<'tcx, Vec<Ty<'tcx>>> {
+    let bound_coroutine_types = tcx.coroutine_hidden_types(def_id).skip_binder();
+    let shifted_coroutine_types =
+        tcx.shift_bound_var_indices(bound_vars.len(), bound_coroutine_types.skip_binder());
+    ty::Binder::bind_with_vars(
+        ty::EarlyBinder::bind(shifted_coroutine_types.to_vec()).instantiate(tcx, args),
+        tcx.mk_bound_variable_kinds_from_iter(
+            bound_vars.iter().chain(bound_coroutine_types.bound_vars()),
+        ),
+    )
+}
+
 impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> {
     fn list(&'o self) -> TraitObligationStackList<'o, 'tcx> {
         TraitObligationStackList::with(self)
@@ -3151,56 +3173,3 @@ pub(crate) enum ProjectionMatchesProjection {
     Ambiguous,
     No,
 }
-
-/// Replace all regions inside the coroutine interior with late bound regions.
-/// Note that each region slot in the types gets a new fresh late bound region, which means that
-/// none of the regions inside relate to any other, even if typeck had previously found constraints
-/// that would cause them to be related.
-#[instrument(level = "trace", skip(infcx), ret)]
-fn bind_coroutine_hidden_types_above<'tcx>(
-    infcx: &InferCtxt<'tcx>,
-    def_id: DefId,
-    args: ty::GenericArgsRef<'tcx>,
-    bound_vars: &ty::List<ty::BoundVariableKind>,
-) -> ty::Binder<'tcx, Vec<Ty<'tcx>>> {
-    let tcx = infcx.tcx;
-    let mut seen_tys = FxHashSet::default();
-
-    let considering_regions = infcx.considering_regions;
-
-    let num_bound_variables = bound_vars.len() as u32;
-    let mut counter = num_bound_variables;
-
-    let hidden_types: Vec<_> = tcx
-        .coroutine_hidden_types(def_id)
-        // Deduplicate tys to avoid repeated work.
-        .filter(|bty| seen_tys.insert(*bty))
-        .map(|mut bty| {
-            // Only remap erased regions if we use them.
-            if considering_regions {
-                bty = bty.map_bound(|ty| {
-                    fold_regions(tcx, ty, |r, current_depth| match r.kind() {
-                        ty::ReErased => {
-                            let br = ty::BoundRegion {
-                                var: ty::BoundVar::from_u32(counter),
-                                kind: ty::BoundRegionKind::Anon,
-                            };
-                            counter += 1;
-                            ty::Region::new_bound(tcx, current_depth, br)
-                        }
-                        r => bug!("unexpected region: {r:?}"),
-                    })
-                })
-            }
-
-            bty.instantiate(tcx, args)
-        })
-        .collect();
-    let bound_vars = tcx.mk_bound_variable_kinds_from_iter(
-        bound_vars.iter().chain(
-            (num_bound_variables..counter)
-                .map(|_| ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon)),
-        ),
-    );
-    ty::Binder::bind_with_vars(hidden_types, bound_vars)
-}
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 18906a6a8ce..54b6c22b2d8 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -708,7 +708,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
             ty::Pat(subty, pat) => {
                 self.require_sized(subty, ObligationCauseCode::Misc);
                 match *pat {
-                    ty::PatternKind::Range { start, end, include_end: _ } => {
+                    ty::PatternKind::Range { start, end } => {
                         let mut check = |c| {
                             let cause = self.cause(ObligationCauseCode::Misc);
                             self.out.push(traits::Obligation::with_depth(
@@ -738,12 +738,8 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
                                 }
                             }
                         };
-                        if let Some(start) = start {
-                            check(start)
-                        }
-                        if let Some(end) = end {
-                            check(end)
-                        }
+                        check(start);
+                        check(end);
                     }
                 }
             }