about summary refs log tree commit diff
path: root/compiler/rustc_infer
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_infer')
-rw-r--r--compiler/rustc_infer/messages.ftl9
-rw-r--r--compiler/rustc_infer/src/errors/mod.rs182
-rw-r--r--compiler/rustc_infer/src/errors/note_and_explain.rs33
-rw-r--r--compiler/rustc_infer/src/infer/at.rs236
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs1
-rw-r--r--compiler/rustc_infer/src/infer/canonical/instantiate.rs2
-rw-r--r--compiler/rustc_infer/src/infer/canonical/mod.rs20
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs1
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs297
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs32
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs31
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs4
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs11
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs18
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs6
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs16
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs8
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs5
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs8
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note.rs56
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs120
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/suggest.rs2
-rw-r--r--compiler/rustc_infer/src/infer/freshen.rs1
-rw-r--r--compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs1
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs181
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types/mod.rs18
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types/table.rs1
-rw-r--r--compiler/rustc_infer/src/infer/outlives/env.rs4
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs9
-rw-r--r--compiler/rustc_infer/src/infer/outlives/verify.rs6
-rw-r--r--compiler/rustc_infer/src/infer/projection.rs10
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/leak_check.rs3
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/relate/combine.rs63
-rw-r--r--compiler/rustc_infer/src/infer/relate/generalize.rs59
-rw-r--r--compiler/rustc_infer/src/infer/relate/glb.rs5
-rw-r--r--compiler/rustc_infer/src/infer/relate/lattice.rs7
-rw-r--r--compiler/rustc_infer/src/infer/relate/lub.rs5
-rw-r--r--compiler/rustc_infer/src/infer/relate/type_relating.rs5
-rw-r--r--compiler/rustc_infer/src/infer/resolve.rs82
-rw-r--r--compiler/rustc_infer/src/infer/snapshot/fudge.rs4
-rw-r--r--compiler/rustc_infer/src/infer/type_variable.rs1
-rw-r--r--compiler/rustc_infer/src/lib.rs8
-rw-r--r--compiler/rustc_infer/src/traits/engine.rs5
-rw-r--r--compiler/rustc_infer/src/traits/mod.rs40
-rw-r--r--compiler/rustc_infer/src/traits/project.rs32
-rw-r--r--compiler/rustc_infer/src/traits/structural_impls.rs8
-rw-r--r--compiler/rustc_infer/src/traits/util.rs18
48 files changed, 908 insertions, 768 deletions
diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl
index 64f52ea7ac1..fbe8d31370c 100644
--- a/compiler/rustc_infer/messages.ftl
+++ b/compiler/rustc_infer/messages.ftl
@@ -104,10 +104,10 @@ infer_compare_impl_item_obligation = ...so that the definition in impl matches t
 infer_consider_specifying_length = consider specifying the actual array length
 infer_data_flows = ...but data{$label_var1_exists ->
     [true] {" "}from `{$label_var1}`
-    *[false] -> {""}
+    *[false] {""}
 } flows{$label_var2_exists ->
     [true] {" "}into `{$label_var2}`
-    *[false] -> {""}
+    *[false] {""}
 } here
 
 infer_data_lifetime_flow = ...but data with one lifetime flows into the other here
@@ -164,7 +164,10 @@ infer_label_bad = {$bad_kind ->
 infer_lf_bound_not_satisfied = lifetime bound not satisfied
 infer_lifetime_mismatch = lifetime mismatch
 
-infer_lifetime_param_suggestion = consider introducing a named lifetime parameter{$is_impl ->
+infer_lifetime_param_suggestion = consider {$is_reuse ->
+    [true] reusing
+    *[false] introducing
+} a named lifetime parameter{$is_impl ->
     [true] {" "}and update trait if needed
     *[false] {""}
 }
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs
index 4593108edac..a801001eaf9 100644
--- a/compiler/rustc_infer/src/errors/mod.rs
+++ b/compiler/rustc_infer/src/errors/mod.rs
@@ -1,9 +1,12 @@
 use hir::GenericParamKind;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{
     codes::*, Applicability, Diag, DiagMessage, DiagStyledString, EmissionGuarantee, IntoDiagArg,
     MultiSpan, SubdiagMessageOp, Subdiagnostic,
 };
 use rustc_hir as hir;
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::intravisit::{walk_ty, Visitor};
 use rustc_hir::FnRetTy;
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_middle::ty::print::TraitRefPrintOnlyTraitPath;
@@ -239,7 +242,7 @@ impl Subdiagnostic for RegionOriginNote<'_> {
     fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
         self,
         diag: &mut Diag<'_, G>,
-        _f: F,
+        _f: &F,
     ) {
         let mut label_or_note = |span, msg: DiagMessage| {
             let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
@@ -304,7 +307,7 @@ impl Subdiagnostic for LifetimeMismatchLabels {
     fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
         self,
         diag: &mut Diag<'_, G>,
-        _f: F,
+        _f: &F,
     ) {
         match self {
             LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
@@ -342,6 +345,7 @@ impl Subdiagnostic for LifetimeMismatchLabels {
 
 pub struct AddLifetimeParamsSuggestion<'a> {
     pub tcx: TyCtxt<'a>,
+    pub generic_param_scope: LocalDefId,
     pub sub: Region<'a>,
     pub ty_sup: &'a hir::Ty<'a>,
     pub ty_sub: &'a hir::Ty<'a>,
@@ -352,34 +356,37 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
     fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
         self,
         diag: &mut Diag<'_, G>,
-        _f: F,
+        _f: &F,
     ) {
         let mut mk_suggestion = || {
-            let (
-                hir::Ty { kind: hir::TyKind::Ref(lifetime_sub, _), .. },
-                hir::Ty { kind: hir::TyKind::Ref(lifetime_sup, _), .. },
-            ) = (self.ty_sub, self.ty_sup)
+            let Some(anon_reg) = self.tcx.is_suitable_region(self.generic_param_scope, self.sub)
             else {
                 return false;
             };
 
-            if !lifetime_sub.is_anonymous() || !lifetime_sup.is_anonymous() {
-                return false;
-            };
-
-            let Some(anon_reg) = self.tcx.is_suitable_region(self.sub) else {
-                return false;
-            };
-
             let node = self.tcx.hir_node_by_def_id(anon_reg.def_id);
             let is_impl = matches!(&node, hir::Node::ImplItem(_));
-            let generics = match node {
+            let (generics, parent_generics) = match node {
                 hir::Node::Item(&hir::Item {
                     kind: hir::ItemKind::Fn(_, ref generics, ..),
                     ..
                 })
                 | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
-                | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics,
+                | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => (
+                    generics,
+                    match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.def_id))
+                    {
+                        hir::Node::Item(hir::Item {
+                            kind: hir::ItemKind::Trait(_, _, ref generics, ..),
+                            ..
+                        })
+                        | hir::Node::Item(hir::Item {
+                            kind: hir::ItemKind::Impl(hir::Impl { ref generics, .. }),
+                            ..
+                        }) => Some(generics),
+                        _ => None,
+                    },
+                ),
                 _ => return false,
             };
 
@@ -390,24 +397,112 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
                 .map(|p| p.name.ident().name)
                 .find(|i| *i != kw::UnderscoreLifetime);
             let introduce_new = suggestion_param_name.is_none();
+
+            let mut default = "'a".to_string();
+            if let Some(parent_generics) = parent_generics {
+                let used: FxHashSet<_> = parent_generics
+                    .params
+                    .iter()
+                    .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
+                    .map(|p| p.name.ident().name)
+                    .filter(|i| *i != kw::UnderscoreLifetime)
+                    .map(|l| l.to_string())
+                    .collect();
+                if let Some(lt) =
+                    ('a'..='z').map(|it| format!("'{it}")).find(|it| !used.contains(it))
+                {
+                    // We want a lifetime that *isn't* present in the `trait` or `impl` that assoc
+                    // `fn` belongs to. We could suggest reusing one of their lifetimes, but it is
+                    // likely to be an over-constraining lifetime requirement, so we always add a
+                    // lifetime to the `fn`.
+                    default = lt;
+                }
+            }
             let suggestion_param_name =
-                suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
-
-            debug!(?lifetime_sup.ident.span);
-            debug!(?lifetime_sub.ident.span);
-            let make_suggestion = |ident: Ident| {
-                let sugg = if ident.name == kw::Empty {
-                    format!("{suggestion_param_name}, ")
-                } else if ident.name == kw::UnderscoreLifetime && ident.span.is_empty() {
-                    format!("{suggestion_param_name} ")
-                } else {
-                    suggestion_param_name.clone()
-                };
-                (ident.span, sugg)
-            };
-            let mut suggestions =
-                vec![make_suggestion(lifetime_sub.ident), make_suggestion(lifetime_sup.ident)];
+                suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| default);
+
+            struct ImplicitLifetimeFinder {
+                suggestions: Vec<(Span, String)>,
+                suggestion_param_name: String,
+            }
 
+            impl<'v> Visitor<'v> for ImplicitLifetimeFinder {
+                fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
+                    let make_suggestion = |ident: Ident| {
+                        if ident.name == kw::Empty && ident.span.is_empty() {
+                            format!("{}, ", self.suggestion_param_name)
+                        } else if ident.name == kw::UnderscoreLifetime && ident.span.is_empty() {
+                            format!("{} ", self.suggestion_param_name)
+                        } else {
+                            self.suggestion_param_name.clone()
+                        }
+                    };
+                    match ty.kind {
+                        hir::TyKind::Path(hir::QPath::Resolved(_, path)) => {
+                            for segment in path.segments {
+                                if let Some(args) = segment.args {
+                                    if args.args.iter().all(|arg| {
+                                        matches!(
+                                            arg,
+                                            hir::GenericArg::Lifetime(lifetime)
+                                            if lifetime.ident.name == kw::Empty
+                                        )
+                                    }) {
+                                        self.suggestions.push((
+                                            segment.ident.span.shrink_to_hi(),
+                                            format!(
+                                                "<{}>",
+                                                args.args
+                                                    .iter()
+                                                    .map(|_| self.suggestion_param_name.clone())
+                                                    .collect::<Vec<_>>()
+                                                    .join(", ")
+                                            ),
+                                        ));
+                                    } else {
+                                        for arg in args.args {
+                                            if let hir::GenericArg::Lifetime(lifetime) = arg
+                                                && lifetime.is_anonymous()
+                                            {
+                                                self.suggestions.push((
+                                                    lifetime.ident.span,
+                                                    make_suggestion(lifetime.ident),
+                                                ));
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                        hir::TyKind::Ref(lifetime, ..) if lifetime.is_anonymous() => {
+                            self.suggestions
+                                .push((lifetime.ident.span, make_suggestion(lifetime.ident)));
+                        }
+                        _ => {}
+                    }
+                    walk_ty(self, ty);
+                }
+            }
+            let mut visitor = ImplicitLifetimeFinder {
+                suggestions: vec![],
+                suggestion_param_name: suggestion_param_name.clone(),
+            };
+            if let Some(fn_decl) = node.fn_decl()
+                && let hir::FnRetTy::Return(ty) = fn_decl.output
+            {
+                visitor.visit_ty(ty);
+            }
+            if visitor.suggestions.is_empty() {
+                // Do not suggest constraining the `&self` param, but rather the return type.
+                // If that is wrong (because it is not sufficient), a follow up error will tell the
+                // user to fix it. This way we lower the chances of *over* constraining, but still
+                // get the cake of "correctly" contrained in two steps.
+                visitor.visit_ty(self.ty_sup);
+            }
+            visitor.visit_ty(self.ty_sub);
+            if visitor.suggestions.is_empty() {
+                return false;
+            }
             if introduce_new {
                 let new_param_suggestion = if let Some(first) =
                     generics.params.iter().find(|p| !p.name.ident().span.is_empty())
@@ -417,15 +512,16 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
                     (generics.span, format!("<{suggestion_param_name}>"))
                 };
 
-                suggestions.push(new_param_suggestion);
+                visitor.suggestions.push(new_param_suggestion);
             }
-
-            diag.multipart_suggestion(
+            diag.multipart_suggestion_verbose(
                 fluent::infer_lifetime_param_suggestion,
-                suggestions,
+                visitor.suggestions,
                 Applicability::MaybeIncorrect,
             );
             diag.arg("is_impl", is_impl);
+            diag.arg("is_reuse", !introduce_new);
+
             true
         };
         if mk_suggestion() && self.add_note {
@@ -454,7 +550,7 @@ impl Subdiagnostic for IntroducesStaticBecauseUnmetLifetimeReq {
     fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
         mut self,
         diag: &mut Diag<'_, G>,
-        _f: F,
+        _f: &F,
     ) {
         self.unmet_requirements
             .push_span_label(self.binding_span, fluent::infer_msl_introduces_static);
@@ -773,7 +869,7 @@ impl Subdiagnostic for ConsiderBorrowingParamHelp {
     fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
         self,
         diag: &mut Diag<'_, G>,
-        f: F,
+        f: &F,
     ) {
         let mut type_param_span: MultiSpan = self.spans.clone().into();
         for &span in &self.spans {
@@ -818,7 +914,7 @@ impl Subdiagnostic for DynTraitConstraintSuggestion {
     fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
         self,
         diag: &mut Diag<'_, G>,
-        f: F,
+        f: &F,
     ) {
         let mut multi_span: MultiSpan = vec![self.span].into();
         multi_span.push_span_label(self.span, fluent::infer_dtcs_has_lifetime_req_label);
@@ -865,7 +961,7 @@ impl Subdiagnostic for ReqIntroducedLocations {
     fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
         mut self,
         diag: &mut Diag<'_, G>,
-        f: F,
+        f: &F,
     ) {
         for sp in self.spans {
             self.span.push_span_label(sp, fluent::infer_ril_introduced_here);
@@ -888,7 +984,7 @@ impl Subdiagnostic for MoreTargeted {
     fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
         self,
         diag: &mut Diag<'_, G>,
-        _f: F,
+        _f: &F,
     ) {
         diag.code(E0772);
         diag.primary_message(fluent::infer_more_targeted);
@@ -1293,7 +1389,7 @@ impl Subdiagnostic for SuggestTuplePatternMany {
     fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
         self,
         diag: &mut Diag<'_, G>,
-        f: F,
+        f: &F,
     ) {
         diag.arg("path", self.path);
         let message = f(diag, crate::fluent_generated::infer_stp_wrap_many.into());
diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs
index 7b962b01408..4fbeb0ec102 100644
--- a/compiler/rustc_infer/src/errors/note_and_explain.rs
+++ b/compiler/rustc_infer/src/errors/note_and_explain.rs
@@ -1,6 +1,8 @@
 use crate::fluent_generated as fluent;
 use crate::infer::error_reporting::nice_region_error::find_anon_type;
 use rustc_errors::{Diag, EmissionGuarantee, IntoDiagArg, SubdiagMessageOp, Subdiagnostic};
+use rustc_hir::def_id::LocalDefId;
+use rustc_middle::bug;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::{symbol::kw, Span};
 
@@ -13,12 +15,15 @@ struct DescriptionCtx<'a> {
 impl<'a> DescriptionCtx<'a> {
     fn new<'tcx>(
         tcx: TyCtxt<'tcx>,
+        generic_param_scope: LocalDefId,
         region: ty::Region<'tcx>,
         alt_span: Option<Span>,
     ) -> Option<Self> {
         let (span, kind, arg) = match *region {
-            ty::ReEarlyParam(ref br) => {
-                let scope = region.free_region_binding_scope(tcx).expect_local();
+            ty::ReEarlyParam(br) => {
+                let scope = tcx
+                    .parent(tcx.generics_of(generic_param_scope).region_param(br, tcx).def_id)
+                    .expect_local();
                 let span = if let Some(param) =
                     tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
                 {
@@ -34,11 +39,12 @@ impl<'a> DescriptionCtx<'a> {
             }
             ty::ReLateParam(ref fr) => {
                 if !fr.bound_region.is_named()
-                    && let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region)
+                    && let Some((ty, _)) =
+                        find_anon_type(tcx, generic_param_scope, region, &fr.bound_region)
                 {
                     (Some(ty.span), "defined_here", String::new())
                 } else {
-                    let scope = region.free_region_binding_scope(tcx).expect_local();
+                    let scope = fr.scope.expect_local();
                     match fr.bound_region {
                         ty::BoundRegionKind::BrNamed(_, name) => {
                             let span = if let Some(param) = tcx
@@ -69,16 +75,8 @@ impl<'a> DescriptionCtx<'a> {
 
             ty::RePlaceholder(_) | ty::ReError(_) => return None,
 
-            // FIXME(#13998) RePlaceholder should probably print like
-            // ReLateParam rather than dumping Debug output on the user.
-            //
-            // We shouldn't really be having unification failures with ReVar
-            // and ReBound though.
-            //
-            // FIXME(@lcnr): figure out why we have to handle `ReBound`
-            // here, this feels somewhat off.
             ty::ReVar(_) | ty::ReBound(..) | ty::ReErased => {
-                (alt_span, "revar", format!("{region:?}"))
+                bug!("unexpected region for DescriptionCtx: {:?}", region);
             }
         };
         Some(DescriptionCtx { span, kind, arg })
@@ -150,12 +148,17 @@ pub struct RegionExplanation<'a> {
 impl RegionExplanation<'_> {
     pub fn new<'tcx>(
         tcx: TyCtxt<'tcx>,
+        generic_param_scope: LocalDefId,
         region: ty::Region<'tcx>,
         alt_span: Option<Span>,
         prefix: PrefixKind,
         suffix: SuffixKind,
     ) -> Option<Self> {
-        Some(Self { desc: DescriptionCtx::new(tcx, region, alt_span)?, prefix, suffix })
+        Some(Self {
+            desc: DescriptionCtx::new(tcx, generic_param_scope, region, alt_span)?,
+            prefix,
+            suffix,
+        })
     }
 }
 
@@ -163,7 +166,7 @@ impl Subdiagnostic for RegionExplanation<'_> {
     fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
         self,
         diag: &mut Diag<'_, G>,
-        f: F,
+        f: &F,
     ) {
         diag.arg("pref_kind", self.prefix);
         diag.arg("suff_kind", self.suffix);
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 0f21d3966c4..17e6d6250ad 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -27,6 +27,7 @@
 
 use super::*;
 
+use rustc_middle::bug;
 use rustc_middle::ty::relate::{Relate, TypeRelation};
 use rustc_middle::ty::{Const, ImplSubject};
 
@@ -47,11 +48,6 @@ pub struct At<'a, 'tcx> {
     pub param_env: ty::ParamEnv<'tcx>,
 }
 
-pub struct Trace<'a, 'tcx> {
-    at: At<'a, 'tcx>,
-    trace: TypeTrace<'tcx>,
-}
-
 impl<'tcx> InferCtxt<'tcx> {
     #[inline]
     pub fn at<'a>(
@@ -108,9 +104,6 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     /// call like `foo(x)`, where `foo: fn(i32)`, you might have
     /// `sup(i32, x)`, since the "expected" type is the type that
     /// appears in the signature.
-    ///
-    /// See [`At::trace`] and [`Trace::sub`] for a version of
-    /// this method that only requires `T: Relate<'tcx>`
     pub fn sup<T>(
         self,
         define_opaque_types: DefineOpaqueTypes,
@@ -120,13 +113,19 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     where
         T: ToTrace<'tcx>,
     {
-        self.trace(expected, actual).sup(define_opaque_types, expected, actual)
+        let mut fields = CombineFields::new(
+            self.infcx,
+            ToTrace::to_trace(self.cause, true, expected, actual),
+            self.param_env,
+            define_opaque_types,
+        );
+        fields
+            .sup()
+            .relate(expected, actual)
+            .map(|_| InferOk { value: (), obligations: fields.obligations })
     }
 
     /// Makes `expected <: actual`.
-    ///
-    /// See [`At::trace`] and [`Trace::sub`] for a version of
-    /// this method that only requires `T: Relate<'tcx>`
     pub fn sub<T>(
         self,
         define_opaque_types: DefineOpaqueTypes,
@@ -136,13 +135,19 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     where
         T: ToTrace<'tcx>,
     {
-        self.trace(expected, actual).sub(define_opaque_types, expected, actual)
+        let mut fields = CombineFields::new(
+            self.infcx,
+            ToTrace::to_trace(self.cause, true, expected, actual),
+            self.param_env,
+            define_opaque_types,
+        );
+        fields
+            .sub()
+            .relate(expected, actual)
+            .map(|_| InferOk { value: (), obligations: fields.obligations })
     }
 
-    /// Makes `expected <: actual`.
-    ///
-    /// See [`At::trace`] and [`Trace::eq`] for a version of
-    /// this method that only requires `T: Relate<'tcx>`
+    /// Makes `expected == actual`.
     pub fn eq<T>(
         self,
         define_opaque_types: DefineOpaqueTypes,
@@ -152,7 +157,40 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     where
         T: ToTrace<'tcx>,
     {
-        self.trace(expected, actual).eq(define_opaque_types, expected, actual)
+        let mut fields = CombineFields::new(
+            self.infcx,
+            ToTrace::to_trace(self.cause, true, expected, actual),
+            self.param_env,
+            define_opaque_types,
+        );
+        fields
+            .equate(StructurallyRelateAliases::No)
+            .relate(expected, actual)
+            .map(|_| InferOk { value: (), obligations: fields.obligations })
+    }
+
+    /// Equates `expected` and `found` while structurally relating aliases.
+    /// This should only be used inside of the next generation trait solver
+    /// when relating rigid aliases.
+    pub fn eq_structurally_relating_aliases<T>(
+        self,
+        expected: T,
+        actual: T,
+    ) -> InferResult<'tcx, ()>
+    where
+        T: ToTrace<'tcx>,
+    {
+        assert!(self.infcx.next_trait_solver());
+        let mut fields = CombineFields::new(
+            self.infcx,
+            ToTrace::to_trace(self.cause, true, expected, actual),
+            self.param_env,
+            DefineOpaqueTypes::Yes,
+        );
+        fields
+            .equate(StructurallyRelateAliases::Yes)
+            .relate(expected, actual)
+            .map(|_| InferOk { value: (), obligations: fields.obligations })
     }
 
     pub fn relate<T>(
@@ -184,9 +222,6 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     /// this can result in an error (e.g., if asked to compute LUB of
     /// u32 and i32), it is meaningful to call one of them the
     /// "expected type".
-    ///
-    /// See [`At::trace`] and [`Trace::lub`] for a version of
-    /// this method that only requires `T: Relate<'tcx>`
     pub fn lub<T>(
         self,
         define_opaque_types: DefineOpaqueTypes,
@@ -196,15 +231,21 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     where
         T: ToTrace<'tcx>,
     {
-        self.trace(expected, actual).lub(define_opaque_types, expected, actual)
+        let mut fields = CombineFields::new(
+            self.infcx,
+            ToTrace::to_trace(self.cause, true, expected, actual),
+            self.param_env,
+            define_opaque_types,
+        );
+        fields
+            .lub()
+            .relate(expected, actual)
+            .map(|value| InferOk { value, obligations: fields.obligations })
     }
 
     /// Computes the greatest-lower-bound, or mutual subtype, of two
     /// values. As with `lub` order doesn't matter, except for error
     /// cases.
-    ///
-    /// See [`At::trace`] and [`Trace::glb`] for a version of
-    /// this method that only requires `T: Relate<'tcx>`
     pub fn glb<T>(
         self,
         define_opaque_types: DefineOpaqueTypes,
@@ -214,105 +255,16 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     where
         T: ToTrace<'tcx>,
     {
-        self.trace(expected, actual).glb(define_opaque_types, expected, actual)
-    }
-
-    /// Sets the "trace" values that will be used for
-    /// error-reporting, but doesn't actually perform any operation
-    /// yet (this is useful when you want to set the trace using
-    /// distinct values from those you wish to operate upon).
-    pub fn trace<T>(self, expected: T, actual: T) -> Trace<'a, 'tcx>
-    where
-        T: ToTrace<'tcx>,
-    {
-        let trace = ToTrace::to_trace(self.cause, true, expected, actual);
-        Trace { at: self, trace }
-    }
-}
-
-impl<'a, 'tcx> Trace<'a, 'tcx> {
-    /// Makes `a <: b`.
-    #[instrument(skip(self), level = "debug")]
-    pub fn sub<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
-    where
-        T: Relate<'tcx>,
-    {
-        let Trace { at, trace } = self;
-        let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
-        fields
-            .sub()
-            .relate(a, b)
-            .map(move |_| InferOk { value: (), obligations: fields.obligations })
-    }
-
-    /// Makes `a :> b`.
-    #[instrument(skip(self), level = "debug")]
-    pub fn sup<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
-    where
-        T: Relate<'tcx>,
-    {
-        let Trace { at, trace } = self;
-        let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
-        fields
-            .sup()
-            .relate(a, b)
-            .map(move |_| InferOk { value: (), obligations: fields.obligations })
-    }
-
-    /// Makes `a == b`.
-    #[instrument(skip(self), level = "debug")]
-    pub fn eq<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
-    where
-        T: Relate<'tcx>,
-    {
-        let Trace { at, trace } = self;
-        let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
-        fields
-            .equate(StructurallyRelateAliases::No)
-            .relate(a, b)
-            .map(move |_| InferOk { value: (), obligations: fields.obligations })
-    }
-
-    /// Equates `a` and `b` while structurally relating aliases. This should only
-    /// be used inside of the next generation trait solver when relating rigid aliases.
-    #[instrument(skip(self), level = "debug")]
-    pub fn eq_structurally_relating_aliases<T>(self, a: T, b: T) -> InferResult<'tcx, ()>
-    where
-        T: Relate<'tcx>,
-    {
-        let Trace { at, trace } = self;
-        debug_assert!(at.infcx.next_trait_solver());
-        let mut fields = at.infcx.combine_fields(trace, at.param_env, DefineOpaqueTypes::Yes);
-        fields
-            .equate(StructurallyRelateAliases::Yes)
-            .relate(a, b)
-            .map(move |_| InferOk { value: (), obligations: fields.obligations })
-    }
-
-    #[instrument(skip(self), level = "debug")]
-    pub fn lub<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, T>
-    where
-        T: Relate<'tcx>,
-    {
-        let Trace { at, trace } = self;
-        let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
-        fields
-            .lub()
-            .relate(a, b)
-            .map(move |t| InferOk { value: t, obligations: fields.obligations })
-    }
-
-    #[instrument(skip(self), level = "debug")]
-    pub fn glb<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, T>
-    where
-        T: Relate<'tcx>,
-    {
-        let Trace { at, trace } = self;
-        let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
+        let mut fields = CombineFields::new(
+            self.infcx,
+            ToTrace::to_trace(self.cause, true, expected, actual),
+            self.param_env,
+            define_opaque_types,
+        );
         fields
             .glb()
-            .relate(a, b)
-            .map(move |t| InferOk { value: t, obligations: fields.obligations })
+            .relate(expected, actual)
+            .map(|value| InferOk { value, obligations: fields.obligations })
     }
 }
 
@@ -384,19 +336,31 @@ impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> {
         a: Self,
         b: Self,
     ) -> TypeTrace<'tcx> {
-        use GenericArgKind::*;
         TypeTrace {
             cause: cause.clone(),
             values: match (a.unpack(), b.unpack()) {
-                (Lifetime(a), Lifetime(b)) => Regions(ExpectedFound::new(a_is_expected, a, b)),
-                (Type(a), Type(b)) => Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
-                (Const(a), Const(b)) => {
+                (GenericArgKind::Lifetime(a), GenericArgKind::Lifetime(b)) => {
+                    Regions(ExpectedFound::new(a_is_expected, a, b))
+                }
+                (GenericArgKind::Type(a), GenericArgKind::Type(b)) => {
+                    Terms(ExpectedFound::new(a_is_expected, a.into(), b.into()))
+                }
+                (GenericArgKind::Const(a), GenericArgKind::Const(b)) => {
                     Terms(ExpectedFound::new(a_is_expected, a.into(), b.into()))
                 }
 
-                (Lifetime(_), Type(_) | Const(_))
-                | (Type(_), Lifetime(_) | Const(_))
-                | (Const(_), Lifetime(_) | Type(_)) => {
+                (
+                    GenericArgKind::Lifetime(_),
+                    GenericArgKind::Type(_) | GenericArgKind::Const(_),
+                )
+                | (
+                    GenericArgKind::Type(_),
+                    GenericArgKind::Lifetime(_) | GenericArgKind::Const(_),
+                )
+                | (
+                    GenericArgKind::Const(_),
+                    GenericArgKind::Lifetime(_) | GenericArgKind::Type(_),
+                ) => {
                     bug!("relating different kinds: {a:?} {b:?}")
                 }
             },
@@ -436,6 +400,20 @@ impl<'tcx> ToTrace<'tcx> for ty::AliasTy<'tcx> {
         a: Self,
         b: Self,
     ) -> TypeTrace<'tcx> {
+        TypeTrace {
+            cause: cause.clone(),
+            values: Aliases(ExpectedFound::new(a_is_expected, a.into(), b.into())),
+        }
+    }
+}
+
+impl<'tcx> ToTrace<'tcx> for ty::AliasTerm<'tcx> {
+    fn to_trace(
+        cause: &ObligationCause<'tcx>,
+        a_is_expected: bool,
+        a: Self,
+        b: Self,
+    ) -> TypeTrace<'tcx> {
         TypeTrace { cause: cause.clone(), values: Aliases(ExpectedFound::new(a_is_expected, a, b)) }
     }
 }
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 4d712e9ffd3..27b06c4b73e 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -9,6 +9,7 @@ use crate::infer::canonical::{
     Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, OriginalQueryValues,
 };
 use crate::infer::InferCtxt;
+use rustc_middle::bug;
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::GenericArg;
 use rustc_middle::ty::{self, BoundVar, InferConst, List, Ty, TyCtxt, TypeFlags, TypeVisitableExt};
diff --git a/compiler/rustc_infer/src/infer/canonical/instantiate.rs b/compiler/rustc_infer/src/infer/canonical/instantiate.rs
index c8adbf7f57a..de0e15ef3de 100644
--- a/compiler/rustc_infer/src/infer/canonical/instantiate.rs
+++ b/compiler/rustc_infer/src/infer/canonical/instantiate.rs
@@ -7,6 +7,8 @@
 //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
 
 use crate::infer::canonical::{Canonical, CanonicalVarValues};
+use rustc_macros::extension;
+use rustc_middle::bug;
 use rustc_middle::ty::fold::{FnMutDelegate, TypeFoldable};
 use rustc_middle::ty::GenericArgKind;
 use rustc_middle::ty::{self, TyCtxt};
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index 734fa919eb5..1abb8086d41 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -21,8 +21,7 @@
 //!
 //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
 
-use crate::infer::ConstVariableOrigin;
-use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin};
+use crate::infer::{InferCtxt, RegionVariableOrigin};
 use rustc_index::IndexVec;
 use rustc_middle::infer::unify_key::EffectVarValue;
 use rustc_middle::ty::fold::TypeFoldable;
@@ -114,10 +113,9 @@ impl<'tcx> InferCtxt<'tcx> {
         match cv_info.kind {
             CanonicalVarKind::Ty(ty_kind) => {
                 let ty = match ty_kind {
-                    CanonicalTyVarKind::General(ui) => self.next_ty_var_in_universe(
-                        TypeVariableOrigin { param_def_id: None, span },
-                        universe_map(ui),
-                    ),
+                    CanonicalTyVarKind::General(ui) => {
+                        self.next_ty_var_in_universe(span, universe_map(ui))
+                    }
 
                     CanonicalTyVarKind::Int => self.next_int_var(),
 
@@ -145,13 +143,9 @@ impl<'tcx> InferCtxt<'tcx> {
                 ty::Region::new_placeholder(self.tcx, placeholder_mapped).into()
             }
 
-            CanonicalVarKind::Const(ui, ty) => self
-                .next_const_var_in_universe(
-                    ty,
-                    ConstVariableOrigin { param_def_id: None, span },
-                    universe_map(ui),
-                )
-                .into(),
+            CanonicalVarKind::Const(ui, ty) => {
+                self.next_const_var_in_universe(ty, span, universe_map(ui)).into()
+            }
             CanonicalVarKind::Effect => {
                 let vid = self
                     .inner
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index b948067e750..1732913e191 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -25,6 +25,7 @@ use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{self, BoundVar, Ty, TyCtxt};
 use rustc_middle::ty::{GenericArg, GenericArgKind};
+use rustc_middle::{bug, span_bug};
 use std::fmt::Debug;
 use std::iter;
 
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 29c9f08a166..95fbc1e66ce 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -61,17 +61,19 @@ use crate::traits::{
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::{
     codes::*, pluralize, struct_span_code_err, Applicability, Diag, DiagCtxt, DiagStyledString,
-    ErrorGuaranteed, IntoDiagArg,
+    ErrorGuaranteed, IntoDiagArg, StringPart,
 };
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
+use rustc_macros::extension;
+use rustc_middle::bug;
 use rustc_middle::dep_graph::DepContext;
-use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError};
+use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError, PrintTraitRefExt as _};
 use rustc_middle::ty::relate::{self, RelateResult, TypeRelation};
-use rustc_middle::ty::ToPredicate;
+use rustc_middle::ty::Upcast;
 use rustc_middle::ty::{
     self, error::TypeError, IsSuggestable, List, Region, Ty, TyCtxt, TypeFoldable,
     TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
@@ -159,6 +161,7 @@ impl<'tcx> Deref for TypeErrCtxt<'_, 'tcx> {
 pub(super) fn note_and_explain_region<'tcx>(
     tcx: TyCtxt<'tcx>,
     err: &mut Diag<'_>,
+    generic_param_scope: LocalDefId,
     prefix: &str,
     region: ty::Region<'tcx>,
     suffix: &str,
@@ -166,16 +169,17 @@ pub(super) fn note_and_explain_region<'tcx>(
 ) {
     let (description, span) = match *region {
         ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::RePlaceholder(_) | ty::ReStatic => {
-            msg_span_from_named_region(tcx, region, alt_span)
+            msg_span_from_named_region(tcx, generic_param_scope, region, alt_span)
         }
 
         ty::ReError(_) => return,
 
-        // We shouldn't really be having unification failures with ReVar
-        // and ReBound though.
-        //
-        // FIXME(@lcnr): Figure out whether this is reachable and if so, why.
-        ty::ReVar(_) | ty::ReBound(..) | ty::ReErased => (format!("lifetime `{region}`"), alt_span),
+        // FIXME(#125431): `ReVar` shouldn't reach here.
+        ty::ReVar(_) => (format!("lifetime `{region}`"), alt_span),
+
+        ty::ReBound(..) | ty::ReErased => {
+            bug!("unexpected region for note_and_explain_region: {:?}", region);
+        }
     };
 
     emit_msg_span(err, prefix, description, span, suffix);
@@ -184,23 +188,27 @@ pub(super) fn note_and_explain_region<'tcx>(
 fn explain_free_region<'tcx>(
     tcx: TyCtxt<'tcx>,
     err: &mut Diag<'_>,
+    generic_param_scope: LocalDefId,
     prefix: &str,
     region: ty::Region<'tcx>,
     suffix: &str,
 ) {
-    let (description, span) = msg_span_from_named_region(tcx, region, None);
+    let (description, span) = msg_span_from_named_region(tcx, generic_param_scope, region, None);
 
     label_msg_span(err, prefix, description, span, suffix);
 }
 
 fn msg_span_from_named_region<'tcx>(
     tcx: TyCtxt<'tcx>,
+    generic_param_scope: LocalDefId,
     region: ty::Region<'tcx>,
     alt_span: Option<Span>,
 ) -> (String, Option<Span>) {
     match *region {
-        ty::ReEarlyParam(ref br) => {
-            let scope = region.free_region_binding_scope(tcx).expect_local();
+        ty::ReEarlyParam(br) => {
+            let scope = tcx
+                .parent(tcx.generics_of(generic_param_scope).region_param(br, tcx).def_id)
+                .expect_local();
             let span = if let Some(param) =
                 tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
             {
@@ -217,21 +225,21 @@ fn msg_span_from_named_region<'tcx>(
         }
         ty::ReLateParam(ref fr) => {
             if !fr.bound_region.is_named()
-                && let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region)
+                && let Some((ty, _)) =
+                    find_anon_type(tcx, generic_param_scope, region, &fr.bound_region)
             {
                 ("the anonymous lifetime defined here".to_string(), Some(ty.span))
             } else {
-                let scope = region.free_region_binding_scope(tcx).expect_local();
                 match fr.bound_region {
                     ty::BoundRegionKind::BrNamed(_, name) => {
                         let span = if let Some(param) = tcx
                             .hir()
-                            .get_generics(scope)
+                            .get_generics(generic_param_scope)
                             .and_then(|generics| generics.get_named(name))
                         {
                             param.span
                         } else {
-                            tcx.def_span(scope)
+                            tcx.def_span(generic_param_scope)
                         };
                         let text = if name == kw::UnderscoreLifetime {
                             "the anonymous lifetime as defined here".to_string()
@@ -242,11 +250,11 @@ fn msg_span_from_named_region<'tcx>(
                     }
                     ty::BrAnon => (
                         "the anonymous lifetime as defined here".to_string(),
-                        Some(tcx.def_span(scope)),
+                        Some(tcx.def_span(generic_param_scope)),
                     ),
                     _ => (
                         format!("the lifetime `{region}` as defined here"),
-                        Some(tcx.def_span(scope)),
+                        Some(tcx.def_span(generic_param_scope)),
                     ),
                 }
             }
@@ -299,6 +307,7 @@ fn label_msg_span(
 #[instrument(level = "trace", skip(tcx))]
 pub fn unexpected_hidden_region_diagnostic<'tcx>(
     tcx: TyCtxt<'tcx>,
+    generic_param_scope: LocalDefId,
     span: Span,
     hidden_ty: Ty<'tcx>,
     hidden_region: ty::Region<'tcx>,
@@ -324,11 +333,12 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
             explain_free_region(
                 tcx,
                 &mut err,
+                generic_param_scope,
                 &format!("hidden type `{hidden_ty}` captures "),
                 hidden_region,
                 "",
             );
-            if let Some(reg_info) = tcx.is_suitable_region(hidden_region) {
+            if let Some(reg_info) = tcx.is_suitable_region(generic_param_scope, hidden_region) {
                 let fn_returns = tcx.return_type_impl_or_dyn_traits(reg_info.def_id);
                 nice_region_error::suggest_new_region_bound(
                     tcx,
@@ -346,6 +356,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
             explain_free_region(
                 tcx,
                 &mut err,
+                generic_param_scope,
                 &format!("hidden type `{}` captures ", hidden_ty),
                 hidden_region,
                 "",
@@ -373,6 +384,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
             note_and_explain_region(
                 tcx,
                 &mut err,
+                generic_param_scope,
                 &format!("hidden type `{hidden_ty}` captures "),
                 hidden_region,
                 "",
@@ -411,7 +423,7 @@ impl<'tcx> InferCtxt<'tcx> {
                     .kind()
                     .map_bound(|kind| match kind {
                         ty::ClauseKind::Projection(projection_predicate)
-                            if projection_predicate.projection_ty.def_id == item_def_id =>
+                            if projection_predicate.projection_term.def_id == item_def_id =>
                         {
                             projection_predicate.term.ty()
                         }
@@ -447,7 +459,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         for error in errors {
             debug!("report_region_errors: error = {:?}", error);
 
-            guar = Some(if let Some(guar) = self.try_report_nice_region_error(&error) {
+            let e = if let Some(guar) =
+                self.try_report_nice_region_error(generic_param_scope, &error)
+            {
                 guar
             } else {
                 match error.clone() {
@@ -460,9 +474,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     // general bit of code that displays the error information
                     RegionResolutionError::ConcreteFailure(origin, sub, sup) => {
                         if sub.is_placeholder() || sup.is_placeholder() {
-                            self.report_placeholder_failure(origin, sub, sup).emit()
+                            self.report_placeholder_failure(generic_param_scope, origin, sub, sup)
+                                .emit()
                         } else {
-                            self.report_concrete_failure(origin, sub, sup).emit()
+                            self.report_concrete_failure(generic_param_scope, origin, sub, sup)
+                                .emit()
                         }
                     }
 
@@ -485,12 +501,29 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         _,
                     ) => {
                         if sub_r.is_placeholder() {
-                            self.report_placeholder_failure(sub_origin, sub_r, sup_r).emit()
+                            self.report_placeholder_failure(
+                                generic_param_scope,
+                                sub_origin,
+                                sub_r,
+                                sup_r,
+                            )
+                            .emit()
                         } else if sup_r.is_placeholder() {
-                            self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit()
+                            self.report_placeholder_failure(
+                                generic_param_scope,
+                                sup_origin,
+                                sub_r,
+                                sup_r,
+                            )
+                            .emit()
                         } else {
                             self.report_sub_sup_conflict(
-                                var_origin, sub_origin, sub_r, sup_origin, sup_r,
+                                generic_param_scope,
+                                var_origin,
+                                sub_origin,
+                                sub_r,
+                                sup_origin,
+                                sup_r,
                             )
                         }
                     }
@@ -511,19 +544,27 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         // value.
                         let sub_r = self.tcx.lifetimes.re_erased;
 
-                        self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit()
+                        self.report_placeholder_failure(
+                            generic_param_scope,
+                            sup_origin,
+                            sub_r,
+                            sup_r,
+                        )
+                        .emit()
                     }
 
                     RegionResolutionError::CannotNormalize(clause, origin) => {
                         let clause: ty::Clause<'tcx> =
-                            clause.map_bound(ty::ClauseKind::TypeOutlives).to_predicate(self.tcx);
+                            clause.map_bound(ty::ClauseKind::TypeOutlives).upcast(self.tcx);
                         self.tcx
                             .dcx()
                             .struct_span_err(origin.span(), format!("cannot normalize `{clause}`"))
                             .emit()
                     }
                 }
-            })
+            };
+
+            guar = Some(e)
         }
 
         guar.unwrap()
@@ -884,9 +925,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 err.help("...or use `match` instead of `let...else`");
             }
             _ => {
-                if let ObligationCauseCode::BindingObligation(_, span)
-                | ObligationCauseCode::ExprBindingObligation(_, span, ..) =
+                if let ObligationCauseCode::WhereClause(_, span)
+                | ObligationCauseCode::WhereClauseInExpr(_, span, ..) =
                     cause.code().peel_derives()
+                    && !span.is_dummy()
                     && let TypeError::RegionsPlaceholderMismatch = terr
                 {
                     err.span_note(*span, "the lifetime requirement is introduced here");
@@ -1052,8 +1094,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 
         // unsafe extern "C" for<'a> fn(&'a T) -> &'a T
         // ^^^^^^
-        values.0.push(sig1.unsafety.prefix_str(), sig1.unsafety != sig2.unsafety);
-        values.1.push(sig2.unsafety.prefix_str(), sig1.unsafety != sig2.unsafety);
+        values.0.push(sig1.safety.prefix_str(), sig1.safety != sig2.safety);
+        values.1.push(sig2.safety.prefix_str(), sig1.safety != sig2.safety);
 
         // unsafe extern "C" for<'a> fn(&'a T) -> &'a T
         //        ^^^^^^^^^^
@@ -1917,6 +1959,23 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     );
                     if !is_simple_error || terr.must_include_note() {
                         diag.note_expected_found(&expected_label, expected, &found_label, found);
+
+                        if let Some(ty::Closure(_, args)) =
+                            exp_found.map(|expected_type_found| expected_type_found.found.kind())
+                        {
+                            diag.highlighted_note(vec![
+                                StringPart::normal("closure has signature: `"),
+                                StringPart::highlighted(
+                                    self.tcx
+                                        .signature_unclosure(
+                                            args.as_closure().sig(),
+                                            rustc_hir::Safety::Safe,
+                                        )
+                                        .to_string(),
+                                ),
+                                StringPart::normal("`"),
+                            ]);
+                        }
                     }
                 }
             }
@@ -1996,7 +2055,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         trace: &TypeTrace<'tcx>,
         terr: TypeError<'tcx>,
     ) -> Vec<TypeErrorAdditionalDiags> {
-        use crate::traits::ObligationCauseCode::{BlockTailExpression, MatchExpressionArm};
         let mut suggestions = Vec::new();
         let span = trace.cause.span();
         let values = self.resolve_vars_if_possible(trace.values);
@@ -2044,10 +2102,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 // If a string was expected and the found expression is a character literal,
                 // perhaps the user meant to write `"s"` to specify a string literal.
                 (ty::Ref(_, r, _), ty::Char) if r.is_str() => {
-                    suggestions.push(TypeErrorAdditionalDiags::MeantStrLiteral {
-                        start: span.with_hi(span.lo() + BytePos(1)),
-                        end: span.with_lo(span.hi() - BytePos(1)),
-                    })
+                    if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
+                        && code.starts_with("'")
+                        && code.ends_with("'")
+                    {
+                        suggestions.push(TypeErrorAdditionalDiags::MeantStrLiteral {
+                            start: span.with_hi(span.lo() + BytePos(1)),
+                            end: span.with_lo(span.hi() - BytePos(1)),
+                        });
+                    }
                 }
                 // For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`,
                 // we try to suggest to add the missing `let` for `if let Some(..) = expr`
@@ -2063,8 +2126,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             }
         }
         let code = trace.cause.code();
-        if let &(MatchExpressionArm(box MatchExpressionArmCause { source, .. })
-        | BlockTailExpression(.., source)) = code
+        if let &(ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
+            source,
+            ..
+        })
+        | ObligationCauseCode::BlockTailExpression(.., source)) = code
             && let hir::MatchSource::TryDesugar(_) = source
             && let Some((expected_ty, found_ty, _)) = self.values_str(trace.values)
         {
@@ -2324,7 +2390,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         '_explain: {
             let (description, span) = match sub.kind() {
                 ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::ReStatic => {
-                    msg_span_from_named_region(self.tcx, sub, Some(span))
+                    msg_span_from_named_region(self.tcx, generic_param_scope, sub, Some(span))
                 }
                 _ => (format!("lifetime `{sub}`"), Some(span)),
             };
@@ -2352,9 +2418,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 generic_param_scope = self.tcx.local_parent(generic_param_scope);
             }
 
-            // type_param_sugg_span is (span, has_bounds)
+            // type_param_sugg_span is (span, has_bounds, needs_parentheses)
             let (type_scope, type_param_sugg_span) = match bound_kind {
-                GenericKind::Param(ref param) => {
+                GenericKind::Param(param) => {
                     let generics = self.tcx.generics_of(generic_param_scope);
                     let def_id = generics.type_param(param, self.tcx).def_id.expect_local();
                     let scope = self.tcx.local_def_id_to_hir_id(def_id).owner.def_id;
@@ -2363,10 +2429,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     // instead we suggest `T: 'a + 'b` in that case.
                     let hir_generics = self.tcx.hir().get_generics(scope).unwrap();
                     let sugg_span = match hir_generics.bounds_span_for_suggestions(def_id) {
-                        Some(span) => Some((span, true)),
+                        Some((span, open_paren_sp)) => Some((span, true, open_paren_sp)),
                         // If `param` corresponds to `Self`, no usable suggestion span.
                         None if generics.has_self && param.index == 0 => None,
-                        None => Some((self.tcx.def_span(def_id).shrink_to_hi(), false)),
+                        None => Some((self.tcx.def_span(def_id).shrink_to_hi(), false, None)),
                     };
                     (scope, sugg_span)
                 }
@@ -2375,7 +2441,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             let suggestion_scope = {
                 let lifetime_scope = match sub.kind() {
                     ty::ReStatic => hir::def_id::CRATE_DEF_ID,
-                    _ => match self.tcx.is_suitable_region(sub) {
+                    _ => match self.tcx.is_suitable_region(generic_param_scope, sub) {
                         Some(info) => info.def_id,
                         None => generic_param_scope,
                     },
@@ -2387,14 +2453,20 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             };
 
             let mut suggs = vec![];
-            let lt_name = self.suggest_name_region(sub, &mut suggs);
+            let lt_name = self.suggest_name_region(generic_param_scope, sub, &mut suggs);
 
-            if let Some((sp, has_lifetimes)) = type_param_sugg_span
+            if let Some((sp, has_lifetimes, open_paren_sp)) = type_param_sugg_span
                 && suggestion_scope == type_scope
             {
                 let suggestion =
                     if has_lifetimes { format!(" + {lt_name}") } else { format!(": {lt_name}") };
-                suggs.push((sp, suggestion))
+
+                if let Some(open_paren_sp) = open_paren_sp {
+                    suggs.push((open_paren_sp, "(".to_string()));
+                    suggs.push((sp, format!("){suggestion}")));
+                } else {
+                    suggs.push((sp, suggestion))
+                }
             } else if let GenericKind::Alias(ref p) = bound_kind
                 && let ty::Projection = p.kind(self.tcx)
                 && let DefKind::AssocTy = self.tcx.def_kind(p.def_id)
@@ -2426,6 +2498,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 
     pub fn suggest_name_region(
         &self,
+        generic_param_scope: LocalDefId,
         lifetime: Region<'tcx>,
         add_lt_suggs: &mut Vec<(Span, String)>,
     ) -> String {
@@ -2472,18 +2545,19 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             }
         }
 
-        let (lifetime_def_id, lifetime_scope) = match self.tcx.is_suitable_region(lifetime) {
-            Some(info) if !lifetime.has_name() => {
-                (info.bound_region.get_id().unwrap().expect_local(), info.def_id)
-            }
-            _ => return lifetime.get_name_or_anon().to_string(),
-        };
+        let (lifetime_def_id, lifetime_scope) =
+            match self.tcx.is_suitable_region(generic_param_scope, lifetime) {
+                Some(info) if !lifetime.has_name() => {
+                    (info.bound_region.get_id().unwrap().expect_local(), info.def_id)
+                }
+                _ => return lifetime.get_name_or_anon().to_string(),
+            };
 
         let new_lt = {
             let generics = self.tcx.generics_of(lifetime_scope);
             let mut used_names =
                 iter::successors(Some(generics), |g| g.parent.map(|p| self.tcx.generics_of(p)))
-                    .flat_map(|g| &g.params)
+                    .flat_map(|g| &g.own_params)
                     .filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime))
                     .map(|p| p.name)
                     .collect::<Vec<_>>();
@@ -2528,6 +2602,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 
     fn report_sub_sup_conflict(
         &self,
+        generic_param_scope: LocalDefId,
         var_origin: RegionVariableOrigin,
         sub_origin: SubregionOrigin<'tcx>,
         sub_region: Region<'tcx>,
@@ -2539,6 +2614,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         note_and_explain_region(
             self.tcx,
             &mut err,
+            generic_param_scope,
             "first, the lifetime cannot outlive ",
             sup_region,
             "...",
@@ -2561,6 +2637,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             note_and_explain_region(
                 self.tcx,
                 &mut err,
+                generic_param_scope,
                 "...but the lifetime must also be valid for ",
                 sub_region,
                 "...",
@@ -2584,6 +2661,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         note_and_explain_region(
             self.tcx,
             &mut err,
+            generic_param_scope,
             "but, the lifetime must be valid for ",
             sub_region,
             "...",
@@ -2751,19 +2829,17 @@ pub enum FailureCode {
 #[extension(pub trait ObligationCauseExt<'tcx>)]
 impl<'tcx> ObligationCause<'tcx> {
     fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode {
-        use self::FailureCode::*;
-        use crate::traits::ObligationCauseCode::*;
         match self.code() {
-            IfExpressionWithNoElse => Error0317,
-            MainFunctionType => Error0580,
-            CompareImplItemObligation { .. }
-            | MatchExpressionArm(_)
-            | IfExpression { .. }
-            | LetElse
-            | StartFunctionType
-            | LangFunctionType(_)
-            | IntrinsicType
-            | MethodReceiver => Error0308,
+            ObligationCauseCode::IfExpressionWithNoElse => FailureCode::Error0317,
+            ObligationCauseCode::MainFunctionType => FailureCode::Error0580,
+            ObligationCauseCode::CompareImplItem { .. }
+            | ObligationCauseCode::MatchExpressionArm(_)
+            | ObligationCauseCode::IfExpression { .. }
+            | ObligationCauseCode::LetElse
+            | ObligationCauseCode::StartFunctionType
+            | ObligationCauseCode::LangFunctionType(_)
+            | ObligationCauseCode::IntrinsicType
+            | ObligationCauseCode::MethodReceiver => FailureCode::Error0308,
 
             // In the case where we have no more specific thing to
             // say, also take a look at the error code, maybe we can
@@ -2772,10 +2848,10 @@ impl<'tcx> ObligationCause<'tcx> {
                 TypeError::CyclicTy(ty)
                     if ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure() =>
                 {
-                    Error0644
+                    FailureCode::Error0644
                 }
-                TypeError::IntrinsicCast => Error0308,
-                _ => Error0308,
+                TypeError::IntrinsicCast => FailureCode::Error0308,
+                _ => FailureCode::Error0308,
             },
         }
     }
@@ -2785,36 +2861,51 @@ impl<'tcx> ObligationCause<'tcx> {
         span: Span,
         subdiags: Vec<TypeErrorAdditionalDiags>,
     ) -> ObligationCauseFailureCode {
-        use crate::traits::ObligationCauseCode::*;
         match self.code() {
-            CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => {
+            ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => {
                 ObligationCauseFailureCode::MethodCompat { span, subdiags }
             }
-            CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => {
+            ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => {
                 ObligationCauseFailureCode::TypeCompat { span, subdiags }
             }
-            CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => {
+            ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => {
                 ObligationCauseFailureCode::ConstCompat { span, subdiags }
             }
-            BlockTailExpression(.., hir::MatchSource::TryDesugar(_)) => {
+            ObligationCauseCode::BlockTailExpression(.., hir::MatchSource::TryDesugar(_)) => {
                 ObligationCauseFailureCode::TryCompat { span, subdiags }
             }
-            MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => match source {
+            ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
+                source, ..
+            }) => match source {
                 hir::MatchSource::TryDesugar(_) => {
                     ObligationCauseFailureCode::TryCompat { span, subdiags }
                 }
                 _ => ObligationCauseFailureCode::MatchCompat { span, subdiags },
             },
-            IfExpression { .. } => ObligationCauseFailureCode::IfElseDifferent { span, subdiags },
-            IfExpressionWithNoElse => ObligationCauseFailureCode::NoElse { span },
-            LetElse => ObligationCauseFailureCode::NoDiverge { span, subdiags },
-            MainFunctionType => ObligationCauseFailureCode::FnMainCorrectType { span },
-            StartFunctionType => ObligationCauseFailureCode::FnStartCorrectType { span, subdiags },
-            &LangFunctionType(lang_item_name) => {
+            ObligationCauseCode::IfExpression { .. } => {
+                ObligationCauseFailureCode::IfElseDifferent { span, subdiags }
+            }
+            ObligationCauseCode::IfExpressionWithNoElse => {
+                ObligationCauseFailureCode::NoElse { span }
+            }
+            ObligationCauseCode::LetElse => {
+                ObligationCauseFailureCode::NoDiverge { span, subdiags }
+            }
+            ObligationCauseCode::MainFunctionType => {
+                ObligationCauseFailureCode::FnMainCorrectType { span }
+            }
+            ObligationCauseCode::StartFunctionType => {
+                ObligationCauseFailureCode::FnStartCorrectType { span, subdiags }
+            }
+            &ObligationCauseCode::LangFunctionType(lang_item_name) => {
                 ObligationCauseFailureCode::FnLangCorrectType { span, subdiags, lang_item_name }
             }
-            IntrinsicType => ObligationCauseFailureCode::IntrinsicCorrectType { span, subdiags },
-            MethodReceiver => ObligationCauseFailureCode::MethodCorrectType { span, subdiags },
+            ObligationCauseCode::IntrinsicType => {
+                ObligationCauseFailureCode::IntrinsicCorrectType { span, subdiags }
+            }
+            ObligationCauseCode::MethodReceiver => {
+                ObligationCauseFailureCode::MethodCorrectType { span, subdiags }
+            }
 
             // In the case where we have no more specific thing to
             // say, also take a look at the error code, maybe we can
@@ -2834,22 +2925,21 @@ impl<'tcx> ObligationCause<'tcx> {
     }
 
     fn as_requirement_str(&self) -> &'static str {
-        use crate::traits::ObligationCauseCode::*;
         match self.code() {
-            CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => {
+            ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => {
                 "method type is compatible with trait"
             }
-            CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => {
+            ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => {
                 "associated type is compatible with trait"
             }
-            CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => {
+            ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => {
                 "const is compatible with trait"
             }
-            MainFunctionType => "`main` function has the correct type",
-            StartFunctionType => "`#[start]` function has the correct type",
-            LangFunctionType(_) => "lang item function has the correct type",
-            IntrinsicType => "intrinsic has the correct type",
-            MethodReceiver => "method receiver has the correct type",
+            ObligationCauseCode::MainFunctionType => "`main` function has the correct type",
+            ObligationCauseCode::StartFunctionType => "`#[start]` function has the correct type",
+            ObligationCauseCode::LangFunctionType(_) => "lang item function has the correct type",
+            ObligationCauseCode::IntrinsicType => "intrinsic has the correct type",
+            ObligationCauseCode::MethodReceiver => "method receiver has the correct type",
             _ => "types are compatible",
         }
     }
@@ -2860,16 +2950,17 @@ pub struct ObligationCauseAsDiagArg<'tcx>(pub ObligationCause<'tcx>);
 
 impl IntoDiagArg for ObligationCauseAsDiagArg<'_> {
     fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
-        use crate::traits::ObligationCauseCode::*;
         let kind = match self.0.code() {
-            CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => "method_compat",
-            CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => "type_compat",
-            CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => "const_compat",
-            MainFunctionType => "fn_main_correct_type",
-            StartFunctionType => "fn_start_correct_type",
-            LangFunctionType(_) => "fn_lang_correct_type",
-            IntrinsicType => "intrinsic_correct_type",
-            MethodReceiver => "method_correct_type",
+            ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => "method_compat",
+            ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => "type_compat",
+            ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => {
+                "const_compat"
+            }
+            ObligationCauseCode::MainFunctionType => "fn_main_correct_type",
+            ObligationCauseCode::StartFunctionType => "fn_start_correct_type",
+            ObligationCauseCode::LangFunctionType(_) => "fn_lang_correct_type",
+            ObligationCauseCode::IntrinsicType => "intrinsic_correct_type",
+            ObligationCauseCode::MethodReceiver => "method_correct_type",
             _ => "other",
         }
         .into();
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index a2a38d1c507..98fd7906e70 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -3,7 +3,6 @@ use crate::errors::{
     SourceKindMultiSuggestion, SourceKindSubdiag,
 };
 use crate::infer::error_reporting::TypeErrCtxt;
-use crate::infer::type_variable::TypeVariableOrigin;
 use crate::infer::InferCtxt;
 use rustc_errors::{codes::*, Diag, IntoDiagArg};
 use rustc_hir as hir;
@@ -12,8 +11,9 @@ use rustc_hir::def::{CtorOf, DefKind, Namespace};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, LetStmt, LocalSource};
+use rustc_middle::bug;
 use rustc_middle::hir::nested_filter;
-use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableValue};
+use rustc_middle::infer::unify_key::ConstVariableValue;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
 use rustc_middle::ty::{
@@ -168,7 +168,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ClosureEraser<'tcx> {
                 let closure_sig = args.as_closure().sig();
                 Ty::new_fn_ptr(
                     self.tcx,
-                    self.tcx.signature_unclosure(closure_sig, hir::Unsafety::Normal),
+                    self.tcx.signature_unclosure(closure_sig, hir::Safety::Safe),
                 )
             }
             _ => ty.super_fold_with(self),
@@ -522,7 +522,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 infer_subdiags.push(SourceKindSubdiag::GenericLabel {
                     span,
                     is_type,
-                    param_name: generics.params[argument_index].name.to_string(),
+                    param_name: generics.own_params[argument_index].name.to_string(),
                     parent_exists,
                     parent_prefix,
                     parent_name,
@@ -542,18 +542,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 
                             match arg.unpack() {
                                 GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
-                                GenericArgKind::Type(_) => self
-                                    .next_ty_var(TypeVariableOrigin {
-                                        span: DUMMY_SP,
-                                        param_def_id: None,
-                                    })
-                                    .into(),
-                                GenericArgKind::Const(arg) => self
-                                    .next_const_var(
-                                        arg.ty(),
-                                        ConstVariableOrigin { span: DUMMY_SP, param_def_id: None },
-                                    )
-                                    .into(),
+                                GenericArgKind::Type(_) => self.next_ty_var(DUMMY_SP).into(),
+                                GenericArgKind::Const(arg) => {
+                                    self.next_const_var(arg.ty(), DUMMY_SP).into()
+                                }
                             }
                         }))
                         .unwrap();
@@ -569,9 +561,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 }
             }
             InferSourceKind::FullyQualifiedMethodCall { receiver, successor, args, def_id } => {
-                let placeholder = Some(
-                    self.next_ty_var(TypeVariableOrigin { span: DUMMY_SP, param_def_id: None }),
-                );
+                let placeholder = Some(self.next_ty_var(DUMMY_SP));
                 if let Some(args) = args.make_suggestable(self.infcx.tcx, true, placeholder) {
                     let mut printer = fmt_printer(self, Namespace::ValueNS);
                     printer.print_def_path(def_id, args).unwrap();
@@ -605,9 +595,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 }
             }
             InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => {
-                let placeholder = Some(
-                    self.next_ty_var(TypeVariableOrigin { span: DUMMY_SP, param_def_id: None }),
-                );
+                let placeholder = Some(self.next_ty_var(DUMMY_SP));
                 if let Some(ty) = ty.make_suggestable(self.infcx.tcx, true, placeholder) {
                     let ty_info = ty_to_string(self, ty, None);
                     multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return(
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
index 84bfa5b5af7..cbeec591960 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
@@ -13,6 +13,7 @@ use crate::infer::TyCtxt;
 
 use rustc_errors::Subdiagnostic;
 use rustc_errors::{Diag, ErrorGuaranteed};
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::Ty;
 use rustc_middle::ty::Region;
 
@@ -66,17 +67,17 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         }
 
         // Determine whether the sub and sup consist of both anonymous (elided) regions.
-        let anon_reg_sup = self.tcx().is_suitable_region(sup)?;
+        let anon_reg_sup = self.tcx().is_suitable_region(self.generic_param_scope, sup)?;
 
-        let anon_reg_sub = self.tcx().is_suitable_region(sub)?;
+        let anon_reg_sub = self.tcx().is_suitable_region(self.generic_param_scope, sub)?;
         let scope_def_id_sup = anon_reg_sup.def_id;
         let bregion_sup = anon_reg_sup.bound_region;
         let scope_def_id_sub = anon_reg_sub.def_id;
         let bregion_sub = anon_reg_sub.bound_region;
 
-        let ty_sup = find_anon_type(self.tcx(), sup, &bregion_sup)?;
+        let ty_sup = find_anon_type(self.tcx(), self.generic_param_scope, sup, &bregion_sup)?;
 
-        let ty_sub = find_anon_type(self.tcx(), sub, &bregion_sub)?;
+        let ty_sub = find_anon_type(self.tcx(), self.generic_param_scope, sub, &bregion_sub)?;
 
         debug!(
             "try_report_anon_anon_conflict: found_param1={:?} sup={:?} br1={:?}",
@@ -127,8 +128,14 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             },
         };
 
-        let suggestion =
-            AddLifetimeParamsSuggestion { tcx: self.tcx(), sub, ty_sup, ty_sub, add_note: true };
+        let suggestion = AddLifetimeParamsSuggestion {
+            tcx: self.tcx(),
+            sub,
+            ty_sup,
+            ty_sub,
+            add_note: true,
+            generic_param_scope: self.generic_param_scope,
+        };
         let err = LifetimeMismatch { span, labels, suggestion };
         let reported = self.tcx().dcx().emit_err(err);
         Some(reported)
@@ -139,11 +146,19 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
 /// removed in favour of public_errors::AddLifetimeParamsSuggestion
 pub fn suggest_adding_lifetime_params<'tcx>(
     tcx: TyCtxt<'tcx>,
+    err: &mut Diag<'_>,
+    generic_param_scope: LocalDefId,
     sub: Region<'tcx>,
     ty_sup: &'tcx Ty<'_>,
     ty_sub: &'tcx Ty<'_>,
-    err: &mut Diag<'_>,
 ) {
-    let suggestion = AddLifetimeParamsSuggestion { tcx, sub, ty_sup, ty_sub, add_note: false };
+    let suggestion = AddLifetimeParamsSuggestion {
+        tcx,
+        sub,
+        ty_sup,
+        ty_sub,
+        add_note: false,
+        generic_param_scope,
+    };
     suggestion.add_to_diag(err);
 }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
index 265a315a559..b91b755d683 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
@@ -1,5 +1,6 @@
 use core::ops::ControlFlow;
 use rustc_hir as hir;
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter;
@@ -23,10 +24,11 @@ use rustc_middle::ty::{self, Region, TyCtxt};
 /// for e.g., `&u8` and `Vec<&u8>`.
 pub fn find_anon_type<'tcx>(
     tcx: TyCtxt<'tcx>,
+    generic_param_scope: LocalDefId,
     region: Region<'tcx>,
     br: &ty::BoundRegionKind,
 ) -> Option<(&'tcx hir::Ty<'tcx>, &'tcx hir::FnSig<'tcx>)> {
-    let anon_reg = tcx.is_suitable_region(region)?;
+    let anon_reg = tcx.is_suitable_region(generic_param_scope, region)?;
     let fn_sig = tcx.hir_node_by_def_id(anon_reg.def_id).fn_sig()?;
 
     fn_sig
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
index b93b8dc03f8..7996b4bf65b 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
@@ -13,6 +13,7 @@ use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{ErrorGuaranteed, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::intravisit::Visitor;
+use rustc_middle::bug;
 use rustc_middle::ty::TypeVisitor;
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
@@ -32,17 +33,20 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         // If we added a "points at argument expression" obligation, we remove it here, we care
         // about the original obligation only.
         let code = match cause.code() {
-            ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => &*parent_code,
+            ObligationCauseCode::FunctionArg { parent_code, .. } => &*parent_code,
             code => code,
         };
         let ObligationCauseCode::MatchImpl(parent, impl_def_id) = code else {
             return None;
         };
-        let (ObligationCauseCode::BindingObligation(_, binding_span)
-        | ObligationCauseCode::ExprBindingObligation(_, binding_span, ..)) = *parent.code()
+        let (ObligationCauseCode::WhereClause(_, binding_span)
+        | ObligationCauseCode::WhereClauseInExpr(_, binding_span, ..)) = *parent.code()
         else {
             return None;
         };
+        if binding_span.is_dummy() {
+            return None;
+        }
 
         // FIXME: we should point at the lifetime
         let multi_span: MultiSpan = vec![binding_span].into();
@@ -53,6 +57,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
 
         let expl = note_and_explain::RegionExplanation::new(
             self.tcx(),
+            self.generic_param_scope,
             sup,
             Some(binding_span),
             note_and_explain::PrefixKind::Empty,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
index 62c163f0b7f..cffdfa88752 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
@@ -2,6 +2,7 @@ use crate::infer::error_reporting::TypeErrCtxt;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
 use crate::infer::lexical_region_resolve::RegionResolutionError::*;
 use rustc_errors::{Diag, ErrorGuaranteed};
+use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::Span;
 
@@ -23,30 +24,39 @@ pub use util::find_param_with_region;
 impl<'cx, 'tcx> TypeErrCtxt<'cx, 'tcx> {
     pub fn try_report_nice_region_error(
         &'cx self,
+        generic_param_scope: LocalDefId,
         error: &RegionResolutionError<'tcx>,
     ) -> Option<ErrorGuaranteed> {
-        NiceRegionError::new(self, error.clone()).try_report()
+        NiceRegionError::new(self, generic_param_scope, error.clone()).try_report()
     }
 }
 
 pub struct NiceRegionError<'cx, 'tcx> {
     cx: &'cx TypeErrCtxt<'cx, 'tcx>,
+    /// The innermost definition that introduces generic parameters that may be involved in
+    /// the region errors we are dealing with.
+    generic_param_scope: LocalDefId,
     error: Option<RegionResolutionError<'tcx>>,
     regions: Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)>,
 }
 
 impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> {
-    pub fn new(cx: &'cx TypeErrCtxt<'cx, 'tcx>, error: RegionResolutionError<'tcx>) -> Self {
-        Self { cx, error: Some(error), regions: None }
+    pub fn new(
+        cx: &'cx TypeErrCtxt<'cx, 'tcx>,
+        generic_param_scope: LocalDefId,
+        error: RegionResolutionError<'tcx>,
+    ) -> Self {
+        Self { cx, error: Some(error), regions: None, generic_param_scope }
     }
 
     pub fn new_from_span(
         cx: &'cx TypeErrCtxt<'cx, 'tcx>,
+        generic_param_scope: LocalDefId,
         span: Span,
         sub: ty::Region<'tcx>,
         sup: ty::Region<'tcx>,
     ) -> Self {
-        Self { cx, error: None, regions: Some((span, sub, sup)) }
+        Self { cx, error: None, regions: Some((span, sub, sup)), generic_param_scope }
     }
 
     fn tcx(&self) -> TyCtxt<'tcx> {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
index 239c2db30e2..29da12e7d15 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
@@ -27,12 +27,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         // version new_ty of its type where the anonymous region is replaced
         // with the named one.
         let (named, anon, anon_param_info, region_info) = if sub.has_name()
-            && let Some(region_info) = self.tcx().is_suitable_region(sup)
+            && let Some(region_info) = self.tcx().is_suitable_region(self.generic_param_scope, sup)
             && let Some(anon_param_info) = self.find_param_with_region(sup, sub)
         {
             (sub, sup, anon_param_info, region_info)
         } else if sup.has_name()
-            && let Some(region_info) = self.tcx().is_suitable_region(sub)
+            && let Some(region_info) = self.tcx().is_suitable_region(self.generic_param_scope, sub)
             && let Some(anon_param_info) = self.find_param_with_region(sub, sup)
         {
             (sup, sub, anon_param_info, region_info)
@@ -72,7 +72,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             return None;
         }
 
-        if find_anon_type(self.tcx(), anon, &br).is_some()
+        if find_anon_type(self.tcx(), self.generic_param_scope, anon, &br).is_some()
             && self.is_self_anon(is_first, scope_def_id)
         {
             return None;
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
index 01e75d59f4d..e125f1858dd 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
@@ -10,9 +10,10 @@ use crate::traits::{ObligationCause, ObligationCauseCode};
 use rustc_data_structures::intern::Interned;
 use rustc_errors::{Diag, IntoDiagArg};
 use rustc_hir::def::Namespace;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
+use rustc_middle::bug;
 use rustc_middle::ty::error::ExpectedFound;
-use rustc_middle::ty::print::{FmtPrinter, Print, RegionHighlightMode};
+use rustc_middle::ty::print::{FmtPrinter, Print, PrintTraitRefExt as _, RegionHighlightMode};
 use rustc_middle::ty::GenericArgsRef;
 use rustc_middle::ty::{self, RePlaceholder, Region, TyCtxt};
 
@@ -240,8 +241,9 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
         let span = cause.span();
 
         let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) =
-            if let ObligationCauseCode::ItemObligation(def_id)
-            | ObligationCauseCode::ExprItemObligation(def_id, ..) = *cause.code()
+            if let ObligationCauseCode::WhereClause(def_id, span)
+            | ObligationCauseCode::WhereClauseInExpr(def_id, span, ..) = *cause.code()
+                && def_id != CRATE_DEF_ID.to_def_id()
             {
                 (
                     true,
@@ -407,10 +409,8 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
             {
                 let closure_sig = self_ty.map(|closure| {
                     if let ty::Closure(_, args) = closure.kind() {
-                        self.tcx().signature_unclosure(
-                            args.as_closure().sig(),
-                            rustc_hir::Unsafety::Normal,
-                        )
+                        self.tcx()
+                            .signature_unclosure(args.as_closure().sig(), rustc_hir::Safety::Safe)
                     } else {
                         bug!("type is not longer closure");
                     }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index 0bbabefaf95..71a86683c21 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -49,7 +49,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                 if let ObligationCauseCode::UnifyReceiver(ctxt) = cause.code() {
                     // This may have a closure and it would cause ICE
                     // through `find_param_with_region` (#78262).
-                    let anon_reg_sup = tcx.is_suitable_region(*sup_r)?;
+                    let anon_reg_sup = tcx.is_suitable_region(self.generic_param_scope, *sup_r)?;
                     let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
                     if fn_returns.is_empty() {
                         return None;
@@ -92,7 +92,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",
             var_origin, sub_origin, sub_r, sup_origin, sup_r
         );
-        let anon_reg_sup = tcx.is_suitable_region(*sup_r)?;
+        let anon_reg_sup = tcx.is_suitable_region(self.generic_param_scope, *sup_r)?;
         debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);
         let sp = var_origin.span();
         let return_sp = sub_origin.span();
@@ -214,8 +214,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                 _ => cause.code(),
             }
             && let (
-                &ObligationCauseCode::ItemObligation(item_def_id)
-                | &ObligationCauseCode::ExprItemObligation(item_def_id, ..),
+                &ObligationCauseCode::WhereClause(item_def_id, _)
+                | &ObligationCauseCode::WhereClauseInExpr(item_def_id, ..),
                 None,
             ) = (code, override_error_code)
         {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index b4cf727bf8f..7f3e23716f9 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -4,13 +4,13 @@ use crate::errors::{ConsiderBorrowingParamHelp, RelationshipHelp, TraitImplDiff}
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
 use crate::infer::{Subtype, ValuePairs};
-use crate::traits::ObligationCauseCode::CompareImplItemObligation;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
 use rustc_middle::hir::nested_filter;
+use rustc_middle::traits::ObligationCauseCode;
 use rustc_middle::ty::error::ExpectedFound;
 use rustc_middle::ty::print::RegionHighlightMode;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor};
@@ -31,7 +31,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             _,
         ) = error.clone()
             && let (Subtype(sup_trace), Subtype(sub_trace)) = (&sup_origin, &sub_origin)
-            && let CompareImplItemObligation { trait_item_def_id, .. } = sub_trace.cause.code()
+            && let ObligationCauseCode::CompareImplItem { trait_item_def_id, .. } =
+                sub_trace.cause.code()
             && sub_trace.values == sup_trace.values
             && let ValuePairs::PolySigs(ExpectedFound { expected, found }) = sub_trace.values
         {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
index f1f8314661f..5f3f1081ca8 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
@@ -37,13 +37,15 @@ pub struct AnonymousParamInfo<'tcx> {
 #[instrument(skip(tcx), level = "debug")]
 pub fn find_param_with_region<'tcx>(
     tcx: TyCtxt<'tcx>,
+    generic_param_scope: LocalDefId,
     anon_region: Region<'tcx>,
     replace_region: Region<'tcx>,
 ) -> Option<AnonymousParamInfo<'tcx>> {
     let (id, bound_region) = match *anon_region {
         ty::ReLateParam(late_param) => (late_param.scope, late_param.bound_region),
         ty::ReEarlyParam(ebr) => {
-            (tcx.parent(ebr.def_id), ty::BoundRegionKind::BrNamed(ebr.def_id, ebr.name))
+            let region_def = tcx.generics_of(generic_param_scope).region_param(ebr, tcx).def_id;
+            (tcx.parent(region_def), ty::BoundRegionKind::BrNamed(region_def, ebr.name))
         }
         _ => return None, // not a free region
     };
@@ -53,7 +55,7 @@ pub fn find_param_with_region<'tcx>(
 
     // FIXME: use def_kind
     // Don't perform this on closures
-    match tcx.hir_node_by_def_id(def_id) {
+    match tcx.hir_node_by_def_id(generic_param_scope) {
         hir::Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
             return None;
         }
@@ -110,7 +112,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         anon_region: Region<'tcx>,
         replace_region: Region<'tcx>,
     ) -> Option<AnonymousParamInfo<'tcx>> {
-        find_param_with_region(self.tcx(), anon_region, replace_region)
+        find_param_with_region(self.tcx(), self.generic_param_scope, anon_region, replace_region)
     }
 
     // Here, we check for the case where the anonymous region
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index 3ae1165d2a4..acb74f8a82c 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -75,6 +75,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 
     pub(super) fn report_concrete_failure(
         &self,
+        generic_param_scope: LocalDefId,
         origin: SubregionOrigin<'tcx>,
         sub: Region<'tcx>,
         sup: Region<'tcx>,
@@ -89,6 +90,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         note_and_explain_region(
                             self.tcx,
                             &mut err,
+                            generic_param_scope,
                             "",
                             sup,
                             " doesn't meet the lifetime requirements",
@@ -99,6 +101,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         note_and_explain_region(
                             self.tcx,
                             &mut err,
+                            generic_param_scope,
                             "the required lifetime does not necessarily outlive ",
                             sub,
                             "",
@@ -106,10 +109,19 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         );
                     }
                     _ => {
-                        note_and_explain_region(self.tcx, &mut err, "", sup, "...", None);
                         note_and_explain_region(
                             self.tcx,
                             &mut err,
+                            generic_param_scope,
+                            "",
+                            sup,
+                            "...",
+                            None,
+                        );
+                        note_and_explain_region(
+                            self.tcx,
+                            &mut err,
+                            generic_param_scope,
                             "...does not necessarily outlive ",
                             sub,
                             "",
@@ -122,6 +134,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             infer::Reborrow(span) => {
                 let reference_valid = note_and_explain::RegionExplanation::new(
                     self.tcx,
+                    generic_param_scope,
                     sub,
                     None,
                     note_and_explain::PrefixKind::RefValidFor,
@@ -129,6 +142,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 );
                 let content_valid = note_and_explain::RegionExplanation::new(
                     self.tcx,
+                    generic_param_scope,
                     sup,
                     None,
                     note_and_explain::PrefixKind::ContentValidFor,
@@ -142,6 +156,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             infer::RelateObjectBound(span) => {
                 let object_valid = note_and_explain::RegionExplanation::new(
                     self.tcx,
+                    generic_param_scope,
                     sub,
                     None,
                     note_and_explain::PrefixKind::TypeObjValidFor,
@@ -149,6 +164,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 );
                 let pointer_valid = note_and_explain::RegionExplanation::new(
                     self.tcx,
+                    generic_param_scope,
                     sup,
                     None,
                     note_and_explain::PrefixKind::SourcePointerValidFor,
@@ -170,7 +186,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     note_and_explain::SuffixKind::Empty
                 };
                 let note = note_and_explain::RegionExplanation::new(
-                    self.tcx, sub, opt_span, prefix, suffix,
+                    self.tcx,
+                    generic_param_scope,
+                    sub,
+                    opt_span,
+                    prefix,
+                    suffix,
                 );
                 self.dcx().create_err(FulfillReqLifetime {
                     span,
@@ -181,6 +202,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             infer::RelateRegionParamBound(span) => {
                 let param_instantiated = note_and_explain::RegionExplanation::new(
                     self.tcx,
+                    generic_param_scope,
                     sup,
                     None,
                     note_and_explain::PrefixKind::LfParamInstantiatedWith,
@@ -188,6 +210,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 );
                 let param_must_outlive = note_and_explain::RegionExplanation::new(
                     self.tcx,
+                    generic_param_scope,
                     sub,
                     None,
                     note_and_explain::PrefixKind::LfParamMustOutlive,
@@ -201,6 +224,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             infer::ReferenceOutlivesReferent(ty, span) => {
                 let pointer_valid = note_and_explain::RegionExplanation::new(
                     self.tcx,
+                    generic_param_scope,
                     sub,
                     None,
                     note_and_explain::PrefixKind::PointerValidFor,
@@ -208,6 +232,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 );
                 let data_valid = note_and_explain::RegionExplanation::new(
                     self.tcx,
+                    generic_param_scope,
                     sup,
                     None,
                     note_and_explain::PrefixKind::DataValidFor,
@@ -239,7 +264,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 err
             }
             infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
-                let mut err = self.report_concrete_failure(*parent, sub, sup);
+                let mut err = self.report_concrete_failure(generic_param_scope, *parent, sub, sup);
 
                 // Don't mention the item name if it's an RPITIT, since that'll just confuse
                 // folks.
@@ -262,6 +287,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             infer::AscribeUserTypeProvePredicate(span) => {
                 let instantiated = note_and_explain::RegionExplanation::new(
                     self.tcx,
+                    generic_param_scope,
                     sup,
                     None,
                     note_and_explain::PrefixKind::LfInstantiatedWith,
@@ -269,6 +295,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 );
                 let must_outlive = note_and_explain::RegionExplanation::new(
                     self.tcx,
+                    generic_param_scope,
                     sub,
                     None,
                     note_and_explain::PrefixKind::LfMustOutlive,
@@ -347,6 +374,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 
     pub(super) fn report_placeholder_failure(
         &self,
+        generic_param_scope: LocalDefId,
         placeholder_origin: SubregionOrigin<'tcx>,
         sub: Region<'tcx>,
         sup: Region<'tcx>,
@@ -357,21 +385,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             infer::Subtype(box ref trace)
                 if matches!(
                     &trace.cause.code().peel_derives(),
-                    ObligationCauseCode::BindingObligation(..)
-                        | ObligationCauseCode::ExprBindingObligation(..)
+                    ObligationCauseCode::WhereClause(..)
+                        | ObligationCauseCode::WhereClauseInExpr(..)
                 ) =>
             {
                 // Hack to get around the borrow checker because trace.cause has an `Rc`.
-                if let ObligationCauseCode::BindingObligation(_, span)
-                | ObligationCauseCode::ExprBindingObligation(_, span, ..) =
+                if let ObligationCauseCode::WhereClause(_, span)
+                | ObligationCauseCode::WhereClauseInExpr(_, span, ..) =
                     &trace.cause.code().peel_derives()
+                    && !span.is_dummy()
                 {
                     let span = *span;
-                    self.report_concrete_failure(placeholder_origin, sub, sup)
+                    self.report_concrete_failure(generic_param_scope, placeholder_origin, sub, sup)
                         .with_span_note(span, "the lifetime requirement is introduced here")
                 } else {
                     unreachable!(
-                        "control flow ensures we have a `BindingObligation` or `ExprBindingObligation` here..."
+                        "control flow ensures we have a `BindingObligation` or `WhereClauseInExpr` here..."
                     )
                 }
             }
@@ -379,7 +408,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 let terr = TypeError::RegionsPlaceholderMismatch;
                 return self.report_and_explain_type_error(trace, terr);
             }
-            _ => return self.report_concrete_failure(placeholder_origin, sub, sup),
+            _ => {
+                return self.report_concrete_failure(
+                    generic_param_scope,
+                    placeholder_origin,
+                    sub,
+                    sup,
+                );
+            }
         }
     }
 }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
index 008b75b4c9a..f4514c23508 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
@@ -28,7 +28,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 
         match err {
             ArgumentSorts(values, _) | Sorts(values) => {
-                match (values.expected.kind(), values.found.kind()) {
+                match (*values.expected.kind(), *values.found.kind()) {
                     (ty::Closure(..), ty::Closure(..)) => {
                         diag.note("no two closures, even if identical, have the same type");
                         diag.help("consider boxing your closure and/or using it as a trait object");
@@ -54,17 +54,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     }
                     (ty::Param(expected), ty::Param(found)) => {
                         let generics = tcx.generics_of(body_owner_def_id);
-                        if let Some(param) = generics.opt_type_param(expected, tcx) {
-                            let e_span = tcx.def_span(param.def_id);
-                            if !sp.contains(e_span) {
-                                diag.span_label(e_span, "expected type parameter");
-                            }
+                        let e_span = tcx.def_span(generics.type_param(expected, tcx).def_id);
+                        if !sp.contains(e_span) {
+                            diag.span_label(e_span, "expected type parameter");
                         }
-                        if let Some(param) = generics.opt_type_param(found, tcx) {
-                            let f_span = tcx.def_span(param.def_id);
-                            if !sp.contains(f_span) {
-                                diag.span_label(f_span, "found type parameter");
-                            }
+                        let f_span = tcx.def_span(generics.type_param(found, tcx).def_id);
+                        if !sp.contains(f_span) {
+                            diag.span_label(f_span, "found type parameter");
                         }
                         diag.note(
                             "a type parameter was expected, but a different one was found; \
@@ -87,29 +83,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     | (ty::Alias(ty::Projection, proj), ty::Param(p))
                         if !tcx.is_impl_trait_in_trait(proj.def_id) =>
                     {
-                        let parent = tcx
-                            .generics_of(body_owner_def_id)
-                            .opt_type_param(p, tcx)
-                            .and_then(|param| {
-                                let p_def_id = param.def_id;
-                                let p_span = tcx.def_span(p_def_id);
-                                let expected = match (values.expected.kind(), values.found.kind()) {
-                                    (ty::Param(_), _) => "expected ",
-                                    (_, ty::Param(_)) => "found ",
-                                    _ => "",
-                                };
-                                if !sp.contains(p_span) {
-                                    diag.span_label(
-                                        p_span,
-                                        format!("{expected}this type parameter"),
-                                    );
-                                }
-                                p_def_id.as_local().and_then(|id| {
-                                    let local_id = tcx.local_def_id_to_hir_id(id);
-                                    let generics = tcx.parent_hir_node(local_id).generics()?;
-                                    Some((id, generics))
-                                })
-                            });
+                        let param = tcx.generics_of(body_owner_def_id).type_param(p, tcx);
+                        let p_def_id = param.def_id;
+                        let p_span = tcx.def_span(p_def_id);
+                        let expected = match (values.expected.kind(), values.found.kind()) {
+                            (ty::Param(_), _) => "expected ",
+                            (_, ty::Param(_)) => "found ",
+                            _ => "",
+                        };
+                        if !sp.contains(p_span) {
+                            diag.span_label(p_span, format!("{expected}this type parameter"));
+                        }
+                        let parent = p_def_id.as_local().and_then(|id| {
+                            let local_id = tcx.local_def_id_to_hir_id(id);
+                            let generics = tcx.parent_hir_node(local_id).generics()?;
+                            Some((id, generics))
+                        });
                         let mut note = true;
                         if let Some((local_id, generics)) = parent {
                             // Synthesize the associated type restriction `Add<Output = Expected>`.
@@ -183,16 +172,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     (ty::Param(p), ty::Dynamic(..) | ty::Alias(ty::Opaque, ..))
                     | (ty::Dynamic(..) | ty::Alias(ty::Opaque, ..), ty::Param(p)) => {
                         let generics = tcx.generics_of(body_owner_def_id);
-                        if let Some(param) = generics.opt_type_param(p, tcx) {
-                            let p_span = tcx.def_span(param.def_id);
-                            let expected = match (values.expected.kind(), values.found.kind()) {
-                                (ty::Param(_), _) => "expected ",
-                                (_, ty::Param(_)) => "found ",
-                                _ => "",
-                            };
-                            if !sp.contains(p_span) {
-                                diag.span_label(p_span, format!("{expected}this type parameter"));
-                            }
+                        let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
+                        let expected = match (values.expected.kind(), values.found.kind()) {
+                            (ty::Param(_), _) => "expected ",
+                            (_, ty::Param(_)) => "found ",
+                            _ => "",
+                        };
+                        if !sp.contains(p_span) {
+                            diag.span_label(p_span, format!("{expected}this type parameter"));
                         }
                         diag.help("type parameters must be constrained to match other types");
                         if tcx.sess.teach(diag.code.unwrap()) {
@@ -233,11 +220,9 @@ impl<T> Trait<T> for X {
                         ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..),
                     ) => {
                         let generics = tcx.generics_of(body_owner_def_id);
-                        if let Some(param) = generics.opt_type_param(p, tcx) {
-                            let p_span = tcx.def_span(param.def_id);
-                            if !sp.contains(p_span) {
-                                diag.span_label(p_span, "expected this type parameter");
-                            }
+                        let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
+                        if !sp.contains(p_span) {
+                            diag.span_label(p_span, "expected this type parameter");
                         }
                         diag.help(format!(
                             "every closure has a distinct type and so could not always match the \
@@ -246,16 +231,14 @@ impl<T> Trait<T> for X {
                     }
                     (ty::Param(p), _) | (_, ty::Param(p)) => {
                         let generics = tcx.generics_of(body_owner_def_id);
-                        if let Some(param) = generics.opt_type_param(p, tcx) {
-                            let p_span = tcx.def_span(param.def_id);
-                            let expected = match (values.expected.kind(), values.found.kind()) {
-                                (ty::Param(_), _) => "expected ",
-                                (_, ty::Param(_)) => "found ",
-                                _ => "",
-                            };
-                            if !sp.contains(p_span) {
-                                diag.span_label(p_span, format!("{expected}this type parameter"));
-                            }
+                        let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
+                        let expected = match (values.expected.kind(), values.found.kind()) {
+                            (ty::Param(_), _) => "expected ",
+                            (_, ty::Param(_)) => "found ",
+                            _ => "",
+                        };
+                        if !sp.contains(p_span) {
+                            diag.span_label(p_span, format!("{expected}this type parameter"));
                         }
                     }
                     (ty::Alias(ty::Projection | ty::Inherent, proj_ty), _)
@@ -452,7 +435,7 @@ impl<T> Trait<T> for X {
                     }
                     (ty::FnPtr(sig), ty::FnDef(def_id, _))
                     | (ty::FnDef(def_id, _), ty::FnPtr(sig)) => {
-                        if tcx.fn_sig(*def_id).skip_binder().unsafety() < sig.unsafety() {
+                        if tcx.fn_sig(def_id).skip_binder().safety() < sig.safety() {
                             diag.note(
                                 "unsafe functions cannot be coerced into safe function pointers",
                             );
@@ -527,7 +510,7 @@ impl<T> Trait<T> for X {
         diag: &mut Diag<'_>,
         msg: impl Fn() -> String,
         body_owner_def_id: DefId,
-        proj_ty: &ty::AliasTy<'tcx>,
+        proj_ty: ty::AliasTy<'tcx>,
         ty: Ty<'tcx>,
     ) -> bool {
         let tcx = self.tcx;
@@ -541,14 +524,12 @@ impl<T> Trait<T> for X {
         };
         // Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`.
         // This will also work for `impl Trait`.
-        let ty::Param(param_ty) = proj_ty.self_ty().kind() else {
+        let ty::Param(param_ty) = *proj_ty.self_ty().kind() else {
             return false;
         };
         let generics = tcx.generics_of(body_owner_def_id);
-        let Some(param) = generics.opt_type_param(param_ty, tcx) else {
-            return false;
-        };
-        let Some(def_id) = param.def_id.as_local() else {
+        let def_id = generics.type_param(param_ty, tcx).def_id;
+        let Some(def_id) = def_id.as_local() else {
             return false;
         };
 
@@ -598,7 +579,7 @@ impl<T> Trait<T> for X {
     fn expected_projection(
         &self,
         diag: &mut Diag<'_>,
-        proj_ty: &ty::AliasTy<'tcx>,
+        proj_ty: ty::AliasTy<'tcx>,
         values: ExpectedFound<Ty<'tcx>>,
         body_owner_def_id: DefId,
         cause_code: &ObligationCauseCode<'_>,
@@ -629,8 +610,7 @@ impl<T> Trait<T> for X {
                     | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }),
             )
         );
-        let impl_comparison =
-            matches!(cause_code, ObligationCauseCode::CompareImplItemObligation { .. });
+        let impl_comparison = matches!(cause_code, ObligationCauseCode::CompareImplItem { .. });
         let assoc = tcx.associated_item(proj_ty.def_id);
         if impl_comparison {
             // We do not want to suggest calling functions when the reason of the
@@ -709,7 +689,7 @@ fn foo(&self) -> Self::T { String::new() }
         &self,
         diag: &mut Diag<'_>,
         msg: impl Fn() -> String,
-        proj_ty: &ty::AliasTy<'tcx>,
+        proj_ty: ty::AliasTy<'tcx>,
         ty: Ty<'tcx>,
     ) -> bool {
         let tcx = self.tcx;
diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
index bf470bb1e3f..75479decebc 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
@@ -167,7 +167,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             exp_span, exp_found.expected, exp_found.found,
         );
 
-        if let ObligationCauseCode::CompareImplItemObligation { .. } = cause.code() {
+        if let ObligationCauseCode::CompareImplItem { .. } = cause.code() {
             return;
         }
 
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index ef9c407acef..b2d89523ea8 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -32,6 +32,7 @@
 //! inferencer knows "so far".
 use super::InferCtxt;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_middle::bug;
 use rustc_middle::infer::unify_key::ToType;
 use rustc_middle::ty::fold::TypeFolder;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitableExt};
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index 5ae7f8bf504..72944c9c7de 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -20,6 +20,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{ReBound, RePlaceholder, ReVar};
 use rustc_middle::ty::{ReEarlyParam, ReErased, ReError, ReLateParam, ReStatic};
 use rustc_middle::ty::{Region, RegionVid};
+use rustc_middle::{bug, span_bug};
 use rustc_span::Span;
 use std::fmt;
 
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 255e688fbc1..c8bb6cf5f9b 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -4,6 +4,7 @@ pub use lexical_region_resolve::RegionResolutionError;
 pub use relate::combine::CombineFields;
 pub use relate::combine::ObligationEmittingRelation;
 pub use relate::StructurallyRelateAliases;
+pub use rustc_macros::{TypeFoldable, TypeVisitable};
 pub use rustc_middle::ty::IntVarValue;
 pub use BoundRegionConversionTime::*;
 pub use RegionVariableOrigin::*;
@@ -20,13 +21,13 @@ use opaque_types::OpaqueTypeStorage;
 use region_constraints::{GenericKind, VarInfos, VerifyBound};
 use region_constraints::{RegionConstraintCollector, RegionConstraintStorage};
 use rustc_data_structures::captures::Captures;
-use rustc_data_structures::fx::FxIndexMap;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::undo_log::Rollback;
 use rustc_data_structures::unify as ut;
 use rustc_errors::{Diag, DiagCtxt, ErrorGuaranteed};
 use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_macros::extension;
 use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
 use rustc_middle::infer::unify_key::ConstVariableValue;
 use rustc_middle::infer::unify_key::EffectVarValue;
@@ -43,6 +44,7 @@ use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{self, GenericParamDefKind, InferConst, InferTy, Ty, TyCtxt};
 use rustc_middle::ty::{ConstVid, EffectVid, FloatVid, IntVid, TyVid};
 use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgs, GenericArgsRef};
+use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 use snapshot::undo_log::InferCtxtUndoLogs;
@@ -367,33 +369,43 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> {
         }
     }
 
-    fn root_ty_var(&self, vid: TyVid) -> TyVid {
-        self.root_var(vid)
+    fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> {
+        self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid)
     }
 
-    fn probe_ty_var(&self, vid: TyVid) -> Option<Ty<'tcx>> {
-        self.probe_ty_var(vid).ok()
+    fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
+        self.defining_opaque_types
     }
 
-    fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> Option<ty::Region<'tcx>> {
-        let re = self
-            .inner
-            .borrow_mut()
-            .unwrap_region_constraints()
-            .opportunistic_resolve_var(self.tcx, vid);
-        if *re == ty::ReVar(vid) { None } else { Some(re) }
+    fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> Ty<'tcx> {
+        match self.probe_ty_var(vid) {
+            Ok(ty) => ty,
+            Err(_) => Ty::new_var(self.tcx, self.root_var(vid)),
+        }
     }
 
-    fn root_ct_var(&self, vid: ConstVid) -> ConstVid {
-        self.root_const_var(vid)
+    fn opportunistic_resolve_int_var(&self, vid: IntVid) -> Ty<'tcx> {
+        self.opportunistic_resolve_int_var(vid)
     }
 
-    fn probe_ct_var(&self, vid: ConstVid) -> Option<ty::Const<'tcx>> {
-        self.probe_const_var(vid).ok()
+    fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> Ty<'tcx> {
+        self.opportunistic_resolve_float_var(vid)
     }
 
-    fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
-        self.defining_opaque_types
+    fn opportunistic_resolve_ct_var(&self, vid: ConstVid, ty: Ty<'tcx>) -> ty::Const<'tcx> {
+        match self.probe_const_var(vid) {
+            Ok(ct) => ct,
+            Err(_) => ty::Const::new_var(self.tcx, self.root_const_var(vid), ty),
+        }
+    }
+
+    fn opportunistic_resolve_effect_var(&self, vid: EffectVid, ty: Ty<'tcx>) -> ty::Const<'tcx> {
+        match self.probe_effect_var(vid) {
+            Some(ct) => ct,
+            None => {
+                ty::Const::new_infer(self.tcx, InferConst::EffectVar(self.root_effect_var(vid)), ty)
+            }
+        }
     }
 }
 
@@ -402,7 +414,7 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> {
 pub enum ValuePairs<'tcx> {
     Regions(ExpectedFound<ty::Region<'tcx>>),
     Terms(ExpectedFound<ty::Term<'tcx>>),
-    Aliases(ExpectedFound<ty::AliasTy<'tcx>>),
+    Aliases(ExpectedFound<ty::AliasTerm<'tcx>>),
     TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>),
     PolySigs(ExpectedFound<ty::PolyFnSig<'tcx>>),
     ExistentialTraitRef(ExpectedFound<ty::PolyExistentialTraitRef<'tcx>>),
@@ -477,8 +489,8 @@ pub enum SubregionOrigin<'tcx> {
 }
 
 // `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
-static_assert_size!(SubregionOrigin<'_>, 32);
+#[cfg(target_pointer_width = "64")]
+rustc_data_structures::static_assert_size!(SubregionOrigin<'_>, 32);
 
 impl<'tcx> SubregionOrigin<'tcx> {
     pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> {
@@ -527,8 +539,8 @@ pub enum RegionVariableOrigin {
 
     /// Region variables created as the values for early-bound regions.
     ///
-    /// FIXME(@lcnr): This can also store a `DefId`, similar to
-    /// `TypeVariableOriginKind::TypeParameterDefinition`.
+    /// FIXME(@lcnr): This should also store a `DefId`, similar to
+    /// `TypeVariableOrigin`.
     RegionParameterDefinition(Span, Symbol),
 
     /// Region variables created when instantiating a binder with
@@ -824,21 +836,6 @@ impl<'tcx> InferCtxt<'tcx> {
             .collect()
     }
 
-    fn combine_fields<'a>(
-        &'a self,
-        trace: TypeTrace<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        define_opaque_types: DefineOpaqueTypes,
-    ) -> CombineFields<'a, 'tcx> {
-        CombineFields {
-            infcx: self,
-            trace,
-            param_env,
-            obligations: PredicateObligations::new(),
-            define_opaque_types,
-        }
-    }
-
     pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, expected: T, actual: T) -> bool
     where
         T: at::ToTrace<'tcx>,
@@ -945,27 +942,14 @@ impl<'tcx> InferCtxt<'tcx> {
             (&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => {
                 return Err((a_vid, b_vid));
             }
-            // We don't silently want to constrain hidden types here, so we assert that either one side is
-            // an infer var, so it'll get constrained to whatever the other side is, or there are no opaque
-            // types involved.
-            // We don't expect this to actually get hit, but if it does, we now at least know how to write
-            // a test for it.
-            (_, ty::Infer(ty::TyVar(_))) => {}
-            (ty::Infer(ty::TyVar(_)), _) => {}
-            _ if r_a != r_b && (r_a, r_b).has_opaque_types() => {
-                span_bug!(
-                    cause.span(),
-                    "opaque types got hidden types registered from within subtype predicate: {r_a:?} vs {r_b:?}"
-                )
-            }
             _ => {}
         }
 
         self.enter_forall(predicate, |ty::SubtypePredicate { a_is_expected, a, b }| {
             if a_is_expected {
-                Ok(self.at(cause, param_env).sub(DefineOpaqueTypes::Yes, a, b))
+                Ok(self.at(cause, param_env).sub(DefineOpaqueTypes::No, a, b))
             } else {
-                Ok(self.at(cause, param_env).sup(DefineOpaqueTypes::Yes, b, a))
+                Ok(self.at(cause, param_env).sup(DefineOpaqueTypes::No, b, a))
             }
         })
     }
@@ -988,72 +972,67 @@ impl<'tcx> InferCtxt<'tcx> {
         self.inner.borrow_mut().type_variables().num_vars()
     }
 
-    pub fn next_ty_var_id(&self, origin: TypeVariableOrigin) -> TyVid {
-        self.inner.borrow_mut().type_variables().new_var(self.universe(), origin)
+    pub fn next_ty_var(&self, span: Span) -> Ty<'tcx> {
+        self.next_ty_var_with_origin(TypeVariableOrigin { span, param_def_id: None })
     }
 
-    pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
-        Ty::new_var(self.tcx, self.next_ty_var_id(origin))
+    pub fn next_ty_var_with_origin(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
+        let vid = self.inner.borrow_mut().type_variables().new_var(self.universe(), origin);
+        Ty::new_var(self.tcx, vid)
     }
 
-    pub fn next_ty_var_id_in_universe(
-        &self,
-        origin: TypeVariableOrigin,
-        universe: ty::UniverseIndex,
-    ) -> TyVid {
+    pub fn next_ty_var_id_in_universe(&self, span: Span, universe: ty::UniverseIndex) -> TyVid {
+        let origin = TypeVariableOrigin { span, param_def_id: None };
         self.inner.borrow_mut().type_variables().new_var(universe, origin)
     }
 
-    pub fn next_ty_var_in_universe(
-        &self,
-        origin: TypeVariableOrigin,
-        universe: ty::UniverseIndex,
-    ) -> Ty<'tcx> {
-        let vid = self.next_ty_var_id_in_universe(origin, universe);
+    pub fn next_ty_var_in_universe(&self, span: Span, universe: ty::UniverseIndex) -> Ty<'tcx> {
+        let vid = self.next_ty_var_id_in_universe(span, universe);
         Ty::new_var(self.tcx, vid)
     }
 
-    pub fn next_const_var(&self, ty: Ty<'tcx>, origin: ConstVariableOrigin) -> ty::Const<'tcx> {
-        ty::Const::new_var(self.tcx, self.next_const_var_id(origin), ty)
+    pub fn next_const_var(&self, ty: Ty<'tcx>, span: Span) -> ty::Const<'tcx> {
+        self.next_const_var_with_origin(ty, ConstVariableOrigin { span, param_def_id: None })
     }
 
-    pub fn next_const_var_in_universe(
+    pub fn next_const_var_with_origin(
         &self,
         ty: Ty<'tcx>,
         origin: ConstVariableOrigin,
-        universe: ty::UniverseIndex,
     ) -> ty::Const<'tcx> {
         let vid = self
             .inner
             .borrow_mut()
             .const_unification_table()
-            .new_key(ConstVariableValue::Unknown { origin, universe })
+            .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() })
             .vid;
         ty::Const::new_var(self.tcx, vid, ty)
     }
 
-    pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid {
-        self.inner
+    pub fn next_const_var_in_universe(
+        &self,
+        ty: Ty<'tcx>,
+        span: Span,
+        universe: ty::UniverseIndex,
+    ) -> ty::Const<'tcx> {
+        let origin = ConstVariableOrigin { span, param_def_id: None };
+        let vid = self
+            .inner
             .borrow_mut()
             .const_unification_table()
-            .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() })
-            .vid
-    }
-
-    fn next_int_var_id(&self) -> IntVid {
-        self.inner.borrow_mut().int_unification_table().new_key(None)
+            .new_key(ConstVariableValue::Unknown { origin, universe })
+            .vid;
+        ty::Const::new_var(self.tcx, vid, ty)
     }
 
     pub fn next_int_var(&self) -> Ty<'tcx> {
-        Ty::new_int_var(self.tcx, self.next_int_var_id())
-    }
-
-    fn next_float_var_id(&self) -> FloatVid {
-        self.inner.borrow_mut().float_unification_table().new_key(None)
+        let vid = self.inner.borrow_mut().int_unification_table().new_key(None);
+        Ty::new_int_var(self.tcx, vid)
     }
 
     pub fn next_float_var(&self) -> Ty<'tcx> {
-        Ty::new_float_var(self.tcx, self.next_float_var_id())
+        let vid = self.inner.borrow_mut().float_unification_table().new_key(None);
+        Ty::new_float_var(self.tcx, vid)
     }
 
     /// Creates a fresh region variable with the next available index.
@@ -1467,24 +1446,13 @@ impl<'tcx> InferCtxt<'tcx> {
             fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx> {
                 self.map
                     .entry(bt.var)
-                    .or_insert_with(|| {
-                        self.infcx
-                            .next_ty_var(TypeVariableOrigin { param_def_id: None, span: self.span })
-                            .into()
-                    })
+                    .or_insert_with(|| self.infcx.next_ty_var(self.span).into())
                     .expect_ty()
             }
             fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx> {
                 self.map
                     .entry(bv)
-                    .or_insert_with(|| {
-                        self.infcx
-                            .next_const_var(
-                                ty,
-                                ConstVariableOrigin { param_def_id: None, span: self.span },
-                            )
-                            .into()
-                    })
+                    .or_insert_with(|| self.infcx.next_const_var(ty, self.span).into())
                     .expect_const()
             }
         }
@@ -1521,15 +1489,6 @@ impl<'tcx> InferCtxt<'tcx> {
         closure_kind_ty.to_opt_closure_kind()
     }
 
-    /// Clears the selection, evaluation, and projection caches. This is useful when
-    /// repeatedly attempting to select an `Obligation` while changing only
-    /// its `ParamEnv`, since `FulfillmentContext` doesn't use probing.
-    pub fn clear_caches(&self) {
-        self.selection_cache.clear();
-        self.evaluation_cache.clear();
-        self.inner.borrow_mut().projection_cache().clear();
-    }
-
     pub fn universe(&self) -> ty::UniverseIndex {
         self.universe.get()
     }
@@ -1900,7 +1859,7 @@ impl<'tcx> SubregionOrigin<'tcx> {
                 SubregionOrigin::ReferenceOutlivesReferent(ref_type, cause.span)
             }
 
-            traits::ObligationCauseCode::CompareImplItemObligation {
+            traits::ObligationCauseCode::CompareImplItem {
                 impl_item_def_id,
                 trait_item_def_id,
                 kind: _,
diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
index 94a546f87ee..8eb3185673b 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
@@ -1,4 +1,3 @@
-use super::type_variable::TypeVariableOrigin;
 use super::{DefineOpaqueTypes, InferResult};
 use crate::errors::OpaqueHiddenTypeDiag;
 use crate::infer::{InferCtxt, InferOk};
@@ -65,7 +64,7 @@ impl<'tcx> InferCtxt<'tcx> {
                     let span = if span.contains(def_span) { def_span } else { span };
                     let code = traits::ObligationCauseCode::OpaqueReturnType(None);
                     let cause = ObligationCause::new(span, body_id, code);
-                    let ty_var = self.next_ty_var(TypeVariableOrigin { param_def_id: None, span });
+                    let ty_var = self.next_ty_var(span);
                     obligations.extend(
                         self.handle_opaque_type(ty, ty_var, &cause, param_env).unwrap().obligations,
                     );
@@ -485,6 +484,19 @@ impl<'tcx> InferCtxt<'tcx> {
         Ok(InferOk { value: (), obligations })
     }
 
+    /// Insert a hidden type into the opaque type storage, making sure
+    /// it hasn't previously been defined. This does not emit any
+    /// constraints and it's the responsibility of the caller to make
+    /// sure that the item bounds of the opaque are checked.
+    pub fn inject_new_hidden_type_unchecked(
+        &self,
+        opaque_type_key: OpaqueTypeKey<'tcx>,
+        hidden_ty: OpaqueHiddenType<'tcx>,
+    ) {
+        let prev = self.inner.borrow_mut().opaque_types().register(opaque_type_key, hidden_ty);
+        assert_eq!(prev, None);
+    }
+
     /// Insert a hidden type into the opaque type storage, equating it
     /// with any previous entries if necessary.
     ///
@@ -576,7 +588,7 @@ impl<'tcx> InferCtxt<'tcx> {
                             && !tcx.is_impl_trait_in_trait(projection_ty.def_id)
                             && !self.next_trait_solver() =>
                     {
-                        self.infer_projection(
+                        self.projection_ty_to_infer(
                             param_env,
                             projection_ty,
                             cause.clone(),
diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs
index a7ddf475436..e07d181e4e0 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/table.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs
@@ -1,4 +1,5 @@
 use rustc_data_structures::undo_log::UndoLogs;
+use rustc_middle::bug;
 use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty};
 
 use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, UndoLog};
diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs
index f8dbfdde30c..5bcb4f29364 100644
--- a/compiler/rustc_infer/src/infer/outlives/env.rs
+++ b/compiler/rustc_infer/src/infer/outlives/env.rs
@@ -3,6 +3,7 @@ use crate::infer::GenericKind;
 use crate::traits::query::OutlivesBound;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_data_structures::transitive_relation::TransitiveRelationBuilder;
+use rustc_middle::bug;
 use rustc_middle::ty::{self, Region};
 
 use super::explicit_outlives_bounds;
@@ -63,8 +64,7 @@ struct OutlivesEnvironmentBuilder<'tcx> {
 /// "Region-bound pairs" tracks outlives relations that are known to
 /// be true, either because of explicit where-clauses like `T: 'a` or
 /// because of implied bounds.
-pub type RegionBoundPairs<'tcx> =
-    FxIndexSet<ty::OutlivesPredicate<GenericKind<'tcx>, Region<'tcx>>>;
+pub type RegionBoundPairs<'tcx> = FxIndexSet<ty::OutlivesPredicate<'tcx, GenericKind<'tcx>>>;
 
 impl<'tcx> OutlivesEnvironment<'tcx> {
     /// Create a builder using `ParamEnv` and add explicit outlives bounds into it.
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index fe323982ec0..32c790523b6 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -67,6 +67,7 @@ use crate::infer::snapshot::undo_log::UndoLog;
 use crate::infer::{self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, VerifyBound};
 use crate::traits::{ObligationCause, ObligationCauseCode};
 use rustc_data_structures::undo_log::UndoLogs;
+use rustc_middle::bug;
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::{
@@ -103,8 +104,12 @@ impl<'tcx> InferCtxt<'tcx> {
                 cause.span,
                 sup_type,
                 match cause.code().peel_derives() {
-                    ObligationCauseCode::BindingObligation(_, span)
-                    | ObligationCauseCode::ExprBindingObligation(_, span, ..) => Some(*span),
+                    ObligationCauseCode::WhereClause(_, span)
+                    | ObligationCauseCode::WhereClauseInExpr(_, span, ..)
+                        if !span.is_dummy() =>
+                    {
+                        Some(*span)
+                    }
                     _ => None,
                 },
             )
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index bd981c20567..7e977b9b954 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -94,7 +94,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
     pub fn approx_declared_bounds_from_env(
         &self,
         alias_ty: ty::AliasTy<'tcx>,
-    ) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
+    ) -> Vec<ty::PolyTypeOutlivesPredicate<'tcx>> {
         let erased_alias_ty = self.tcx.erase_regions(alias_ty.to_ty(self.tcx));
         self.declared_generic_bounds_from_env_for_erased_ty(erased_alias_ty)
     }
@@ -193,7 +193,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
     fn declared_generic_bounds_from_env(
         &self,
         generic_ty: Ty<'tcx>,
-    ) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
+    ) -> Vec<ty::PolyTypeOutlivesPredicate<'tcx>> {
         assert!(matches!(generic_ty.kind(), ty::Param(_) | ty::Placeholder(_)));
         self.declared_generic_bounds_from_env_for_erased_ty(generic_ty)
     }
@@ -213,7 +213,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
     fn declared_generic_bounds_from_env_for_erased_ty(
         &self,
         erased_ty: Ty<'tcx>,
-    ) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
+    ) -> Vec<ty::PolyTypeOutlivesPredicate<'tcx>> {
         let tcx = self.tcx;
 
         // To start, collect bounds from user environment. Note that
diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs
index e60efe37fd9..16786347980 100644
--- a/compiler/rustc_infer/src/infer/projection.rs
+++ b/compiler/rustc_infer/src/infer/projection.rs
@@ -3,7 +3,6 @@ use rustc_middle::ty::{self, Ty};
 
 use crate::traits::{Obligation, PredicateObligation};
 
-use super::type_variable::TypeVariableOrigin;
 use super::InferCtxt;
 
 impl<'tcx> InferCtxt<'tcx> {
@@ -13,7 +12,7 @@ impl<'tcx> InferCtxt<'tcx> {
     /// of the given projection. This allows us to proceed with projections
     /// while they cannot be resolved yet due to missing information or
     /// simply due to the lack of access to the trait resolution machinery.
-    pub fn infer_projection(
+    pub fn projection_ty_to_infer(
         &self,
         param_env: ty::ParamEnv<'tcx>,
         projection_ty: ty::AliasTy<'tcx>,
@@ -23,12 +22,9 @@ impl<'tcx> InferCtxt<'tcx> {
     ) -> Ty<'tcx> {
         debug_assert!(!self.next_trait_solver());
         let def_id = projection_ty.def_id;
-        let ty_var = self.next_ty_var(TypeVariableOrigin {
-            param_def_id: None,
-            span: self.tcx.def_span(def_id),
-        });
+        let ty_var = self.next_ty_var(self.tcx.def_span(def_id));
         let projection = ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Projection(
-            ty::ProjectionPredicate { projection_ty, term: ty_var.into() },
+            ty::ProjectionPredicate { projection_term: projection_ty.into(), term: ty_var.into() },
         )));
         let obligation =
             Obligation::with_depth(self.tcx, cause, recursion_depth, param_env, projection);
diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
index 06f8dd4a4c6..255ca52d3e9 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
@@ -3,6 +3,7 @@ use crate::infer::snapshot::CombinedSnapshot;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::graph::{scc::Sccs, vec_graph::VecGraph};
 use rustc_index::Idx;
+use rustc_middle::span_bug;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::relate::RelateResult;
 
@@ -382,7 +383,7 @@ impl<'tcx> MiniGraph<'tcx> {
                 edges.push((source_node, target_node));
             },
         );
-        let graph = VecGraph::new(nodes.len(), edges);
+        let graph = VecGraph::<_, false>::new(nodes.len(), edges);
         let sccs = Sccs::new(&graph);
         Self { nodes, sccs }
     }
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index 3d6b54721d0..6f755e07ff1 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -11,11 +11,13 @@ use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::undo_log::UndoLogs;
 use rustc_data_structures::unify as ut;
 use rustc_index::IndexVec;
+use rustc_macros::{TypeFoldable, TypeVisitable};
 use rustc_middle::infer::unify_key::{RegionVariableValue, RegionVidKey};
 use rustc_middle::ty::ReStatic;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{ReBound, ReVar};
 use rustc_middle::ty::{Region, RegionVid};
+use rustc_middle::{bug, span_bug};
 use rustc_span::Span;
 
 use std::ops::Range;
diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs
index 8a3125f9ded..6b41e450684 100644
--- a/compiler/rustc_infer/src/infer/relate/combine.rs
+++ b/compiler/rustc_infer/src/infer/relate/combine.rs
@@ -22,13 +22,14 @@ use super::glb::Glb;
 use super::lub::Lub;
 use super::type_relating::TypeRelating;
 use super::StructurallyRelateAliases;
-use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace};
+use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, TypeTrace};
 use crate::traits::{Obligation, PredicateObligations};
-use rustc_middle::infer::canonical::OriginalQueryValues;
+use rustc_middle::bug;
 use rustc_middle::infer::unify_key::EffectVarValue;
+use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::relate::{RelateResult, TypeRelation};
-use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, InferConst, Ty, TyCtxt, TypeVisitableExt, Upcast};
 use rustc_middle::ty::{IntType, UintType};
 use rustc_span::Span;
 
@@ -41,6 +42,17 @@ pub struct CombineFields<'infcx, 'tcx> {
     pub define_opaque_types: DefineOpaqueTypes,
 }
 
+impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
+    pub fn new(
+        infcx: &'infcx InferCtxt<'tcx>,
+        trace: TypeTrace<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        define_opaque_types: DefineOpaqueTypes,
+    ) -> Self {
+        Self { infcx, trace, param_env, define_opaque_types, obligations: vec![] }
+    }
+}
+
 impl<'tcx> InferCtxt<'tcx> {
     pub fn super_combine_tys<R>(
         &self,
@@ -158,36 +170,11 @@ impl<'tcx> InferCtxt<'tcx> {
         let a = self.shallow_resolve_const(a);
         let b = self.shallow_resolve_const(b);
 
-        // We should never have to relate the `ty` field on `Const` as it is checked elsewhere that consts have the
-        // correct type for the generic param they are an argument for. However there have been a number of cases
-        // historically where asserting that the types are equal has found bugs in the compiler so this is valuable
-        // to check even if it is a bit nasty impl wise :(
-        //
-        // This probe is probably not strictly necessary but it seems better to be safe and not accidentally find
-        // ourselves with a check to find bugs being required for code to compile because it made inference progress.
-        self.probe(|_| {
-            if a.ty() == b.ty() {
-                return;
-            }
-
-            // We don't have access to trait solving machinery in `rustc_infer` so the logic for determining if the
-            // two const param's types are able to be equal has to go through a canonical query with the actual logic
-            // in `rustc_trait_selection`.
-            let canonical = self.canonicalize_query(
-                relation.param_env().and((a.ty(), b.ty())),
-                &mut OriginalQueryValues::default(),
-            );
-            self.tcx.check_tys_might_be_eq(canonical).unwrap_or_else(|_| {
-                // The error will only be reported later. If we emit an ErrorGuaranteed
-                // here, then we will never get to the code that actually emits the error.
-                self.tcx.dcx().delayed_bug(format!(
-                    "cannot relate consts of different types (a={a:?}, b={b:?})",
-                ));
-                // We treat these constants as if they were of the same type, so that any
-                // such constants being used in impls make these impls match barring other mismatches.
-                // This helps with diagnostics down the road.
-            });
-        });
+        // It is always an error if the types of two constants that are related are not equal.
+        let InferOk { value: (), obligations } = self
+            .at(&ObligationCause::dummy_with_span(relation.span()), relation.param_env())
+            .eq(DefineOpaqueTypes::No, a.ty(), b.ty())?;
+        relation.register_obligations(obligations);
 
         match (a.kind(), b.kind()) {
             (
@@ -336,7 +323,10 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
         self.obligations.extend(obligations);
     }
 
-    pub fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ToPredicate<'tcx>>) {
+    pub fn register_predicates(
+        &mut self,
+        obligations: impl IntoIterator<Item: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
+    ) {
         self.obligations.extend(obligations.into_iter().map(|to_pred| {
             Obligation::new(self.infcx.tcx, self.trace.cause.clone(), self.param_env, to_pred)
         }))
@@ -359,7 +349,10 @@ pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> {
     /// Register predicates that must hold in order for this relation to hold. Uses
     /// a default obligation cause, [`ObligationEmittingRelation::register_obligations`] should
     /// be used if control over the obligation causes is required.
-    fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ToPredicate<'tcx>>);
+    fn register_predicates(
+        &mut self,
+        obligations: impl IntoIterator<Item: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
+    );
 
     /// Register `AliasRelate` obligation(s) that both types must be related to each other.
     fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>);
diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs
index 74929daffe2..d4c7d752c95 100644
--- a/compiler/rustc_infer/src/infer/relate/generalize.rs
+++ b/compiler/rustc_infer/src/infer/relate/generalize.rs
@@ -1,11 +1,12 @@
 use std::mem;
 
 use super::StructurallyRelateAliases;
-use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableValue};
+use crate::infer::type_variable::TypeVariableValue;
 use crate::infer::{InferCtxt, ObligationEmittingRelation, RegionVariableOrigin};
 use rustc_data_structures::sso::SsoHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir::def_id::DefId;
+use rustc_middle::bug;
 use rustc_middle::infer::unify_key::ConstVariableValue;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
@@ -101,7 +102,7 @@ impl<'tcx> InferCtxt<'tcx> {
                         // instead create a new inference variable `?normalized_source`, emitting
                         // `Projection(normalized_source, ?ty_normalized)` and `?normalized_source <: generalized_ty`.
                         relation.register_predicates([ty::ProjectionPredicate {
-                            projection_ty: data,
+                            projection_term: data.into(),
                             term: generalized_ty.into(),
                         }]);
                     }
@@ -350,11 +351,14 @@ impl<'tcx> Generalizer<'_, 'tcx> {
         &mut self,
         alias: ty::AliasTy<'tcx>,
     ) -> Result<Ty<'tcx>, TypeError<'tcx>> {
-        if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() {
-            return Ok(self.infcx.next_ty_var_in_universe(
-                TypeVariableOrigin { param_def_id: None, span: self.span },
-                self.for_universe,
-            ));
+        // We do not eagerly replace aliases with inference variables if they have
+        // escaping bound vars, see the method comment for details. However, when we
+        // are inside of an alias with escaping bound vars replacing nested aliases
+        // with inference variables can cause incorrect ambiguity.
+        //
+        // cc trait-system-refactor-initiative#110
+        if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() && !self.in_alias {
+            return Ok(self.infcx.next_ty_var_in_universe(self.span, self.for_universe));
         }
 
         let is_nested_alias = mem::replace(&mut self.in_alias, true);
@@ -374,10 +378,7 @@ impl<'tcx> Generalizer<'_, 'tcx> {
                     }
 
                     debug!("generalization failure in alias");
-                    Ok(self.infcx.next_ty_var_in_universe(
-                        TypeVariableOrigin { param_def_id: None, span: self.span },
-                        self.for_universe,
-                    ))
+                    Ok(self.infcx.next_ty_var_in_universe(self.span, self.for_universe))
                 }
             }
         };
@@ -492,9 +493,30 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
                             let origin = inner.type_variables().var_origin(vid);
                             let new_var_id =
                                 inner.type_variables().new_var(self.for_universe, origin);
-                            let u = Ty::new_var(self.tcx(), new_var_id);
-                            debug!("replacing original vid={:?} with new={:?}", vid, u);
-                            Ok(u)
+                            // If we're in the new solver and create a new inference
+                            // variable inside of an alias we eagerly constrain that
+                            // inference variable to prevent unexpected ambiguity errors.
+                            //
+                            // This is incomplete as it pulls down the universe of the
+                            // original inference variable, even though the alias could
+                            // normalize to a type which does not refer to that type at
+                            // all. I don't expect this to cause unexpected errors in
+                            // practice.
+                            //
+                            // We only need to do so for type and const variables, as
+                            // region variables do not impact normalization, and will get
+                            // correctly constrained by `AliasRelate` later on.
+                            //
+                            // cc trait-system-refactor-initiative#108
+                            if self.infcx.next_trait_solver()
+                                && !self.infcx.intercrate
+                                && self.in_alias
+                            {
+                                inner.type_variables().equate(vid, new_var_id);
+                            }
+
+                            debug!("replacing original vid={:?} with new={:?}", vid, new_var_id);
+                            Ok(Ty::new_var(self.tcx(), new_var_id))
                         }
                     }
                 }
@@ -614,6 +636,15 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
                                     universe: self.for_universe,
                                 })
                                 .vid;
+
+                            // See the comment for type inference variables
+                            // for more details.
+                            if self.infcx.next_trait_solver()
+                                && !self.infcx.intercrate
+                                && self.in_alias
+                            {
+                                variable_table.union(vid, new_var_id);
+                            }
                             Ok(ty::Const::new_var(self.tcx(), new_var_id, c.ty()))
                         }
                     }
diff --git a/compiler/rustc_infer/src/infer/relate/glb.rs b/compiler/rustc_infer/src/infer/relate/glb.rs
index b86d1b2671d..a224a86492a 100644
--- a/compiler/rustc_infer/src/infer/relate/glb.rs
+++ b/compiler/rustc_infer/src/infer/relate/glb.rs
@@ -140,7 +140,10 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> {
         self.fields.param_env
     }
 
-    fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>) {
+    fn register_predicates(
+        &mut self,
+        obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
+    ) {
         self.fields.register_predicates(obligations);
     }
 
diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs
index f9470c9b8f6..38e25b0d9b6 100644
--- a/compiler/rustc_infer/src/infer/relate/lattice.rs
+++ b/compiler/rustc_infer/src/infer/relate/lattice.rs
@@ -18,7 +18,6 @@
 //! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order)
 
 use super::combine::ObligationEmittingRelation;
-use crate::infer::type_variable::TypeVariableOrigin;
 use crate::infer::{DefineOpaqueTypes, InferCtxt};
 use crate::traits::ObligationCause;
 
@@ -88,14 +87,12 @@ where
         // iterate on the subtype obligations that are returned, but I
         // think this suffices. -nmatsakis
         (&ty::Infer(TyVar(..)), _) => {
-            let v = infcx
-                .next_ty_var(TypeVariableOrigin { param_def_id: None, span: this.cause().span });
+            let v = infcx.next_ty_var(this.cause().span);
             this.relate_bound(v, b, a)?;
             Ok(v)
         }
         (_, &ty::Infer(TyVar(..))) => {
-            let v = infcx
-                .next_ty_var(TypeVariableOrigin { param_def_id: None, span: this.cause().span });
+            let v = infcx.next_ty_var(this.cause().span);
             this.relate_bound(v, a, b)?;
             Ok(v)
         }
diff --git a/compiler/rustc_infer/src/infer/relate/lub.rs b/compiler/rustc_infer/src/infer/relate/lub.rs
index 20f5f65c984..83ab7770770 100644
--- a/compiler/rustc_infer/src/infer/relate/lub.rs
+++ b/compiler/rustc_infer/src/infer/relate/lub.rs
@@ -140,7 +140,10 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> {
         self.fields.param_env
     }
 
-    fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>) {
+    fn register_predicates(
+        &mut self,
+        obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
+    ) {
         self.fields.register_predicates(obligations);
     }
 
diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs
index 86a24eef7f5..21064fff97f 100644
--- a/compiler/rustc_infer/src/infer/relate/type_relating.rs
+++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs
@@ -312,7 +312,10 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for TypeRelating<'_, '_, 'tcx> {
         self.structurally_relate_aliases
     }
 
-    fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>) {
+    fn register_predicates(
+        &mut self,
+        obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
+    ) {
         self.fields.register_predicates(obligations);
     }
 
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index 758aac004dc..21ef2e89523 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -1,4 +1,5 @@
 use super::{FixupError, FixupResult, InferCtxt};
+use rustc_middle::bug;
 use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable};
@@ -172,84 +173,3 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> {
         }
     }
 }
-
-///////////////////////////////////////////////////////////////////////////
-// EAGER RESOLUTION
-
-/// Resolves ty, region, and const vars to their inferred values or their root vars.
-pub struct EagerResolver<'a, 'tcx> {
-    infcx: &'a InferCtxt<'tcx>,
-}
-
-impl<'a, 'tcx> EagerResolver<'a, 'tcx> {
-    pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
-        EagerResolver { infcx }
-    }
-}
-
-impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EagerResolver<'_, 'tcx> {
-    fn interner(&self) -> TyCtxt<'tcx> {
-        self.infcx.tcx
-    }
-
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        match *t.kind() {
-            ty::Infer(ty::TyVar(vid)) => match self.infcx.probe_ty_var(vid) {
-                Ok(t) => t.fold_with(self),
-                Err(_) => Ty::new_var(self.infcx.tcx, self.infcx.root_var(vid)),
-            },
-            ty::Infer(ty::IntVar(vid)) => self.infcx.opportunistic_resolve_int_var(vid),
-            ty::Infer(ty::FloatVar(vid)) => self.infcx.opportunistic_resolve_float_var(vid),
-            _ => {
-                if t.has_infer() {
-                    t.super_fold_with(self)
-                } else {
-                    t
-                }
-            }
-        }
-    }
-
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        match *r {
-            ty::ReVar(vid) => self
-                .infcx
-                .inner
-                .borrow_mut()
-                .unwrap_region_constraints()
-                .opportunistic_resolve_var(self.infcx.tcx, vid),
-            _ => r,
-        }
-    }
-
-    fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        match c.kind() {
-            ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
-                // FIXME: we need to fold the ty too, I think.
-                match self.infcx.probe_const_var(vid) {
-                    Ok(c) => c.fold_with(self),
-                    Err(_) => {
-                        ty::Const::new_var(self.infcx.tcx, self.infcx.root_const_var(vid), c.ty())
-                    }
-                }
-            }
-            ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)) => {
-                debug_assert_eq!(c.ty(), self.infcx.tcx.types.bool);
-                self.infcx.probe_effect_var(vid).unwrap_or_else(|| {
-                    ty::Const::new_infer(
-                        self.infcx.tcx,
-                        ty::InferConst::EffectVar(self.infcx.root_effect_var(vid)),
-                        self.infcx.tcx.types.bool,
-                    )
-                })
-            }
-            _ => {
-                if c.has_infer() {
-                    c.super_fold_with(self)
-                } else {
-                    c
-                }
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_infer/src/infer/snapshot/fudge.rs b/compiler/rustc_infer/src/infer/snapshot/fudge.rs
index 83667f7276d..4408251c99d 100644
--- a/compiler/rustc_infer/src/infer/snapshot/fudge.rs
+++ b/compiler/rustc_infer/src/infer/snapshot/fudge.rs
@@ -195,7 +195,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> {
                     // Recreate it with a fresh variable here.
                     let idx = vid.as_usize() - self.type_vars.0.start.as_usize();
                     let origin = self.type_vars.1[idx];
-                    self.infcx.next_ty_var(origin)
+                    self.infcx.next_ty_var_with_origin(origin)
                 } else {
                     // This variable was created before the
                     // "fudging". Since we refresh all type
@@ -244,7 +244,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> {
                 // Recreate it with a fresh variable here.
                 let idx = vid.index() - self.const_vars.0.start.index();
                 let origin = self.const_vars.1[idx];
-                self.infcx.next_const_var(ct.ty(), origin)
+                self.infcx.next_const_var_with_origin(ct.ty(), origin)
             } else {
                 ct
             }
diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs
index 96afa257ebb..b56b39e61f0 100644
--- a/compiler/rustc_infer/src/infer/type_variable.rs
+++ b/compiler/rustc_infer/src/infer/type_variable.rs
@@ -1,6 +1,7 @@
 use rustc_data_structures::undo_log::Rollback;
 use rustc_hir::def_id::DefId;
 use rustc_index::IndexVec;
+use rustc_middle::bug;
 use rustc_middle::ty::{self, Ty, TyVid};
 use rustc_span::Span;
 
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index 0444cbe2ee4..28d908abf83 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -18,7 +18,6 @@
 #![allow(internal_features)]
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::untranslatable_diagnostic)]
-#![cfg_attr(bootstrap, feature(associated_type_bounds))]
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
 #![feature(extend_one)]
@@ -31,14 +30,7 @@
 #![recursion_limit = "512"] // For rustdoc
 
 #[macro_use]
-extern crate rustc_macros;
-#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
-#[macro_use]
-extern crate rustc_data_structures;
-#[macro_use]
 extern crate tracing;
-#[macro_use]
-extern crate rustc_middle;
 
 mod errors;
 pub mod infer;
diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs
index c495810858f..e27e6a0a4a1 100644
--- a/compiler/rustc_infer/src/traits/engine.rs
+++ b/compiler/rustc_infer/src/traits/engine.rs
@@ -1,7 +1,8 @@
 use crate::infer::InferCtxt;
 use crate::traits::Obligation;
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::{self, ToPredicate, Ty};
+use rustc_macros::extension;
+use rustc_middle::ty::{self, Ty, Upcast};
 
 use super::FulfillmentError;
 use super::{ObligationCause, PredicateObligation};
@@ -25,7 +26,7 @@ pub trait TraitEngine<'tcx>: 'tcx {
                 cause,
                 recursion_depth: 0,
                 param_env,
-                predicate: ty::Binder::dummy(trait_ref).to_predicate(infcx.tcx),
+                predicate: trait_ref.upcast(infcx.tcx),
             },
         );
     }
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index 94ad0f5b1c8..0ae4340098b 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -16,7 +16,7 @@ use rustc_hir as hir;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::solve::Certainty;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::{self, Const, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, Const, Ty, TyCtxt, Upcast};
 use rustc_span::Span;
 
 pub use self::ImplSource::*;
@@ -27,7 +27,7 @@ pub use self::engine::{TraitEngine, TraitEngineExt};
 pub use self::project::MismatchedProjectionTypes;
 pub(crate) use self::project::UndoLog;
 pub use self::project::{
-    Normalized, NormalizedTy, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey,
+    Normalized, NormalizedTerm, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey,
     ProjectionCacheStorage, Reveal,
 };
 pub use rustc_middle::traits::*;
@@ -105,15 +105,15 @@ impl<'tcx> PredicateObligation<'tcx> {
 impl<'tcx> PolyTraitObligation<'tcx> {
     pub fn derived_cause(
         &self,
-        variant: impl FnOnce(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>,
+        variant: impl FnOnce(DerivedCause<'tcx>) -> ObligationCauseCode<'tcx>,
     ) -> ObligationCause<'tcx> {
         self.cause.clone().derived_cause(self.predicate, variant)
     }
 }
 
 // `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
-static_assert_size!(PredicateObligation<'_>, 48);
+#[cfg(target_pointer_width = "64")]
+rustc_data_structures::static_assert_size!(PredicateObligation<'_>, 48);
 
 pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>;
 
@@ -138,10 +138,10 @@ pub enum FulfillmentErrorCode<'tcx> {
     /// Inherently impossible to fulfill; this trait is implemented if and only
     /// if it is already implemented.
     Cycle(Vec<PredicateObligation<'tcx>>),
-    SelectionError(SelectionError<'tcx>),
-    ProjectionError(MismatchedProjectionTypes<'tcx>),
-    SubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
-    ConstEquateError(ExpectedFound<Const<'tcx>>, TypeError<'tcx>),
+    Select(SelectionError<'tcx>),
+    Project(MismatchedProjectionTypes<'tcx>),
+    Subtype(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
+    ConstEquate(ExpectedFound<Const<'tcx>>, TypeError<'tcx>),
     Ambiguity {
         /// Overflow is only `Some(suggest_recursion_limit)` when using the next generation
         /// trait solver `-Znext-solver`. With the old solver overflow is eagerly handled by
@@ -155,7 +155,7 @@ impl<'tcx, O> Obligation<'tcx, O> {
         tcx: TyCtxt<'tcx>,
         cause: ObligationCause<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        predicate: impl ToPredicate<'tcx, O>,
+        predicate: impl Upcast<TyCtxt<'tcx>, O>,
     ) -> Obligation<'tcx, O> {
         Self::with_depth(tcx, cause, 0, param_env, predicate)
     }
@@ -173,9 +173,9 @@ impl<'tcx, O> Obligation<'tcx, O> {
         cause: ObligationCause<'tcx>,
         recursion_depth: usize,
         param_env: ty::ParamEnv<'tcx>,
-        predicate: impl ToPredicate<'tcx, O>,
+        predicate: impl Upcast<TyCtxt<'tcx>, O>,
     ) -> Obligation<'tcx, O> {
-        let predicate = predicate.to_predicate(tcx);
+        let predicate = predicate.upcast(tcx);
         Obligation { cause, param_env, recursion_depth, predicate }
     }
 
@@ -184,7 +184,7 @@ impl<'tcx, O> Obligation<'tcx, O> {
         span: Span,
         body_id: LocalDefId,
         param_env: ty::ParamEnv<'tcx>,
-        trait_ref: impl ToPredicate<'tcx, O>,
+        trait_ref: impl Upcast<TyCtxt<'tcx>, O>,
     ) -> Obligation<'tcx, O> {
         Obligation::new(tcx, ObligationCause::misc(span, body_id), param_env, trait_ref)
     }
@@ -192,7 +192,7 @@ impl<'tcx, O> Obligation<'tcx, O> {
     pub fn with<P>(
         &self,
         tcx: TyCtxt<'tcx>,
-        value: impl ToPredicate<'tcx, P>,
+        value: impl Upcast<TyCtxt<'tcx>, P>,
     ) -> Obligation<'tcx, P> {
         Obligation::with_depth(tcx, self.cause.clone(), self.recursion_depth, self.param_env, value)
     }
@@ -206,6 +206,18 @@ impl<'tcx> FulfillmentError<'tcx> {
     ) -> FulfillmentError<'tcx> {
         FulfillmentError { obligation, code, root_obligation }
     }
+
+    pub fn is_true_error(&self) -> bool {
+        match self.code {
+            FulfillmentErrorCode::Select(_)
+            | FulfillmentErrorCode::Project(_)
+            | FulfillmentErrorCode::Subtype(_, _)
+            | FulfillmentErrorCode::ConstEquate(_, _) => true,
+            FulfillmentErrorCode::Cycle(_) | FulfillmentErrorCode::Ambiguity { overflow: _ } => {
+                false
+            }
+        }
+    }
 }
 
 impl<'tcx> PolyTraitObligation<'tcx> {
diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs
index 31ceb234332..b696264aab0 100644
--- a/compiler/rustc_infer/src/traits/project.rs
+++ b/compiler/rustc_infer/src/traits/project.rs
@@ -8,7 +8,7 @@ use rustc_data_structures::{
     snapshot_map::{self, SnapshotMapRef, SnapshotMapStorage},
     undo_log::Rollback,
 };
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty;
 
 pub use rustc_middle::traits::{EvaluationResult, Reveal};
 
@@ -26,7 +26,7 @@ pub struct Normalized<'tcx, T> {
     pub obligations: Vec<PredicateObligation<'tcx>>,
 }
 
-pub type NormalizedTy<'tcx> = Normalized<'tcx, Ty<'tcx>>;
+pub type NormalizedTerm<'tcx> = Normalized<'tcx, ty::Term<'tcx>>;
 
 impl<'tcx, T> Normalized<'tcx, T> {
     pub fn with<U>(self, value: U) -> Normalized<'tcx, U> {
@@ -77,12 +77,13 @@ pub struct ProjectionCacheStorage<'tcx> {
 
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
 pub struct ProjectionCacheKey<'tcx> {
-    ty: ty::AliasTy<'tcx>,
+    term: ty::AliasTerm<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
 }
 
 impl<'tcx> ProjectionCacheKey<'tcx> {
-    pub fn new(ty: ty::AliasTy<'tcx>) -> Self {
-        Self { ty }
+    pub fn new(term: ty::AliasTerm<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
+        Self { term, param_env }
     }
 }
 
@@ -92,8 +93,8 @@ pub enum ProjectionCacheEntry<'tcx> {
     Ambiguous,
     Recur,
     Error,
-    NormalizedTy {
-        ty: Normalized<'tcx, ty::Term<'tcx>>,
+    NormalizedTerm {
+        ty: NormalizedTerm<'tcx>,
         /// If we were able to successfully evaluate the
         /// corresponding cache entry key during predicate
         /// evaluation, then this field stores the final
@@ -174,11 +175,7 @@ impl<'tcx> ProjectionCache<'_, 'tcx> {
     }
 
     /// Indicates that `key` was normalized to `value`.
-    pub fn insert_term(
-        &mut self,
-        key: ProjectionCacheKey<'tcx>,
-        value: Normalized<'tcx, ty::Term<'tcx>>,
-    ) {
+    pub fn insert_term(&mut self, key: ProjectionCacheKey<'tcx>, value: NormalizedTerm<'tcx>) {
         debug!(
             "ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}",
             key, value
@@ -189,7 +186,7 @@ impl<'tcx> ProjectionCache<'_, 'tcx> {
             return;
         }
         let fresh_key =
-            map.insert(key, ProjectionCacheEntry::NormalizedTy { ty: value, complete: None });
+            map.insert(key, ProjectionCacheEntry::NormalizedTerm { ty: value, complete: None });
         assert!(!fresh_key, "never started projecting `{key:?}`");
     }
 
@@ -200,13 +197,16 @@ impl<'tcx> ProjectionCache<'_, 'tcx> {
     pub fn complete(&mut self, key: ProjectionCacheKey<'tcx>, result: EvaluationResult) {
         let mut map = self.map();
         match map.get(&key) {
-            Some(ProjectionCacheEntry::NormalizedTy { ty, complete: _ }) => {
+            Some(ProjectionCacheEntry::NormalizedTerm { ty, complete: _ }) => {
                 info!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty);
                 let mut ty = ty.clone();
                 if result.must_apply_considering_regions() {
                     ty.obligations = vec![];
                 }
-                map.insert(key, ProjectionCacheEntry::NormalizedTy { ty, complete: Some(result) });
+                map.insert(
+                    key,
+                    ProjectionCacheEntry::NormalizedTerm { ty, complete: Some(result) },
+                );
             }
             ref value => {
                 // Type inference could "strand behind" old cache entries. Leave
@@ -218,7 +218,7 @@ impl<'tcx> ProjectionCache<'_, 'tcx> {
 
     pub fn is_complete(&mut self, key: ProjectionCacheKey<'tcx>) -> Option<EvaluationResult> {
         self.map().get(&key).and_then(|res| match res {
-            ProjectionCacheEntry::NormalizedTy { ty: _, complete } => *complete,
+            ProjectionCacheEntry::NormalizedTerm { ty: _, complete } => *complete,
             _ => None,
         })
     }
diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs
index 064e09b8750..b616d37e5b5 100644
--- a/compiler/rustc_infer/src/traits/structural_impls.rs
+++ b/compiler/rustc_infer/src/traits/structural_impls.rs
@@ -39,12 +39,12 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         use traits::FulfillmentErrorCode::*;
         match *self {
-            SelectionError(ref e) => write!(f, "{e:?}"),
-            ProjectionError(ref e) => write!(f, "{e:?}"),
-            SubtypeError(ref a, ref b) => {
+            Select(ref e) => write!(f, "{e:?}"),
+            Project(ref e) => write!(f, "{e:?}"),
+            Subtype(ref a, ref b) => {
                 write!(f, "CodeSubtypeError({a:?}, {b:?})")
             }
-            ConstEquateError(ref a, ref b) => {
+            ConstEquate(ref a, ref b) => {
                 write!(f, "CodeConstEquateError({a:?}, {b:?})")
             }
             Ambiguity { overflow: None } => write!(f, "Ambiguity"),
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index 6d43011d33c..cc12a4bf091 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -1,9 +1,9 @@
 use smallvec::smallvec;
 
 use crate::infer::outlives::components::{push_outlives_components, Component};
-use crate::traits::{self, Obligation, PredicateObligation};
+use crate::traits::{self, Obligation, ObligationCauseCode, PredicateObligation};
 use rustc_data_structures::fx::FxHashSet;
-use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 
@@ -129,7 +129,7 @@ impl<'tcx> Elaboratable<'tcx> for PredicateObligation<'tcx> {
         index: usize,
     ) -> Self {
         let cause = self.cause.clone().derived_cause(parent_trait_pred, |derived| {
-            traits::ImplDerivedObligation(Box::new(traits::ImplDerivedObligationCause {
+            ObligationCauseCode::ImplDerived(Box::new(traits::ImplDerivedCause {
                 derived,
                 impl_or_alias_def_id: parent_trait_pred.def_id(),
                 impl_def_predicate_index: Some(index),
@@ -357,9 +357,7 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
                                 None
                             }
                         })
-                        .map(|clause| {
-                            elaboratable.child(bound_clause.rebind(clause).to_predicate(tcx))
-                        }),
+                        .map(|clause| elaboratable.child(bound_clause.rebind(clause).upcast(tcx))),
                 );
             }
             ty::ClauseKind::RegionOutlives(..) => {
@@ -409,14 +407,14 @@ pub fn supertraits<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_ref: ty::PolyTraitRef<'tcx>,
 ) -> FilterToTraits<Elaborator<'tcx, ty::Predicate<'tcx>>> {
-    elaborate(tcx, [trait_ref.to_predicate(tcx)]).filter_only_self().filter_to_traits()
+    elaborate(tcx, [trait_ref.upcast(tcx)]).filter_only_self().filter_to_traits()
 }
 
 pub fn transitive_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
 ) -> FilterToTraits<Elaborator<'tcx, ty::Predicate<'tcx>>> {
-    elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.to_predicate(tcx)))
+    elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.upcast(tcx)))
         .filter_only_self()
         .filter_to_traits()
 }
@@ -431,7 +429,7 @@ pub fn transitive_bounds_that_define_assoc_item<'tcx>(
     trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
     assoc_name: Ident,
 ) -> FilterToTraits<Elaborator<'tcx, ty::Predicate<'tcx>>> {
-    elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.to_predicate(tcx)))
+    elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.upcast(tcx)))
         .filter_only_self_that_defines(assoc_name)
         .filter_to_traits()
 }
@@ -457,7 +455,7 @@ impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<
 
     fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
         while let Some(pred) = self.base_iterator.next() {
-            if let Some(data) = pred.to_opt_poly_trait_pred() {
+            if let Some(data) = pred.as_trait_clause() {
                 return Some(data.map_bound(|t| t.trait_ref));
             }
         }