about summary refs log tree commit diff
path: root/compiler/rustc_hir_analysis/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_analysis/src')
-rw-r--r--compiler/rustc_hir_analysis/src/bounds.rs110
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs56
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs117
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs12
-rw-r--r--compiler/rustc_hir_analysis/src/check/dropck.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/check/entry.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/errs.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs55
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsicck.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs34
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs127
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs178
-rw-r--r--compiler/rustc_hir_analysis/src/check_unused.rs13
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/mod.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs104
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs349
-rw-r--r--compiler/rustc_hir_analysis/src/collect/dump.rs91
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs111
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs51
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs94
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs39
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs43
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs33
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs70
-rw-r--r--compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs (renamed from compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs)74
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs162
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs277
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs123
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs20
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs610
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs52
-rw-r--r--compiler/rustc_hir_analysis/src/hir_wf_check.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs25
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/dump.rs29
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/explicit.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/mod.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/test.rs31
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/utils.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors.rs36
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs57
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs56
-rw-r--r--compiler/rustc_hir_analysis/src/variance/dump.rs32
-rw-r--r--compiler/rustc_hir_analysis/src/variance/mod.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/variance/test.rs37
48 files changed, 1787 insertions, 1589 deletions
diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs
index 38ecd7dd082..c30a6f1eeb9 100644
--- a/compiler/rustc_hir_analysis/src/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/bounds.rs
@@ -1,8 +1,12 @@
 //! Bounds are restrictions applied to some types after they've been lowered from the HIR to the
 //! [`rustc_middle::ty`] form.
 
+use rustc_data_structures::fx::FxIndexMap;
+use rustc_hir::def::DefKind;
 use rustc_hir::LangItem;
+use rustc_middle::ty::fold::FnMutDelegate;
 use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
+use rustc_span::def_id::DefId;
 use rustc_span::Span;
 
 /// Collects together a list of type bounds. These lists of bounds occur in many places
@@ -24,6 +28,7 @@ use rustc_span::Span;
 #[derive(Default, PartialEq, Eq, Clone, Debug)]
 pub struct Bounds<'tcx> {
     clauses: Vec<(ty::Clause<'tcx>, Span)>,
+    effects_min_tys: FxIndexMap<Ty<'tcx>, Span>,
 }
 
 impl<'tcx> Bounds<'tcx> {
@@ -40,12 +45,14 @@ impl<'tcx> Bounds<'tcx> {
     pub fn push_trait_bound(
         &mut self,
         tcx: TyCtxt<'tcx>,
-        trait_ref: ty::PolyTraitRef<'tcx>,
+        defining_def_id: DefId,
+        bound_trait_ref: ty::PolyTraitRef<'tcx>,
         span: Span,
         polarity: ty::PredicatePolarity,
+        constness: ty::BoundConstness,
     ) {
         let clause = (
-            trait_ref
+            bound_trait_ref
                 .map_bound(|trait_ref| {
                     ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity })
                 })
@@ -53,11 +60,98 @@ impl<'tcx> Bounds<'tcx> {
             span,
         );
         // FIXME(-Znext-solver): We can likely remove this hack once the new trait solver lands.
-        if tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
+        if tcx.is_lang_item(bound_trait_ref.def_id(), LangItem::Sized) {
             self.clauses.insert(0, clause);
         } else {
             self.clauses.push(clause);
         }
+
+        if !tcx.features().effects {
+            return;
+        }
+        // For `T: ~const Tr` or `T: const Tr`, we need to add an additional bound on the
+        // associated type of `<T as Tr>` and make sure that the effect is compatible.
+        let compat_val = match (tcx.def_kind(defining_def_id), constness) {
+            // FIXME(effects): revisit the correctness of this
+            (_, ty::BoundConstness::Const) => tcx.consts.false_,
+            // body owners that can have trait bounds
+            (DefKind::Const | DefKind::Fn | DefKind::AssocFn, ty::BoundConstness::ConstIfConst) => {
+                tcx.expected_host_effect_param_for_body(defining_def_id)
+            }
+
+            (_, ty::BoundConstness::NotConst) => {
+                if !tcx.is_const_trait(bound_trait_ref.def_id()) {
+                    return;
+                }
+                tcx.consts.true_
+            }
+
+            (
+                DefKind::Trait | DefKind::Impl { of_trait: true },
+                ty::BoundConstness::ConstIfConst,
+            ) => {
+                // this is either a where clause on an impl/trait header or on a trait.
+                // push `<T as Tr>::Effects` into the set for the `Min` bound.
+                let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else {
+                    tcx.dcx().span_delayed_bug(span, "`~const` on trait without Effects assoc");
+                    return;
+                };
+
+                let ty = bound_trait_ref
+                    .map_bound(|trait_ref| Ty::new_projection(tcx, assoc, trait_ref.args));
+
+                // When the user has written `for<'a, T> X<'a, T>: ~const Foo`, replace the
+                // binders to dummy ones i.e. `X<'static, ()>` so they can be referenced in
+                // the `Min` associated type properly (which doesn't allow using `for<>`)
+                // This should work for any bound variables as long as they don't have any
+                // bounds e.g. `for<T: Trait>`.
+                // FIXME(effects) reconsider this approach to allow compatibility with `for<T: Tr>`
+                let ty = tcx.replace_bound_vars_uncached(
+                    ty,
+                    FnMutDelegate {
+                        regions: &mut |_| tcx.lifetimes.re_static,
+                        types: &mut |_| tcx.types.unit,
+                        consts: &mut |_| unimplemented!("`~const` does not support const binders"),
+                    },
+                );
+
+                self.effects_min_tys.insert(ty, span);
+                return;
+            }
+            // for
+            // ```
+            // trait Foo { type Bar: ~const Trait }
+            // ```
+            // ensure that `<Self::Bar as Trait>::Effects: TyCompat<Self::Effects>`.
+            //
+            // FIXME(effects) this is equality for now, which wouldn't be helpful for a non-const implementor
+            // that uses a `Bar` that implements `Trait` with `Maybe` effects.
+            (DefKind::AssocTy, ty::BoundConstness::ConstIfConst) => {
+                // FIXME(effects): implement this
+                return;
+            }
+            // probably illegal in this position.
+            (_, ty::BoundConstness::ConstIfConst) => {
+                tcx.dcx().span_delayed_bug(span, "invalid `~const` encountered");
+                return;
+            }
+        };
+        // create a new projection type `<T as Tr>::Effects`
+        let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else {
+            tcx.dcx().span_delayed_bug(
+                span,
+                "`~const` trait bound has no effect assoc yet no errors encountered?",
+            );
+            return;
+        };
+        let self_ty = Ty::new_projection(tcx, assoc, bound_trait_ref.skip_binder().args);
+        // make `<T as Tr>::Effects: Compat<runtime>`
+        let new_trait_ref = ty::TraitRef::new(
+            tcx,
+            tcx.require_lang_item(LangItem::EffectsCompat, Some(span)),
+            [ty::GenericArg::from(self_ty), compat_val.into()],
+        );
+        self.clauses.push((bound_trait_ref.rebind(new_trait_ref).upcast(tcx), span));
     }
 
     pub fn push_projection_bound(
@@ -79,7 +173,15 @@ impl<'tcx> Bounds<'tcx> {
         self.clauses.insert(0, (trait_ref.upcast(tcx), span));
     }
 
-    pub fn clauses(&self) -> impl Iterator<Item = (ty::Clause<'tcx>, Span)> + '_ {
+    pub fn clauses(
+        &self,
+        // FIXME(effects): remove tcx
+        _tcx: TyCtxt<'tcx>,
+    ) -> impl Iterator<Item = (ty::Clause<'tcx>, Span)> + '_ {
         self.clauses.iter().cloned()
     }
+
+    pub fn effects_min_tys(&self) -> impl Iterator<Item = Ty<'tcx>> + '_ {
+        self.effects_min_tys.keys().copied()
+    }
 }
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index b5c06751405..bf8ef18c04f 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -15,6 +15,7 @@ use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
 use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
 use rustc_middle::middle::stability::EvalResult;
 use rustc_middle::span_bug;
+use rustc_middle::ty::error::TypeErrorToStringExt;
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
 use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt};
@@ -24,9 +25,9 @@ use rustc_middle::ty::{
 };
 use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
 use rustc_target::abi::FieldIdx;
+use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedDirective;
+use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits;
-use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedDirective;
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_type_ir::fold::TypeFoldable;
 
@@ -46,13 +47,9 @@ pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
             .emit();
         }
         None => {
-            tcx.node_span_lint(
-                UNSUPPORTED_CALLING_CONVENTIONS,
-                hir_id,
-                span,
-                "use of calling convention not supported on this target",
-                |_| {},
-            );
+            tcx.node_span_lint(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| {
+                lint.primary_message("use of calling convention not supported on this target");
+            });
         }
     }
 
@@ -243,8 +240,8 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {
             UNINHABITED_STATIC,
             tcx.local_def_id_to_hir_id(def_id),
             span,
-            "static of uninhabited type",
             |lint| {
+                lint.primary_message("static of uninhabited type");
                 lint
                 .note("uninhabited statics cannot be initialized, and any access would be an immediate error");
             },
@@ -346,7 +343,7 @@ fn check_opaque_meets_bounds<'tcx>(
     let param_env = tcx.param_env(defining_use_anchor);
 
     let infcx = tcx.infer_ctxt().with_opaque_type_inference(defining_use_anchor).build();
-    let ocx = ObligationCtxt::new(&infcx);
+    let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
     let args = match *origin {
         hir::OpaqueTyOrigin::FnReturn(parent)
@@ -484,9 +481,12 @@ fn sanity_check_found_hidden_type<'tcx>(
 /// 2. Checking that all lifetimes that are implicitly captured are mentioned.
 /// 3. Asserting that all parameters mentioned in the captures list are invariant.
 fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDefId) {
-    let hir::OpaqueTy { precise_capturing_args, .. } =
+    let hir::OpaqueTy { bounds, .. } =
         *tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty();
-    let Some((precise_capturing_args, _)) = precise_capturing_args else {
+    let Some(precise_capturing_args) = bounds.iter().find_map(|bound| match *bound {
+        hir::GenericBound::Use(bounds, ..) => Some(bounds),
+        _ => None,
+    }) else {
         // No precise capturing args; nothing to validate
         return;
     };
@@ -538,11 +538,9 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe
                 // the cases that were stabilized with the `impl_trait_projection`
                 // feature -- see <https://github.com/rust-lang/rust/pull/115659>.
                 if let DefKind::LifetimeParam = tcx.def_kind(def_id)
-                    && let ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. })
-                    | ty::ReLateParam(ty::LateParamRegion {
-                        bound_region: ty::BoundRegionKind::BrNamed(def_id, _),
-                        ..
-                    }) = *tcx.map_opaque_lifetime_to_parent_lifetime(def_id.expect_local())
+                    && let Some(def_id) = tcx
+                        .map_opaque_lifetime_to_parent_lifetime(def_id.expect_local())
+                        .opt_param_def_id(tcx, tcx.parent(opaque_def_id.to_def_id()))
                 {
                     shadowed_captures.insert(def_id);
                 }
@@ -585,12 +583,9 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe
                     // Check if the lifetime param was captured but isn't named in the precise captures list.
                     if variances[param.index as usize] == ty::Invariant {
                         if let DefKind::OpaqueTy = tcx.def_kind(tcx.parent(param.def_id))
-                            && let ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. })
-                            | ty::ReLateParam(ty::LateParamRegion {
-                                bound_region: ty::BoundRegionKind::BrNamed(def_id, _),
-                                ..
-                            }) = *tcx
+                            && let Some(def_id) = tcx
                                 .map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local())
+                                .opt_param_def_id(tcx, tcx.parent(opaque_def_id.to_def_id()))
                         {
                             tcx.dcx().emit_err(errors::LifetimeNotCaptured {
                                 opaque_span,
@@ -724,7 +719,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
                             tcx,
                             assoc_item,
                             assoc_item,
-                            ty::TraitRef::new(tcx, def_id.to_def_id(), trait_args),
+                            ty::TraitRef::new_from_args(tcx, def_id.to_def_id(), trait_args),
                         );
                     }
                     _ => {}
@@ -810,7 +805,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
 
                         let item = tcx.hir().foreign_item(item.id);
                         match &item.kind {
-                            hir::ForeignItemKind::Fn(fn_decl, _, _) => {
+                            hir::ForeignItemKind::Fn(fn_decl, _, _, _) => {
                                 require_c_abi_if_c_variadic(tcx, fn_decl, abi, item.span);
                             }
                             hir::ForeignItemKind::Static(..) => {
@@ -884,7 +879,8 @@ pub(super) fn check_specialization_validity<'tcx>(
     let result = opt_result.unwrap_or(Ok(()));
 
     if let Err(parent_impl) = result {
-        if !tcx.is_impl_trait_in_trait(impl_item) {
+        // FIXME(effects) the associated type from effects could be specialized
+        if !tcx.is_impl_trait_in_trait(impl_item) && !tcx.is_effects_desugared_assoc_ty(impl_item) {
             report_forbidden_specialization(tcx, impl_item, parent_impl);
         } else {
             tcx.dcx().delayed_bug(format!("parent item: {parent_impl:?} not marked as default"));
@@ -1315,9 +1311,11 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
                     REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
                     tcx.local_def_id_to_hir_id(adt.did().expect_local()),
                     span,
-                    "zero-sized fields in `repr(transparent)` cannot \
-                    contain external non-exhaustive types",
                     |lint| {
+                        lint.primary_message(
+                            "zero-sized fields in `repr(transparent)` cannot \
+                             contain external non-exhaustive types",
+                        );
                         let note = if non_exhaustive {
                             "is marked with `#[non_exhaustive]`"
                         } else {
@@ -1734,7 +1732,7 @@ pub(super) fn check_coroutine_obligations(
         .with_opaque_type_inference(def_id)
         .build();
 
-    let ocx = ObligationCtxt::new(&infcx);
+    let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
     for (predicate, cause) in &typeck_results.coroutine_stalled_predicates {
         ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, *predicate));
     }
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 44bf8fd2d93..6c53625b590 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -10,7 +10,7 @@ use rustc_hir::intravisit;
 use rustc_hir::{GenericParamKind, ImplItemKind};
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
-use rustc_infer::traits::{util, FulfillmentError};
+use rustc_infer::traits::util;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::util::ExplicitSelf;
@@ -21,11 +21,12 @@ use rustc_middle::ty::{
 use rustc_middle::ty::{GenericParamDefKind, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_span::Span;
+use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt;
+use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::regions::InferCtxtRegionExt;
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
 use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_trait_selection::traits::{
-    self, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal,
+    self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal,
 };
 use std::borrow::Cow;
 use std::iter;
@@ -225,7 +226,7 @@ fn compare_method_predicate_entailment<'tcx>(
     let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
 
     let infcx = &tcx.infer_ctxt().build();
-    let ocx = ObligationCtxt::new(infcx);
+    let ocx = ObligationCtxt::new_with_diagnostics(infcx);
 
     debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds());
 
@@ -397,7 +398,7 @@ struct RemapLateBound<'a, 'tcx> {
 }
 
 impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateBound<'_, 'tcx> {
-    fn interner(&self) -> TyCtxt<'tcx> {
+    fn cx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
@@ -449,7 +450,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateBound<'_, 'tcx> {
 pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_m_def_id: LocalDefId,
-) -> Result<&'tcx DefIdMap<ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed> {
+) -> Result<&'tcx DefIdMap<ty::EarlyBinder<'tcx, Ty<'tcx>>>, ErrorGuaranteed> {
     let impl_m = tcx.opt_associated_item(impl_m_def_id.to_def_id()).unwrap();
     let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap();
     let impl_trait_ref =
@@ -493,7 +494,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
     );
 
     let infcx = &tcx.infer_ctxt().build();
-    let ocx = ObligationCtxt::new(infcx);
+    let ocx = ObligationCtxt::new_with_diagnostics(infcx);
 
     // Normalize the impl signature with fresh variables for lifetime inference.
     let misc_cause = ObligationCause::misc(return_span, impl_m_def_id);
@@ -764,17 +765,20 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
     Ok(&*tcx.arena.alloc(remapped_types))
 }
 
-struct ImplTraitInTraitCollector<'a, 'tcx> {
-    ocx: &'a ObligationCtxt<'a, 'tcx>,
+struct ImplTraitInTraitCollector<'a, 'tcx, E> {
+    ocx: &'a ObligationCtxt<'a, 'tcx, E>,
     types: FxIndexMap<DefId, (Ty<'tcx>, ty::GenericArgsRef<'tcx>)>,
     span: Span,
     param_env: ty::ParamEnv<'tcx>,
     body_id: LocalDefId,
 }
 
-impl<'a, 'tcx> ImplTraitInTraitCollector<'a, 'tcx> {
+impl<'a, 'tcx, E> ImplTraitInTraitCollector<'a, 'tcx, E>
+where
+    E: 'tcx,
+{
     fn new(
-        ocx: &'a ObligationCtxt<'a, 'tcx>,
+        ocx: &'a ObligationCtxt<'a, 'tcx, E>,
         span: Span,
         param_env: ty::ParamEnv<'tcx>,
         body_id: LocalDefId,
@@ -783,14 +787,17 @@ impl<'a, 'tcx> ImplTraitInTraitCollector<'a, 'tcx> {
     }
 }
 
-impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx> {
-    fn interner(&self) -> TyCtxt<'tcx> {
+impl<'tcx, E> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx, E>
+where
+    E: 'tcx,
+{
+    fn cx(&self) -> TyCtxt<'tcx> {
         self.ocx.infcx.tcx
     }
 
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
         if let ty::Alias(ty::Projection, proj) = ty.kind()
-            && self.interner().is_impl_trait_in_trait(proj.def_id)
+            && self.cx().is_impl_trait_in_trait(proj.def_id)
         {
             if let Some((ty, _)) = self.types.get(&proj.def_id) {
                 return *ty;
@@ -804,9 +811,9 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx> {
             self.types.insert(proj.def_id, (infer_ty, proj.args));
             // Recurse into bounds
             for (pred, pred_span) in self
-                .interner()
+                .cx()
                 .explicit_item_bounds(proj.def_id)
-                .iter_instantiated_copied(self.interner(), proj.args)
+                .iter_instantiated_copied(self.cx(), proj.args)
             {
                 let pred = pred.fold_with(self);
                 let pred = self.ocx.normalize(
@@ -816,7 +823,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx> {
                 );
 
                 self.ocx.register_obligation(traits::Obligation::new(
-                    self.interner(),
+                    self.cx(),
                     ObligationCause::new(
                         self.span,
                         self.body_id,
@@ -847,7 +854,7 @@ struct RemapHiddenTyRegions<'tcx> {
 impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for RemapHiddenTyRegions<'tcx> {
     type Error = ErrorGuaranteed;
 
-    fn interner(&self) -> TyCtxt<'tcx> {
+    fn cx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
@@ -876,7 +883,8 @@ impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for RemapHiddenTyRegions<'tcx> {
             ty::ReLateParam(_) => {}
             // Remap early-bound regions as long as they don't come from the `impl` itself,
             // in which case we don't really need to renumber them.
-            ty::ReEarlyParam(ebr) if self.tcx.parent(ebr.def_id) != self.impl_def_id => {}
+            ty::ReEarlyParam(ebr)
+                if ebr.index >= self.tcx.generics_of(self.impl_def_id).count() as u32 => {}
             _ => return Ok(region),
         }
 
@@ -889,12 +897,8 @@ impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for RemapHiddenTyRegions<'tcx> {
                 );
             }
         } else {
-            let guar = match region.kind() {
-                ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. })
-                | ty::ReLateParam(ty::LateParamRegion {
-                    bound_region: ty::BoundRegionKind::BrNamed(def_id, _),
-                    ..
-                }) => {
+            let guar = match region.opt_param_def_id(self.tcx, self.tcx.parent(self.def_id)) {
+                Some(def_id) => {
                     let return_span = if let ty::Alias(ty::Opaque, opaque_ty) = self.ty.kind() {
                         self.tcx.def_span(opaque_ty.def_id)
                     } else {
@@ -914,7 +918,7 @@ impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for RemapHiddenTyRegions<'tcx> {
                         .with_note(format!("hidden type inferred to be `{}`", self.ty))
                         .emit()
                 }
-                _ => {
+                None => {
                     // This code path is not reached in any tests, but may be
                     // reachable. If this is triggered, it should be converted
                     // to `delayed_bug` and the triggering case turned into a
@@ -928,7 +932,6 @@ impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for RemapHiddenTyRegions<'tcx> {
         Ok(ty::Region::new_early_param(
             self.tcx,
             ty::EarlyParamRegion {
-                def_id: e.def_id,
                 name: e.name,
                 index: (e.index as usize - self.num_trait_args + self.num_impl_args) as u32,
             },
@@ -979,7 +982,7 @@ fn report_trait_method_mismatch<'tcx>(
                 .next()
                 .unwrap_or(impl_err_span);
 
-            diag.span_suggestion(
+            diag.span_suggestion_verbose(
                 span,
                 "change the self-receiver type to match the trait",
                 sugg,
@@ -1003,12 +1006,12 @@ fn report_trait_method_mismatch<'tcx>(
                         }
                         hir::FnRetTy::Return(hir_ty) => {
                             let sugg = trait_sig.output();
-                            diag.span_suggestion(hir_ty.span, msg, sugg, ap);
+                            diag.span_suggestion_verbose(hir_ty.span, msg, sugg, ap);
                         }
                     };
                 };
             } else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
-                diag.span_suggestion(
+                diag.span_suggestion_verbose(
                     impl_err_span,
                     "change the parameter type to match the trait",
                     trait_ty,
@@ -1781,7 +1784,7 @@ fn compare_const_predicate_entailment<'tcx>(
     );
 
     let infcx = tcx.infer_ctxt().build();
-    let ocx = ObligationCtxt::new(&infcx);
+    let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
     let impl_ct_own_bounds = impl_ct_predicates.instantiate_own(tcx, impl_args);
     for (predicate, span) in impl_ct_own_bounds {
@@ -1914,7 +1917,7 @@ fn compare_type_predicate_entailment<'tcx>(
     let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing);
     let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
     let infcx = tcx.infer_ctxt().build();
-    let ocx = ObligationCtxt::new(&infcx);
+    let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
     debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds());
 
@@ -1981,12 +1984,12 @@ pub(super) fn check_type_bounds<'tcx>(
     let rebased_args = impl_ty_args.rebase_onto(tcx, container_id, impl_trait_ref.args);
 
     let infcx = tcx.infer_ctxt().build();
-    let ocx = ObligationCtxt::new(&infcx);
+    let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
-    // A synthetic impl Trait for RPITIT desugaring has no HIR, which we currently use to get the
-    // span for an impl's associated type. Instead, for these, use the def_span for the synthesized
-    // associated type.
-    let impl_ty_span = if impl_ty.is_impl_trait_in_trait() {
+    // A synthetic impl Trait for RPITIT desugaring or assoc type for effects desugaring has no HIR,
+    // which we currently use to get the span for an impl's associated type. Instead, for these,
+    // use the def_span for the synthesized  associated type.
+    let impl_ty_span = if impl_ty.is_impl_trait_in_trait() || impl_ty.is_effects_desugaring {
         tcx.def_span(impl_ty_def_id)
     } else {
         match tcx.hir_node_by_def_id(impl_ty_def_id) {
@@ -2030,10 +2033,19 @@ pub(super) fn check_type_bounds<'tcx>(
     // to its definition type. This should be the param-env we use to *prove* the
     // predicate too, but we don't do that because of performance issues.
     // See <https://github.com/rust-lang/rust/pull/117542#issue-1976337685>.
+    let trait_projection_ty = Ty::new_projection_from_args(tcx, trait_ty.def_id, rebased_args);
+    let impl_identity_ty = tcx.type_of(impl_ty.def_id).instantiate_identity();
     let normalize_param_env = param_env_with_gat_bounds(tcx, impl_ty, impl_trait_ref);
     for mut obligation in util::elaborate(tcx, obligations) {
-        let normalized_predicate =
-            ocx.normalize(&normalize_cause, normalize_param_env, obligation.predicate);
+        let normalized_predicate = if infcx.next_trait_solver() {
+            obligation.predicate.fold_with(&mut ReplaceTy {
+                tcx,
+                from: trait_projection_ty,
+                to: impl_identity_ty,
+            })
+        } else {
+            ocx.normalize(&normalize_cause, normalize_param_env, obligation.predicate)
+        };
         debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate);
         obligation.predicate = normalized_predicate;
 
@@ -2054,6 +2066,22 @@ pub(super) fn check_type_bounds<'tcx>(
     ocx.resolve_regions_and_report_errors(impl_ty_def_id, &outlives_env)
 }
 
+struct ReplaceTy<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    from: Ty<'tcx>,
+    to: Ty<'tcx>,
+}
+
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceTy<'tcx> {
+    fn cx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        if self.from == ty { self.to } else { ty.super_fold_with(self) }
+    }
+}
+
 /// Install projection predicates that allow GATs to project to their own
 /// definition types. This is not allowed in general in cases of default
 /// associated types in trait definitions, or when specialization is involved,
@@ -2171,9 +2199,6 @@ fn param_env_with_gat_bounds<'tcx>(
                         tcx,
                         ty::INNERMOST,
                         ty::BoundVar::from_usize(bound_vars.len() - 1),
-                        tcx.type_of(param.def_id)
-                            .no_bound_vars()
-                            .expect("const parameter types cannot be generic"),
                     )
                     .into()
                 }
@@ -2206,7 +2231,11 @@ fn param_env_with_gat_bounds<'tcx>(
             _ => predicates.push(
                 ty::Binder::bind_with_vars(
                     ty::ProjectionPredicate {
-                        projection_term: ty::AliasTerm::new(tcx, trait_ty.def_id, rebased_args),
+                        projection_term: ty::AliasTerm::new_from_args(
+                            tcx,
+                            trait_ty.def_id,
+                            rebased_args,
+                        ),
                         term: normalize_impl_ty.into(),
                     },
                     bound_vars,
@@ -2254,7 +2283,7 @@ fn try_report_async_mismatch<'tcx>(
             && let Some(proj) = proj.no_bound_vars()
             && infcx.can_eq(
                 error.root_obligation.param_env,
-                proj.term.ty().unwrap(),
+                proj.term.expect_type(),
                 impl_sig.output(),
             )
         {
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
index ca08eeea227..ad3324f79e2 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
@@ -171,10 +171,10 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
     }
     // Resolve any lifetime variables that may have been introduced during normalization.
     let Ok((trait_bounds, impl_bounds)) = infcx.fully_resolve((trait_bounds, impl_bounds)) else {
-        // This code path is not reached in any tests, but may be reachable. If
-        // this is triggered, it should be converted to `delayed_bug` and the
-        // triggering case turned into a test.
-        tcx.dcx().bug("encountered errors when checking RPITIT refinement (resolution)");
+        // If resolution didn't fully complete, we cannot continue checking RPITIT refinement, and
+        // delay a bug as the original code contains load-bearing errors.
+        tcx.dcx().delayed_bug("encountered errors when checking RPITIT refinement (resolution)");
+        return;
     };
 
     // For quicker lookup, use an `IndexSet` (we don't use one earlier because
@@ -267,7 +267,7 @@ fn report_mismatched_rpitit_signature<'tcx>(
             .explicit_item_bounds(future_ty.def_id)
             .iter_instantiated_copied(tcx, future_ty.args)
             .find_map(|(clause, _)| match clause.kind().no_bound_vars()? {
-                ty::ClauseKind::Projection(proj) => proj.term.ty(),
+                ty::ClauseKind::Projection(proj) => proj.term.as_type(),
                 _ => None,
             })
         else {
@@ -322,7 +322,7 @@ struct Anonymize<'tcx> {
 }
 
 impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Anonymize<'tcx> {
-    fn interner(&self) -> TyCtxt<'tcx> {
+    fn cx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs
index be412dde968..19371448025 100644
--- a/compiler/rustc_hir_analysis/src/check/dropck.rs
+++ b/compiler/rustc_hir_analysis/src/check/dropck.rs
@@ -1,6 +1,7 @@
 // FIXME(@lcnr): Move this module out of `rustc_hir_analysis`.
 //
 // We don't do any drop checking during hir typeck.
+
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed};
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
@@ -123,7 +124,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
     adt_to_impl_args: GenericArgsRef<'tcx>,
 ) -> Result<(), ErrorGuaranteed> {
     let infcx = tcx.infer_ctxt().build();
-    let ocx = ObligationCtxt::new(&infcx);
+    let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
     // Take the param-env of the adt and instantiate the args that show up in
     // the implementation's self type. This gives us the assumptions that the
diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs
index 25ac31c16c7..ce921f64481 100644
--- a/compiler/rustc_hir_analysis/src/check/entry.rs
+++ b/compiler/rustc_hir_analysis/src/check/entry.rs
@@ -7,7 +7,7 @@ use rustc_session::config::EntryFnType;
 use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_span::{symbol::sym, Span};
 use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
+use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
 
 use std::ops::Not;
@@ -133,7 +133,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
             main_diagnostics_def_id,
             ObligationCauseCode::MainFunctionType,
         );
-        let ocx = traits::ObligationCtxt::new(&infcx);
+        let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);
         let norm_return_ty = ocx.normalize(&cause, param_env, return_ty);
         ocx.register_bound(cause, param_env, norm_return_ty, term_did);
         let errors = ocx.select_all_or_error();
diff --git a/compiler/rustc_hir_analysis/src/check/errs.rs b/compiler/rustc_hir_analysis/src/check/errs.rs
index a49626eed35..17cb20df754 100644
--- a/compiler/rustc_hir_analysis/src/check/errs.rs
+++ b/compiler/rustc_hir_analysis/src/check/errs.rs
@@ -41,7 +41,8 @@ fn path_if_static_mut(tcx: TyCtxt<'_>, expr: &hir::Expr<'_>) -> Option<String> {
     if let hir::ExprKind::Path(qpath) = expr.kind
         && let hir::QPath::Resolved(_, path) = qpath
         && let hir::def::Res::Def(def_kind, _) = path.res
-        && let hir::def::DefKind::Static { mutability: Mutability::Mut, nested: false } = def_kind
+        && let hir::def::DefKind::Static { safety: _, mutability: Mutability::Mut, nested: false } =
+            def_kind
     {
         return Some(qpath_to_string(&tcx, &qpath));
     }
@@ -62,7 +63,7 @@ fn handle_static_mut_ref(
         } else {
             (errors::StaticMutRefSugg::Shared { span, var }, "shared")
         };
-        tcx.sess.psess.dcx.emit_err(errors::StaticMutRef { span, sugg, shared });
+        tcx.dcx().emit_err(errors::StaticMutRef { span, sugg, shared });
     } else {
         let (sugg, shared) = if mutable == Mutability::Mut {
             (errors::RefOfMutStaticSugg::Mut { span, var }, "mutable")
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 50fe20346cf..6282499883b 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -26,15 +26,12 @@ fn equate_intrinsic_type<'tcx>(
     n_cts: usize,
     sig: ty::PolyFnSig<'tcx>,
 ) {
-    let (own_counts, span) = match tcx.hir_node_by_def_id(def_id) {
+    let (generics, span) = match tcx.hir_node_by_def_id(def_id) {
         hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. })
         | hir::Node::ForeignItem(hir::ForeignItem {
-            kind: hir::ForeignItemKind::Fn(.., generics),
+            kind: hir::ForeignItemKind::Fn(.., generics, _),
             ..
-        }) => {
-            let own_counts = tcx.generics_of(def_id).own_counts();
-            (own_counts, generics.span)
-        }
+        }) => (tcx.generics_of(def_id), generics.span),
         _ => {
             struct_span_code_err!(tcx.dcx(), span, E0622, "intrinsic must be a function")
                 .with_span_label(span, "expected a function")
@@ -42,6 +39,7 @@ fn equate_intrinsic_type<'tcx>(
             return;
         }
     };
+    let own_counts = generics.own_counts();
 
     let gen_count_ok = |found: usize, expected: usize, descr: &str| -> bool {
         if found != expected {
@@ -57,9 +55,17 @@ fn equate_intrinsic_type<'tcx>(
         }
     };
 
+    // the host effect param should be invisible as it shouldn't matter
+    // whether effects is enabled for the intrinsic provider crate.
+    let consts_count = if generics.host_effect_index.is_some() {
+        own_counts.consts - 1
+    } else {
+        own_counts.consts
+    };
+
     if gen_count_ok(own_counts.lifetimes, n_lts, "lifetime")
         && gen_count_ok(own_counts.types, n_tps, "type")
-        && gen_count_ok(own_counts.consts, n_cts, "const")
+        && gen_count_ok(consts_count, n_cts, "const")
     {
         let _ = check_function_signature(
             tcx,
@@ -130,6 +136,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
         | sym::is_val_statically_known
         | sym::ptr_mask
         | sym::aggregate_raw_ptr
+        | sym::ptr_metadata
         | sym::ub_checks
         | sym::fadd_algebraic
         | sym::fsub_algebraic
@@ -164,9 +171,8 @@ pub fn check_intrinsic_type(
 ) {
     let generics = tcx.generics_of(intrinsic_id);
     let param = |n| {
-        if let Some(&ty::GenericParamDef {
-            name, kind: ty::GenericParamDefKind::Type { .. }, ..
-        }) = generics.opt_param_at(n as usize, tcx)
+        if let &ty::GenericParamDef { name, kind: ty::GenericParamDefKind::Type { .. }, .. } =
+            generics.param_at(n as usize, tcx)
         {
             Ty::new_param(tcx, n, name)
         } else {
@@ -429,17 +435,17 @@ pub fn check_intrinsic_type(
 
             sym::ptr_guaranteed_cmp => (
                 1,
-                1,
+                0,
                 vec![Ty::new_imm_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0))],
                 tcx.types.u8,
             ),
 
             sym::const_allocate => {
-                (0, 1, vec![tcx.types.usize, tcx.types.usize], Ty::new_mut_ptr(tcx, tcx.types.u8))
+                (0, 0, vec![tcx.types.usize, tcx.types.usize], Ty::new_mut_ptr(tcx, tcx.types.u8))
             }
             sym::const_deallocate => (
                 0,
-                1,
+                0,
                 vec![Ty::new_mut_ptr(tcx, tcx.types.u8), tcx.types.usize, tcx.types.usize],
                 tcx.types.unit,
             ),
@@ -478,16 +484,16 @@ pub fn check_intrinsic_type(
             | sym::frem_algebraic => (1, 0, vec![param(0), param(0)], param(0)),
             sym::float_to_int_unchecked => (2, 0, vec![param(0)], param(1)),
 
-            sym::assume => (0, 1, vec![tcx.types.bool], tcx.types.unit),
-            sym::likely => (0, 1, vec![tcx.types.bool], tcx.types.bool),
-            sym::unlikely => (0, 1, vec![tcx.types.bool], tcx.types.bool),
+            sym::assume => (0, 0, vec![tcx.types.bool], tcx.types.unit),
+            sym::likely => (0, 0, vec![tcx.types.bool], tcx.types.bool),
+            sym::unlikely => (0, 0, vec![tcx.types.bool], tcx.types.bool),
 
             sym::read_via_copy => (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)),
             sym::write_via_move => {
                 (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit)
             }
 
-            sym::typed_swap => (1, 1, vec![Ty::new_mut_ptr(tcx, param(0)); 2], tcx.types.unit),
+            sym::typed_swap => (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)); 2], tcx.types.unit),
 
             sym::discriminant_value => {
                 let assoc_items = tcx.associated_item_def_ids(
@@ -504,7 +510,11 @@ pub fn check_intrinsic_type(
                         ty::Region::new_bound(tcx, ty::INNERMOST, br),
                         param(0),
                     )],
-                    Ty::new_projection(tcx, discriminant_def_id, tcx.mk_args(&[param(0).into()])),
+                    Ty::new_projection_from_args(
+                        tcx,
+                        discriminant_def_id,
+                        tcx.mk_args(&[param(0).into()]),
+                    ),
                 )
             }
 
@@ -566,9 +576,9 @@ pub fn check_intrinsic_type(
 
             sym::black_box => (1, 0, vec![param(0)], param(0)),
 
-            sym::is_val_statically_known => (1, 1, vec![param(0)], tcx.types.bool),
+            sym::is_val_statically_known => (1, 0, vec![param(0)], tcx.types.bool),
 
-            sym::const_eval_select => (4, 1, vec![param(0), param(1), param(2)], param(3)),
+            sym::const_eval_select => (4, 0, vec![param(0), param(1), param(2)], param(3)),
 
             sym::vtable_size | sym::vtable_align => {
                 (0, 0, vec![Ty::new_imm_ptr(tcx, tcx.types.unit)], tcx.types.usize)
@@ -576,9 +586,10 @@ pub fn check_intrinsic_type(
 
             // This type check is not particularly useful, but the `where` bounds
             // on the definition in `core` do the heavy lifting for checking it.
-            sym::aggregate_raw_ptr => (3, 1, vec![param(1), param(2)], param(0)),
+            sym::aggregate_raw_ptr => (3, 0, vec![param(1), param(2)], param(0)),
+            sym::ptr_metadata => (2, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(1)),
 
-            sym::ub_checks => (0, 1, Vec::new(), tcx.types.bool),
+            sym::ub_checks => (0, 0, Vec::new(), tcx.types.bool),
 
             sym::simd_eq
             | sym::simd_ne
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index b09de1a4a09..2e965c59ebb 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
@@ -1,6 +1,6 @@
 use rustc_ast::InlineAsmTemplatePiece;
 use rustc_data_structures::fx::FxIndexSet;
-use rustc_hir as hir;
+use rustc_hir::{self as hir, LangItem};
 use rustc_middle::bug;
 use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy};
 use rustc_session::lint;
@@ -62,8 +62,10 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
             ty::Int(IntTy::I64) | ty::Uint(UintTy::U64) => Some(InlineAsmType::I64),
             ty::Int(IntTy::I128) | ty::Uint(UintTy::U128) => Some(InlineAsmType::I128),
             ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => Some(asm_ty_isize),
+            ty::Float(FloatTy::F16) => Some(InlineAsmType::F16),
             ty::Float(FloatTy::F32) => Some(InlineAsmType::F32),
             ty::Float(FloatTy::F64) => Some(InlineAsmType::F64),
+            ty::Float(FloatTy::F128) => Some(InlineAsmType::F128),
             ty::FnPtr(_) => Some(asm_ty_isize),
             ty::RawPtr(ty, _) if self.is_thin_ptr_ty(ty) => Some(asm_ty_isize),
             ty::Adt(adt, args) if adt.repr().simd() => {
@@ -105,8 +107,10 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                             width => bug!("unsupported pointer width: {width}"),
                         })
                     }
+                    ty::Float(FloatTy::F16) => Some(InlineAsmType::VecF16(size)),
                     ty::Float(FloatTy::F32) => Some(InlineAsmType::VecF32(size)),
                     ty::Float(FloatTy::F64) => Some(InlineAsmType::VecF64(size)),
+                    ty::Float(FloatTy::F128) => Some(InlineAsmType::VecF128(size)),
                     _ => None,
                 }
             }
@@ -134,7 +138,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
             // `!` is allowed for input but not for output (issue #87802)
             ty::Never if is_input => return None,
             _ if ty.references_error() => return None,
-            ty::Adt(adt, args) if Some(adt.did()) == self.tcx.lang_items().maybe_uninit() => {
+            ty::Adt(adt, args) if self.tcx.is_lang_item(adt.did(), LangItem::MaybeUninit) => {
                 let fields = &adt.non_enum_variant().fields;
                 let ty = fields[FieldIdx::from_u32(1)].ty(self.tcx, args);
                 // FIXME: Are we just trying to map to the `T` in `MaybeUninit<T>`?
@@ -281,8 +285,8 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                     lint::builtin::ASM_SUB_REGISTER,
                     expr.hir_id,
                     spans,
-                    "formatting may not be suitable for sub-register argument",
                     |lint| {
+                        lint.primary_message("formatting may not be suitable for sub-register argument");
                         lint.span_label(expr.span, "for this argument");
                         lint.help(format!(
                             "use `{{{idx}:{suggested_modifier}}}` to have the register formatted as `{suggested_result}` (for {suggested_size}-bit values)",
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 0083da2a1e4..9fef31acef8 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -82,7 +82,7 @@ use rustc_errors::{pluralize, struct_span_code_err, Diag};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
 use rustc_index::bit_set::BitSet;
-use rustc_infer::infer::error_reporting::ObligationCauseExt as _;
+use rustc_infer::error_reporting::infer::ObligationCauseExt as _;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{self, TyCtxtInferExt as _};
 use rustc_infer::traits::ObligationCause;
@@ -96,10 +96,10 @@ use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{def_id::CRATE_DEF_ID, BytePos, Span, Symbol, DUMMY_SP};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::traits::error_reporting::suggestions::{
+use rustc_trait_selection::error_reporting::traits::suggestions::{
     ReturnsVisitor, TypeErrCtxtExt as _,
 };
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
+use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::ObligationCtxt;
 
 use crate::errors;
@@ -112,6 +112,7 @@ pub fn provide(providers: &mut Providers) {
     wfcheck::provide(providers);
     *providers = Providers {
         adt_destructor,
+        adt_async_destructor,
         region_scope_tree,
         collect_return_position_impl_trait_in_trait_tys,
         compare_impl_const: compare_impl_item::compare_impl_const_raw,
@@ -124,6 +125,10 @@ fn adt_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::Destructor>
     tcx.calculate_dtor(def_id.to_def_id(), dropck::check_drop_impl)
 }
 
+fn adt_async_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::AsyncDestructor> {
+    tcx.calculate_async_dtor(def_id.to_def_id(), dropck::check_drop_impl)
+}
+
 /// Given a `DefId` for an opaque type in return position, find its parent item's return
 /// expressions.
 fn get_owner_return_paths(
@@ -206,11 +211,18 @@ fn missing_items_err(
         .collect::<Vec<_>>()
         .join("`, `");
 
-    // `Span` before impl block closing brace.
-    let hi = full_impl_span.hi() - BytePos(1);
-    // Point at the place right before the closing brace of the relevant `impl` to suggest
-    // adding the associated item at the end of its body.
-    let sugg_sp = full_impl_span.with_lo(hi).with_hi(hi);
+    let sugg_sp = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(full_impl_span)
+        && snippet.ends_with("}")
+    {
+        // `Span` before impl block closing brace.
+        let hi = full_impl_span.hi() - BytePos(1);
+        // Point at the place right before the closing brace of the relevant `impl` to suggest
+        // adding the associated item at the end of its body.
+        full_impl_span.with_lo(hi).with_hi(hi)
+    } else {
+        full_impl_span.shrink_to_hi()
+    };
+
     // Obtain the level of indentation ending in `sugg_sp`.
     let padding =
         tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(|| String::new());
@@ -436,7 +448,9 @@ fn fn_sig_suggestion<'tcx>(
         output = if let ty::Alias(_, alias_ty) = *output.kind() {
             tcx.explicit_item_super_predicates(alias_ty.def_id)
                 .iter_instantiated_copied(tcx, alias_ty.args)
-                .find_map(|(bound, _)| bound.as_projection_clause()?.no_bound_vars()?.term.ty())
+                .find_map(|(bound, _)| {
+                    bound.as_projection_clause()?.no_bound_vars()?.term.as_type()
+                })
                 .unwrap_or_else(|| {
                     span_bug!(
                         ident.span,
@@ -594,7 +608,7 @@ pub fn check_function_signature<'tcx>(
     let param_env = ty::ParamEnv::empty();
 
     let infcx = &tcx.infer_ctxt().build();
-    let ocx = ObligationCtxt::new(infcx);
+    let ocx = ObligationCtxt::new_with_diagnostics(infcx);
 
     let actual_sig = tcx.fn_sig(fn_id).instantiate_identity();
 
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index e51f95eed02..2b5efd3b2f6 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -6,7 +6,6 @@
 //!
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html
 
-use rustc_ast::visit::visit_opt;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
@@ -168,7 +167,14 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h
                 hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => visitor.visit_stmt(statement),
             }
         }
-        visit_opt!(visitor, visit_expr, &blk.expr);
+        if let Some(tail_expr) = blk.expr {
+            if visitor.tcx.features().shorter_tail_lifetimes
+                && blk.span.edition().at_least_rust_2024()
+            {
+                visitor.terminating_scopes.insert(tail_expr.hir_id.local_id);
+            }
+            visitor.visit_expr(tail_expr);
+        }
     }
 
     visitor.cx = prev_cx;
@@ -782,25 +788,8 @@ impl<'tcx> RegionResolutionVisitor<'tcx> {
         }
         self.enter_scope(Scope { id, data: ScopeData::Node });
     }
-}
-
-impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
-    fn visit_block(&mut self, b: &'tcx Block<'tcx>) {
-        resolve_block(self, b);
-    }
-
-    fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
-        let body_id = body.id();
-        let owner_id = self.tcx.hir().body_owner_def_id(body_id);
-
-        debug!(
-            "visit_body(id={:?}, span={:?}, body.id={:?}, cx.parent={:?})",
-            owner_id,
-            self.tcx.sess.source_map().span_to_diagnostic_string(body.value.span),
-            body_id,
-            self.cx.parent
-        );
 
+    fn enter_body(&mut self, hir_id: hir::HirId, f: impl FnOnce(&mut Self)) {
         // Save all state that is specific to the outer function
         // body. These will be restored once down below, once we've
         // visited the body.
@@ -812,43 +801,12 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
         // control flow assumptions. This doesn't apply to nested
         // bodies within the `+=` statements. See #69307.
         let outer_pessimistic_yield = mem::replace(&mut self.pessimistic_yield, false);
-        self.terminating_scopes.insert(body.value.hir_id.local_id);
+        self.terminating_scopes.insert(hir_id.local_id);
 
-        self.enter_scope(Scope { id: body.value.hir_id.local_id, data: ScopeData::CallSite });
-        self.enter_scope(Scope { id: body.value.hir_id.local_id, data: ScopeData::Arguments });
+        self.enter_scope(Scope { id: hir_id.local_id, data: ScopeData::CallSite });
+        self.enter_scope(Scope { id: hir_id.local_id, data: ScopeData::Arguments });
 
-        // The arguments and `self` are parented to the fn.
-        self.cx.var_parent = self.cx.parent.take();
-        for param in body.params {
-            self.visit_pat(param.pat);
-        }
-
-        // The body of the every fn is a root scope.
-        self.cx.parent = self.cx.var_parent;
-        if self.tcx.hir().body_owner_kind(owner_id).is_fn_or_closure() {
-            self.visit_expr(body.value)
-        } else {
-            // Only functions have an outer terminating (drop) scope, while
-            // temporaries in constant initializers may be 'static, but only
-            // according to rvalue lifetime semantics, using the same
-            // syntactical rules used for let initializers.
-            //
-            // e.g., in `let x = &f();`, the temporary holding the result from
-            // the `f()` call lives for the entirety of the surrounding block.
-            //
-            // Similarly, `const X: ... = &f();` would have the result of `f()`
-            // live for `'static`, implying (if Drop restrictions on constants
-            // ever get lifted) that the value *could* have a destructor, but
-            // it'd get leaked instead of the destructor running during the
-            // evaluation of `X` (if at all allowed by CTFE).
-            //
-            // However, `const Y: ... = g(&f());`, like `let y = g(&f());`,
-            // would *not* let the `f()` temporary escape into an outer scope
-            // (i.e., `'static`), which means that after `g` returns, it drops,
-            // and all the associated destruction scope rules apply.
-            self.cx.var_parent = None;
-            resolve_local(self, None, Some(body.value));
-        }
+        f(self);
 
         // Restore context we had at the start.
         self.expr_and_pat_count = outer_ec;
@@ -856,6 +814,60 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
         self.terminating_scopes = outer_ts;
         self.pessimistic_yield = outer_pessimistic_yield;
     }
+}
+
+impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
+    fn visit_block(&mut self, b: &'tcx Block<'tcx>) {
+        resolve_block(self, b);
+    }
+
+    fn visit_body(&mut self, body: &hir::Body<'tcx>) {
+        let body_id = body.id();
+        let owner_id = self.tcx.hir().body_owner_def_id(body_id);
+
+        debug!(
+            "visit_body(id={:?}, span={:?}, body.id={:?}, cx.parent={:?})",
+            owner_id,
+            self.tcx.sess.source_map().span_to_diagnostic_string(body.value.span),
+            body_id,
+            self.cx.parent
+        );
+
+        self.enter_body(body.value.hir_id, |this| {
+            if this.tcx.hir().body_owner_kind(owner_id).is_fn_or_closure() {
+                // The arguments and `self` are parented to the fn.
+                this.cx.var_parent = this.cx.parent.take();
+                for param in body.params {
+                    this.visit_pat(param.pat);
+                }
+
+                // The body of the every fn is a root scope.
+                this.cx.parent = this.cx.var_parent;
+                this.visit_expr(body.value)
+            } else {
+                // Only functions have an outer terminating (drop) scope, while
+                // temporaries in constant initializers may be 'static, but only
+                // according to rvalue lifetime semantics, using the same
+                // syntactical rules used for let initializers.
+                //
+                // e.g., in `let x = &f();`, the temporary holding the result from
+                // the `f()` call lives for the entirety of the surrounding block.
+                //
+                // Similarly, `const X: ... = &f();` would have the result of `f()`
+                // live for `'static`, implying (if Drop restrictions on constants
+                // ever get lifted) that the value *could* have a destructor, but
+                // it'd get leaked instead of the destructor running during the
+                // evaluation of `X` (if at all allowed by CTFE).
+                //
+                // However, `const Y: ... = g(&f());`, like `let y = g(&f());`,
+                // would *not* let the `f()` temporary escape into an outer scope
+                // (i.e., `'static`), which means that after `g` returns, it drops,
+                // and all the associated destruction scope rules apply.
+                this.cx.var_parent = None;
+                resolve_local(this, None, Some(body.value));
+            }
+        })
+    }
 
     fn visit_arm(&mut self, a: &'tcx Arm<'tcx>) {
         resolve_arm(self, a);
@@ -887,7 +899,7 @@ pub fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
         return tcx.region_scope_tree(typeck_root_def_id);
     }
 
-    let scope_tree = if let Some(body_id) = tcx.hir().maybe_body_owned_by(def_id.expect_local()) {
+    let scope_tree = if let Some(body) = tcx.hir().maybe_body_owned_by(def_id.expect_local()) {
         let mut visitor = RegionResolutionVisitor {
             tcx,
             scope_tree: ScopeTree::default(),
@@ -898,9 +910,8 @@ pub fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
             fixup_scopes: vec![],
         };
 
-        let body = tcx.hir().body(body_id);
         visitor.scope_tree.root_body = Some(body.value.hir_id);
-        visitor.visit_body(body);
+        visitor.visit_body(&body);
         visitor.scope_tree
     } else {
         ScopeTree::default()
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index e8ede804c3f..b2ef07d65c5 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -29,29 +29,30 @@ use rustc_session::parse::feature_err;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt;
 use rustc_trait_selection::regions::InferCtxtRegionExt;
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
 use rustc_trait_selection::traits::misc::{
     type_allowed_to_implement_const_param_ty, ConstParamTyImplementationError,
 };
 use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_trait_selection::traits::{
-    self, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc,
+    self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc,
 };
+use rustc_type_ir::solve::NoSolution;
 use rustc_type_ir::TypeFlags;
 
 use std::cell::LazyCell;
 use std::ops::{ControlFlow, Deref};
 
 pub(super) struct WfCheckingCtxt<'a, 'tcx> {
-    pub(super) ocx: ObligationCtxt<'a, 'tcx>,
+    pub(super) ocx: ObligationCtxt<'a, 'tcx, FulfillmentError<'tcx>>,
     span: Span,
     body_def_id: LocalDefId,
     param_env: ty::ParamEnv<'tcx>,
 }
 impl<'a, 'tcx> Deref for WfCheckingCtxt<'a, 'tcx> {
-    type Target = ObligationCtxt<'a, 'tcx>;
+    type Target = ObligationCtxt<'a, 'tcx, FulfillmentError<'tcx>>;
     fn deref(&self) -> &Self::Target {
         &self.ocx
     }
@@ -106,7 +107,7 @@ where
 {
     let param_env = tcx.param_env(body_def_id);
     let infcx = &tcx.infer_ctxt().build();
-    let ocx = ObligationCtxt::new(infcx);
+    let ocx = ObligationCtxt::new_with_diagnostics(infcx);
 
     let mut wfcx = WfCheckingCtxt { ocx, span, body_def_id, param_env };
 
@@ -119,16 +120,7 @@ where
 
     let errors = wfcx.select_all_or_error();
     if !errors.is_empty() {
-        let err = infcx.err_ctxt().report_fulfillment_errors(errors);
-        if tcx.dcx().has_errors().is_some() {
-            return Err(err);
-        } else {
-            // HACK(oli-obk): tests/ui/specialization/min_specialization/specialize_on_type_error.rs
-            // causes an delayed bug during normalization, without reporting an error, so we need
-            // to act as if no error happened, in order to let our callers continue and report an
-            // error later in check_impl_items_against_trait.
-            return Ok(());
-        }
+        return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
     }
 
     debug!(?assumed_wf_types);
@@ -486,7 +478,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
                             param_env,
                             item_def_id,
                             tcx.explicit_item_bounds(item_def_id)
-                                .instantiate_identity_iter_copied()
+                                .iter_identity_copied()
                                 .collect::<Vec<_>>(),
                             &FxIndexSet::default(),
                             gat_def_id,
@@ -675,11 +667,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
                 let region_param = gat_generics.param_at(*region_a_idx, tcx);
                 let region_param = ty::Region::new_early_param(
                     tcx,
-                    ty::EarlyParamRegion {
-                        def_id: region_param.def_id,
-                        index: region_param.index,
-                        name: region_param.name,
-                    },
+                    ty::EarlyParamRegion { index: region_param.index, name: region_param.name },
                 );
                 // The predicate we expect to see. (In our example,
                 // `Self: 'me`.)
@@ -708,21 +696,13 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
                 let region_a_param = gat_generics.param_at(*region_a_idx, tcx);
                 let region_a_param = ty::Region::new_early_param(
                     tcx,
-                    ty::EarlyParamRegion {
-                        def_id: region_a_param.def_id,
-                        index: region_a_param.index,
-                        name: region_a_param.name,
-                    },
+                    ty::EarlyParamRegion { index: region_a_param.index, name: region_a_param.name },
                 );
                 // Same for the region.
                 let region_b_param = gat_generics.param_at(*region_b_idx, tcx);
                 let region_b_param = ty::Region::new_early_param(
                     tcx,
-                    ty::EarlyParamRegion {
-                        def_id: region_b_param.def_id,
-                        index: region_b_param.index,
-                        name: region_b_param.name,
-                    },
+                    ty::EarlyParamRegion { index: region_b_param.index, name: region_b_param.name },
                 );
                 // The predicate we expect to see.
                 bounds.insert(
@@ -893,7 +873,7 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem
         _ => {}
     }
     if !trait_should_be_self.is_empty() {
-        if tcx.check_is_object_safe(trait_def_id) {
+        if tcx.is_object_safe(trait_def_id) {
             return;
         }
         let sugg = trait_should_be_self.iter().map(|span| (*span, "Self".to_string())).collect();
@@ -934,7 +914,12 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
         hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => Ok(()),
 
         // Const parameters are well formed if their type is structural match.
-        hir::GenericParamKind::Const { ty: hir_ty, default: _, is_host_effect: _ } => {
+        hir::GenericParamKind::Const {
+            ty: hir_ty,
+            default: _,
+            is_host_effect: _,
+            synthetic: _,
+        } => {
             let ty = tcx.type_of(param.def_id).instantiate_identity();
 
             if tcx.features().adt_const_params {
@@ -1220,17 +1205,16 @@ fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: ty::AssocIt
     let bounds = wfcx.tcx().explicit_item_bounds(item.def_id);
 
     debug!("check_associated_type_bounds: bounds={:?}", bounds);
-    let wf_obligations =
-        bounds.instantiate_identity_iter_copied().flat_map(|(bound, bound_span)| {
-            let normalized_bound = wfcx.normalize(span, None, bound);
-            traits::wf::clause_obligations(
-                wfcx.infcx,
-                wfcx.param_env,
-                wfcx.body_def_id,
-                normalized_bound,
-                bound_span,
-            )
-        });
+    let wf_obligations = bounds.iter_identity_copied().flat_map(|(bound, bound_span)| {
+        let normalized_bound = wfcx.normalize(span, None, bound);
+        traits::wf::clause_obligations(
+            wfcx.infcx,
+            wfcx.param_env,
+            wfcx.body_def_id,
+            normalized_bound,
+            bound_span,
+        )
+    });
 
     wfcx.register_obligations(wf_obligations);
 }
@@ -1728,13 +1712,12 @@ fn receiver_is_valid<'tcx>(
     let cause =
         ObligationCause::new(span, wfcx.body_def_id, traits::ObligationCauseCode::MethodReceiver);
 
-    let can_eq_self = |ty| infcx.can_eq(wfcx.param_env, self_ty, ty);
-
-    // `self: Self` is always valid.
-    if can_eq_self(receiver_ty) {
-        if let Err(err) = wfcx.eq(&cause, wfcx.param_env, self_ty, receiver_ty) {
-            infcx.err_ctxt().report_mismatched_types(&cause, self_ty, receiver_ty, err).emit();
-        }
+    // Special case `receiver == self_ty`, which doesn't necessarily require the `Receiver` lang item.
+    if let Ok(()) = wfcx.infcx.commit_if_ok(|_| {
+        let ocx = ObligationCtxt::new(wfcx.infcx);
+        ocx.eq(&cause, wfcx.param_env, self_ty, receiver_ty)?;
+        if ocx.select_all_or_error().is_empty() { Ok(()) } else { Err(NoSolution) }
+    }) {
         return true;
     }
 
@@ -1745,58 +1728,51 @@ fn receiver_is_valid<'tcx>(
         autoderef = autoderef.include_raw_pointers();
     }
 
-    // The first type is `receiver_ty`, which we know its not equal to `self_ty`; skip it.
-    autoderef.next();
-
     let receiver_trait_def_id = tcx.require_lang_item(LangItem::Receiver, Some(span));
 
     // Keep dereferencing `receiver_ty` until we get to `self_ty`.
-    loop {
-        if let Some((potential_self_ty, _)) = autoderef.next() {
-            debug!(
-                "receiver_is_valid: potential self type `{:?}` to match `{:?}`",
-                potential_self_ty, self_ty
-            );
-
-            if can_eq_self(potential_self_ty) {
-                wfcx.register_obligations(autoderef.into_obligations());
+    while let Some((potential_self_ty, _)) = autoderef.next() {
+        debug!(
+            "receiver_is_valid: potential self type `{:?}` to match `{:?}`",
+            potential_self_ty, self_ty
+        );
 
-                if let Err(err) = wfcx.eq(&cause, wfcx.param_env, self_ty, potential_self_ty) {
-                    infcx
-                        .err_ctxt()
-                        .report_mismatched_types(&cause, self_ty, potential_self_ty, err)
-                        .emit();
-                }
+        // Check if the self type unifies. If it does, then commit the result
+        // since it may have region side-effects.
+        if let Ok(()) = wfcx.infcx.commit_if_ok(|_| {
+            let ocx = ObligationCtxt::new(wfcx.infcx);
+            ocx.eq(&cause, wfcx.param_env, self_ty, potential_self_ty)?;
+            if ocx.select_all_or_error().is_empty() { Ok(()) } else { Err(NoSolution) }
+        }) {
+            wfcx.register_obligations(autoderef.into_obligations());
+            return true;
+        }
 
+        // Without `feature(arbitrary_self_types)`, we require that each step in the
+        // deref chain implement `receiver`.
+        if !arbitrary_self_types_enabled {
+            if !receiver_is_implemented(
+                wfcx,
+                receiver_trait_def_id,
+                cause.clone(),
+                potential_self_ty,
+            ) {
+                // We cannot proceed.
                 break;
-            } else {
-                // Without `feature(arbitrary_self_types)`, we require that each step in the
-                // deref chain implement `receiver`
-                if !arbitrary_self_types_enabled
-                    && !receiver_is_implemented(
-                        wfcx,
-                        receiver_trait_def_id,
-                        cause.clone(),
-                        potential_self_ty,
-                    )
-                {
-                    return false;
-                }
             }
-        } else {
-            debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty);
-            return false;
-        }
-    }
 
-    // Without `feature(arbitrary_self_types)`, we require that `receiver_ty` implements `Receiver`.
-    if !arbitrary_self_types_enabled
-        && !receiver_is_implemented(wfcx, receiver_trait_def_id, cause.clone(), receiver_ty)
-    {
-        return false;
+            // Register the bound, in case it has any region side-effects.
+            wfcx.register_bound(
+                cause.clone(),
+                wfcx.param_env,
+                potential_self_ty,
+                receiver_trait_def_id,
+            );
+        }
     }
 
-    true
+    debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty);
+    false
 }
 
 fn receiver_is_implemented<'tcx>(
@@ -2101,16 +2077,14 @@ fn lint_redundant_lifetimes<'tcx>(
         }
 
         for &victim in &lifetimes[(idx + 1)..] {
-            // We should only have late-bound lifetimes of the `BrNamed` variety,
-            // since we get these signatures straight from `hir_lowering`. And any
-            // other regions (ReError/ReStatic/etc.) shouldn't matter, since we
+            // All region parameters should have a `DefId` available as:
+            // - Late-bound parameters should be of the`BrNamed` variety,
+            // since we get these signatures straight from `hir_lowering`.
+            // - Early-bound parameters unconditionally have a `DefId` available.
+            //
+            // Any other regions (ReError/ReStatic/etc.) shouldn't matter, since we
             // can't really suggest to remove them.
-            let (ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. })
-            | ty::ReLateParam(ty::LateParamRegion {
-                bound_region: ty::BoundRegionKind::BrNamed(def_id, _),
-                ..
-            })) = victim.kind()
-            else {
+            let Some(def_id) = victim.opt_param_def_id(tcx, owner_id.to_def_id()) else {
                 continue;
             };
 
diff --git a/compiler/rustc_hir_analysis/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs
index aa5db4f6aa7..ed23dc2a827 100644
--- a/compiler/rustc_hir_analysis/src/check_unused.rs
+++ b/compiler/rustc_hir_analysis/src/check_unused.rs
@@ -35,11 +35,12 @@ fn check_unused_traits(tcx: TyCtxt<'_>, (): ()) {
             continue;
         }
         let (path, _) = item.expect_use();
-        let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) {
-            format!("unused import: `{snippet}`")
-        } else {
-            "unused import".to_owned()
-        };
-        tcx.node_span_lint(lint::builtin::UNUSED_IMPORTS, item.hir_id(), path.span, msg, |_| {});
+        tcx.node_span_lint(lint::builtin::UNUSED_IMPORTS, item.hir_id(), path.span, |lint| {
+            if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) {
+                lint.primary_message(format!("unused import: `{snippet}`"));
+            } else {
+                lint.primary_message("unused import");
+            }
+        });
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 8f0aba1c38c..2ecb170ec89 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -17,7 +17,7 @@ use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
 use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt};
 use rustc_span::{Span, DUMMY_SP};
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
+use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt;
 use rustc_trait_selection::traits::misc::{
     type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy,
     ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason,
@@ -267,7 +267,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
                         .join(", "),
                 }));
             } else {
-                let ocx = ObligationCtxt::new(&infcx);
+                let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
                 for field in coerced_fields {
                     ocx.register_obligation(Obligation::new(
                         tcx,
@@ -480,7 +480,7 @@ pub fn coerce_unsized_info<'tcx>(
     };
 
     // Register an obligation for `A: Trait<B>`.
-    let ocx = ObligationCtxt::new(&infcx);
+    let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
     let cause = traits::ObligationCause::misc(span, impl_did);
     let obligation = Obligation::new(
         tcx,
@@ -554,7 +554,7 @@ fn infringing_fields_error(
                         if let ty::Param(_) = ty.kind() {
                             bounds.push((
                                 format!("{ty}"),
-                                trait_ref.print_only_trait_path().to_string(),
+                                trait_ref.print_trait_sugared().to_string(),
                                 Some(trait_ref.def_id),
                             ));
                         }
diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs
index 054a3af212a..e9961d3ad08 100644
--- a/compiler/rustc_hir_analysis/src/coherence/mod.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs
@@ -8,11 +8,11 @@
 use crate::errors;
 use rustc_errors::{codes::*, struct_span_code_err};
 use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::LangItem;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
 use rustc_session::parse::feature_err;
 use rustc_span::{sym, ErrorGuaranteed};
-use rustc_trait_selection::traits;
 
 mod builtin;
 mod inherent_impls;
@@ -50,7 +50,7 @@ fn enforce_trait_manually_implementable(
 ) -> Result<(), ErrorGuaranteed> {
     let impl_header_span = tcx.def_span(impl_def_id);
 
-    if tcx.lang_items().freeze_trait() == Some(trait_def_id) {
+    if tcx.is_lang_item(trait_def_id, LangItem::Freeze) {
         if !tcx.features().freeze_impls {
             feature_err(
                 &tcx.sess,
@@ -76,7 +76,7 @@ fn enforce_trait_manually_implementable(
 
         // Maintain explicit error code for `Unsize`, since it has a useful
         // explanation about using `CoerceUnsized` instead.
-        if Some(trait_def_id) == tcx.lang_items().unsize_trait() {
+        if tcx.is_lang_item(trait_def_id, LangItem::Unsize) {
             err.code(E0328);
         }
 
@@ -192,14 +192,14 @@ fn check_object_overlap<'tcx>(
         });
 
         for component_def_id in component_def_ids {
-            if !tcx.check_is_object_safe(component_def_id) {
+            if !tcx.is_object_safe(component_def_id) {
                 // Without the 'object_safe_for_dispatch' feature this is an error
                 // which will be reported by wfcheck. Ignore it here.
                 // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`.
                 // With the feature enabled, the trait is not implemented automatically,
                 // so this is valid.
             } else {
-                let mut supertrait_def_ids = traits::supertrait_def_ids(tcx, component_def_id);
+                let mut supertrait_def_ids = tcx.supertrait_def_ids(component_def_id);
                 if supertrait_def_ids.any(|d| d == trait_def_id) {
                     let span = tcx.def_span(impl_def_id);
                     return Err(struct_span_code_err!(
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index bdac0d9b0b4..16f72f38d60 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -14,7 +14,6 @@ use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_trait_selection::traits::{self, IsFirstInputType, UncoveredTyParams};
 use rustc_trait_selection::traits::{OrphanCheckErr, OrphanCheckMode};
-use rustc_trait_selection::traits::{StructurallyNormalizeExt, TraitEngineExt};
 
 #[instrument(level = "debug", skip(tcx))]
 pub(crate) fn orphan_check_impl(
@@ -287,7 +286,7 @@ fn orphan_check<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_def_id: LocalDefId,
     mode: OrphanCheckMode,
-) -> Result<(), OrphanCheckErr<'tcx, FxIndexSet<DefId>>> {
+) -> Result<(), OrphanCheckErr<TyCtxt<'tcx>, FxIndexSet<DefId>>> {
     // We only accept this routine to be invoked on implementations
     // of a trait, not inherent implementations.
     let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
@@ -317,27 +316,26 @@ fn orphan_check<'tcx>(
         }
 
         let ty = if infcx.next_trait_solver() {
-            let mut fulfill_cx = <dyn traits::TraitEngine<'_>>::new(&infcx);
-            infcx
-                .at(&cause, ty::ParamEnv::empty())
-                .structurally_normalize(ty, &mut *fulfill_cx)
-                .map(|ty| infcx.resolve_vars_if_possible(ty))
-                .unwrap_or(ty)
+            ocx.structurally_normalize(
+                &cause,
+                ty::ParamEnv::empty(),
+                infcx.resolve_vars_if_possible(ty),
+            )
+            .unwrap_or(ty)
         } else {
             ty
         };
 
-        Ok(ty)
+        Ok::<_, !>(ty)
     };
 
-    let Ok(result) = traits::orphan_check_trait_ref::<!>(
+    let result = traits::orphan_check_trait_ref(
         &infcx,
         trait_ref,
         traits::InCrate::Local { mode },
         lazily_normalize_ty,
-    ) else {
-        unreachable!()
-    };
+    )
+    .into_ok();
 
     // (2)  Try to map the remaining inference vars back to generic params.
     result.map_err(|err| match err {
@@ -370,7 +368,7 @@ fn emit_orphan_check_error<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_ref: ty::TraitRef<'tcx>,
     impl_def_id: LocalDefId,
-    err: traits::OrphanCheckErr<'tcx, FxIndexSet<DefId>>,
+    err: traits::OrphanCheckErr<TyCtxt<'tcx>, FxIndexSet<DefId>>,
 ) -> ErrorGuaranteed {
     match err {
         traits::OrphanCheckErr::NonLocalInputType(tys) => {
@@ -404,74 +402,56 @@ fn emit_orphan_check_error<'tcx>(
                 match *ty.kind() {
                     ty::Slice(_) => {
                         if is_foreign {
-                            diag.subdiagnostic(
-                                tcx.dcx(),
-                                errors::OnlyCurrentTraitsForeign { span },
-                            );
+                            diag.subdiagnostic(errors::OnlyCurrentTraitsForeign { span });
                         } else {
-                            diag.subdiagnostic(
-                                tcx.dcx(),
-                                errors::OnlyCurrentTraitsName { span, name: "slices" },
-                            );
+                            diag.subdiagnostic(errors::OnlyCurrentTraitsName {
+                                span,
+                                name: "slices",
+                            });
                         }
                     }
                     ty::Array(..) => {
                         if is_foreign {
-                            diag.subdiagnostic(
-                                tcx.dcx(),
-                                errors::OnlyCurrentTraitsForeign { span },
-                            );
+                            diag.subdiagnostic(errors::OnlyCurrentTraitsForeign { span });
                         } else {
-                            diag.subdiagnostic(
-                                tcx.dcx(),
-                                errors::OnlyCurrentTraitsName { span, name: "arrays" },
-                            );
+                            diag.subdiagnostic(errors::OnlyCurrentTraitsName {
+                                span,
+                                name: "arrays",
+                            });
                         }
                     }
                     ty::Tuple(..) => {
                         if is_foreign {
-                            diag.subdiagnostic(
-                                tcx.dcx(),
-                                errors::OnlyCurrentTraitsForeign { span },
-                            );
+                            diag.subdiagnostic(errors::OnlyCurrentTraitsForeign { span });
                         } else {
-                            diag.subdiagnostic(
-                                tcx.dcx(),
-                                errors::OnlyCurrentTraitsName { span, name: "tuples" },
-                            );
+                            diag.subdiagnostic(errors::OnlyCurrentTraitsName {
+                                span,
+                                name: "tuples",
+                            });
                         }
                     }
                     ty::Alias(ty::Opaque, ..) => {
-                        diag.subdiagnostic(tcx.dcx(), errors::OnlyCurrentTraitsOpaque { span });
+                        diag.subdiagnostic(errors::OnlyCurrentTraitsOpaque { span });
                     }
                     ty::RawPtr(ptr_ty, mutbl) => {
                         if !trait_ref.self_ty().has_param() {
-                            diag.subdiagnostic(
-                                tcx.dcx(),
-                                errors::OnlyCurrentTraitsPointerSugg {
-                                    wrapper_span: impl_.self_ty.span,
-                                    struct_span: item.span.shrink_to_lo(),
-                                    mut_key: mutbl.prefix_str(),
-                                    ptr_ty,
-                                },
-                            );
+                            diag.subdiagnostic(errors::OnlyCurrentTraitsPointerSugg {
+                                wrapper_span: impl_.self_ty.span,
+                                struct_span: item.span.shrink_to_lo(),
+                                mut_key: mutbl.prefix_str(),
+                                ptr_ty,
+                            });
                         }
-                        diag.subdiagnostic(
-                            tcx.dcx(),
-                            errors::OnlyCurrentTraitsPointer { span, pointer: ty },
-                        );
+                        diag.subdiagnostic(errors::OnlyCurrentTraitsPointer { span, pointer: ty });
                     }
                     ty::Adt(adt_def, _) => {
-                        diag.subdiagnostic(
-                            tcx.dcx(),
-                            errors::OnlyCurrentTraitsAdt {
-                                span,
-                                name: tcx.def_path_str(adt_def.did()),
-                            },
-                        );
+                        diag.subdiagnostic(errors::OnlyCurrentTraitsAdt {
+                            span,
+                            name: tcx.def_path_str(adt_def.did()),
+                        });
                     }
                     _ => {
-                        diag.subdiagnostic(tcx.dcx(), errors::OnlyCurrentTraitsTy { span, ty });
+                        diag.subdiagnostic(errors::OnlyCurrentTraitsTy { span, ty });
                     }
                 }
             }
@@ -501,7 +481,7 @@ fn emit_orphan_check_error<'tcx>(
 
 fn lint_uncovered_ty_params<'tcx>(
     tcx: TyCtxt<'tcx>,
-    UncoveredTyParams { uncovered, local_ty }: UncoveredTyParams<'tcx, FxIndexSet<DefId>>,
+    UncoveredTyParams { uncovered, local_ty }: UncoveredTyParams<TyCtxt<'tcx>, FxIndexSet<DefId>>,
     impl_def_id: LocalDefId,
 ) {
     let hir_id = tcx.local_def_id_to_hir_id(impl_def_id);
@@ -558,7 +538,7 @@ struct TyVarReplacer<'cx, 'tcx> {
 }
 
 impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for TyVarReplacer<'cx, 'tcx> {
-    fn interner(&self) -> TyCtxt<'tcx> {
+    fn cx(&self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
 
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index b760b86a7bf..e0aad299163 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -18,11 +18,13 @@ use rustc_ast::Recovered;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_data_structures::unord::UnordMap;
-use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey};
-use rustc_hir as hir;
+use rustc_errors::{
+    struct_span_code_err, Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, StashKey, E0228,
+};
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::intravisit::{self, Visitor};
+use rustc_hir::intravisit::{self, walk_generics, Visitor};
+use rustc_hir::{self as hir};
 use rustc_hir::{GenericParamKind, Node};
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::ObligationCause;
@@ -33,10 +35,9 @@ use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, Upcast};
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
-use rustc_target::abi::FieldIdx;
 use rustc_target::spec::abi;
+use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName;
 use rustc_trait_selection::infer::InferCtxtExt;
-use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
 use rustc_trait_selection::traits::ObligationCtxt;
 use std::cell::Cell;
 use std::iter;
@@ -44,9 +45,9 @@ use std::ops::Bound;
 
 use crate::check::intrinsic::intrinsic_operation_unsafety;
 use crate::errors;
-use crate::hir_ty_lowering::HirTyLowerer;
-pub use type_of::test_opaque_hidden_types;
+use crate::hir_ty_lowering::{HirTyLowerer, RegionInferReason};
 
+pub(crate) mod dump;
 mod generics_of;
 mod item_bounds;
 mod predicates_of;
@@ -70,10 +71,10 @@ pub fn provide(providers: &mut Providers) {
         predicates_of: predicates_of::predicates_of,
         predicates_defined_on,
         explicit_predicates_of: predicates_of::explicit_predicates_of,
-        super_predicates_of: predicates_of::super_predicates_of,
-        implied_predicates_of: predicates_of::implied_predicates_of,
-        super_predicates_that_define_assoc_item:
-            predicates_of::super_predicates_that_define_assoc_item,
+        explicit_super_predicates_of: predicates_of::explicit_super_predicates_of,
+        explicit_implied_predicates_of: predicates_of::explicit_implied_predicates_of,
+        explicit_supertraits_containing_assoc_item:
+            predicates_of::explicit_supertraits_containing_assoc_item,
         trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds,
         type_param_predicates: predicates_of::type_param_predicates,
         trait_def,
@@ -83,7 +84,6 @@ pub fn provide(providers: &mut Providers) {
         coroutine_kind,
         coroutine_for_closure,
         is_type_alias_impl_trait,
-        find_field,
         ..*providers
     };
 }
@@ -161,7 +161,7 @@ pub struct CollectItemTypesVisitor<'tcx> {
 /// and suggest adding type parameters in the appropriate place, taking into consideration any and
 /// all already existing generic type parameters to avoid suggesting a name that is already in use.
 pub(crate) fn placeholder_type_error<'tcx>(
-    tcx: TyCtxt<'tcx>,
+    cx: &dyn HirTyLowerer<'tcx>,
     generics: Option<&hir::Generics<'_>>,
     placeholder_types: Vec<Span>,
     suggest: bool,
@@ -172,21 +172,21 @@ pub(crate) fn placeholder_type_error<'tcx>(
         return;
     }
 
-    placeholder_type_error_diag(tcx, generics, placeholder_types, vec![], suggest, hir_ty, kind)
+    placeholder_type_error_diag(cx, generics, placeholder_types, vec![], suggest, hir_ty, kind)
         .emit();
 }
 
-pub(crate) fn placeholder_type_error_diag<'tcx>(
-    tcx: TyCtxt<'tcx>,
+pub(crate) fn placeholder_type_error_diag<'cx, 'tcx>(
+    cx: &'cx dyn HirTyLowerer<'tcx>,
     generics: Option<&hir::Generics<'_>>,
     placeholder_types: Vec<Span>,
     additional_spans: Vec<Span>,
     suggest: bool,
     hir_ty: Option<&hir::Ty<'_>>,
     kind: &'static str,
-) -> Diag<'tcx> {
+) -> Diag<'cx> {
     if placeholder_types.is_empty() {
-        return bad_placeholder(tcx, additional_spans, kind);
+        return bad_placeholder(cx, additional_spans, kind);
     }
 
     let params = generics.map(|g| g.params).unwrap_or_default();
@@ -210,7 +210,7 @@ pub(crate) fn placeholder_type_error_diag<'tcx>(
     }
 
     let mut err =
-        bad_placeholder(tcx, placeholder_types.into_iter().chain(additional_spans).collect(), kind);
+        bad_placeholder(cx, placeholder_types.into_iter().chain(additional_spans).collect(), kind);
 
     // Suggest, but only if it is not a function in const or static
     if suggest {
@@ -224,7 +224,7 @@ pub(crate) fn placeholder_type_error_diag<'tcx>(
 
             // Check if parent is const or static
             is_const_or_static = matches!(
-                tcx.parent_hir_node(hir_ty.hir_id),
+                cx.tcx().parent_hir_node(hir_ty.hir_id),
                 Node::Item(&hir::Item {
                     kind: hir::ItemKind::Const(..) | hir::ItemKind::Static(..),
                     ..
@@ -267,7 +267,16 @@ fn reject_placeholder_type_signatures_in_item<'tcx>(
     let mut visitor = HirPlaceholderCollector::default();
     visitor.visit_item(item);
 
-    placeholder_type_error(tcx, Some(generics), visitor.0, suggest, None, item.kind.descr());
+    let icx = ItemCtxt::new(tcx, item.owner_id.def_id);
+
+    placeholder_type_error(
+        icx.lowerer(),
+        Some(generics),
+        visitor.0,
+        suggest,
+        None,
+        item.kind.descr(),
+    );
 }
 
 impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
@@ -329,15 +338,15 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
 ///////////////////////////////////////////////////////////////////////////
 // Utility types and common code for the above passes.
 
-fn bad_placeholder<'tcx>(
-    tcx: TyCtxt<'tcx>,
+fn bad_placeholder<'cx, 'tcx>(
+    cx: &'cx dyn HirTyLowerer<'tcx>,
     mut spans: Vec<Span>,
     kind: &'static str,
-) -> Diag<'tcx> {
+) -> Diag<'cx> {
     let kind = if kind.ends_with('s') { format!("{kind}es") } else { format!("{kind}s") };
 
     spans.sort();
-    tcx.dcx().create_err(errors::PlaceholderNotAllowedItemSignatures { spans, kind })
+    cx.dcx().create_err(errors::PlaceholderNotAllowedItemSignatures { spans, kind })
 }
 
 impl<'tcx> ItemCtxt<'tcx> {
@@ -370,32 +379,37 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
         self.tcx
     }
 
-    fn item_def_id(&self) -> DefId {
-        self.item_def_id.to_def_id()
+    fn dcx(&self) -> DiagCtxtHandle<'_> {
+        self.tcx.dcx().taintable_handle(&self.tainted_by_errors)
     }
 
-    fn allow_infer(&self) -> bool {
-        false
+    fn item_def_id(&self) -> LocalDefId {
+        self.item_def_id
     }
 
-    fn re_infer(&self, _: Option<&ty::GenericParamDef>, _: Span) -> Option<ty::Region<'tcx>> {
-        None
+    fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> {
+        if let RegionInferReason::BorrowedObjectLifetimeDefault = reason {
+            let e = struct_span_code_err!(
+                self.dcx(),
+                span,
+                E0228,
+                "the lifetime bound for this object type cannot be deduced \
+                from context; please supply an explicit bound"
+            )
+            .emit();
+            ty::Region::new_error(self.tcx(), e)
+        } else {
+            // This indicates an illegal lifetime in a non-assoc-trait position
+            ty::Region::new_error_with_message(self.tcx(), span, "unelided lifetime in signature")
+        }
     }
 
     fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
         Ty::new_error_with_message(self.tcx(), span, "bad placeholder type")
     }
 
-    fn ct_infer(&self, ty: Ty<'tcx>, _: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> {
-        let ty = self.tcx.fold_regions(ty, |r, _| match *r {
-            rustc_type_ir::RegionKind::ReStatic => r,
-
-            // This is never reached in practice. If it ever is reached,
-            // `ReErased` should be changed to `ReStatic`, and any other region
-            // left alone.
-            r => bug!("unexpected region: {r:?}"),
-        });
-        ty::Const::new_error_with_message(self.tcx(), ty, span, "bad placeholder constant")
+    fn ct_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> {
+        ty::Const::new_error_with_message(self.tcx(), span, "bad placeholder constant")
     }
 
     fn probe_ty_param_bounds(
@@ -421,7 +435,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
                 item_segment,
                 trait_ref.args,
             );
-            Ty::new_projection(self.tcx(), item_def_id, item_args)
+            Ty::new_projection_from_args(self.tcx(), item_def_id, item_args)
         } else {
             // There are no late-bound regions; we can just ignore the binder.
             let (mut mpart_sugg, mut inferred_sugg) = (None, None);
@@ -453,7 +467,6 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
                                         poly_trait_ref,
                                         |_| {
                                             ty::Region::new_early_param(self.tcx, ty::EarlyParamRegion {
-                                                def_id: item_def_id,
                                                 index: 0,
                                                 name: Symbol::intern(&lt_name),
                                             })
@@ -508,8 +521,87 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
         None
     }
 
-    fn set_tainted_by_errors(&self, err: ErrorGuaranteed) {
-        self.tainted_by_errors.set(Some(err));
+    fn lower_fn_sig(
+        &self,
+        decl: &hir::FnDecl<'tcx>,
+        generics: Option<&hir::Generics<'_>>,
+        hir_id: rustc_hir::HirId,
+        hir_ty: Option<&hir::Ty<'_>>,
+    ) -> (Vec<Ty<'tcx>>, Ty<'tcx>) {
+        let tcx = self.tcx();
+        // We proactively collect all the inferred type params to emit a single error per fn def.
+        let mut visitor = HirPlaceholderCollector::default();
+        let mut infer_replacements = vec![];
+
+        if let Some(generics) = generics {
+            walk_generics(&mut visitor, generics);
+        }
+
+        let input_tys = decl
+            .inputs
+            .iter()
+            .enumerate()
+            .map(|(i, a)| {
+                if let hir::TyKind::Infer = a.kind {
+                    if let Some(suggested_ty) =
+                        self.lowerer().suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i))
+                    {
+                        infer_replacements.push((a.span, suggested_ty.to_string()));
+                        return Ty::new_error_with_message(tcx, a.span, suggested_ty.to_string());
+                    }
+                }
+
+                // Only visit the type looking for `_` if we didn't fix the type above
+                visitor.visit_ty(a);
+                self.lowerer().lower_arg_ty(a, None)
+            })
+            .collect();
+
+        let output_ty = match decl.output {
+            hir::FnRetTy::Return(output) => {
+                if let hir::TyKind::Infer = output.kind
+                    && let Some(suggested_ty) =
+                        self.lowerer().suggest_trait_fn_ty_for_impl_fn_infer(hir_id, None)
+                {
+                    infer_replacements.push((output.span, suggested_ty.to_string()));
+                    Ty::new_error_with_message(tcx, output.span, suggested_ty.to_string())
+                } else {
+                    visitor.visit_ty(output);
+                    self.lower_ty(output)
+                }
+            }
+            hir::FnRetTy::DefaultReturn(..) => tcx.types.unit,
+        };
+
+        if !(visitor.0.is_empty() && infer_replacements.is_empty()) {
+            // We check for the presence of
+            // `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`.
+
+            let mut diag = crate::collect::placeholder_type_error_diag(
+                self,
+                generics,
+                visitor.0,
+                infer_replacements.iter().map(|(s, _)| *s).collect(),
+                true,
+                hir_ty,
+                "function",
+            );
+
+            if !infer_replacements.is_empty() {
+                diag.multipart_suggestion(
+                    format!(
+                    "try replacing `_` with the type{} in the corresponding trait method signature",
+                    rustc_errors::pluralize!(infer_replacements.len()),
+                ),
+                    infer_replacements,
+                    Applicability::MachineApplicable,
+                );
+            }
+
+            diag.emit();
+        }
+
+        (input_tys, output_ty)
     }
 }
 
@@ -555,6 +647,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
     let it = tcx.hir().item(item_id);
     debug!(item = %it.ident, id = %it.hir_id());
     let def_id = item_id.owner_id.def_id;
+    let icx = ItemCtxt::new(tcx, def_id);
 
     match &it.kind {
         // These don't define types.
@@ -579,7 +672,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
                         let mut visitor = HirPlaceholderCollector::default();
                         visitor.visit_foreign_item(item);
                         placeholder_type_error(
-                            tcx,
+                            icx.lowerer(),
                             None,
                             visitor.0,
                             false,
@@ -607,14 +700,14 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
         hir::ItemKind::Trait(..) => {
             tcx.ensure().generics_of(def_id);
             tcx.ensure().trait_def(def_id);
-            tcx.at(it.span).super_predicates_of(def_id);
+            tcx.at(it.span).explicit_super_predicates_of(def_id);
             tcx.ensure().predicates_of(def_id);
             tcx.ensure().associated_items(def_id);
         }
         hir::ItemKind::TraitAlias(..) => {
             tcx.ensure().generics_of(def_id);
-            tcx.at(it.span).implied_predicates_of(def_id);
-            tcx.at(it.span).super_predicates_of(def_id);
+            tcx.at(it.span).explicit_implied_predicates_of(def_id);
+            tcx.at(it.span).explicit_super_predicates_of(def_id);
             tcx.ensure().predicates_of(def_id);
         }
         hir::ItemKind::Struct(struct_def, _) | hir::ItemKind::Union(struct_def, _) => {
@@ -658,7 +751,14 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
             if !ty.is_suggestable_infer_ty() {
                 let mut visitor = HirPlaceholderCollector::default();
                 visitor.visit_item(it);
-                placeholder_type_error(tcx, None, visitor.0, false, None, it.kind.descr());
+                placeholder_type_error(
+                    icx.lowerer(),
+                    None,
+                    visitor.0,
+                    false,
+                    None,
+                    it.kind.descr(),
+                );
             }
         }
 
@@ -676,6 +776,7 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
     let trait_item = tcx.hir().trait_item(trait_item_id);
     let def_id = trait_item_id.owner_id;
     tcx.ensure().generics_of(def_id);
+    let icx = ItemCtxt::new(tcx, def_id.def_id);
 
     match trait_item.kind {
         hir::TraitItemKind::Fn(..) => {
@@ -692,7 +793,14 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
                 // Account for `const C: _;`.
                 let mut visitor = HirPlaceholderCollector::default();
                 visitor.visit_trait_item(trait_item);
-                placeholder_type_error(tcx, None, visitor.0, false, None, "associated constant");
+                placeholder_type_error(
+                    icx.lowerer(),
+                    None,
+                    visitor.0,
+                    false,
+                    None,
+                    "associated constant",
+                );
             }
         }
 
@@ -703,7 +811,7 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
             // Account for `type T = _;`.
             let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_trait_item(trait_item);
-            placeholder_type_error(tcx, None, visitor.0, false, None, "associated type");
+            placeholder_type_error(icx.lowerer(), None, visitor.0, false, None, "associated type");
         }
 
         hir::TraitItemKind::Type(_, None) => {
@@ -714,7 +822,7 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
             let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_trait_item(trait_item);
 
-            placeholder_type_error(tcx, None, visitor.0, false, None, "associated type");
+            placeholder_type_error(icx.lowerer(), None, visitor.0, false, None, "associated type");
         }
     };
 
@@ -727,6 +835,7 @@ fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
     tcx.ensure().type_of(def_id);
     tcx.ensure().predicates_of(def_id);
     let impl_item = tcx.hir().impl_item(impl_item_id);
+    let icx = ItemCtxt::new(tcx, def_id.def_id);
     match impl_item.kind {
         hir::ImplItemKind::Fn(..) => {
             tcx.ensure().codegen_fn_attrs(def_id);
@@ -737,14 +846,21 @@ fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
             let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_impl_item(impl_item);
 
-            placeholder_type_error(tcx, None, visitor.0, false, None, "associated type");
+            placeholder_type_error(icx.lowerer(), None, visitor.0, false, None, "associated type");
         }
         hir::ImplItemKind::Const(ty, _) => {
             // Account for `const T: _ = ..;`
             if !ty.is_suggestable_infer_ty() {
                 let mut visitor = HirPlaceholderCollector::default();
                 visitor.visit_impl_item(impl_item);
-                placeholder_type_error(tcx, None, visitor.0, false, None, "associated constant");
+                placeholder_type_error(
+                    icx.lowerer(),
+                    None,
+                    visitor.0,
+                    false,
+                    None,
+                    "associated constant",
+                );
             }
         }
     }
@@ -796,23 +912,6 @@ fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
     }
 }
 
-fn find_field(tcx: TyCtxt<'_>, (def_id, ident): (DefId, Ident)) -> Option<FieldIdx> {
-    let adt = tcx.adt_def(def_id);
-    if adt.is_enum() {
-        return None;
-    }
-
-    adt.non_enum_variant().fields.iter_enumerated().find_map(|(idx, field)| {
-        if field.is_unnamed() {
-            let field_ty = tcx.type_of(field.did).instantiate_identity();
-            let adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field");
-            tcx.find_field((adt_def.did(), ident)).map(|_| idx)
-        } else {
-            (field.ident(tcx).normalize_to_macros_2_0() == ident).then_some(idx)
-        }
-    })
-}
-
 #[derive(Clone, Copy)]
 struct NestedSpan {
     span: Span,
@@ -1007,7 +1106,10 @@ fn lower_variant(
             vis: tcx.visibility(f.def_id),
         })
         .collect();
-    let recovered = matches!(def, hir::VariantData::Struct { recovered: Recovered::Yes(_), .. });
+    let recovered = match def {
+        hir::VariantData::Struct { recovered: Recovered::Yes(guar), .. } => Some(*guar),
+        _ => None,
+    };
     ty::VariantDef::new(
         ident.name,
         variant_did.map(LocalDefId::to_def_id),
@@ -1110,6 +1212,11 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
         _ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"),
     };
 
+    let constness = if tcx.has_attr(def_id, sym::const_trait) {
+        hir::Constness::Const
+    } else {
+        hir::Constness::NotConst
+    };
     let paren_sugar = tcx.has_attr(def_id, sym::rustc_paren_sugar);
     if paren_sugar && !tcx.features().unboxed_closures {
         tcx.dcx().emit_err(errors::ParenSugarAttribute { span: item.span });
@@ -1117,6 +1224,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
 
     let is_marker = tcx.has_attr(def_id, sym::marker);
     let rustc_coinductive = tcx.has_attr(def_id, sym::rustc_coinductive);
+    let is_fundamental = tcx.has_attr(def_id, sym::fundamental);
 
     // FIXME: We could probably do way better attribute validation here.
     let mut skip_array_during_method_dispatch = false;
@@ -1264,10 +1372,12 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
     ty::TraitDef {
         def_id: def_id.to_def_id(),
         safety,
+        constness,
         paren_sugar,
         has_auto_impl: is_auto,
         is_marker,
         is_coinductive: rustc_coinductive || is_auto,
+        is_fundamental,
         skip_array_during_method_dispatch,
         skip_boxed_slice_during_method_dispatch,
         specialization_kind,
@@ -1278,7 +1388,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
 }
 
 #[instrument(level = "debug", skip(tcx))]
-fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<'_>> {
+fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFnSig<'_>> {
     use rustc_hir::Node::*;
     use rustc_hir::*;
 
@@ -1293,7 +1403,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<
             ..
         })
         | Item(hir::Item { kind: ItemKind::Fn(sig, generics, _), .. }) => {
-            infer_return_ty_for_fn_sig(tcx, sig, generics, def_id, &icx)
+            infer_return_ty_for_fn_sig(sig, generics, def_id, &icx)
         }
 
         ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => {
@@ -1310,7 +1420,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<
                     None,
                 )
             } else {
-                infer_return_ty_for_fn_sig(tcx, sig, generics, def_id, &icx)
+                infer_return_ty_for_fn_sig(sig, generics, def_id, &icx)
             }
         }
 
@@ -1322,9 +1432,11 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<
             icx.lowerer().lower_fn_ty(hir_id, header.safety, header.abi, decl, Some(generics), None)
         }
 
-        ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(fn_decl, _, _), .. }) => {
+        ForeignItem(&hir::ForeignItem {
+            kind: ForeignItemKind::Fn(fn_decl, _, _, safety), ..
+        }) => {
             let abi = tcx.hir().get_foreign_abi(hir_id);
-            compute_sig_of_foreign_fn_decl(tcx, def_id, fn_decl, abi)
+            compute_sig_of_foreign_fn_decl(tcx, def_id, fn_decl, abi, safety)
         }
 
         Ctor(data) | Variant(hir::Variant { data, .. }) if data.ctor().is_some() => {
@@ -1361,27 +1473,44 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<
 }
 
 fn infer_return_ty_for_fn_sig<'tcx>(
-    tcx: TyCtxt<'tcx>,
     sig: &hir::FnSig<'tcx>,
     generics: &hir::Generics<'_>,
     def_id: LocalDefId,
     icx: &ItemCtxt<'tcx>,
 ) -> ty::PolyFnSig<'tcx> {
+    let tcx = icx.tcx;
     let hir_id = tcx.local_def_id_to_hir_id(def_id);
 
     match sig.decl.output.get_infer_ret_ty() {
         Some(ty) => {
             let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id];
             // Typeck doesn't expect erased regions to be returned from `type_of`.
+            // This is a heuristic approach. If the scope has region paramters,
+            // we should change fn_sig's lifetime from `ReErased` to `ReError`,
+            // otherwise to `ReStatic`.
+            let has_region_params = generics.params.iter().any(|param| match param.kind {
+                GenericParamKind::Lifetime { .. } => true,
+                _ => false,
+            });
             let fn_sig = tcx.fold_regions(fn_sig, |r, _| match *r {
-                ty::ReErased => tcx.lifetimes.re_static,
+                ty::ReErased => {
+                    if has_region_params {
+                        ty::Region::new_error_with_message(
+                            tcx,
+                            DUMMY_SP,
+                            "erased region is not allowed here in return type",
+                        )
+                    } else {
+                        tcx.lifetimes.re_static
+                    }
+                }
                 _ => r,
             });
 
             let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_ty(ty);
 
-            let mut diag = bad_placeholder(tcx, visitor.0, "return type");
+            let mut diag = bad_placeholder(icx.lowerer(), visitor.0, "return type");
             let ret_ty = fn_sig.output();
             // Don't leak types into signatures unless they're nameable!
             // For example, if a function returns itself, we don't want that
@@ -1479,7 +1608,7 @@ pub fn suggest_impl_trait<'tcx>(
         ),
         (
             infcx.tcx.lang_items().future_trait(),
-            infcx.tcx.get_diagnostic_item(sym::FutureOutput),
+            infcx.tcx.lang_items().future_output(),
             format_as_assoc,
         ),
         (
@@ -1521,7 +1650,7 @@ pub fn suggest_impl_trait<'tcx>(
             let item_ty = ocx.normalize(
                 &ObligationCause::dummy(),
                 param_env,
-                Ty::new_projection(infcx.tcx, assoc_item_def_id, args),
+                Ty::new_projection_from_args(infcx.tcx, assoc_item_def_id, args),
             );
             // FIXME(compiler-errors): We may benefit from resolving regions here.
             if ocx.select_where_possible().is_empty()
@@ -1552,44 +1681,19 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::ImplTrai
     let icx = ItemCtxt::new(tcx, def_id);
     let item = tcx.hir().expect_item(def_id);
     let impl_ = item.expect_impl();
-    impl_
-        .of_trait
-        .as_ref()
-        .map(|hir_trait_ref| {
-            let self_ty = tcx.type_of(def_id).instantiate_identity();
+    impl_.of_trait.as_ref().map(|ast_trait_ref| {
+        let selfty = tcx.type_of(def_id).instantiate_identity();
 
-            let trait_ref = if let Some(ErrorGuaranteed { .. }) = check_impl_constness(
-                tcx,
-                tcx.is_const_trait_impl_raw(def_id.to_def_id()),
-                hir_trait_ref,
-            ) {
-                // we have a const impl, but for a trait without `#[const_trait]`, so
-                // without the host param. If we continue with the HIR trait ref, we get
-                // ICEs for generic arg count mismatch. We do a little HIR editing to
-                // make HIR ty lowering happy.
-                let mut path_segments = hir_trait_ref.path.segments.to_vec();
-                let last_segment = path_segments.len() - 1;
-                let mut args = *path_segments[last_segment].args();
-                let last_arg = args.args.len() - 1;
-                assert!(matches!(args.args[last_arg], hir::GenericArg::Const(anon_const) if anon_const.is_desugared_from_effects));
-                args.args = &args.args[..args.args.len() - 1];
-                path_segments[last_segment].args = Some(tcx.hir_arena.alloc(args));
-                let path = hir::Path {
-                    span: hir_trait_ref.path.span,
-                    res: hir_trait_ref.path.res,
-                    segments: tcx.hir_arena.alloc_slice(&path_segments),
-                };
-                let trait_ref = tcx.hir_arena.alloc(hir::TraitRef { path: tcx.hir_arena.alloc(path), hir_ref_id: hir_trait_ref.hir_ref_id });
-                icx.lowerer().lower_impl_trait_ref(trait_ref, self_ty)
-            } else {
-                icx.lowerer().lower_impl_trait_ref(hir_trait_ref, self_ty)
-            };
-            ty::ImplTraitHeader {
-                trait_ref: ty::EarlyBinder::bind(trait_ref),
-                safety: impl_.safety,
-                polarity: polarity_of_impl(tcx, def_id, impl_, item.span)
-            }
-        })
+        check_impl_constness(tcx, tcx.is_const_trait_impl_raw(def_id.to_def_id()), ast_trait_ref);
+
+        let trait_ref = icx.lowerer().lower_impl_trait_ref(ast_trait_ref, selfty);
+
+        ty::ImplTraitHeader {
+            trait_ref: ty::EarlyBinder::bind(trait_ref),
+            safety: impl_.safety,
+            polarity: polarity_of_impl(tcx, def_id, impl_, item.span),
+        }
+    })
 }
 
 fn check_impl_constness(
@@ -1602,7 +1706,7 @@ fn check_impl_constness(
     }
 
     let trait_def_id = hir_trait_ref.trait_def_id()?;
-    if tcx.has_attr(trait_def_id, sym::const_trait) {
+    if tcx.is_const_trait(trait_def_id) {
         return None;
     }
 
@@ -1696,11 +1800,12 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
     def_id: LocalDefId,
     decl: &'tcx hir::FnDecl<'tcx>,
     abi: abi::Abi,
+    safety: hir::Safety,
 ) -> ty::PolyFnSig<'tcx> {
     let safety = if abi == abi::Abi::RustIntrinsic {
         intrinsic_operation_unsafety(tcx, def_id)
     } else {
-        hir::Safety::Unsafe
+        safety
     };
     let hir_id = tcx.local_def_id_to_hir_id(def_id);
     let fty =
diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs
new file mode 100644
index 00000000000..c73d3a5390d
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/collect/dump.rs
@@ -0,0 +1,91 @@
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
+use rustc_hir::intravisit;
+use rustc_middle::hir::nested_filter::OnlyBodies;
+use rustc_middle::ty::TyCtxt;
+use rustc_span::sym;
+
+pub(crate) fn opaque_hidden_types(tcx: TyCtxt<'_>) {
+    if !tcx.has_attr(CRATE_DEF_ID, sym::rustc_hidden_type_of_opaques) {
+        return;
+    }
+
+    for id in tcx.hir().items() {
+        let DefKind::OpaqueTy = tcx.def_kind(id.owner_id) else { continue };
+
+        let ty = tcx.type_of(id.owner_id).instantiate_identity();
+
+        tcx.dcx().emit_err(crate::errors::TypeOf { span: tcx.def_span(id.owner_id), ty });
+    }
+}
+
+pub(crate) fn predicates_and_item_bounds(tcx: TyCtxt<'_>) {
+    for id in tcx.hir_crate_items(()).owners() {
+        if tcx.has_attr(id, sym::rustc_dump_predicates) {
+            let preds = tcx.predicates_of(id).instantiate_identity(tcx).predicates;
+            let span = tcx.def_span(id);
+
+            let mut diag = tcx.dcx().struct_span_err(span, sym::rustc_dump_predicates.as_str());
+            for pred in preds {
+                diag.note(format!("{pred:?}"));
+            }
+            diag.emit();
+        }
+        if tcx.has_attr(id, sym::rustc_dump_item_bounds) {
+            let bounds = tcx.item_bounds(id).instantiate_identity();
+            let span = tcx.def_span(id);
+
+            let mut diag = tcx.dcx().struct_span_err(span, sym::rustc_dump_item_bounds.as_str());
+            for bound in bounds {
+                diag.note(format!("{bound:?}"));
+            }
+            diag.emit();
+        }
+    }
+}
+
+pub(crate) fn def_parents(tcx: TyCtxt<'_>) {
+    for did in tcx.hir().body_owners() {
+        if tcx.has_attr(did, sym::rustc_dump_def_parents) {
+            struct AnonConstFinder<'tcx> {
+                tcx: TyCtxt<'tcx>,
+                anon_consts: Vec<LocalDefId>,
+            }
+
+            impl<'tcx> intravisit::Visitor<'tcx> for AnonConstFinder<'tcx> {
+                type NestedFilter = OnlyBodies;
+
+                fn nested_visit_map(&mut self) -> Self::Map {
+                    self.tcx.hir()
+                }
+
+                fn visit_anon_const(&mut self, c: &'tcx rustc_hir::AnonConst) {
+                    self.anon_consts.push(c.def_id);
+                    intravisit::walk_anon_const(self, c)
+                }
+            }
+
+            // Look for any anon consts inside of this body owner as there is no way to apply
+            // the `rustc_dump_def_parents` attribute to the anon const so it would not be possible
+            // to see what its def parent is.
+            let mut anon_ct_finder = AnonConstFinder { tcx, anon_consts: vec![] };
+            intravisit::walk_expr(&mut anon_ct_finder, tcx.hir().body_owned_by(did).value);
+
+            for did in [did].into_iter().chain(anon_ct_finder.anon_consts) {
+                let span = tcx.def_span(did);
+
+                let mut diag = tcx.dcx().struct_span_err(
+                    span,
+                    format!("{}: {did:?}", sym::rustc_dump_def_parents.as_str()),
+                );
+
+                let mut current_did = did.to_def_id();
+                while let Some(parent_did) = tcx.opt_parent(current_did) {
+                    current_did = parent_did;
+                    diag.span_note(tcx.def_span(parent_did), format!("{parent_did:?}"));
+                }
+                diag.emit();
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 6b41f79cf1e..22d465c8e62 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -1,3 +1,5 @@
+use std::ops::ControlFlow;
+
 use crate::middle::resolve_bound_vars as rbv;
 use hir::{
     intravisit::{self, Visitor},
@@ -11,6 +13,7 @@ use rustc_session::lint;
 use rustc_span::symbol::{kw, Symbol};
 use rustc_span::Span;
 
+#[instrument(level = "debug", skip(tcx))]
 pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
     use rustc_hir::*;
 
@@ -66,19 +69,29 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
         // FIXME(#43408) always enable this once `lazy_normalization` is
         // stable enough and does not need a feature gate anymore.
         Node::AnonConst(_) => {
-            let parent_def_id = tcx.hir().get_parent_item(hir_id);
+            let parent_did = tcx.parent(def_id.to_def_id());
+
+            // We don't do this unconditionally because the `DefId` parent of an anon const
+            // might be an implicitly created closure during `async fn` desugaring. This would
+            // have the wrong generics.
+            //
+            // i.e. `async fn foo<'a>() { let a = [(); { 1 + 2 }]; bar().await() }`
+            // would implicitly have a closure in its body that would be the parent of
+            // the `{ 1 + 2 }` anon const. This closure's generics is simply a witness
+            // instead of `['a]`.
+            let parent_did = if let DefKind::AnonConst = tcx.def_kind(parent_did) {
+                parent_did
+            } else {
+                tcx.hir().get_parent_item(hir_id).to_def_id()
+            };
+            debug!(?parent_did);
 
             let mut in_param_ty = false;
             for (_parent, node) in tcx.hir().parent_iter(hir_id) {
                 if let Some(generics) = node.generics() {
-                    let mut visitor = AnonConstInParamTyDetector {
-                        in_param_ty: false,
-                        found_anon_const_in_param_ty: false,
-                        ct: hir_id,
-                    };
+                    let mut visitor = AnonConstInParamTyDetector { in_param_ty: false, ct: hir_id };
 
-                    visitor.visit_generics(generics);
-                    in_param_ty = visitor.found_anon_const_in_param_ty;
+                    in_param_ty = visitor.visit_generics(generics).is_break();
                     break;
                 }
             }
@@ -121,7 +134,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
                     //
                     // This has some implications for how we get the predicates available to the anon const
                     // see `explicit_predicates_of` for more information on this
-                    let generics = tcx.generics_of(parent_def_id.to_def_id());
+                    let generics = tcx.generics_of(parent_did);
                     let param_def_idx = generics.param_def_id_to_index[&param_id.to_def_id()];
                     // In the above example this would be .params[..N#0]
                     let own_params = generics.params_to(param_def_idx as usize, tcx).to_owned();
@@ -147,7 +160,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
                     //
                     // Note that we do not supply the parent generics when using
                     // `min_const_generics`.
-                    Some(parent_def_id.to_def_id())
+                    Some(parent_did)
                 }
             } else {
                 let parent_node = tcx.parent_hir_node(hir_id);
@@ -159,7 +172,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
                     Node::Expr(Expr { kind: ExprKind::Repeat(_, constant), .. })
                         if constant.hir_id() == hir_id =>
                     {
-                        Some(parent_def_id.to_def_id())
+                        Some(parent_did)
                     }
                     // Exclude `GlobalAsm` here which cannot have generics.
                     Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
@@ -171,7 +184,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
                             _ => false,
                         }) =>
                     {
-                        Some(parent_def_id.to_def_id())
+                        Some(parent_did)
                     }
                     _ => None,
                 }
@@ -317,8 +330,9 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
                             lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
                             param.hir_id,
                             param.span,
-                            TYPE_DEFAULT_NOT_ALLOWED,
-                            |_| {},
+                            |lint| {
+                                lint.primary_message(TYPE_DEFAULT_NOT_ALLOWED);
+                            },
                         );
                     }
                     Defaults::Deny => {
@@ -337,7 +351,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
                 kind,
             })
         }
-        GenericParamKind::Const { ty: _, default, is_host_effect } => {
+        GenericParamKind::Const { ty: _, default, is_host_effect, synthetic } => {
             if !matches!(allow_defaults, Defaults::Allowed)
                 && default.is_some()
                 // `host` effect params are allowed to have defaults.
@@ -371,6 +385,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
                 kind: ty::GenericParamDefKind::Const {
                     has_default: default.is_some(),
                     is_host_effect,
+                    synthetic,
                 },
             })
         }
@@ -442,50 +457,45 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
     struct LateBoundRegionsDetector<'tcx> {
         tcx: TyCtxt<'tcx>,
         outer_index: ty::DebruijnIndex,
-        has_late_bound_regions: Option<Span>,
     }
 
     impl<'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'tcx> {
-        fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
-            if self.has_late_bound_regions.is_some() {
-                return;
-            }
+        type Result = ControlFlow<Span>;
+        fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) -> ControlFlow<Span> {
             match ty.kind {
                 hir::TyKind::BareFn(..) => {
                     self.outer_index.shift_in(1);
-                    intravisit::walk_ty(self, ty);
+                    let res = intravisit::walk_ty(self, ty);
                     self.outer_index.shift_out(1);
+                    res
                 }
                 _ => intravisit::walk_ty(self, ty),
             }
         }
 
-        fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) {
-            if self.has_late_bound_regions.is_some() {
-                return;
-            }
+        fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) -> ControlFlow<Span> {
             self.outer_index.shift_in(1);
-            intravisit::walk_poly_trait_ref(self, tr);
+            let res = intravisit::walk_poly_trait_ref(self, tr);
             self.outer_index.shift_out(1);
+            res
         }
 
-        fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
-            if self.has_late_bound_regions.is_some() {
-                return;
-            }
-
+        fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) -> ControlFlow<Span> {
             match self.tcx.named_bound_var(lt.hir_id) {
-                Some(rbv::ResolvedArg::StaticLifetime | rbv::ResolvedArg::EarlyBound(..)) => {}
+                Some(rbv::ResolvedArg::StaticLifetime | rbv::ResolvedArg::EarlyBound(..)) => {
+                    ControlFlow::Continue(())
+                }
                 Some(rbv::ResolvedArg::LateBound(debruijn, _, _))
-                    if debruijn < self.outer_index => {}
+                    if debruijn < self.outer_index =>
+                {
+                    ControlFlow::Continue(())
+                }
                 Some(
                     rbv::ResolvedArg::LateBound(..)
                     | rbv::ResolvedArg::Free(..)
                     | rbv::ResolvedArg::Error(_),
                 )
-                | None => {
-                    self.has_late_bound_regions = Some(lt.ident.span);
-                }
+                | None => ControlFlow::Break(lt.ident.span),
             }
         }
     }
@@ -495,11 +505,7 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
         generics: &'tcx hir::Generics<'tcx>,
         decl: &'tcx hir::FnDecl<'tcx>,
     ) -> Option<Span> {
-        let mut visitor = LateBoundRegionsDetector {
-            tcx,
-            outer_index: ty::INNERMOST,
-            has_late_bound_regions: None,
-        };
+        let mut visitor = LateBoundRegionsDetector { tcx, outer_index: ty::INNERMOST };
         for param in generics.params {
             if let GenericParamKind::Lifetime { .. } = param.kind {
                 if tcx.is_late_bound(param.hir_id) {
@@ -507,8 +513,7 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
                 }
             }
         }
-        visitor.visit_fn_decl(decl);
-        visitor.has_late_bound_regions
+        visitor.visit_fn_decl(decl).break_value()
     }
 
     let decl = node.fn_decl()?;
@@ -518,25 +523,29 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
 
 struct AnonConstInParamTyDetector {
     in_param_ty: bool,
-    found_anon_const_in_param_ty: bool,
     ct: HirId,
 }
 
 impl<'v> Visitor<'v> for AnonConstInParamTyDetector {
-    fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) {
-        if let GenericParamKind::Const { ty, default: _, is_host_effect: _ } = p.kind {
+    type Result = ControlFlow<()>;
+
+    fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) -> Self::Result {
+        if let GenericParamKind::Const { ty, default: _, is_host_effect: _, synthetic: _ } = p.kind
+        {
             let prev = self.in_param_ty;
             self.in_param_ty = true;
-            self.visit_ty(ty);
+            let res = self.visit_ty(ty);
             self.in_param_ty = prev;
+            res
+        } else {
+            ControlFlow::Continue(())
         }
     }
 
-    fn visit_anon_const(&mut self, c: &'v hir::AnonConst) {
+    fn visit_anon_const(&mut self, c: &'v hir::AnonConst) -> Self::Result {
         if self.in_param_ty && self.ct == c.hir_id {
-            self.found_anon_const_in_param_ty = true;
-        } else {
-            intravisit::walk_anon_const(self, c)
+            return ControlFlow::Break(());
         }
+        intravisit::walk_anon_const(self, c)
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index dd1d209389d..c03e074c80b 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -8,6 +8,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFold
 use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::Span;
+use rustc_type_ir::Upcast;
 
 /// For associated types we include both bounds written on the type
 /// (`type X: Trait`) and predicates from the trait: `where Self::X: Trait`.
@@ -23,7 +24,7 @@ fn associated_type_bounds<'tcx>(
     span: Span,
     filter: PredicateFilter,
 ) -> &'tcx [(ty::Clause<'tcx>, Span)] {
-    let item_ty = Ty::new_projection(
+    let item_ty = Ty::new_projection_from_args(
         tcx,
         assoc_item_def_id.to_def_id(),
         GenericArgs::identity_for_item(tcx, assoc_item_def_id),
@@ -46,7 +47,7 @@ fn associated_type_bounds<'tcx>(
         }
     });
 
-    let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses().chain(bounds_from_parent));
+    let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses(tcx).chain(bounds_from_parent));
     debug!(
         "associated_type_bounds({}) = {:?}",
         tcx.def_path_str(assoc_item_def_id.to_def_id()),
@@ -59,7 +60,7 @@ fn associated_type_bounds<'tcx>(
 /// impl trait it isn't possible to write a suitable predicate on the
 /// containing function and for type-alias impl trait we don't have a backwards
 /// compatibility issue.
-#[instrument(level = "trace", skip(tcx), ret)]
+#[instrument(level = "trace", skip(tcx, item_ty))]
 fn opaque_type_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
     opaque_def_id: LocalDefId,
@@ -75,21 +76,21 @@ fn opaque_type_bounds<'tcx>(
         icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
         debug!(?bounds);
 
-        tcx.arena.alloc_from_iter(bounds.clauses())
+        tcx.arena.alloc_from_iter(bounds.clauses(tcx))
     })
 }
 
 pub(super) fn explicit_item_bounds(
     tcx: TyCtxt<'_>,
     def_id: LocalDefId,
-) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> {
+) -> ty::EarlyBinder<'_, &'_ [(ty::Clause<'_>, Span)]> {
     explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::All)
 }
 
 pub(super) fn explicit_item_super_predicates(
     tcx: TyCtxt<'_>,
     def_id: LocalDefId,
-) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> {
+) -> ty::EarlyBinder<'_, &'_ [(ty::Clause<'_>, Span)]> {
     explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::SelfOnly)
 }
 
@@ -97,7 +98,7 @@ pub(super) fn explicit_item_bounds_with_filter(
     tcx: TyCtxt<'_>,
     def_id: LocalDefId,
     filter: PredicateFilter,
-) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> {
+) -> ty::EarlyBinder<'_, &'_ [(ty::Clause<'_>, Span)]> {
     match tcx.opt_rpitit_info(def_id.to_def_id()) {
         // RPITIT's bounds are the same as opaque type bounds, but with
         // a projection self type.
@@ -108,7 +109,7 @@ pub(super) fn explicit_item_bounds_with_filter(
                 tcx,
                 opaque_def_id.expect_local(),
                 opaque_ty.bounds,
-                Ty::new_projection(
+                Ty::new_projection_from_args(
                     tcx,
                     def_id.to_def_id(),
                     ty::GenericArgs::identity_for_item(tcx, def_id),
@@ -124,6 +125,32 @@ pub(super) fn explicit_item_bounds_with_filter(
         None => {}
     }
 
+    if tcx.is_effects_desugared_assoc_ty(def_id.to_def_id()) {
+        let mut predicates = Vec::new();
+
+        let parent = tcx.local_parent(def_id);
+
+        let preds = tcx.explicit_predicates_of(parent);
+
+        if let ty::AssocItemContainer::TraitContainer = tcx.associated_item(def_id).container {
+            // for traits, emit `type Effects: TyCompat<<(T1::Effects, ..) as Min>::Output>`
+            let tup = Ty::new(tcx, ty::Tuple(preds.effects_min_tys));
+            // FIXME(effects) span
+            let span = tcx.def_span(def_id);
+            let assoc = tcx.require_lang_item(hir::LangItem::EffectsIntersectionOutput, Some(span));
+            let proj = Ty::new_projection(tcx, assoc, [tup]);
+            let self_proj = Ty::new_projection(
+                tcx,
+                def_id.to_def_id(),
+                ty::GenericArgs::identity_for_item(tcx, def_id),
+            );
+            let trait_ = tcx.require_lang_item(hir::LangItem::EffectsTyCompat, Some(span));
+            let trait_ref = ty::TraitRef::new(tcx, trait_, [self_proj, proj]);
+            predicates.push((ty::Binder::dummy(trait_ref).upcast(tcx), span));
+        }
+        return ty::EarlyBinder::bind(tcx.arena.alloc_from_iter(predicates));
+    }
+
     let bounds = match tcx.hir_node_by_def_id(def_id) {
         hir::Node::TraitItem(hir::TraitItem {
             kind: hir::TraitItemKind::Type(bounds, _),
@@ -166,7 +193,7 @@ pub(super) fn explicit_item_bounds_with_filter(
     ty::EarlyBinder::bind(bounds)
 }
 
-pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<ty::Clauses<'_>> {
+pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<'_, ty::Clauses<'_>> {
     tcx.explicit_item_bounds(def_id).map_bound(|bounds| {
         tcx.mk_clauses_from_iter(util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound)))
     })
@@ -175,7 +202,7 @@ pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<ty:
 pub(super) fn item_super_predicates(
     tcx: TyCtxt<'_>,
     def_id: DefId,
-) -> ty::EarlyBinder<ty::Clauses<'_>> {
+) -> ty::EarlyBinder<'_, ty::Clauses<'_>> {
     tcx.explicit_item_super_predicates(def_id).map_bound(|bounds| {
         tcx.mk_clauses_from_iter(
             util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound)).filter_only_self(),
@@ -186,7 +213,7 @@ pub(super) fn item_super_predicates(
 pub(super) fn item_non_self_assumptions(
     tcx: TyCtxt<'_>,
     def_id: DefId,
-) -> ty::EarlyBinder<ty::Clauses<'_>> {
+) -> ty::EarlyBinder<'_, ty::Clauses<'_>> {
     let all_bounds: FxIndexSet<_> = tcx.item_bounds(def_id).skip_binder().iter().collect();
     let own_bounds: FxIndexSet<_> =
         tcx.item_super_predicates(def_id).skip_binder().iter().collect();
@@ -203,7 +230,7 @@ struct AssocTyToOpaque<'tcx> {
 }
 
 impl<'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTyToOpaque<'tcx> {
-    fn interner(&self) -> TyCtxt<'tcx> {
+    fn cx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 606f1653767..b89d034fc2e 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -1,7 +1,7 @@
 use crate::bounds::Bounds;
 use crate::collect::ItemCtxt;
 use crate::constrained_generic_params as cgp;
-use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter};
+use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter, RegionInferReason};
 use hir::{HirId, Node};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir as hir;
@@ -57,6 +57,7 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic
 #[instrument(level = "trace", skip(tcx), ret)]
 fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::GenericPredicates<'_> {
     use rustc_hir::*;
+    use rustc_middle::ty::Ty;
 
     match tcx.opt_rpitit_info(def_id.to_def_id()) {
         Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) => {
@@ -84,6 +85,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
             return ty::GenericPredicates {
                 parent: Some(tcx.parent(def_id.to_def_id())),
                 predicates: tcx.arena.alloc_from_iter(predicates),
+                effects_min_tys: ty::List::empty(),
             };
         }
 
@@ -105,6 +107,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
             return ty::GenericPredicates {
                 parent: Some(impl_def_id),
                 predicates: tcx.arena.alloc_from_iter(impl_predicates),
+                effects_min_tys: ty::List::empty(),
             };
         }
 
@@ -117,7 +120,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
     let mut is_trait = None;
     let mut is_default_impl_trait = None;
 
-    // FIXME: Should ItemCtxt take a LocalDefId?
     let icx = ItemCtxt::new(tcx, def_id);
 
     const NO_GENERICS: &hir::Generics<'_> = hir::Generics::empty();
@@ -125,6 +127,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
     // We use an `IndexSet` to preserve order of insertion.
     // Preserving the order of insertion is important here so as not to break UI tests.
     let mut predicates: FxIndexSet<(ty::Clause<'_>, Span)> = FxIndexSet::default();
+    let mut effects_min_tys = Vec::new();
 
     let hir_generics = node.generics().unwrap_or(NO_GENERICS);
     if let Node::Item(item) = node {
@@ -151,11 +154,13 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
     // on a trait we must also consider the bounds that follow the trait's name,
     // like `trait Foo: A + B + C`.
     if let Some(self_bounds) = is_trait {
-        predicates.extend(
-            icx.lowerer()
-                .lower_mono_bounds(tcx.types.self_param, self_bounds, PredicateFilter::All)
-                .clauses(),
+        let bounds = icx.lowerer().lower_mono_bounds(
+            tcx.types.self_param,
+            self_bounds,
+            PredicateFilter::All,
         );
+        predicates.extend(bounds.clauses(tcx));
+        effects_min_tys.extend(bounds.effects_min_tys());
     }
 
     // In default impls, we can assume that the self type implements
@@ -170,12 +175,11 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
         predicates.insert((trait_ref.upcast(tcx), tcx.def_span(def_id)));
     }
 
-    // Collect the predicates that were written inline by the user on each
-    // type parameter (e.g., `<T: Foo>`). Also add `ConstArgHasType` predicates
-    // for each const parameter.
+    // Add implicit predicates that should be treated as if the user has written them,
+    // including the implicit `T: Sized` for all generic parameters, and `ConstArgHasType`
+    // for const params.
     for param in hir_generics.params {
         match param.kind {
-            // We already dealt with early bound lifetimes above.
             GenericParamKind::Lifetime { .. } => (),
             GenericParamKind::Type { .. } => {
                 let param_ty = icx.lowerer().lower_ty_param(param.hir_id);
@@ -189,7 +193,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                     param.span,
                 );
                 trace!(?bounds);
-                predicates.extend(bounds.clauses());
+                predicates.extend(bounds.clauses(tcx));
                 trace!(?predicates);
             }
             hir::GenericParamKind::Const { .. } => {
@@ -197,7 +201,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                     .type_of(param.def_id.to_def_id())
                     .no_bound_vars()
                     .expect("const parameters cannot be generic");
-                let ct = icx.lowerer().lower_const_param(param.hir_id, ct_ty);
+                let ct = icx.lowerer().lower_const_param(param.hir_id);
                 predicates
                     .insert((ty::ClauseKind::ConstArgHasType(ct, ct_ty).upcast(tcx), param.span));
             }
@@ -205,7 +209,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
     }
 
     trace!(?predicates);
-    // Add in the bounds that appear in the where-clause.
+    // Add inline `<T: Foo>` bounds and bounds in the where clause.
     for predicate in hir_generics.predicates {
         match predicate {
             hir::WherePredicate::BoundPredicate(bound_pred) => {
@@ -240,16 +244,20 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                     bound_vars,
                     OnlySelfBounds(false),
                 );
-                predicates.extend(bounds.clauses());
+                predicates.extend(bounds.clauses(tcx));
+                effects_min_tys.extend(bounds.effects_min_tys());
             }
 
             hir::WherePredicate::RegionPredicate(region_pred) => {
-                let r1 = icx.lowerer().lower_lifetime(region_pred.lifetime, None);
+                let r1 = icx
+                    .lowerer()
+                    .lower_lifetime(region_pred.lifetime, RegionInferReason::RegionPredicate);
                 predicates.extend(region_pred.bounds.iter().map(|bound| {
                     let (r2, span) = match bound {
-                        hir::GenericBound::Outlives(lt) => {
-                            (icx.lowerer().lower_lifetime(lt, None), lt.ident.span)
-                        }
+                        hir::GenericBound::Outlives(lt) => (
+                            icx.lowerer().lower_lifetime(lt, RegionInferReason::RegionPredicate),
+                            lt.ident.span,
+                        ),
                         bound => {
                             span_bug!(
                                 bound.span(),
@@ -296,7 +304,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
     // and the duplicated parameter, to ensure that they do not get out of sync.
     if let Node::Item(&Item { kind: ItemKind::OpaqueTy(..), .. }) = node {
         let opaque_ty_node = tcx.parent_hir_node(hir_id);
-        let Node::Ty(&Ty { kind: TyKind::OpaqueDef(_, lifetimes, _), .. }) = opaque_ty_node else {
+        let Node::Ty(&hir::Ty { kind: TyKind::OpaqueDef(_, lifetimes, _), .. }) = opaque_ty_node
+        else {
             bug!("unexpected {opaque_ty_node:?}")
         };
         debug!(?lifetimes);
@@ -305,9 +314,30 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
         debug!(?predicates);
     }
 
+    // add `Self::Effects: Compat<HOST>` to ensure non-const impls don't get called
+    // in const contexts.
+    if let Node::TraitItem(&TraitItem { kind: TraitItemKind::Fn(..), .. }) = node
+        && let Some(host_effect_index) = generics.host_effect_index
+    {
+        let parent = generics.parent.unwrap();
+        let Some(assoc_def_id) = tcx.associated_type_for_effects(parent) else {
+            bug!("associated_type_for_effects returned None when there is host effect in generics");
+        };
+        let effects =
+            Ty::new_projection(tcx, assoc_def_id, ty::GenericArgs::identity_for_item(tcx, parent));
+        let param = generics.param_at(host_effect_index, tcx);
+        let span = tcx.def_span(param.def_id);
+        let host = ty::Const::new_param(tcx, ty::ParamConst::for_def(param));
+        let compat = tcx.require_lang_item(LangItem::EffectsCompat, Some(span));
+        let trait_ref =
+            ty::TraitRef::new(tcx, compat, [ty::GenericArg::from(effects), host.into()]);
+        predicates.push((ty::Binder::dummy(trait_ref).upcast(tcx), span));
+    }
+
     ty::GenericPredicates {
         parent: generics.parent,
         predicates: tcx.arena.alloc_from_iter(predicates),
+        effects_min_tys: tcx.mk_type_list(&effects_min_tys),
     }
 }
 
@@ -323,7 +353,7 @@ fn compute_bidirectional_outlives_predicates<'tcx>(
         if let ty::ReEarlyParam(..) = *orig_lifetime {
             let dup_lifetime = ty::Region::new_early_param(
                 tcx,
-                ty::EarlyParamRegion { def_id: param.def_id, index: param.index, name: param.name },
+                ty::EarlyParamRegion { index: param.index, name: param.name },
             );
             let span = tcx.def_span(param.def_id);
             predicates.push((
@@ -458,6 +488,7 @@ pub(super) fn explicit_predicates_of<'tcx>(
             ty::GenericPredicates {
                 parent: predicates_and_bounds.parent,
                 predicates: tcx.arena.alloc_slice(&predicates),
+                effects_min_tys: predicates_and_bounds.effects_min_tys,
             }
         }
     } else {
@@ -509,6 +540,7 @@ pub(super) fn explicit_predicates_of<'tcx>(
             return GenericPredicates {
                 parent: parent_preds.parent,
                 predicates: { tcx.arena.alloc_from_iter(filtered_predicates) },
+                effects_min_tys: parent_preds.effects_min_tys,
             };
         }
         gather_explicit_predicates_of(tcx, def_id)
@@ -518,21 +550,21 @@ pub(super) fn explicit_predicates_of<'tcx>(
 /// Ensures that the super-predicates of the trait with a `DefId`
 /// of `trait_def_id` are lowered and stored. This also ensures that
 /// the transitive super-predicates are lowered.
-pub(super) fn super_predicates_of(
+pub(super) fn explicit_super_predicates_of(
     tcx: TyCtxt<'_>,
     trait_def_id: LocalDefId,
 ) -> ty::GenericPredicates<'_> {
     implied_predicates_with_filter(tcx, trait_def_id.to_def_id(), PredicateFilter::SelfOnly)
 }
 
-pub(super) fn super_predicates_that_define_assoc_item(
+pub(super) fn explicit_supertraits_containing_assoc_item(
     tcx: TyCtxt<'_>,
     (trait_def_id, assoc_name): (DefId, Ident),
 ) -> ty::GenericPredicates<'_> {
     implied_predicates_with_filter(tcx, trait_def_id, PredicateFilter::SelfThatDefines(assoc_name))
 }
 
-pub(super) fn implied_predicates_of(
+pub(super) fn explicit_implied_predicates_of(
     tcx: TyCtxt<'_>,
     trait_def_id: LocalDefId,
 ) -> ty::GenericPredicates<'_> {
@@ -559,7 +591,7 @@ pub(super) fn implied_predicates_with_filter(
         // if `assoc_name` is None, then the query should've been redirected to an
         // external provider
         assert!(matches!(filter, PredicateFilter::SelfThatDefines(_)));
-        return tcx.super_predicates_of(trait_def_id);
+        return tcx.explicit_super_predicates_of(trait_def_id);
     };
 
     let Node::Item(item) = tcx.hir_node_by_def_id(trait_def_id) else {
@@ -586,7 +618,7 @@ pub(super) fn implied_predicates_with_filter(
 
     // Combine the two lists to form the complete set of superbounds:
     let implied_bounds =
-        &*tcx.arena.alloc_from_iter(superbounds.clauses().chain(where_bounds_that_match));
+        &*tcx.arena.alloc_from_iter(superbounds.clauses(tcx).chain(where_bounds_that_match));
     debug!(?implied_bounds);
 
     // Now require that immediate supertraits are lowered, which will, in
@@ -600,7 +632,7 @@ pub(super) fn implied_predicates_with_filter(
                 if let ty::ClauseKind::Trait(bound) = pred.kind().skip_binder()
                     && bound.polarity == ty::PredicatePolarity::Positive
                 {
-                    tcx.at(span).super_predicates_of(bound.def_id());
+                    tcx.at(span).explicit_super_predicates_of(bound.def_id());
                 }
             }
         }
@@ -610,14 +642,18 @@ pub(super) fn implied_predicates_with_filter(
                 if let ty::ClauseKind::Trait(bound) = pred.kind().skip_binder()
                     && bound.polarity == ty::PredicatePolarity::Positive
                 {
-                    tcx.at(span).implied_predicates_of(bound.def_id());
+                    tcx.at(span).explicit_implied_predicates_of(bound.def_id());
                 }
             }
         }
         _ => {}
     }
 
-    ty::GenericPredicates { parent: None, predicates: implied_bounds }
+    ty::GenericPredicates {
+        parent: None,
+        predicates: implied_bounds,
+        effects_min_tys: ty::List::empty(),
+    }
 }
 
 /// Returns the predicates defined on `item_def_id` of the form
@@ -743,7 +779,7 @@ impl<'tcx> ItemCtxt<'tcx> {
             );
         }
 
-        bounds.clauses().collect()
+        bounds.clauses(self.tcx).collect()
     }
 
     #[instrument(level = "trace", skip(self))]
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index 5c7733065c6..cad7870a0a1 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -603,7 +603,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
 
     fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
         match item.kind {
-            hir::ForeignItemKind::Fn(_, _, generics) => {
+            hir::ForeignItemKind::Fn(_, _, generics, _) => {
                 self.visit_early_late(item.hir_id(), generics, |this| {
                     intravisit::walk_foreign_item(this, item);
                 })
@@ -951,7 +951,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                     self.visit_ty(ty);
                 }
             }
-            GenericParamKind::Const { ty, default, is_host_effect: _ } => {
+            GenericParamKind::Const { ty, default, .. } => {
                 self.visit_ty(ty);
                 if let Some(default) = default {
                     self.visit_body(self.tcx.hir().body(default.body));
@@ -1468,12 +1468,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
         depth: usize,
         generic_args: &'tcx hir::GenericArgs<'tcx>,
     ) {
-        if generic_args.parenthesized == hir::GenericArgsParentheses::ParenSugar {
-            self.visit_fn_like_elision(
-                generic_args.inputs(),
-                Some(generic_args.bindings[0].ty()),
-                false,
-            );
+        if let Some((inputs, output)) = generic_args.paren_sugar_inputs_output() {
+            self.visit_fn_like_elision(inputs, Some(output), false);
             return;
         }
 
@@ -1608,8 +1604,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
             }
         }
 
-        // Hack: when resolving the type `XX` in binding like `dyn
-        // Foo<'b, Item = XX>`, the current object-lifetime default
+        // Hack: When resolving the type `XX` in an assoc ty binding like
+        // `dyn Foo<'b, Item = XX>`, the current object-lifetime default
         // would be to examine the trait `Foo` to check whether it has
         // a lifetime bound declared on `Item`. e.g., if `Foo` is
         // declared like so, then the default object lifetime bound in
@@ -1637,7 +1633,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
 
         // Resolve lifetimes found in the bindings, so either in the type `XX` in `Item = XX` or
         // in the trait ref `YY<...>` in `Item: YY<...>`.
-        for binding in generic_args.bindings {
+        for constraint in generic_args.constraints {
             let scope = Scope::ObjectLifetimeDefault {
                 lifetime: if has_lifetime_parameter {
                     None
@@ -1646,7 +1642,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                 },
                 s: self.scope,
             };
-            // If the binding is parenthesized, then this must be `feature(return_type_notation)`.
+            // If the args are parenthesized, then this must be `feature(return_type_notation)`.
             // In that case, introduce a binder over all of the function's early and late bound vars.
             //
             // For example, given
@@ -1659,13 +1655,14 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
             //    `for<'a> T::Trait<'a, x(): for<'b> Other<'b>>`
             // this is going to expand to something like:
             //    `for<'a> for<'r, T> <T as Trait<'a>>::x::<'r, T>::{opaque#0}: for<'b> Other<'b>`.
-            if binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation {
+            if constraint.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation
+            {
                 let bound_vars = if let Some(type_def_id) = type_def_id
                     && self.tcx.def_kind(type_def_id) == DefKind::Trait
                     && let Some((mut bound_vars, assoc_fn)) = BoundVarContext::supertrait_hrtb_vars(
                         self.tcx,
                         type_def_id,
-                        binding.ident,
+                        constraint.ident,
                         ty::AssocKind::Fn,
                     ) {
                     bound_vars.extend(self.tcx.generics_of(assoc_fn.def_id).own_params.iter().map(
@@ -1686,22 +1683,22 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                 } else {
                     self.tcx
                         .dcx()
-                        .span_delayed_bug(binding.ident.span, "bad return type notation here");
+                        .span_delayed_bug(constraint.ident.span, "bad return type notation here");
                     vec![]
                 };
                 self.with(scope, |this| {
                     let scope = Scope::Supertrait { bound_vars, s: this.scope };
                     this.with(scope, |this| {
                         let (bound_vars, _) = this.poly_trait_ref_binder_info();
-                        this.record_late_bound_vars(binding.hir_id, bound_vars);
-                        this.visit_assoc_type_binding(binding)
+                        this.record_late_bound_vars(constraint.hir_id, bound_vars);
+                        this.visit_assoc_item_constraint(constraint)
                     });
                 });
             } else if let Some(type_def_id) = type_def_id {
                 let bound_vars = BoundVarContext::supertrait_hrtb_vars(
                     self.tcx,
                     type_def_id,
-                    binding.ident,
+                    constraint.ident,
                     ty::AssocKind::Type,
                 )
                 .map(|(bound_vars, _)| bound_vars);
@@ -1710,10 +1707,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                         bound_vars: bound_vars.unwrap_or_default(),
                         s: this.scope,
                     };
-                    this.with(scope, |this| this.visit_assoc_type_binding(binding));
+                    this.with(scope, |this| this.visit_assoc_item_constraint(constraint));
                 });
             } else {
-                self.with(scope, |this| this.visit_assoc_type_binding(binding));
+                self.with(scope, |this| this.visit_assoc_item_constraint(constraint));
             }
         }
     }
@@ -1763,7 +1760,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
             if let Some(assoc_item) = trait_defines_associated_item_named(def_id) {
                 break Some((bound_vars.into_iter().collect(), assoc_item));
             }
-            let predicates = tcx.super_predicates_that_define_assoc_item((def_id, assoc_name));
+            let predicates = tcx.explicit_supertraits_containing_assoc_item((def_id, assoc_name));
             let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| {
                 let bound_predicate = pred.kind();
                 match bound_predicate.skip_binder() {
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 1475e53c47c..974dd415f46 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -12,10 +12,10 @@ use rustc_span::symbol::Ident;
 use rustc_span::{Span, DUMMY_SP};
 
 use crate::errors::TypeofReservedKeywordUsed;
+use crate::hir_ty_lowering::HirTyLowerer;
 
 use super::bad_placeholder;
 use super::ItemCtxt;
-pub use opaque::test_opaque_hidden_types;
 
 mod opaque;
 
@@ -220,9 +220,10 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
                     .position(|arg| arg.hir_id() == hir_id)
                     .map(|index| (index, seg))
                     .or_else(|| {
-                        args.bindings
+                        args.constraints
                             .iter()
-                            .filter_map(TypeBinding::opt_const)
+                            .copied()
+                            .filter_map(AssocItemConstraint::ct)
                             .position(|ct| ct.hir_id == hir_id)
                             .map(|idx| (idx, seg))
                     })
@@ -309,7 +310,7 @@ fn get_path_containing_arg_in_pat<'hir>(
     arg_path
 }
 
-pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty<'_>> {
+pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, Ty<'_>> {
     use rustc_hir::*;
     use rustc_middle::ty::Ty;
 
@@ -357,7 +358,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
                 .and_then(|body_id| {
                     ty.is_suggestable_infer_ty().then(|| {
                         infer_placeholder_type(
-                            tcx,
+                            icx.lowerer(),
                             def_id,
                             body_id,
                             ty.span,
@@ -381,7 +382,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
             ImplItemKind::Const(ty, body_id) => {
                 if ty.is_suggestable_infer_ty() {
                     infer_placeholder_type(
-                        tcx,
+                        icx.lowerer(),
                         def_id,
                         body_id,
                         ty.span,
@@ -405,7 +406,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
             ItemKind::Static(ty, .., body_id) => {
                 if ty.is_suggestable_infer_ty() {
                     infer_placeholder_type(
-                        tcx,
+                        icx.lowerer(),
                         def_id,
                         body_id,
                         ty.span,
@@ -418,7 +419,14 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
             }
             ItemKind::Const(ty, _, body_id) => {
                 if ty.is_suggestable_infer_ty() {
-                    infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant")
+                    infer_placeholder_type(
+                        icx.lowerer(),
+                        def_id,
+                        body_id,
+                        ty.span,
+                        item.ident,
+                        "constant",
+                    )
                 } else {
                     icx.lower_ty(ty)
                 }
@@ -463,7 +471,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
                 let args = ty::GenericArgs::identity_for_item(tcx, def_id);
                 Ty::new_fn_def(tcx, def_id.to_def_id(), args)
             }
-            ForeignItemKind::Static(t, _) => icx.lower_ty(t),
+            ForeignItemKind::Static(t, _, _) => icx.lower_ty(t),
             ForeignItemKind::Type => Ty::new_foreign(tcx, def_id.to_def_id()),
         },
 
@@ -502,7 +510,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
             bug!("unexpected sort of node in type_of(): {:?}", x);
         }
     };
-    if let Err(e) = icx.check_tainted_by_errors() {
+    if let Err(e) = icx.check_tainted_by_errors()
+        && !output.references_error()
+    {
         ty::EarlyBinder::bind(Ty::new_error(tcx, e))
     } else {
         ty::EarlyBinder::bind(output)
@@ -512,7 +522,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
 pub(super) fn type_of_opaque(
     tcx: TyCtxt<'_>,
     def_id: DefId,
-) -> Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> {
+) -> Result<ty::EarlyBinder<'_, Ty<'_>>, CyclePlaceholder> {
     if let Some(def_id) = def_id.as_local() {
         use rustc_hir::*;
 
@@ -557,21 +567,22 @@ pub(super) fn type_of_opaque(
     }
 }
 
-fn infer_placeholder_type<'a>(
-    tcx: TyCtxt<'a>,
+fn infer_placeholder_type<'tcx>(
+    cx: &dyn HirTyLowerer<'tcx>,
     def_id: LocalDefId,
     body_id: hir::BodyId,
     span: Span,
     item_ident: Ident,
     kind: &'static str,
-) -> Ty<'a> {
+) -> Ty<'tcx> {
+    let tcx = cx.tcx();
     let ty = tcx.diagnostic_only_typeck(def_id).node_type(body_id.hir_id);
 
     // If this came from a free `const` or `static mut?` item,
     // then the user may have written e.g. `const A = 42;`.
     // In this case, the parser has stashed a diagnostic for
     // us to improve in typeck so we do that now.
-    let guar = tcx
+    let guar = cx
         .dcx()
         .try_steal_modify_and_emit_err(span, StashKey::ItemNoType, |err| {
             if !ty.references_error() {
@@ -600,7 +611,7 @@ fn infer_placeholder_type<'a>(
             }
         })
         .unwrap_or_else(|| {
-            let mut diag = bad_placeholder(tcx, vec![span], kind);
+            let mut diag = bad_placeholder(cx, vec![span], kind);
 
             if !ty.references_error() {
                 if let Some(ty) = ty.make_suggestable(tcx, false, None) {
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
index 1bec8c496ad..d1048b742a0 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
@@ -1,28 +1,14 @@
 use rustc_errors::StashKey;
 use rustc_hir::def::DefKind;
-use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{self as hir, def, Expr, ImplItem, Item, Node, TraitItem};
 use rustc_middle::bug;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
-use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP};
+use rustc_span::DUMMY_SP;
 
-use crate::errors::{TaitForwardCompat, TypeOf, UnconstrainedOpaqueType};
-
-pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
-    let mut res = Ok(());
-    if tcx.has_attr(CRATE_DEF_ID, sym::rustc_hidden_type_of_opaques) {
-        for id in tcx.hir().items() {
-            if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) {
-                let type_of = tcx.type_of(id.owner_id).instantiate_identity();
-
-                res = Err(tcx.dcx().emit_err(TypeOf { span: tcx.def_span(id.owner_id), type_of }));
-            }
-        }
-    }
-    res
-}
+use crate::errors::{TaitForwardCompat, TaitForwardCompat2, UnconstrainedOpaqueType};
 
 /// Checks "defining uses" of opaque `impl Trait` in associated types.
 /// These can only be defined by associated items of the same trait.
@@ -229,13 +215,14 @@ impl TaitConstraintLocator<'_> {
             return;
         }
 
+        let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id);
+
         let mut constrained = false;
         for (&opaque_type_key, &hidden_type) in &tables.concrete_opaque_types {
             if opaque_type_key.def_id != self.def_id {
                 continue;
             }
             constrained = true;
-            let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id);
 
             if !opaque_types_defined_by.contains(&self.def_id) {
                 self.tcx.dcx().emit_err(TaitForwardCompat {
@@ -259,6 +246,16 @@ impl TaitConstraintLocator<'_> {
 
         if !constrained {
             debug!("no constraints in typeck results");
+            if opaque_types_defined_by.contains(&self.def_id) {
+                self.tcx.dcx().emit_err(TaitForwardCompat2 {
+                    span: self
+                        .tcx
+                        .def_ident_span(item_def_id)
+                        .unwrap_or_else(|| self.tcx.def_span(item_def_id)),
+                    opaque_type_span: self.tcx.def_span(self.def_id),
+                    opaque_type: self.tcx.def_path_str(self.def_id),
+                });
+            }
             return;
         };
 
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 1c99713b3ae..0ee87a13e9e 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -2,13 +2,14 @@
 
 use crate::fluent_generated as fluent;
 use rustc_errors::{
-    codes::*, Applicability, Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level, MultiSpan,
+    codes::*, Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan,
 };
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::Ty;
 use rustc_span::{symbol::Ident, Span, Symbol};
 mod pattern_types;
 pub use pattern_types::*;
+pub mod wrong_number_of_generic_args;
 
 mod precise_captures;
 pub(crate) use precise_captures::*;
@@ -56,6 +57,18 @@ pub struct AssocKindMismatchWrapInBracesSugg {
 }
 
 #[derive(Diagnostic)]
+#[diag(hir_analysis_assoc_item_is_private, code = E0624)]
+pub struct AssocItemIsPrivate {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub kind: &'static str,
+    pub name: Ident,
+    #[label(hir_analysis_defined_here_label)]
+    pub defined_here_label: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(hir_analysis_assoc_item_not_found, code = E0220)]
 pub struct AssocItemNotFound<'a> {
     #[primary_span]
@@ -290,8 +303,8 @@ pub struct AmbiguousLifetimeBound {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis_assoc_type_binding_not_allowed, code = E0229)]
-pub struct AssocTypeBindingNotAllowed {
+#[diag(hir_analysis_assoc_item_constraints_not_allowed_here, code = E0229)]
+pub struct AssocItemConstraintsNotAllowedHere {
     #[primary_span]
     #[label]
     pub span: Span,
@@ -390,6 +403,17 @@ pub struct TaitForwardCompat {
     pub item_span: Span,
 }
 
+#[derive(Diagnostic)]
+#[diag(hir_analysis_tait_forward_compat2)]
+#[note]
+pub struct TaitForwardCompat2 {
+    #[primary_span]
+    pub span: Span,
+    #[note(hir_analysis_opaque)]
+    pub opaque_type_span: Span,
+    pub opaque_type: String,
+}
+
 pub struct MissingTypeParams {
     pub span: Span,
     pub def_span: Span,
@@ -401,7 +425,7 @@ pub struct MissingTypeParams {
 // Manual implementation of `Diagnostic` to be able to call `span_to_snippet`.
 impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingTypeParams {
     #[track_caller]
-    fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> {
+    fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
         let mut err = Diag::new(dcx, level, fluent::hir_analysis_missing_type_params);
         err.span(self.span);
         err.code(E0393);
@@ -430,12 +454,11 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingTypeParams {
             } else {
                 // The user wrote `Iterator`, so we don't have a type we can suggest, but at
                 // least we can clue them to the correct syntax `Iterator<Type>`.
-                err.span_suggestion(
-                    self.span,
+                err.span_suggestion_verbose(
+                    self.span.shrink_to_hi(),
                     fluent::hir_analysis_suggestion,
                     format!(
-                        "{}<{}>",
-                        snippet,
+                        "<{}>",
                         self.missing_type_params
                             .iter()
                             .map(|n| n.to_string())
@@ -659,7 +682,7 @@ pub(crate) enum CannotCaptureLateBound {
 pub(crate) struct VariancesOf {
     #[primary_span]
     pub span: Span,
-    pub variances_of: String,
+    pub variances: String,
 }
 
 #[derive(Diagnostic)]
@@ -667,30 +690,7 @@ pub(crate) struct VariancesOf {
 pub(crate) struct TypeOf<'tcx> {
     #[primary_span]
     pub span: Span,
-    pub type_of: Ty<'tcx>,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis_pass_to_variadic_function, code = E0617)]
-pub(crate) struct PassToVariadicFunction<'tcx, 'a> {
-    #[primary_span]
-    pub span: Span,
     pub ty: Ty<'tcx>,
-    pub cast_ty: &'a str,
-    #[suggestion(code = "{replace}", applicability = "machine-applicable")]
-    pub sugg_span: Option<Span>,
-    pub replace: String,
-    #[help]
-    pub help: Option<()>,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis_cast_thin_pointer_to_fat_pointer, code = E0607)]
-pub(crate) struct CastThinPointerToFatPointer<'tcx> {
-    #[primary_span]
-    pub span: Span,
-    pub expr_ty: Ty<'tcx>,
-    pub cast_ty: String,
 }
 
 #[derive(Diagnostic)]
@@ -1676,3 +1676,9 @@ pub struct InvalidReceiverTy<'tcx> {
     pub span: Span,
     pub receiver_ty: Ty<'tcx>,
 }
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_effects_without_next_solver)]
+#[note]
+#[help]
+pub struct EffectsWithoutNextSolver;
diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
index 9ddba7a6e7a..6426ad9dc18 100644
--- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
@@ -1,8 +1,8 @@
-use crate::structured_errors::StructuredDiag;
-use rustc_errors::{codes::*, pluralize, Applicability, Diag, MultiSpan};
+use rustc_errors::{
+    codes::*, pluralize, Applicability, Diag, Diagnostic, EmissionGuarantee, MultiSpan,
+};
 use rustc_hir as hir;
 use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt};
-use rustc_session::Session;
 use rustc_span::def_id::DefId;
 use std::iter;
 
@@ -489,7 +489,11 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
                 .in_definition_order()
                 .filter(|item| item.kind == AssocKind::Type)
                 .filter(|item| {
-                    !self.gen_args.bindings.iter().any(|binding| binding.ident.name == item.name)
+                    !self
+                        .gen_args
+                        .constraints
+                        .iter()
+                        .any(|constraint| constraint.ident.name == item.name)
                 })
                 .map(|item| item.name.to_ident_string())
                 .collect()
@@ -537,14 +541,8 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
         }
     }
 
-    fn start_diagnostics(&self) -> Diag<'tcx> {
-        let span = self.path_segment.ident.span;
-        let msg = self.create_error_message();
-        self.tcx.dcx().struct_span_err(span, msg).with_code(self.code())
-    }
-
     /// Builds the `expected 1 type argument / supplied 2 type arguments` message.
-    fn notify(&self, err: &mut Diag<'_>) {
+    fn notify(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
         let (quantifier, bound) = self.get_quantifier_and_bound();
         let provided_args = self.num_provided_args();
 
@@ -596,7 +594,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
         }
     }
 
-    fn suggest(&self, err: &mut Diag<'_>) {
+    fn suggest(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
         debug!(
             "suggest(self.provided {:?}, self.gen_args.span(): {:?})",
             self.num_provided_args(),
@@ -624,7 +622,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
     /// ```text
     /// type Map = HashMap<String>;
     /// ```
-    fn suggest_adding_args(&self, err: &mut Diag<'_>) {
+    fn suggest_adding_args(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
         if self.gen_args.parenthesized != hir::GenericArgsParentheses::No {
             return;
         }
@@ -643,7 +641,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
         }
     }
 
-    fn suggest_adding_lifetime_args(&self, err: &mut Diag<'_>) {
+    fn suggest_adding_lifetime_args(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
         debug!("suggest_adding_lifetime_args(path_segment: {:?})", self.path_segment);
         let num_missing_args = self.num_missing_lifetime_args();
         let num_params_to_take = num_missing_args;
@@ -679,11 +677,11 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
                     (last_lt.span().shrink_to_hi(), false)
                 };
                 let has_non_lt_args = self.num_provided_type_or_const_args() != 0;
-                let has_bindings = !self.gen_args.bindings.is_empty();
+                let has_constraints = !self.gen_args.constraints.is_empty();
 
                 let sugg_prefix = if is_first { "" } else { ", " };
                 let sugg_suffix =
-                    if is_first && (has_non_lt_args || has_bindings) { ", " } else { "" };
+                    if is_first && (has_non_lt_args || has_constraints) { ", " } else { "" };
 
                 let sugg = format!("{sugg_prefix}{suggested_args}{sugg_suffix}");
                 debug!("sugg: {:?}", sugg);
@@ -697,7 +695,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
         }
     }
 
-    fn suggest_adding_type_and_const_args(&self, err: &mut Diag<'_>) {
+    fn suggest_adding_type_and_const_args(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
         let num_missing_args = self.num_missing_type_or_const_args();
         let msg = format!("add missing {} argument{}", self.kind(), pluralize!(num_missing_args));
 
@@ -741,7 +739,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
 
                 let sugg_prefix = if is_first { "" } else { ", " };
                 let sugg_suffix =
-                    if is_first && !self.gen_args.bindings.is_empty() { ", " } else { "" };
+                    if is_first && !self.gen_args.constraints.is_empty() { ", " } else { "" };
 
                 let sugg = format!("{sugg_prefix}{suggested_args}{sugg_suffix}");
                 debug!("sugg: {:?}", sugg);
@@ -757,7 +755,10 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
     /// ```compile_fail
     /// Into::into::<Option<_>>(42) // suggests considering `Into::<Option<_>>::into(42)`
     /// ```
-    fn suggest_moving_args_from_assoc_fn_to_trait(&self, err: &mut Diag<'_>) {
+    fn suggest_moving_args_from_assoc_fn_to_trait(
+        &self,
+        err: &mut Diag<'_, impl EmissionGuarantee>,
+    ) {
         let trait_ = match self.tcx.trait_of_item(self.def_id) {
             Some(def_id) => def_id,
             None => return,
@@ -813,7 +814,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
 
     fn suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path(
         &self,
-        err: &mut Diag<'_>,
+        err: &mut Diag<'_, impl EmissionGuarantee>,
         qpath: &'tcx hir::QPath<'tcx>,
         msg: String,
         num_assoc_fn_excess_args: usize,
@@ -846,7 +847,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
 
     fn suggest_moving_args_from_assoc_fn_to_trait_for_method_call(
         &self,
-        err: &mut Diag<'_>,
+        err: &mut Diag<'_, impl EmissionGuarantee>,
         trait_def_id: DefId,
         expr: &'tcx hir::Expr<'tcx>,
         msg: String,
@@ -900,7 +901,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
     /// ```text
     /// type Map = HashMap<String, String, String, String>;
     /// ```
-    fn suggest_removing_args_or_generics(&self, err: &mut Diag<'_>) {
+    fn suggest_removing_args_or_generics(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
         let num_provided_lt_args = self.num_provided_lifetime_args();
         let num_provided_type_const_args = self.num_provided_type_or_const_args();
         let unbound_types = self.get_unbound_associated_types();
@@ -918,7 +919,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
         let provided_args_matches_unbound_traits =
             unbound_types.len() == num_redundant_type_or_const_args;
 
-        let remove_lifetime_args = |err: &mut Diag<'_>| {
+        let remove_lifetime_args = |err: &mut Diag<'_, _>| {
             let mut lt_arg_spans = Vec::new();
             let mut found_redundant = false;
             for arg in self.gen_args.args {
@@ -959,7 +960,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
             );
         };
 
-        let remove_type_or_const_args = |err: &mut Diag<'_>| {
+        let remove_type_or_const_args = |err: &mut Diag<'_, _>| {
             let mut gen_arg_spans = Vec::new();
             let mut found_redundant = false;
             for arg in self.gen_args.args {
@@ -1056,7 +1057,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
     }
 
     /// Builds the `type defined here` message.
-    fn show_definition(&self, err: &mut Diag<'_>) {
+    fn show_definition(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
         let mut spans: MultiSpan = if let Some(def_span) = self.tcx.def_ident_span(self.def_id) {
             if self.tcx.sess.source_map().is_span_accessible(def_span) {
                 def_span.into()
@@ -1107,7 +1108,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
     }
 
     /// Add note if `impl Trait` is explicitly specified.
-    fn note_synth_provided(&self, err: &mut Diag<'_>) {
+    fn note_synth_provided(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
         if !self.is_synth_provided() {
             return;
         }
@@ -1116,17 +1117,16 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
     }
 }
 
-impl<'tcx> StructuredDiag<'tcx> for WrongNumberOfGenericArgs<'_, 'tcx> {
-    fn session(&self) -> &Session {
-        self.tcx.sess
-    }
-
-    fn code(&self) -> ErrCode {
-        E0107
-    }
-
-    fn diagnostic_common(&self) -> Diag<'tcx> {
-        let mut err = self.start_diagnostics();
+impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for WrongNumberOfGenericArgs<'_, '_> {
+    fn into_diag(
+        self,
+        dcx: rustc_errors::DiagCtxtHandle<'a>,
+        level: rustc_errors::Level,
+    ) -> Diag<'a, G> {
+        let msg = self.create_error_message();
+        let mut err = Diag::new(dcx, level, msg);
+        err.code(E0107);
+        err.span(self.path_segment.ident.span);
 
         self.notify(&mut err);
         self.suggest(&mut err);
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index b0ae73fcc4b..a1feef9e15b 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -18,6 +18,8 @@ use crate::bounds::Bounds;
 use crate::errors;
 use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter};
 
+use super::RegionInferReason;
+
 impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     /// Add a `Sized` bound to the `bounds` if appropriate.
     ///
@@ -74,7 +76,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
 
         if unbounds.len() > 1 {
-            tcx.dcx().emit_err(errors::MultipleRelaxedDefaultBounds {
+            self.dcx().emit_err(errors::MultipleRelaxedDefaultBounds {
                 spans: unbounds.iter().map(|ptr| ptr.span).collect(),
             });
         }
@@ -88,7 +90,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 continue;
             }
             // There was a `?Trait` bound, but it was not `?Sized`; warn.
-            tcx.dcx().span_warn(
+            self.dcx().span_warn(
                 unbound.span,
                 "relaxing a default bound only does something for `?Sized`; \
                 all other traits are not bound by default",
@@ -166,7 +168,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     );
                 }
                 hir::GenericBound::Outlives(lifetime) => {
-                    let region = self.lower_lifetime(lifetime, None);
+                    let region = self.lower_lifetime(lifetime, RegionInferReason::OutlivesBound);
                     bounds.push_region_bound(
                         self.tcx(),
                         ty::Binder::bind_with_vars(
@@ -176,6 +178,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         lifetime.ident.span,
                     );
                 }
+                hir::GenericBound::Use(..) => {
+                    // We don't actually lower `use` into the type layer.
+                }
             }
         }
     }
@@ -230,32 +235,34 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         bounds
     }
 
-    /// Lower an associated item binding from HIR into `bounds`.
+    /// Lower an associated item constraint from the HIR into `bounds`.
     ///
     /// ### A Note on Binders
     ///
     /// Given something like `T: for<'a> Iterator<Item = &'a u32>`,
     /// the `trait_ref` here will be `for<'a> T: Iterator`.
-    /// The `binding` data however is from *inside* the binder
+    /// The `constraint` data however is from *inside* the binder
     /// (e.g., `&'a u32`) and hence may reference bound regions.
-    #[instrument(level = "debug", skip(self, bounds, dup_bindings, path_span))]
-    pub(super) fn lower_assoc_item_binding(
+    #[instrument(level = "debug", skip(self, bounds, duplicates, path_span))]
+    pub(super) fn lower_assoc_item_constraint(
         &self,
         hir_ref_id: hir::HirId,
         trait_ref: ty::PolyTraitRef<'tcx>,
-        binding: &hir::TypeBinding<'tcx>,
+        constraint: &hir::AssocItemConstraint<'tcx>,
         bounds: &mut Bounds<'tcx>,
-        dup_bindings: &mut FxIndexMap<DefId, Span>,
+        duplicates: &mut FxIndexMap<DefId, Span>,
         path_span: Span,
         only_self_bounds: OnlySelfBounds,
     ) -> Result<(), ErrorGuaranteed> {
         let tcx = self.tcx();
 
-        let assoc_kind = if binding.gen_args.parenthesized
+        let assoc_kind = if constraint.gen_args.parenthesized
             == hir::GenericArgsParentheses::ReturnTypeNotation
         {
             ty::AssocKind::Fn
-        } else if let hir::TypeBindingKind::Equality { term: hir::Term::Const(_) } = binding.kind {
+        } else if let hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(_) } =
+            constraint.kind
+        {
             ty::AssocKind::Const
         } else {
             ty::AssocKind::Type
@@ -272,7 +279,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let candidate = if self.probe_trait_that_defines_assoc_item(
             trait_ref.def_id(),
             assoc_kind,
-            binding.ident,
+            constraint.ident,
         ) {
             // Simple case: The assoc item is defined in the current trait.
             trait_ref
@@ -284,48 +291,33 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 trait_ref.skip_binder().print_only_trait_name(),
                 None,
                 assoc_kind,
-                binding.ident,
+                constraint.ident,
                 path_span,
-                Some(binding),
+                Some(constraint),
             )?
         };
 
-        let (assoc_ident, def_scope) =
-            tcx.adjust_ident_and_get_scope(binding.ident, candidate.def_id(), hir_ref_id);
-
-        // We have already adjusted the item name above, so compare with `.normalize_to_macros_2_0()`
-        // instead of calling `filter_by_name_and_kind` which would needlessly normalize the
-        // `assoc_ident` again and again.
-        let assoc_item = tcx
-            .associated_items(candidate.def_id())
-            .filter_by_name_unhygienic(assoc_ident.name)
-            .find(|i| i.kind == assoc_kind && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident)
-            .expect("missing associated item");
-
-        if !assoc_item.visibility(tcx).is_accessible_from(def_scope, tcx) {
-            let reported = tcx
-                .dcx()
-                .struct_span_err(
-                    binding.span,
-                    format!("{} `{}` is private", assoc_item.kind, binding.ident),
-                )
-                .with_span_label(binding.span, format!("private {}", assoc_item.kind))
-                .emit();
-            self.set_tainted_by_errors(reported);
-        }
-        tcx.check_stability(assoc_item.def_id, Some(hir_ref_id), binding.span, None);
+        let assoc_item = self
+            .probe_assoc_item(
+                constraint.ident,
+                assoc_kind,
+                hir_ref_id,
+                constraint.span,
+                candidate.def_id(),
+            )
+            .expect("failed to find associated item");
 
-        dup_bindings
+        duplicates
             .entry(assoc_item.def_id)
             .and_modify(|prev_span| {
-                tcx.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified {
-                    span: binding.span,
+                self.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified {
+                    span: constraint.span,
                     prev_span: *prev_span,
-                    item_name: binding.ident,
+                    item_name: constraint.ident,
                     def_path: tcx.def_path_str(assoc_item.container_id(tcx)),
                 });
             })
-            .or_insert(binding.span);
+            .or_insert(constraint.span);
 
         let projection_term = if let ty::AssocKind::Fn = assoc_kind {
             let mut emitted_bad_param_err = None;
@@ -346,7 +338,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         .into(),
                         ty::GenericParamDefKind::Type { .. } => {
                             let guar = *emitted_bad_param_err.get_or_insert_with(|| {
-                                tcx.dcx().emit_err(
+                                self.dcx().emit_err(
                                     crate::errors::ReturnTypeNotationIllegalParam::Type {
                                         span: path_span,
                                         param_span: tcx.def_span(param.def_id),
@@ -357,18 +349,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         }
                         ty::GenericParamDefKind::Const { .. } => {
                             let guar = *emitted_bad_param_err.get_or_insert_with(|| {
-                                tcx.dcx().emit_err(
+                                self.dcx().emit_err(
                                     crate::errors::ReturnTypeNotationIllegalParam::Const {
                                         span: path_span,
                                         param_span: tcx.def_span(param.def_id),
                                     },
                                 )
                             });
-                            let ty = tcx
-                                .type_of(param.def_id)
-                                .no_bound_vars()
-                                .expect("ct params cannot have early bound vars");
-                            ty::Const::new_error(tcx, guar, ty).into()
+                            ty::Const::new_error(tcx, guar).into()
                         }
                     };
                     num_bound_vars += 1;
@@ -383,8 +371,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             {
                 alias_ty.into()
             } else {
-                return Err(tcx.dcx().emit_err(crate::errors::ReturnTypeNotationOnNonRpitit {
-                    span: binding.span,
+                return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationOnNonRpitit {
+                    span: constraint.span,
                     ty: tcx.liberate_late_bound_regions(assoc_item.def_id, output),
                     fn_span: tcx.hir().span_if_local(assoc_item.def_id),
                     note: (),
@@ -398,19 +386,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output);
             let instantiation_output = ty::EarlyBinder::bind(shifted_output).instantiate(tcx, args);
 
-            let bound_vars = tcx.late_bound_vars(binding.hir_id);
+            let bound_vars = tcx.late_bound_vars(constraint.hir_id);
             ty::Binder::bind_with_vars(instantiation_output, bound_vars)
         } else {
             // Create the generic arguments for the associated type or constant by joining the
             // parent arguments (the arguments of the trait) and the own arguments (the ones of
             // the associated item itself) and construct an alias type using them.
-            let alias_ty = candidate.map_bound(|trait_ref| {
-                let ident = Ident::new(assoc_item.name, binding.ident.span);
+            let alias_term = candidate.map_bound(|trait_ref| {
                 let item_segment = hir::PathSegment {
-                    ident,
-                    hir_id: binding.hir_id,
+                    ident: constraint.ident,
+                    hir_id: constraint.hir_id,
                     res: Res::Err,
-                    args: Some(binding.gen_args),
+                    args: Some(constraint.gen_args),
                     infer_args: false,
                 };
 
@@ -422,30 +409,30 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 );
                 debug!(?alias_args);
 
-                ty::AliasTerm::new(tcx, assoc_item.def_id, alias_args)
+                ty::AliasTerm::new_from_args(tcx, assoc_item.def_id, alias_args)
             });
 
             // Provide the resolved type of the associated constant to `type_of(AnonConst)`.
-            if let hir::TypeBindingKind::Equality { term: hir::Term::Const(anon_const) } =
-                binding.kind
-            {
-                let ty = alias_ty.map_bound(|ty| tcx.type_of(ty.def_id).instantiate(tcx, ty.args));
-                let ty = check_assoc_const_binding_type(tcx, assoc_ident, ty, binding.hir_id);
+            if let Some(anon_const) = constraint.ct() {
+                let ty = alias_term
+                    .map_bound(|alias| tcx.type_of(alias.def_id).instantiate(tcx, alias.args));
+                let ty =
+                    check_assoc_const_binding_type(self, constraint.ident, ty, constraint.hir_id);
                 tcx.feed_anon_const_type(anon_const.def_id, ty::EarlyBinder::bind(ty));
             }
 
-            alias_ty
+            alias_term
         };
 
-        match binding.kind {
-            hir::TypeBindingKind::Equality { .. } if let ty::AssocKind::Fn = assoc_kind => {
-                return Err(tcx.dcx().emit_err(crate::errors::ReturnTypeNotationEqualityBound {
-                    span: binding.span,
+        match constraint.kind {
+            hir::AssocItemConstraintKind::Equality { .. } if let ty::AssocKind::Fn = assoc_kind => {
+                return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationEqualityBound {
+                    span: constraint.span,
                 }));
             }
             // Lower an equality constraint like `Item = u32` as found in HIR bound `T: Iterator<Item = u32>`
             // to a projection predicate: `<T as Iterator>::Item = u32`.
-            hir::TypeBindingKind::Equality { term } => {
+            hir::AssocItemConstraintKind::Equality { term } => {
                 let term = match term {
                     hir::Term::Ty(ty) => self.lower_ty(ty).into(),
                     hir::Term::Const(ct) => ty::Const::from_anon_const(tcx, ct.def_id).into(),
@@ -469,18 +456,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 // struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
                 //                         ----  ----     ^^^^^^^
                 // NOTE(associated_const_equality): This error should be impossible to trigger
-                //                                  with associated const equality bounds.
+                //                                  with associated const equality constraints.
                 self.validate_late_bound_regions(
                     late_bound_in_projection_ty,
                     late_bound_in_term,
                     |br_name| {
                         struct_span_code_err!(
-                            tcx.dcx(),
-                            binding.span,
+                            self.dcx(),
+                            constraint.span,
                             E0582,
                             "binding for associated type `{}` references {}, \
-                                which does not appear in the trait input types",
-                            binding.ident,
+                             which does not appear in the trait input types",
+                            constraint.ident,
                             br_name
                         )
                     },
@@ -492,12 +479,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         projection_term,
                         term,
                     }),
-                    binding.span,
+                    constraint.span,
                 );
             }
             // Lower a constraint like `Item: Debug` as found in HIR bound `T: Iterator<Item: Debug>`
             // to a bound involving a projection: `<T as Iterator>::Item: Debug`.
-            hir::TypeBindingKind::Constraint { bounds: hir_bounds } => {
+            hir::AssocItemConstraintKind::Bound { bounds: hir_bounds } => {
                 // NOTE: If `only_self_bounds` is true, do NOT expand this associated type bound into
                 // a trait predicate, since we only want to add predicates for the `Self` type.
                 if !only_self_bounds.0 {
@@ -532,7 +519,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 ///
 /// [^1]: <https://github.com/rust-lang/project-const-generics/issues/28>.
 fn check_assoc_const_binding_type<'tcx>(
-    tcx: TyCtxt<'tcx>,
+    cx: &dyn HirTyLowerer<'tcx>,
     assoc_const: Ident,
     ty: ty::Binder<'tcx, Ty<'tcx>>,
     hir_id: hir::HirId,
@@ -549,13 +536,14 @@ fn check_assoc_const_binding_type<'tcx>(
     }
 
     let mut collector = GenericParamAndBoundVarCollector {
-        tcx,
+        cx,
         params: Default::default(),
         vars: Default::default(),
         depth: ty::INNERMOST,
     };
     let mut guar = ty.visit_with(&mut collector).break_value();
 
+    let tcx = cx.tcx();
     let ty_note = ty
         .make_suggestable(tcx, false, None)
         .map(|ty| crate::errors::TyOfAssocConstBindingNote { assoc_const, ty });
@@ -569,7 +557,7 @@ fn check_assoc_const_binding_type<'tcx>(
     for index in collector.params {
         let param = generics.param_at(index as _, tcx);
         let is_self_param = param.name == rustc_span::symbol::kw::SelfUpper;
-        guar.get_or_insert(tcx.dcx().emit_err(crate::errors::ParamInTyOfAssocConstBinding {
+        guar.get_or_insert(cx.dcx().emit_err(crate::errors::ParamInTyOfAssocConstBinding {
             span: assoc_const.span,
             assoc_const,
             param_name: param.name,
@@ -587,7 +575,7 @@ fn check_assoc_const_binding_type<'tcx>(
         }));
     }
     for (var_def_id, var_name) in collector.vars {
-        guar.get_or_insert(tcx.dcx().emit_err(
+        guar.get_or_insert(cx.dcx().emit_err(
             crate::errors::EscapingBoundVarInTyOfAssocConstBinding {
                 span: assoc_const.span,
                 assoc_const,
@@ -603,14 +591,14 @@ fn check_assoc_const_binding_type<'tcx>(
     Ty::new_error(tcx, guar)
 }
 
-struct GenericParamAndBoundVarCollector<'tcx> {
-    tcx: TyCtxt<'tcx>,
+struct GenericParamAndBoundVarCollector<'a, 'tcx> {
+    cx: &'a dyn HirTyLowerer<'tcx>,
     params: FxIndexSet<u32>,
     vars: FxIndexSet<(DefId, Symbol)>,
     depth: ty::DebruijnIndex,
 }
 
-impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'tcx> {
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'_, 'tcx> {
     type Result = ControlFlow<ErrorGuaranteed>;
 
     fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
@@ -633,7 +621,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'tcx>
                     ty::BoundTyKind::Param(def_id, name) => (def_id, name),
                     ty::BoundTyKind::Anon => {
                         let reported = self
-                            .tcx
+                            .cx
                             .dcx()
                             .delayed_bug(format!("unexpected anon bound ty: {:?}", bt.var));
                         return ControlFlow::Break(reported);
@@ -656,7 +644,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'tcx>
                     ty::BrNamed(def_id, name) => (def_id, name),
                     ty::BrAnon | ty::BrEnv => {
                         let guar = self
-                            .tcx
+                            .cx
                             .dcx()
                             .delayed_bug(format!("unexpected bound region kind: {:?}", br.kind));
                         return ControlFlow::Break(guar);
@@ -674,7 +662,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'tcx>
                 self.params.insert(param.index);
             }
             ty::ConstKind::Bound(db, ty::BoundVar { .. }) if db >= self.depth => {
-                let guar = self.tcx.dcx().delayed_bug("unexpected escaping late-bound const var");
+                let guar = self.cx.dcx().delayed_bug("unexpected escaping late-bound const var");
                 return ControlFlow::Break(guar);
             }
             _ if ct.has_param() || ct.has_bound_vars() => return ct.super_visit_with(self),
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index 9c687d3282b..968f38cf05d 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -1,10 +1,9 @@
 use crate::errors::{
-    self, AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
+    self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams,
     ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits,
 };
 use crate::fluent_generated as fluent;
 use crate::hir_ty_lowering::HirTyLowerer;
-use crate::traits::error_reporting::report_object_safety_error;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::unord::UnordMap;
@@ -12,10 +11,9 @@ use rustc_errors::MultiSpan;
 use rustc_errors::{
     codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed,
 };
-use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_infer::traits::FulfillmentError;
+use rustc_hir::{self as hir, Node};
 use rustc_middle::bug;
 use rustc_middle::query::Key;
 use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
@@ -28,6 +26,8 @@ use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::BytePos;
 use rustc_span::{Span, Symbol, DUMMY_SP};
+use rustc_trait_selection::error_reporting::traits::report_object_safety_error;
+use rustc_trait_selection::traits::FulfillmentError;
 use rustc_trait_selection::traits::{
     object_safety_violations_for_assoc_item, TraitAliasExpansionInfo,
 };
@@ -46,7 +46,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             return;
         }
 
-        self.tcx().dcx().emit_err(MissingTypeParams {
+        self.dcx().emit_err(MissingTypeParams {
             span,
             def_span: self.tcx().def_span(def_id),
             span_snippet: self.tcx().sess.source_map().span_to_snippet(span).ok(),
@@ -109,7 +109,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         if is_impl {
             let trait_name = self.tcx().def_path_str(trait_def_id);
-            self.tcx().dcx().emit_err(ManualImplementation { span, trait_name });
+            self.dcx().emit_err(ManualImplementation { span, trait_name });
         }
     }
 
@@ -121,7 +121,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         assoc_kind: ty::AssocKind,
         assoc_name: Ident,
         span: Span,
-        binding: Option<&hir::TypeBinding<'tcx>>,
+        constraint: Option<&hir::AssocItemConstraint<'tcx>>,
     ) -> ErrorGuaranteed
     where
         I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
@@ -135,7 +135,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 .find(|item| tcx.hygienic_eq(assoc_name, item.ident(tcx), r.def_id()))
         }) {
             return self.complain_about_assoc_kind_mismatch(
-                assoc_item, assoc_kind, assoc_name, span, binding,
+                assoc_item, assoc_kind, assoc_name, span, constraint,
             );
         }
 
@@ -156,7 +156,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         if is_dummy {
             err.label = Some(errors::AssocItemNotFoundLabel::NotFound { span });
-            return tcx.dcx().emit_err(err);
+            return self.dcx().emit_err(err);
         }
 
         let all_candidate_names: Vec<_> = all_candidates()
@@ -174,7 +174,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 assoc_kind: assoc_kind_str,
                 suggested_name,
             });
-            return tcx.dcx().emit_err(err);
+            return self.dcx().emit_err(err);
         }
 
         // If we didn't find a good item in the supertraits (or couldn't get
@@ -239,10 +239,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                             assoc_kind: assoc_kind_str,
                             suggested_name,
                         });
-                        return tcx.dcx().emit_err(err);
+                        return self.dcx().emit_err(err);
                     }
 
-                    let mut err = tcx.dcx().create_err(err);
+                    let mut err = self.dcx().create_err(err);
                     if suggest_constraining_type_param(
                         tcx,
                         generics,
@@ -264,7 +264,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     }
                     return err.emit();
                 }
-                return tcx.dcx().emit_err(err);
+                return self.dcx().emit_err(err);
             }
         }
 
@@ -291,7 +291,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             err.label = Some(errors::AssocItemNotFoundLabel::NotFound { span: assoc_name.span });
         }
 
-        tcx.dcx().emit_err(err)
+        self.dcx().emit_err(err)
     }
 
     fn complain_about_assoc_kind_mismatch(
@@ -300,18 +300,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         assoc_kind: ty::AssocKind,
         ident: Ident,
         span: Span,
-        binding: Option<&hir::TypeBinding<'tcx>>,
+        constraint: Option<&hir::AssocItemConstraint<'tcx>>,
     ) -> ErrorGuaranteed {
         let tcx = self.tcx();
 
         let bound_on_assoc_const_label = if let ty::AssocKind::Const = assoc_item.kind
-            && let Some(binding) = binding
-            && let hir::TypeBindingKind::Constraint { .. } = binding.kind
+            && let Some(constraint) = constraint
+            && let hir::AssocItemConstraintKind::Bound { .. } = constraint.kind
         {
-            let lo = if binding.gen_args.span_ext.is_dummy() {
+            let lo = if constraint.gen_args.span_ext.is_dummy() {
                 ident.span
             } else {
-                binding.gen_args.span_ext
+                constraint.gen_args.span_ext
             };
             Some(lo.between(span.shrink_to_hi()))
         } else {
@@ -319,8 +319,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         };
 
         // FIXME(associated_const_equality): This has quite a few false positives and negatives.
-        let wrap_in_braces_sugg = if let Some(binding) = binding
-            && let hir::TypeBindingKind::Equality { term: hir::Term::Ty(hir_ty) } = binding.kind
+        let wrap_in_braces_sugg = if let Some(constraint) = constraint
+            && let Some(hir_ty) = constraint.ty()
             && let ty = self.lower_ty(hir_ty)
             && (ty.is_enum() || ty.references_error())
             && tcx.features().associated_const_equality
@@ -333,10 +333,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             None
         };
 
-        // For equality bounds, we want to blame the term (RHS) instead of the item (LHS) since
+        // For equality constraints, we want to blame the term (RHS) instead of the item (LHS) since
         // one can argue that that's more “intuitive” to the user.
-        let (span, expected_because_label, expected, got) = if let Some(binding) = binding
-            && let hir::TypeBindingKind::Equality { term } = binding.kind
+        let (span, expected_because_label, expected, got) = if let Some(constraint) = constraint
+            && let hir::AssocItemConstraintKind::Equality { term } = constraint.kind
         {
             let span = match term {
                 hir::Term::Ty(ty) => ty.span,
@@ -347,7 +347,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             (ident.span, None, assoc_kind, assoc_item.kind)
         };
 
-        tcx.dcx().emit_err(errors::AssocKindMismatch {
+        self.dcx().emit_err(errors::AssocKindMismatch {
             span,
             expected: super::assoc_kind_str(expected),
             got: super::assoc_kind_str(got),
@@ -366,8 +366,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         traits: &[String],
         name: Symbol,
     ) -> ErrorGuaranteed {
-        let mut err =
-            struct_span_code_err!(self.tcx().dcx(), span, E0223, "ambiguous associated type");
+        let mut err = struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type");
         if self
             .tcx()
             .resolutions(())
@@ -463,9 +462,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 }
             }
         }
-        let reported = err.emit();
-        self.set_tainted_by_errors(reported);
-        reported
+        err.emit()
     }
 
     pub(crate) fn complain_about_ambiguous_inherent_assoc_ty(
@@ -475,16 +472,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         span: Span,
     ) -> ErrorGuaranteed {
         let mut err = struct_span_code_err!(
-            self.tcx().dcx(),
+            self.dcx(),
             name.span,
             E0034,
             "multiple applicable items in scope"
         );
         err.span_label(name.span, format!("multiple `{name}` found"));
         self.note_ambiguous_inherent_assoc_ty(&mut err, candidates, span);
-        let reported = err.emit();
-        self.set_tainted_by_errors(reported);
-        reported
+        err.emit()
     }
 
     // FIXME(fmease): Heavily adapted from `rustc_hir_typeck::method::suggest`. Deduplicate.
@@ -576,7 +571,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             };
 
             let mut err = struct_span_code_err!(
-                tcx.dcx(),
+                self.dcx(),
                 name.span,
                 E0220,
                 "associated type `{name}` not found for `{self_ty}` in the current scope"
@@ -662,7 +657,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         bounds.sort();
         bounds.dedup();
 
-        let mut err = tcx.dcx().struct_span_err(
+        let mut err = self.dcx().struct_span_err(
             name.span,
             format!("the associated type `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied")
         );
@@ -702,7 +697,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     pub(crate) fn complain_about_missing_assoc_tys(
         &self,
         associated_types: FxIndexMap<Span, FxIndexSet<DefId>>,
-        potential_assoc_types: Vec<Span>,
+        potential_assoc_types: Vec<usize>,
         trait_bounds: &[hir::PolyTraitRef<'_>],
     ) {
         if associated_types.values().all(|v| v.is_empty()) {
@@ -745,7 +740,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         if object_safety_violations {
             return;
         }
+
+        // related to issue #91997, turbofishes added only when in an expr or pat
+        let mut in_expr_or_pat = false;
         if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) {
+            let grandparent = tcx.parent_hir_node(tcx.parent_hir_id(bound.trait_ref.hir_ref_id));
+            in_expr_or_pat = match grandparent {
+                Node::Expr(_) | Node::Pat(_) => true,
+                _ => false,
+            };
             match bound.trait_ref.path.segments {
                 // FIXME: `trait_ref.path.span` can point to a full path with multiple
                 // segments, even though `trait_ref.path.segments` is of length `1`. Work
@@ -791,8 +794,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 let path = poly_trait_ref.trait_ref.path.segments.last()?;
                 let args = path.args?;
 
-                Some(args.bindings.iter().filter_map(|binding| {
-                    let ident = binding.ident;
+                Some(args.constraints.iter().filter_map(|constraint| {
+                    let ident = constraint.ident;
                     let trait_def = path.res.def_id();
                     let assoc_item = tcx.associated_items(trait_def).find_by_name_and_kind(
                         tcx,
@@ -829,7 +832,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         trait_bound_spans.sort();
         let mut err = struct_span_code_err!(
-            tcx.dcx(),
+            self.dcx(),
             trait_bound_spans,
             E0191,
             "the value of the associated type{} {} must be specified",
@@ -901,6 +904,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
                     // suggestion.
                     format!("{}, {}>", &snippet[..snippet.len() - 1], types.join(", "))
+                } else if in_expr_or_pat {
+                    // The user wrote `Iterator`, so we don't have a type we can suggest, but at
+                    // least we can clue them to the correct syntax `Iterator::<Item = Type>`.
+                    format!("{}::<{}>", snippet, types.join(", "))
                 } else {
                     // The user wrote `Iterator`, so we don't have a type we can suggest, but at
                     // least we can clue them to the correct syntax `Iterator<Item = Type>`.
@@ -974,7 +981,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
         }
 
-        self.set_tainted_by_errors(err.emit());
+        err.emit();
     }
 
     /// On ambiguous associated type, look for an associated function whose name matches the
@@ -1011,17 +1018,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 .filter_by_name_unhygienic(Symbol::intern(&name))
                 .next()
         {
-            let reported =
-                struct_span_code_err!(tcx.dcx(), span, E0223, "ambiguous associated type")
-                    .with_span_suggestion_verbose(
-                        ident2.span.to(ident3.span),
-                        format!("there is an associated function with a similar name: `{name}`"),
-                        name,
-                        Applicability::MaybeIncorrect,
-                    )
-                    .emit();
-            self.set_tainted_by_errors(reported);
-            Err(reported)
+            Err(struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type")
+                .with_span_suggestion_verbose(
+                    ident2.span.to(ident3.span),
+                    format!("there is an associated function with a similar name: `{name}`"),
+                    name,
+                    Applicability::MaybeIncorrect,
+                )
+                .emit())
         } else {
             Ok(())
         }
@@ -1120,7 +1124,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let last_span = *arg_spans.last().unwrap();
         let span: MultiSpan = arg_spans.into();
         let mut err = struct_span_code_err!(
-            self.tcx().dcx(),
+            self.dcx(),
             span,
             E0109,
             "{kind} arguments are not allowed on {this_type}",
@@ -1130,20 +1134,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             err.span_label(span, format!("not allowed on {what}"));
         }
         generics_args_err_extend(self.tcx(), segments, &mut err, err_extend);
-        let reported = err.emit();
-        self.set_tainted_by_errors(reported);
-        reported
+        err.emit()
     }
 
     pub fn report_trait_object_addition_traits_error(
         &self,
         regular_traits: &Vec<TraitAliasExpansionInfo<'_>>,
     ) -> ErrorGuaranteed {
-        let tcx = self.tcx();
         let first_trait = &regular_traits[0];
         let additional_trait = &regular_traits[1];
         let mut err = struct_span_code_err!(
-            tcx.dcx(),
+            self.dcx(),
             additional_trait.bottom().1,
             E0225,
             "only auto traits can be used as additional traits in a trait object"
@@ -1169,9 +1170,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
              for more information on them, visit \
              <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>",
         );
-        let reported = err.emit();
-        self.set_tainted_by_errors(reported);
-        reported
+        err.emit()
     }
 
     pub fn report_trait_object_with_no_traits_error(
@@ -1185,21 +1184,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             .map(|&(trait_ref, _)| trait_ref.def_id())
             .find(|&trait_ref| tcx.is_trait_alias(trait_ref))
             .map(|trait_ref| tcx.def_span(trait_ref));
-        let reported =
-            tcx.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
-        self.set_tainted_by_errors(reported);
-        reported
+
+        self.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span })
     }
 }
 
-/// Emits an error regarding forbidden type binding associations
-pub fn prohibit_assoc_item_binding(
-    tcx: TyCtxt<'_>,
-    binding: &hir::TypeBinding<'_>,
+/// Emit an error for the given associated item constraint.
+pub fn prohibit_assoc_item_constraint(
+    cx: &dyn HirTyLowerer<'_>,
+    constraint: &hir::AssocItemConstraint<'_>,
     segment: Option<(DefId, &hir::PathSegment<'_>, Span)>,
 ) -> ErrorGuaranteed {
-    let mut err = tcx.dcx().create_err(AssocTypeBindingNotAllowed {
-        span: binding.span,
+    let tcx = cx.tcx();
+    let mut err = cx.dcx().create_err(AssocItemConstraintsNotAllowedHere {
+        span: constraint.span,
         fn_trait_expansion: if let Some((_, segment, span)) = segment
             && segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar
         {
@@ -1217,13 +1215,11 @@ pub fn prohibit_assoc_item_binding(
     // otherwise suggest the removal of the binding.
     if let Some((def_id, segment, _)) = segment
         && segment.args().parenthesized == hir::GenericArgsParentheses::No
-        && let hir::TypeBindingKind::Equality { term } = binding.kind
     {
         // Suggests removal of the offending binding
         let suggest_removal = |e: &mut Diag<'_>| {
-            let bindings = segment.args().bindings;
+            let constraints = segment.args().constraints;
             let args = segment.args().args;
-            let binding_span = binding.span;
 
             // Compute the span to remove based on the position
             // of the binding. We do that as follows:
@@ -1236,26 +1232,21 @@ pub fn prohibit_assoc_item_binding(
             //     the start of the next span or will simply be the
             //     span encomassing everything within the generics brackets
 
-            let Some(binding_index) = bindings.iter().position(|b| b.hir_id == binding.hir_id)
-            else {
+            let Some(index) = constraints.iter().position(|b| b.hir_id == constraint.hir_id) else {
                 bug!("a type binding exists but its HIR ID not found in generics");
             };
 
-            let preceding_span = if binding_index > 0 {
-                Some(bindings[binding_index - 1].span)
+            let preceding_span = if index > 0 {
+                Some(constraints[index - 1].span)
             } else {
                 args.last().map(|a| a.span())
             };
 
-            let next_span = if binding_index < bindings.len() - 1 {
-                Some(bindings[binding_index + 1].span)
-            } else {
-                None
-            };
+            let next_span = constraints.get(index + 1).map(|constraint| constraint.span);
 
             let removal_span = match (preceding_span, next_span) {
-                (Some(prec), _) => binding_span.with_lo(prec.hi()),
-                (None, Some(next)) => binding_span.with_hi(next.lo()),
+                (Some(prec), _) => constraint.span.with_lo(prec.hi()),
+                (None, Some(next)) => constraint.span.with_hi(next.lo()),
                 (None, None) => {
                     let Some(generics_span) = segment.args().span_ext() else {
                         bug!("a type binding exists but generic span is empty");
@@ -1266,14 +1257,12 @@ pub fn prohibit_assoc_item_binding(
             };
 
             // Now emit the suggestion
-            if let Ok(suggestion) = tcx.sess.source_map().span_to_snippet(removal_span) {
-                e.span_suggestion_verbose(
-                    removal_span,
-                    "consider removing this type binding",
-                    suggestion,
-                    Applicability::MaybeIncorrect,
-                );
-            }
+            e.span_suggestion_verbose(
+                removal_span,
+                format!("consider removing this associated item {}", constraint.kind.descr()),
+                "",
+                Applicability::MaybeIncorrect,
+            );
         };
 
         // Suggest replacing the associated item binding with a generic argument.
@@ -1281,7 +1270,7 @@ pub fn prohibit_assoc_item_binding(
         let suggest_direct_use = |e: &mut Diag<'_>, sp: Span| {
             if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(sp) {
                 e.span_suggestion_verbose(
-                    binding.span,
+                    constraint.span,
                     format!("to use `{snippet}` as a generic argument specify it directly"),
                     snippet,
                     Applicability::MaybeIncorrect,
@@ -1289,22 +1278,78 @@ pub fn prohibit_assoc_item_binding(
             }
         };
 
-        // Check if the type has a generic param with the
-        // same name as the assoc type name in type binding
+        // Check if the type has a generic param with the same name
+        // as the assoc type name in the associated item binding.
         let generics = tcx.generics_of(def_id);
-        let matching_param =
-            generics.own_params.iter().find(|p| p.name.as_str() == binding.ident.as_str());
+        let matching_param = generics.own_params.iter().find(|p| p.name == constraint.ident.name);
 
         // Now emit the appropriate suggestion
         if let Some(matching_param) = matching_param {
-            match (&matching_param.kind, term) {
-                (GenericParamDefKind::Type { .. }, hir::Term::Ty(ty)) => {
-                    suggest_direct_use(&mut err, ty.span);
-                }
-                (GenericParamDefKind::Const { .. }, hir::Term::Const(c)) => {
+            match (constraint.kind, &matching_param.kind) {
+                (
+                    hir::AssocItemConstraintKind::Equality { term: hir::Term::Ty(ty) },
+                    GenericParamDefKind::Type { .. },
+                ) => suggest_direct_use(&mut err, ty.span),
+                (
+                    hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(c) },
+                    GenericParamDefKind::Const { .. },
+                ) => {
                     let span = tcx.hir().span(c.hir_id);
                     suggest_direct_use(&mut err, span);
                 }
+                (hir::AssocItemConstraintKind::Bound { bounds }, _) => {
+                    // Suggest `impl<T: Bound> Trait<T> for Foo` when finding
+                    // `impl Trait<T: Bound> for Foo`
+
+                    // Get the parent impl block based on the binding we have
+                    // and the trait DefId
+                    let impl_block = tcx
+                        .hir()
+                        .parent_iter(constraint.hir_id)
+                        .find_map(|(_, node)| node.impl_block_of_trait(def_id));
+
+                    let type_with_constraints =
+                        tcx.sess.source_map().span_to_snippet(constraint.span);
+
+                    if let Some(impl_block) = impl_block
+                        && let Ok(type_with_constraints) = type_with_constraints
+                    {
+                        // Filter out the lifetime parameters because
+                        // they should be declared before the type parameter
+                        let lifetimes: String = bounds
+                            .iter()
+                            .filter_map(|bound| {
+                                if let hir::GenericBound::Outlives(lifetime) = bound {
+                                    Some(format!("{lifetime}, "))
+                                } else {
+                                    None
+                                }
+                            })
+                            .collect();
+                        // Figure out a span and suggestion string based on
+                        // whether there are any existing parameters
+                        let param_decl = if let Some(param_span) =
+                            impl_block.generics.span_for_param_suggestion()
+                        {
+                            (param_span, format!(", {lifetimes}{type_with_constraints}"))
+                        } else {
+                            (
+                                impl_block.generics.span.shrink_to_lo(),
+                                format!("<{lifetimes}{type_with_constraints}>"),
+                            )
+                        };
+                        let suggestions = vec![
+                            param_decl,
+                            (constraint.span.with_lo(constraint.ident.span.hi()), String::new()),
+                        ];
+
+                        err.multipart_suggestion_verbose(
+                            "declare the type parameter right after the `impl` keyword",
+                            suggestions,
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                }
                 _ => suggest_removal(&mut err),
             }
         } else {
@@ -1322,8 +1367,7 @@ pub(crate) fn fn_trait_to_string(
 ) -> String {
     let args = trait_segment
         .args
-        .as_ref()
-        .and_then(|args| args.args.get(0))
+        .and_then(|args| args.args.first())
         .and_then(|arg| match arg {
             hir::GenericArg::Type(ty) => match ty.kind {
                 hir::TyKind::Tup(t) => t
@@ -1334,7 +1378,7 @@ pub(crate) fn fn_trait_to_string(
                 _ => tcx.sess.source_map().span_to_snippet(ty.span),
             }
             .map(|s| {
-                // `s.empty()` checks to see if the type is the unit tuple, if so we don't want a comma
+                // `is_empty()` checks to see if the type is the unit tuple, if so we don't want a comma
                 if parenthesized || s.is_empty() { format!("({s})") } else { format!("({s},)") }
             })
             .ok(),
@@ -1344,20 +1388,17 @@ pub(crate) fn fn_trait_to_string(
 
     let ret = trait_segment
         .args()
-        .bindings
+        .constraints
         .iter()
-        .find_map(|b| match (b.ident.name == sym::Output, &b.kind) {
-            (true, hir::TypeBindingKind::Equality { term }) => {
-                let span = match term {
-                    hir::Term::Ty(ty) => ty.span,
-                    hir::Term::Const(c) => tcx.hir().span(c.hir_id),
-                };
-
-                (span != tcx.hir().span(trait_segment.hir_id))
-                    .then_some(tcx.sess.source_map().span_to_snippet(span).ok())
-                    .flatten()
+        .find_map(|c| {
+            if c.ident.name == sym::Output
+                && let Some(ty) = c.ty()
+                && ty.span != tcx.hir().span(trait_segment.hir_id)
+            {
+                tcx.sess.source_map().span_to_snippet(ty.span).ok()
+            } else {
+                None
             }
-            _ => None,
         })
         .unwrap_or_else(|| "()".to_string());
 
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
index 749f78e7920..b1c77db9f37 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
@@ -1,9 +1,9 @@
-use super::IsMethodCall;
+use super::{HirTyLowerer, IsMethodCall};
+use crate::errors::wrong_number_of_generic_args::{GenericArgsInfo, WrongNumberOfGenericArgs};
 use crate::hir_ty_lowering::{
-    errors::prohibit_assoc_item_binding, ExplicitLateBound, GenericArgCountMismatch,
+    errors::prohibit_assoc_item_constraint, ExplicitLateBound, GenericArgCountMismatch,
     GenericArgCountResult, GenericArgPosition, GenericArgsLowerer,
 };
-use crate::structured_errors::{GenericArgsInfo, StructuredDiag, WrongNumberOfGenericArgs};
 use rustc_ast::ast::ParamKindOrd;
 use rustc_errors::{
     codes::*, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, MultiSpan,
@@ -13,7 +13,7 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::GenericArg;
 use rustc_middle::ty::{
-    self, GenericArgsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty, TyCtxt,
+    self, GenericArgsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty,
 };
 use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS;
 use rustc_span::symbol::{kw, sym};
@@ -22,15 +22,16 @@ use smallvec::SmallVec;
 /// Report an error that a generic argument did not match the generic parameter that was
 /// expected.
 fn generic_arg_mismatch_err(
-    tcx: TyCtxt<'_>,
+    cx: &dyn HirTyLowerer<'_>,
     arg: &GenericArg<'_>,
     param: &GenericParamDef,
     possible_ordering_error: bool,
     help: Option<String>,
 ) -> ErrorGuaranteed {
+    let tcx = cx.tcx();
     let sess = tcx.sess;
     let mut err = struct_span_code_err!(
-        tcx.dcx(),
+        cx.dcx(),
         arg.span(),
         E0747,
         "{} provided when a {} was expected",
@@ -171,7 +172,7 @@ fn generic_arg_mismatch_err(
 /// - `inferred_kind`: if no parameter was provided, and inference
 ///   is enabled, then creates a suitable inference variable.
 pub fn lower_generic_args<'tcx: 'a, 'a>(
-    tcx: TyCtxt<'tcx>,
+    cx: &dyn HirTyLowerer<'tcx>,
     def_id: DefId,
     parent_args: &[ty::GenericArg<'tcx>],
     has_self: bool,
@@ -179,6 +180,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
     arg_count: &GenericArgCountResult,
     ctx: &mut impl GenericArgsLowerer<'a, 'tcx>,
 ) -> GenericArgsRef<'tcx> {
+    let tcx = cx.tcx();
     // Collect the segments of the path; we need to instantiate arguments
     // for parameters throughout the entire path (wherever there are
     // generic parameters).
@@ -214,10 +216,11 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
             if let Some(&param) = params.peek() {
                 if param.index == 0 {
                     if let GenericParamDefKind::Type { .. } = param.kind {
+                        assert_eq!(&args[..], &[]);
                         args.push(
                             self_ty
                                 .map(|ty| ty.into())
-                                .unwrap_or_else(|| ctx.inferred_kind(None, param, true)),
+                                .unwrap_or_else(|| ctx.inferred_kind(&args, param, true)),
                         );
                         params.next();
                     }
@@ -255,6 +258,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
                             | GenericParamDefKind::Lifetime,
                             _,
                         ) => {
+                            // FIXME(effects): this should be removed
                             // SPECIAL CASE FOR DESUGARED EFFECT PARAMS
                             // This comes from the following example:
                             //
@@ -267,7 +271,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
                             // Since this is a const impl, we need to insert a host arg at the end of
                             // `PartialEq`'s generics, but this errors since `Rhs` isn't specified.
                             // To work around this, we infer all arguments until we reach the host param.
-                            args.push(ctx.inferred_kind(Some(&args), param, infer_args));
+                            args.push(ctx.inferred_kind(&args, param, infer_args));
                             params.next();
                         }
                         (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _)
@@ -281,7 +285,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
                             GenericParamDefKind::Const { .. },
                             _,
                         ) => {
-                            args.push(ctx.provided_kind(param, arg));
+                            args.push(ctx.provided_kind(&args, param, arg));
                             args_iter.next();
                             params.next();
                         }
@@ -292,7 +296,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
                         ) => {
                             // We expected a lifetime argument, but got a type or const
                             // argument. That means we're inferring the lifetimes.
-                            args.push(ctx.inferred_kind(None, param, infer_args));
+                            args.push(ctx.inferred_kind(&args, param, infer_args));
                             force_infer_lt = Some((arg, param));
                             params.next();
                         }
@@ -324,7 +328,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
                                 param_types_present.dedup();
 
                                 generic_arg_mismatch_err(
-                                    tcx,
+                                    cx,
                                     arg,
                                     param,
                                     !args_iter.clone().is_sorted_by_key(|arg| arg.to_ord()),
@@ -379,7 +383,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
                         assert_eq!(kind, "lifetime");
                         let (provided_arg, param) =
                             force_infer_lt.expect("lifetimes ought to have been inferred");
-                        generic_arg_mismatch_err(tcx, provided_arg, param, false, None);
+                        generic_arg_mismatch_err(cx, provided_arg, param, false, None);
                     }
 
                     break;
@@ -388,7 +392,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
                 (None, Some(&param)) => {
                     // If there are fewer arguments than parameters, it means
                     // we're inferring the remaining arguments.
-                    args.push(ctx.inferred_kind(Some(&args), param, infer_args));
+                    args.push(ctx.inferred_kind(&args, param, infer_args));
                     params.next();
                 }
 
@@ -403,7 +407,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
 /// Checks that the correct number of generic arguments have been provided.
 /// Used specifically for function calls.
 pub fn check_generic_arg_count_for_call(
-    tcx: TyCtxt<'_>,
+    cx: &dyn HirTyLowerer<'_>,
     def_id: DefId,
     generics: &ty::Generics,
     seg: &hir::PathSegment<'_>,
@@ -414,14 +418,14 @@ pub fn check_generic_arg_count_for_call(
         IsMethodCall::No => GenericArgPosition::Value,
     };
     let has_self = generics.parent.is_none() && generics.has_self;
-    check_generic_arg_count(tcx, def_id, seg, generics, gen_pos, has_self)
+    check_generic_arg_count(cx, def_id, seg, generics, gen_pos, has_self)
 }
 
 /// Checks that the correct number of generic arguments have been provided.
 /// This is used both for datatypes and function calls.
-#[instrument(skip(tcx, gen_pos), level = "debug")]
+#[instrument(skip(cx, gen_pos), level = "debug")]
 pub(crate) fn check_generic_arg_count(
-    tcx: TyCtxt<'_>,
+    cx: &dyn HirTyLowerer<'_>,
     def_id: DefId,
     seg: &hir::PathSegment<'_>,
     gen_params: &ty::Generics,
@@ -444,7 +448,7 @@ pub(crate) fn check_generic_arg_count(
         .own_params
         .iter()
         .filter(|param| {
-            matches!(param.kind, ty::GenericParamDefKind::Const { is_host_effect: true, .. })
+            matches!(param.kind, ty::GenericParamDefKind::Const { synthetic: true, .. })
         })
         .count();
     let named_const_param_count = param_counts.consts - synth_const_param_count;
@@ -452,13 +456,13 @@ pub(crate) fn check_generic_arg_count(
         (gen_pos != GenericArgPosition::Type || seg.infer_args) && !gen_args.has_lifetime_params();
 
     if gen_pos != GenericArgPosition::Type
-        && let Some(b) = gen_args.bindings.first()
+        && let Some(c) = gen_args.constraints.first()
     {
-        prohibit_assoc_item_binding(tcx, b, None);
+        prohibit_assoc_item_constraint(cx, c, None);
     }
 
     let explicit_late_bound =
-        prohibit_explicit_late_bound_lifetimes(tcx, gen_params, gen_args, gen_pos);
+        prohibit_explicit_late_bound_lifetimes(cx, gen_params, gen_args, gen_pos);
 
     let mut invalid_args = vec![];
 
@@ -474,16 +478,9 @@ pub(crate) fn check_generic_arg_count(
             return Ok(());
         }
 
-        if provided_args > max_expected_args {
-            invalid_args.extend(
-                gen_args.args[max_expected_args..provided_args].iter().map(|arg| arg.span()),
-            );
-        };
+        invalid_args.extend(min_expected_args..provided_args);
 
         let gen_args_info = if provided_args > min_expected_args {
-            invalid_args.extend(
-                gen_args.args[min_expected_args..provided_args].iter().map(|arg| arg.span()),
-            );
             let num_redundant_args = provided_args - min_expected_args;
             GenericArgsInfo::ExcessLifetimes { num_redundant_args }
         } else {
@@ -491,17 +488,15 @@ pub(crate) fn check_generic_arg_count(
             GenericArgsInfo::MissingLifetimes { num_missing_args }
         };
 
-        let reported = WrongNumberOfGenericArgs::new(
-            tcx,
+        let reported = cx.dcx().emit_err(WrongNumberOfGenericArgs::new(
+            cx.tcx(),
             gen_args_info,
             seg,
             gen_params,
             has_self as usize,
             gen_args,
             def_id,
-        )
-        .diagnostic()
-        .emit();
+        ));
 
         Err(reported)
     };
@@ -537,12 +532,9 @@ pub(crate) fn check_generic_arg_count(
 
         let num_default_params = expected_max - expected_min;
 
+        let mut all_params_are_binded = false;
         let gen_args_info = if provided > expected_max {
-            invalid_args.extend(
-                gen_args.args[args_offset + expected_max..args_offset + provided]
-                    .iter()
-                    .map(|arg| arg.span()),
-            );
+            invalid_args.extend((expected_max..provided).map(|i| i + args_offset));
             let num_redundant_args = provided - expected_max;
 
             // Provide extra note if synthetic arguments like `impl Trait` are specified.
@@ -557,6 +549,20 @@ pub(crate) fn check_generic_arg_count(
         } else {
             let num_missing_args = expected_max - provided;
 
+            let constraint_names: Vec<_> =
+                gen_args.constraints.iter().map(|b| b.ident.name).collect();
+            let param_names: Vec<_> = gen_params
+                .own_params
+                .iter()
+                .filter(|param| !has_self || param.index != 0) // Assumes `Self` will always be the first parameter
+                .map(|param| param.name)
+                .collect();
+            if constraint_names == param_names {
+                // We set this to true and delay emitting `WrongNumberOfGenericArgs`
+                // to provide a succinct error for cases like issue #113073
+                all_params_are_binded = true;
+            };
+
             GenericArgsInfo::MissingTypesOrConsts {
                 num_missing_args,
                 num_default_params,
@@ -566,17 +572,19 @@ pub(crate) fn check_generic_arg_count(
 
         debug!(?gen_args_info);
 
-        let reported = WrongNumberOfGenericArgs::new(
-            tcx,
-            gen_args_info,
-            seg,
-            gen_params,
-            params_offset,
-            gen_args,
-            def_id,
-        )
-        .diagnostic()
-        .emit_unless(gen_args.has_err());
+        let reported = gen_args.has_err().unwrap_or_else(|| {
+            cx.dcx()
+                .create_err(WrongNumberOfGenericArgs::new(
+                    cx.tcx(),
+                    gen_args_info,
+                    seg,
+                    gen_params,
+                    params_offset,
+                    gen_args,
+                    def_id,
+                ))
+                .emit_unless(all_params_are_binded)
+        });
 
         Err(reported)
     };
@@ -608,14 +616,14 @@ pub(crate) fn check_generic_arg_count(
         explicit_late_bound,
         correct: lifetimes_correct
             .and(args_correct)
-            .map_err(|reported| GenericArgCountMismatch { reported: Some(reported), invalid_args }),
+            .map_err(|reported| GenericArgCountMismatch { reported, invalid_args }),
     }
 }
 
 /// Prohibits explicit lifetime arguments if late-bound lifetime parameters
 /// are present. This is used both for datatypes and function calls.
 pub(crate) fn prohibit_explicit_late_bound_lifetimes(
-    tcx: TyCtxt<'_>,
+    cx: &dyn HirTyLowerer<'_>,
     def: &ty::Generics,
     args: &hir::GenericArgs<'_>,
     position: GenericArgPosition,
@@ -636,18 +644,19 @@ pub(crate) fn prohibit_explicit_late_bound_lifetimes(
         if position == GenericArgPosition::Value
             && args.num_lifetime_params() != param_counts.lifetimes
         {
-            struct_span_code_err!(tcx.dcx(), span, E0794, "{}", msg)
+            struct_span_code_err!(cx.dcx(), span, E0794, "{}", msg)
                 .with_span_note(span_late, note)
                 .emit();
         } else {
             let mut multispan = MultiSpan::from_span(span);
             multispan.push_span_label(span_late, note);
-            tcx.node_span_lint(
+            cx.tcx().node_span_lint(
                 LATE_BOUND_LIFETIME_ARGUMENTS,
                 args.args[0].hir_id(),
                 multispan,
-                msg,
-                |_| {},
+                |lint| {
+                    lint.primary_message(msg);
+                },
             );
         }
 
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
index d9d36f5299b..29c71c3fa50 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
@@ -4,7 +4,7 @@ use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_lint_defs::{builtin::BARE_TRAIT_OBJECTS, Applicability};
 use rustc_span::Span;
-use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
+use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName;
 
 use super::HirTyLowerer;
 
@@ -60,7 +60,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             let msg = "trait objects must include the `dyn` keyword";
             let label = "add `dyn` keyword before this trait";
             let mut diag =
-                rustc_errors::struct_span_code_err!(tcx.dcx(), self_ty.span, E0782, "{}", msg);
+                rustc_errors::struct_span_code_err!(self.dcx(), self_ty.span, E0782, "{}", msg);
             if self_ty.span.can_be_used_for_suggestions()
                 && !self.maybe_suggest_impl_trait(self_ty, &mut diag)
             {
@@ -72,8 +72,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             self.maybe_suggest_assoc_ty_bound(self_ty, &mut diag);
             diag.stash(self_ty.span, StashKey::TraitMissingMethod);
         } else {
-            let msg = "trait objects without an explicit `dyn` are deprecated";
-            tcx.node_span_lint(BARE_TRAIT_OBJECTS, self_ty.hir_id, self_ty.span, msg, |lint| {
+            tcx.node_span_lint(BARE_TRAIT_OBJECTS, self_ty.hir_id, self_ty.span, |lint| {
+                lint.primary_message("trait objects without an explicit `dyn` are deprecated");
                 if self_ty.span.can_be_used_for_suggestions() {
                     lint.multipart_suggestion_verbose(
                         "if this is an object-safe trait, use `dyn`",
@@ -182,7 +182,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                             // For recursive traits, don't downgrade the error. (#119652)
                             is_downgradable = false;
                         }
-                        tcx.check_is_object_safe(id)
+                        tcx.is_object_safe(id)
                     }
                     _ => false,
                 })
@@ -268,8 +268,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     fn maybe_suggest_assoc_ty_bound(&self, self_ty: &hir::Ty<'_>, diag: &mut Diag<'_>) {
         let mut parents = self.tcx().hir().parent_iter(self_ty.hir_id);
 
-        if let Some((_, hir::Node::TypeBinding(binding))) = parents.next()
-            && let hir::TypeBindingKind::Equality { term: hir::Term::Ty(obj_ty) } = binding.kind
+        if let Some((_, hir::Node::AssocItemConstraint(constraint))) = parents.next()
+            && let Some(obj_ty) = constraint.ty()
         {
             if let Some((_, hir::Node::TraitRef(..))) = parents.next()
                 && let Some((_, hir::Node::Ty(ty))) = parents.next()
@@ -279,10 +279,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 return;
             }
 
-            let lo = if binding.gen_args.span_ext.is_dummy() {
-                binding.ident.span
+            let lo = if constraint.gen_args.span_ext.is_dummy() {
+                constraint.ident.span
             } else {
-                binding.gen_args.span_ext
+                constraint.gen_args.span_ext
             };
             let hi = obj_ty.span;
 
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 4b1c0da6ce1..a665306f2c6 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -20,21 +20,20 @@ mod lint;
 mod object_safety;
 
 use crate::bounds::Bounds;
-use crate::collect::HirPlaceholderCollector;
 use crate::errors::{AmbiguousLifetimeBound, WildPatTy};
-use crate::hir_ty_lowering::errors::{prohibit_assoc_item_binding, GenericsArgsErrExtend};
+use crate::hir_ty_lowering::errors::{prohibit_assoc_item_constraint, GenericsArgsErrExtend};
 use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
 use crate::middle::resolve_bound_vars as rbv;
 use crate::require_c_abi_if_c_variadic;
 use rustc_ast::TraitObjectSyntax;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_errors::{
-    codes::*, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, FatalError,
+    codes::*, struct_span_code_err, Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed,
+    FatalError,
 };
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::intravisit::{walk_generics, Visitor as _};
 use rustc_hir::{GenericArg, GenericArgs, HirId};
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::ObligationCause;
@@ -49,8 +48,9 @@ use rustc_middle::{bug, span_bug};
 use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::symbol::{kw, Ident, Symbol};
-use rustc_span::{sym, Span, DUMMY_SP};
+use rustc_span::{Span, DUMMY_SP};
 use rustc_target::spec::abi;
+use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::wf::object_region_bounds;
 use rustc_trait_selection::traits::{self, ObligationCtxt};
 
@@ -82,6 +82,20 @@ pub enum PredicateFilter {
     SelfAndAssociatedTypeBounds,
 }
 
+#[derive(Debug)]
+pub enum RegionInferReason<'a> {
+    /// Lifetime on a trait object behind a reference.
+    /// This allows inferring information from the reference.
+    BorrowedObjectLifetimeDefault,
+    /// A trait object's lifetime.
+    ObjectLifetimeDefault,
+    /// Generic lifetime parameter
+    Param(&'a ty::GenericParamDef),
+    RegionPredicate,
+    Reference,
+    OutlivesBound,
+}
+
 /// A context which can lower type-system entities from the [HIR][hir] to
 /// the [`rustc_middle::ty`] representation.
 ///
@@ -89,26 +103,19 @@ pub enum PredicateFilter {
 pub trait HirTyLowerer<'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx>;
 
-    /// Returns the [`DefId`] of the overarching item whose constituents get lowered.
-    fn item_def_id(&self) -> DefId;
+    fn dcx(&self) -> DiagCtxtHandle<'_>;
 
-    /// Returns `true` if the current context allows the use of inference variables.
-    fn allow_infer(&self) -> bool;
+    /// Returns the [`LocalDefId`] of the overarching item whose constituents get lowered.
+    fn item_def_id(&self) -> LocalDefId;
 
     /// Returns the region to use when a lifetime is omitted (and not elided).
-    fn re_infer(&self, param: Option<&ty::GenericParamDef>, span: Span)
-    -> Option<ty::Region<'tcx>>;
+    fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx>;
 
     /// Returns the type to use when a type is omitted.
     fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx>;
 
     /// Returns the const to use when a const is omitted.
-    fn ct_infer(
-        &self,
-        ty: Ty<'tcx>,
-        param: Option<&ty::GenericParamDef>,
-        span: Span,
-    ) -> Const<'tcx>;
+    fn ct_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx>;
 
     /// Probe bounds in scope where the bounded type coincides with the given type parameter.
     ///
@@ -151,6 +158,14 @@ pub trait HirTyLowerer<'tcx> {
         poly_trait_ref: ty::PolyTraitRef<'tcx>,
     ) -> Ty<'tcx>;
 
+    fn lower_fn_sig(
+        &self,
+        decl: &hir::FnDecl<'tcx>,
+        generics: Option<&hir::Generics<'_>>,
+        hir_id: HirId,
+        hir_ty: Option<&hir::Ty<'_>>,
+    ) -> (Vec<Ty<'tcx>>, Ty<'tcx>);
+
     /// Returns `AdtDef` if `ty` is an ADT.
     ///
     /// Note that `ty` might be a alias type that needs normalization.
@@ -165,12 +180,6 @@ pub trait HirTyLowerer<'tcx> {
     /// The inference context of the lowering context if applicable.
     fn infcx(&self) -> Option<&InferCtxt<'tcx>>;
 
-    /// Taint the context with errors.
-    ///
-    /// Invoke this when you encounter an error from some prior pass like name resolution.
-    /// This is used to help suppress derived errors typeck might otherwise report.
-    fn set_tainted_by_errors(&self, e: ErrorGuaranteed);
-
     /// Convenience method for coercing the lowering context into a trait object type.
     ///
     /// Most lowering routines are defined on the trait object type directly
@@ -215,12 +224,11 @@ pub(crate) enum GenericArgPosition {
 
 /// A marker denoting that the generic arguments that were
 /// provided did not match the respective generic parameters.
-#[derive(Clone, Default, Debug)]
+#[derive(Clone, Debug)]
 pub struct GenericArgCountMismatch {
-    /// Indicates whether a fatal error was reported (`Some`), or just a lint (`None`).
-    pub reported: Option<ErrorGuaranteed>,
-    /// A list of spans of arguments provided that were not valid.
-    pub invalid_args: Vec<Span>,
+    pub reported: ErrorGuaranteed,
+    /// A list of indices of arguments provided that were not valid.
+    pub invalid_args: Vec<usize>,
 }
 
 /// Decorates the result of a generic argument count mismatch
@@ -240,13 +248,14 @@ pub trait GenericArgsLowerer<'a, 'tcx> {
 
     fn provided_kind(
         &mut self,
+        preceding_args: &[ty::GenericArg<'tcx>],
         param: &ty::GenericParamDef,
         arg: &GenericArg<'tcx>,
     ) -> ty::GenericArg<'tcx>;
 
     fn inferred_kind(
         &mut self,
-        args: Option<&[ty::GenericArg<'tcx>]>,
+        preceding_args: &[ty::GenericArg<'tcx>],
         param: &ty::GenericParamDef,
         infer_args: bool,
     ) -> ty::GenericArg<'tcx>;
@@ -258,7 +267,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     pub fn lower_lifetime(
         &self,
         lifetime: &hir::Lifetime,
-        def: Option<&ty::GenericParamDef>,
+        reason: RegionInferReason<'_>,
     ) -> ty::Region<'tcx> {
         let tcx = self.tcx();
         let lifetime_name = |def_id| tcx.hir().name(tcx.local_def_id_to_hir_id(def_id));
@@ -280,7 +289,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local());
                 let generics = tcx.generics_of(item_def_id);
                 let index = generics.param_def_id_to_index[&def_id];
-                ty::Region::new_early_param(tcx, ty::EarlyParamRegion { def_id, index, name })
+                ty::Region::new_early_param(tcx, ty::EarlyParamRegion { index, name })
             }
 
             Some(rbv::ResolvedArg::Free(scope, id)) => {
@@ -292,21 +301,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
             Some(rbv::ResolvedArg::Error(guar)) => ty::Region::new_error(tcx, guar),
 
-            None => {
-                self.re_infer(def, lifetime.ident.span).unwrap_or_else(|| {
-                    debug!(?lifetime, "unelided lifetime in signature");
-
-                    // This indicates an illegal lifetime
-                    // elision. `resolve_lifetime` should have
-                    // reported an error in this case -- but if
-                    // not, let's error out.
-                    ty::Region::new_error_with_message(
-                        tcx,
-                        lifetime.ident.span,
-                        "unelided lifetime in signature",
-                    )
-                })
-            }
+            None => self.re_infer(lifetime.ident.span, reason),
         }
     }
 
@@ -324,8 +319,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             None,
             ty::BoundConstness::NotConst,
         );
-        if let Some(b) = item_segment.args().bindings.first() {
-            prohibit_assoc_item_binding(self.tcx(), b, Some((def_id, item_segment, span)));
+        if let Some(c) = item_segment.args().constraints.first() {
+            prohibit_assoc_item_constraint(self, c, Some((def_id, item_segment, span)));
         }
         args
     }
@@ -335,7 +330,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     /// If this is a trait reference, you also need to pass the self type `self_ty`.
     /// The lowering process may involve applying defaulted type parameters.
     ///
-    /// Associated item bindings are not handled here!
+    /// Associated item constraints are not handled here! They are either lowered via
+    /// `lower_assoc_item_constraint` or rejected via `prohibit_assoc_item_constraint`.
     ///
     /// ### Example
     ///
@@ -349,7 +345,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     ///    which will have been resolved to a `def_id`
     /// 3. The `generic_args` contains info on the `<...>` contents. The `usize` type
     ///    parameters are returned in the `GenericArgsRef`
-    /// 4. Associated type bindings like `Output = u32` are contained in `generic_args.bindings`.
+    /// 4. Associated item constraints like `Output = u32` are contained in `generic_args.constraints`.
     ///
     /// Note that the type listing given here is *exactly* what the user provided.
     ///
@@ -395,7 +391,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
 
         let mut arg_count = check_generic_arg_count(
-            tcx,
+            self,
             def_id,
             segment,
             generics,
@@ -403,16 +399,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             self_ty.is_some(),
         );
 
-        if let Err(err) = &arg_count.correct
-            && let Some(reported) = err.reported
-        {
-            self.set_tainted_by_errors(reported);
-        }
-
         // Skip processing if type has no generic parameters.
         // Traits always have `Self` as a generic parameter, which means they will not return early
-        // here and so associated type bindings will be handled regardless of whether there are any
-        // non-`Self` generic parameters.
+        // here and so associated item constraints will be handled regardless of whether there are
+        // any non-`Self` generic parameters.
         if generics.is_own_empty() {
             return (tcx.mk_args(parent_args), arg_count);
         }
@@ -422,8 +412,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             def_id: DefId,
             generic_args: &'a GenericArgs<'tcx>,
             span: Span,
-            inferred_params: Vec<Span>,
             infer_args: bool,
+            incorrect_args: &'a Result<(), GenericArgCountMismatch>,
         }
 
         impl<'a, 'tcx> GenericArgsLowerer<'a, 'tcx> for GenericArgsCtxt<'a, 'tcx> {
@@ -438,12 +428,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
             fn provided_kind(
                 &mut self,
+                _preceding_args: &[ty::GenericArg<'tcx>],
                 param: &ty::GenericParamDef,
                 arg: &GenericArg<'tcx>,
             ) -> ty::GenericArg<'tcx> {
                 let tcx = self.lowerer.tcx();
 
-                let mut handle_ty_args = |has_default, ty: &hir::Ty<'tcx>| {
+                if let Err(incorrect) = self.incorrect_args {
+                    if incorrect.invalid_args.contains(&(param.index as usize)) {
+                        return param.to_error(tcx);
+                    }
+                }
+
+                let handle_ty_args = |has_default, ty: &hir::Ty<'tcx>| {
                     if has_default {
                         tcx.check_optional_stability(
                             param.def_id,
@@ -460,17 +457,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                             },
                         );
                     }
-                    if let (hir::TyKind::Infer, false) = (&ty.kind, self.lowerer.allow_infer()) {
-                        self.inferred_params.push(ty.span);
-                        Ty::new_misc_error(tcx).into()
-                    } else {
-                        self.lowerer.lower_ty(ty).into()
-                    }
+                    self.lowerer.lower_ty(ty).into()
                 };
 
                 match (&param.kind, arg) {
                     (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
-                        self.lowerer.lower_lifetime(lt, Some(param)).into()
+                        self.lowerer.lower_lifetime(lt, RegionInferReason::Param(param)).into()
                     }
                     (&GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => {
                         handle_ty_args(has_default, ty)
@@ -484,17 +476,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         ty::Const::from_anon_const(tcx, did).into()
                     }
                     (&GenericParamDefKind::Const { .. }, hir::GenericArg::Infer(inf)) => {
-                        let ty = tcx
-                            .at(self.span)
-                            .type_of(param.def_id)
-                            .no_bound_vars()
-                            .expect("const parameter types cannot be generic");
-                        if self.lowerer.allow_infer() {
-                            self.lowerer.ct_infer(ty, Some(param), inf.span).into()
-                        } else {
-                            self.inferred_params.push(inf.span);
-                            ty::Const::new_misc_error(tcx, ty).into()
-                        }
+                        self.lowerer.ct_infer(Some(param), inf.span).into()
                     }
                     (kind, arg) => span_bug!(
                         self.span,
@@ -505,38 +487,37 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
             fn inferred_kind(
                 &mut self,
-                args: Option<&[ty::GenericArg<'tcx>]>,
+                preceding_args: &[ty::GenericArg<'tcx>],
                 param: &ty::GenericParamDef,
                 infer_args: bool,
             ) -> ty::GenericArg<'tcx> {
                 let tcx = self.lowerer.tcx();
+
+                if let Err(incorrect) = self.incorrect_args {
+                    if incorrect.invalid_args.contains(&(param.index as usize)) {
+                        return param.to_error(tcx);
+                    }
+                }
                 match param.kind {
-                    GenericParamDefKind::Lifetime => self
-                        .lowerer
-                        .re_infer(Some(param), self.span)
-                        .unwrap_or_else(|| {
-                            debug!(?param, "unelided lifetime in signature");
-
-                            // This indicates an illegal lifetime in a non-assoc-trait position
-                            ty::Region::new_error_with_message(
-                                tcx,
-                                self.span,
-                                "unelided lifetime in signature",
-                            )
-                        })
-                        .into(),
+                    GenericParamDefKind::Lifetime => {
+                        self.lowerer.re_infer(self.span, RegionInferReason::Param(param)).into()
+                    }
                     GenericParamDefKind::Type { has_default, .. } => {
                         if !infer_args && has_default {
                             // No type parameter provided, but a default exists.
-                            let args = args.unwrap();
-                            if args.iter().any(|arg| match arg.unpack() {
-                                GenericArgKind::Type(ty) => ty.references_error(),
-                                _ => false,
-                            }) {
+                            if let Some(prev) =
+                                preceding_args.iter().find_map(|arg| match arg.unpack() {
+                                    GenericArgKind::Type(ty) => ty.error_reported().err(),
+                                    _ => None,
+                                })
+                            {
                                 // Avoid ICE #86756 when type error recovery goes awry.
-                                return Ty::new_misc_error(tcx).into();
+                                return Ty::new_error(tcx, prev).into();
                             }
-                            tcx.at(self.span).type_of(param.def_id).instantiate(tcx, args).into()
+                            tcx.at(self.span)
+                                .type_of(param.def_id)
+                                .instantiate(tcx, preceding_args)
+                                .into()
                         } else if infer_args {
                             self.lowerer.ty_infer(Some(param), self.span).into()
                         } else {
@@ -551,48 +532,46 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                             .no_bound_vars()
                             .expect("const parameter types cannot be generic");
                         if let Err(guar) = ty.error_reported() {
-                            return ty::Const::new_error(tcx, guar, ty).into();
+                            return ty::Const::new_error(tcx, guar).into();
                         }
                         // FIXME(effects) see if we should special case effect params here
                         if !infer_args && has_default {
                             tcx.const_param_default(param.def_id)
-                                .instantiate(tcx, args.unwrap())
+                                .instantiate(tcx, preceding_args)
                                 .into()
                         } else {
                             if infer_args {
-                                self.lowerer.ct_infer(ty, Some(param), self.span).into()
+                                self.lowerer.ct_infer(Some(param), self.span).into()
                             } else {
                                 // We've already errored above about the mismatch.
-                                ty::Const::new_misc_error(tcx, ty).into()
+                                ty::Const::new_misc_error(tcx).into()
                             }
                         }
                     }
                 }
             }
         }
+        if let ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst = constness
+            && generics.has_self
+            && !tcx.is_const_trait(def_id)
+        {
+            let reported = self.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait {
+                span,
+                modifier: constness.as_str(),
+            });
+            arg_count.correct = Err(GenericArgCountMismatch { reported, invalid_args: vec![] });
+        }
 
         let mut args_ctx = GenericArgsCtxt {
             lowerer: self,
             def_id,
             span,
             generic_args: segment.args(),
-            inferred_params: vec![],
             infer_args: segment.infer_args,
+            incorrect_args: &arg_count.correct,
         };
-        if let ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst = constness
-            && generics.has_self
-            && !tcx.has_attr(def_id, sym::const_trait)
-        {
-            let e = tcx.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait {
-                span,
-                modifier: constness.as_str(),
-            });
-            self.set_tainted_by_errors(e);
-            arg_count.correct =
-                Err(GenericArgCountMismatch { reported: Some(e), invalid_args: vec![] });
-        }
         let args = lower_generic_args(
-            tcx,
+            self,
             def_id,
             parent_args,
             self_ty.is_some(),
@@ -621,8 +600,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             None,
             ty::BoundConstness::NotConst,
         );
-        if let Some(b) = item_segment.args().bindings.first() {
-            prohibit_assoc_item_binding(self.tcx(), b, Some((item_def_id, item_segment, span)));
+        if let Some(c) = item_segment.args().constraints.first() {
+            prohibit_assoc_item_constraint(self, c, Some((item_def_id, item_segment, span)));
         }
         args
     }
@@ -654,13 +633,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     ///
     /// *Polymorphic* in the sense that it may bind late-bound vars.
     ///
-    /// This may generate auxiliary bounds if the trait reference contains associated item bindings.
+    /// This may generate auxiliary bounds iff the trait reference contains associated item constraints.
     ///
     /// ### Example
     ///
     /// Given the trait ref `Iterator<Item = u32>` and the self type `Ty`, this will add the
     ///
-    /// 1. *trait predicate* `<Ty as Iterator>` (known as `Foo: Iterator` in surface syntax) and the
+    /// 1. *trait predicate* `<Ty as Iterator>` (known as `Ty: Iterator` in the surface syntax) and the
     /// 2. *projection predicate* `<Ty as Iterator>::Item = u32`
     ///
     /// to `bounds`.
@@ -707,34 +686,41 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         debug!(?bound_vars);
 
         let poly_trait_ref = ty::Binder::bind_with_vars(
-            ty::TraitRef::new(tcx, trait_def_id, generic_args),
+            ty::TraitRef::new_from_args(tcx, trait_def_id, generic_args),
             bound_vars,
         );
 
         debug!(?poly_trait_ref);
-        bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity);
+        bounds.push_trait_bound(
+            tcx,
+            self.item_def_id().to_def_id(),
+            poly_trait_ref,
+            span,
+            polarity,
+            constness,
+        );
 
-        let mut dup_bindings = FxIndexMap::default();
-        for binding in trait_segment.args().bindings {
-            // Don't register additional associated type bounds for negative bounds,
-            // since we should have emitten an error for them earlier, and they will
-            // not be well-formed!
+        let mut dup_constraints = FxIndexMap::default();
+        for constraint in trait_segment.args().constraints {
+            // Don't register any associated item constraints for negative bounds,
+            // since we should have emitted an error for them earlier, and they
+            // would not be well-formed!
             if polarity != ty::PredicatePolarity::Positive {
                 assert!(
-                    self.tcx().dcx().has_errors().is_some(),
-                    "negative trait bounds should not have bindings",
+                    self.dcx().has_errors().is_some(),
+                    "negative trait bounds should not have assoc item constraints",
                 );
                 continue;
             }
 
             // Specify type to assert that error was already reported in `Err` case.
-            let _: Result<_, ErrorGuaranteed> = self.lower_assoc_item_binding(
+            let _: Result<_, ErrorGuaranteed> = self.lower_assoc_item_constraint(
                 trait_ref.hir_ref_id,
                 poly_trait_ref,
-                binding,
+                constraint,
                 bounds,
-                &mut dup_bindings,
-                binding.span,
+                &mut dup_constraints,
+                constraint.span,
                 only_self_bounds,
             );
             // Okay to ignore `Err` because of `ErrorGuaranteed` (see above).
@@ -766,10 +752,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             Some(self_ty),
             constness,
         );
-        if let Some(b) = trait_segment.args().bindings.first() {
-            prohibit_assoc_item_binding(self.tcx(), b, Some((trait_def_id, trait_segment, span)));
+        if let Some(c) = trait_segment.args().constraints.first() {
+            prohibit_assoc_item_constraint(self, c, Some((trait_def_id, trait_segment, span)));
         }
-        ty::TraitRef::new(self.tcx(), trait_def_id, generic_args)
+        ty::TraitRef::new_from_args(self.tcx(), trait_def_id, generic_args)
     }
 
     fn probe_trait_that_defines_assoc_item(
@@ -799,7 +785,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             // Type aliases defined in crates that have the
             // feature `lazy_type_alias` enabled get encoded as a type alias that normalization will
             // then actually instantiate the where bounds of.
-            let alias_ty = ty::AliasTy::new(tcx, did, args);
+            let alias_ty = ty::AliasTy::new_from_args(tcx, did, args);
             Ty::new_alias(tcx, ty::Weak, alias_ty)
         } else {
             tcx.at(span).type_of(did).instantiate(tcx, args)
@@ -849,7 +835,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     ///
     /// This fails if there is no such bound in the list of candidates or if there are multiple
     /// candidates in which case it reports ambiguity.
-    #[instrument(level = "debug", skip(self, all_candidates, ty_param_name, binding), ret)]
+    #[instrument(level = "debug", skip(self, all_candidates, ty_param_name, constraint), ret)]
     fn probe_single_bound_for_assoc_item<I>(
         &self,
         all_candidates: impl Fn() -> I,
@@ -858,7 +844,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         assoc_kind: ty::AssocKind,
         assoc_name: Ident,
         span: Span,
-        binding: Option<&hir::TypeBinding<'tcx>>,
+        constraint: Option<&hir::AssocItemConstraint<'tcx>>,
     ) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed>
     where
         I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
@@ -877,9 +863,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 assoc_kind,
                 assoc_name,
                 span,
-                binding,
+                constraint,
             );
-            self.set_tainted_by_errors(reported);
             return Err(reported);
         };
         debug!(?bound);
@@ -889,7 +874,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
             let assoc_kind_str = assoc_kind_str(assoc_kind);
             let ty_param_name = &ty_param_name.to_string();
-            let mut err = tcx.dcx().create_err(crate::errors::AmbiguousAssocItem {
+            let mut err = self.dcx().create_err(crate::errors::AmbiguousAssocItem {
                 span,
                 assoc_kind: assoc_kind_str,
                 assoc_name,
@@ -897,8 +882,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             });
             // Provide a more specific error code index entry for equality bindings.
             err.code(
-                if let Some(binding) = binding
-                    && let hir::TypeBindingKind::Equality { .. } = binding.kind
+                if let Some(constraint) = constraint
+                    && let hir::AssocItemConstraintKind::Equality { .. } = constraint.kind
                 {
                     E0222
                 } else {
@@ -906,7 +891,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 },
             );
 
-            // FIXME(#97583): Resugar equality bounds to type/const bindings.
+            // FIXME(#97583): Print associated item bindings properly (i.e., not as equality predicates!).
             // FIXME: Turn this into a structured, translateable & more actionable suggestion.
             let mut where_bounds = vec![];
             for bound in [bound, bound2].into_iter().chain(matching_candidates) {
@@ -921,9 +906,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         bound_span,
                         format!("ambiguous `{assoc_name}` from `{}`", bound.print_trait_sugared(),),
                     );
-                    if let Some(binding) = binding {
-                        match binding.kind {
-                            hir::TypeBindingKind::Equality { term } => {
+                    if let Some(constraint) = constraint {
+                        match constraint.kind {
+                            hir::AssocItemConstraintKind::Equality { term } => {
                                 let term: ty::Term<'_> = match term {
                                     hir::Term::Ty(ty) => self.lower_ty(ty).into(),
                                     hir::Term::Const(ct) => {
@@ -937,7 +922,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                                 ));
                             }
                             // FIXME: Provide a suggestion.
-                            hir::TypeBindingKind::Constraint { bounds: _ } => {}
+                            hir::AssocItemConstraintKind::Bound { bounds: _ } => {}
                         }
                     } else {
                         err.span_suggestion_verbose(
@@ -962,7 +947,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 ));
             }
             let reported = err.emit();
-            self.set_tainted_by_errors(reported);
             if !where_bounds.is_empty() {
                 return Err(reported);
             }
@@ -1061,7 +1045,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 // trait reference.
                 let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else {
                     // A cycle error occurred, most likely.
-                    tcx.dcx().span_bug(span, "expected cycle error");
+                    self.dcx().span_bug(span, "expected cycle error");
                 };
 
                 self.probe_single_bound_for_assoc_item(
@@ -1091,10 +1075,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 let reported = if variant_resolution.is_some() {
                     // Variant in type position
                     let msg = format!("expected type, found variant `{assoc_ident}`");
-                    tcx.dcx().span_err(span, msg)
+                    self.dcx().span_err(span, msg)
                 } else if qself_ty.is_enum() {
                     let mut err = struct_span_code_err!(
-                        tcx.dcx(),
+                        self.dcx(),
                         assoc_ident.span,
                         E0599,
                         "no variant named `{}` found for enum `{}`",
@@ -1135,7 +1119,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 } else if let ty::Alias(ty::Opaque, alias_ty) = qself_ty.kind() {
                     // `<impl Trait as OtherTrait>::Assoc` makes no sense.
                     struct_span_code_err!(
-                        tcx.dcx(),
+                        self.dcx(),
                         tcx.def_span(alias_ty.def_id),
                         E0667,
                         "`impl Trait` is not allowed in path parameters"
@@ -1155,45 +1139,41 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         assoc_ident.name,
                     )
                 };
-                self.set_tainted_by_errors(reported);
                 return Err(reported);
             }
         };
 
         let trait_did = bound.def_id();
-        let assoc_ty_did = self.probe_assoc_ty(assoc_ident, hir_ref_id, span, trait_did).unwrap();
-        let ty = self.lower_assoc_ty(span, assoc_ty_did, assoc_segment, bound);
+        let assoc_ty = self
+            .probe_assoc_item(assoc_ident, ty::AssocKind::Type, hir_ref_id, span, trait_did)
+            .expect("failed to find associated type");
+        let ty = self.lower_assoc_ty(span, assoc_ty.def_id, assoc_segment, bound);
 
         if let Some(variant_def_id) = variant_resolution {
-            tcx.node_span_lint(
-                AMBIGUOUS_ASSOCIATED_ITEMS,
-                hir_ref_id,
-                span,
-                "ambiguous associated item",
-                |lint| {
-                    let mut could_refer_to = |kind: DefKind, def_id, also| {
-                        let note_msg = format!(
-                            "`{}` could{} refer to the {} defined here",
-                            assoc_ident,
-                            also,
-                            tcx.def_kind_descr(kind, def_id)
-                        );
-                        lint.span_note(tcx.def_span(def_id), note_msg);
-                    };
+            tcx.node_span_lint(AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, |lint| {
+                lint.primary_message("ambiguous associated item");
+                let mut could_refer_to = |kind: DefKind, def_id, also| {
+                    let note_msg = format!(
+                        "`{}` could{} refer to the {} defined here",
+                        assoc_ident,
+                        also,
+                        tcx.def_kind_descr(kind, def_id)
+                    );
+                    lint.span_note(tcx.def_span(def_id), note_msg);
+                };
 
-                    could_refer_to(DefKind::Variant, variant_def_id, "");
-                    could_refer_to(DefKind::AssocTy, assoc_ty_did, " also");
+                could_refer_to(DefKind::Variant, variant_def_id, "");
+                could_refer_to(DefKind::AssocTy, assoc_ty.def_id, " also");
 
-                    lint.span_suggestion(
-                        span,
-                        "use fully-qualified syntax",
-                        format!("<{} as {}>::{}", qself_ty, tcx.item_name(trait_did), assoc_ident),
-                        Applicability::MachineApplicable,
-                    );
-                },
-            );
+                lint.span_suggestion(
+                    span,
+                    "use fully-qualified syntax",
+                    format!("<{} as {}>::{}", qself_ty, tcx.item_name(trait_did), assoc_ident),
+                    Applicability::MachineApplicable,
+                );
+            });
         }
-        Ok((ty, DefKind::AssocTy, assoc_ty_did))
+        Ok((ty, DefKind::AssocTy, assoc_ty.def_id))
     }
 
     fn probe_inherent_assoc_ty(
@@ -1220,7 +1200,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let candidates: Vec<_> = tcx
             .inherent_impls(adt_did)?
             .iter()
-            .filter_map(|&impl_| Some((impl_, self.probe_assoc_ty_unchecked(name, block, impl_)?)))
+            .filter_map(|&impl_| {
+                let (item, scope) =
+                    self.probe_assoc_item_unchecked(name, ty::AssocKind::Type, block, impl_)?;
+                Some((impl_, (item.def_id, scope)))
+            })
             .collect();
 
         if candidates.is_empty() {
@@ -1264,7 +1248,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             },
         )?;
 
-        self.check_assoc_ty(assoc_item, name, def_scope, block, span);
+        self.check_assoc_item(assoc_item, name, def_scope, block, span);
 
         // FIXME(fmease): Currently creating throwaway `parent_args` to please
         // `lower_generic_args_of_assoc_item`. Modify the latter instead (or sth. similar) to
@@ -1276,7 +1260,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 .chain(args.into_iter().skip(parent_args.len())),
         );
 
-        let ty = Ty::new_alias(tcx, ty::Inherent, ty::AliasTy::new(tcx, assoc_item, args));
+        let ty =
+            Ty::new_alias(tcx, ty::Inherent, ty::AliasTy::new_from_args(tcx, assoc_item, args));
 
         Ok(Some((ty, assoc_item)))
     }
@@ -1298,7 +1283,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             .copied()
             .filter(|&(impl_, _)| {
                 infcx.probe(|_| {
-                    let ocx = ObligationCtxt::new(infcx);
+                    let ocx = ObligationCtxt::new_with_diagnostics(infcx);
                     let self_ty = ocx.normalize(&ObligationCause::dummy(), param_env, self_ty);
 
                     let impl_args = infcx.fresh_args_for_item(span, impl_);
@@ -1351,50 +1336,68 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
     }
 
-    fn probe_assoc_ty(&self, name: Ident, block: HirId, span: Span, scope: DefId) -> Option<DefId> {
-        let (item, def_scope) = self.probe_assoc_ty_unchecked(name, block, scope)?;
-        self.check_assoc_ty(item, name, def_scope, block, span);
+    /// Given name and kind search for the assoc item in the provided scope and check if it's accessible[^1].
+    ///
+    /// [^1]: I.e., accessible in the provided scope wrt. visibility and stability.
+    fn probe_assoc_item(
+        &self,
+        ident: Ident,
+        kind: ty::AssocKind,
+        block: HirId,
+        span: Span,
+        scope: DefId,
+    ) -> Option<ty::AssocItem> {
+        let (item, scope) = self.probe_assoc_item_unchecked(ident, kind, block, scope)?;
+        self.check_assoc_item(item.def_id, ident, scope, block, span);
         Some(item)
     }
 
-    fn probe_assoc_ty_unchecked(
+    /// Given name and kind search for the assoc item in the provided scope
+    /// *without* checking if it's accessible[^1].
+    ///
+    /// [^1]: I.e., accessible in the provided scope wrt. visibility and stability.
+    fn probe_assoc_item_unchecked(
         &self,
-        name: Ident,
+        ident: Ident,
+        kind: ty::AssocKind,
         block: HirId,
         scope: DefId,
-    ) -> Option<(DefId, DefId)> {
+    ) -> Option<(ty::AssocItem, /*scope*/ DefId)> {
         let tcx = self.tcx();
-        let (ident, def_scope) = tcx.adjust_ident_and_get_scope(name, scope, block);
 
+        let (ident, def_scope) = tcx.adjust_ident_and_get_scope(ident, scope, block);
         // We have already adjusted the item name above, so compare with `.normalize_to_macros_2_0()`
         // instead of calling `filter_by_name_and_kind` which would needlessly normalize the
         // `ident` again and again.
-        let item = tcx.associated_items(scope).in_definition_order().find(|i| {
-            i.kind.namespace() == Namespace::TypeNS
-                && i.ident(tcx).normalize_to_macros_2_0() == ident
-        })?;
+        let item = tcx
+            .associated_items(scope)
+            .filter_by_name_unhygienic(ident.name)
+            .find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == ident)?;
 
-        Some((item.def_id, def_scope))
+        Some((*item, def_scope))
     }
 
-    fn check_assoc_ty(&self, item: DefId, name: Ident, def_scope: DefId, block: HirId, span: Span) {
+    /// Check if the given assoc item is accessible in the provided scope wrt. visibility and stability.
+    fn check_assoc_item(
+        &self,
+        item_def_id: DefId,
+        ident: Ident,
+        scope: DefId,
+        block: HirId,
+        span: Span,
+    ) {
         let tcx = self.tcx();
-        let kind = DefKind::AssocTy;
-
-        if !tcx.visibility(item).is_accessible_from(def_scope, tcx) {
-            let kind = tcx.def_kind_descr(kind, item);
-            let msg = format!("{kind} `{name}` is private");
-            let def_span = tcx.def_span(item);
-            let reported = tcx
-                .dcx()
-                .struct_span_err(span, msg)
-                .with_code(E0624)
-                .with_span_label(span, format!("private {kind}"))
-                .with_span_label(def_span, format!("{kind} defined here"))
-                .emit();
-            self.set_tainted_by_errors(reported);
+
+        if !tcx.visibility(item_def_id).is_accessible_from(scope, tcx) {
+            self.dcx().emit_err(crate::errors::AssocItemIsPrivate {
+                span,
+                kind: tcx.def_descr(item_def_id),
+                name: ident,
+                defined_here_label: tcx.def_span(item_def_id),
+            });
         }
-        tcx.check_stability(item, Some(block), span, None);
+
+        tcx.check_stability(item_def_id, Some(block), span, None);
     }
 
     fn probe_traits_that_match_assoc_ty(
@@ -1477,16 +1480,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             let def_id = self.item_def_id();
             debug!(item_def_id = ?def_id);
 
-            let parent_def_id = def_id
-                .as_local()
-                .map(|def_id| tcx.local_def_id_to_hir_id(def_id))
-                .map(|hir_id| tcx.hir().get_parent_item(hir_id).to_def_id());
+            // FIXME: document why/how this is different from `tcx.local_parent(def_id)`
+            let parent_def_id =
+                tcx.hir().get_parent_item(tcx.local_def_id_to_hir_id(def_id)).to_def_id();
             debug!(?parent_def_id);
 
             // If the trait in segment is the same as the trait defining the item,
             // use the `<Self as ..>` syntax in the error.
-            let is_part_of_self_trait_constraints = def_id == trait_def_id;
-            let is_part_of_fn_in_self_trait = parent_def_id == Some(trait_def_id);
+            let is_part_of_self_trait_constraints = def_id.to_def_id() == trait_def_id;
+            let is_part_of_fn_in_self_trait = parent_def_id == trait_def_id;
 
             let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
                 vec!["Self".to_string()]
@@ -1525,7 +1527,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let item_args =
             self.lower_generic_args_of_assoc_item(span, item_def_id, item_segment, trait_ref.args);
 
-        Ty::new_projection(tcx, item_def_id, item_args)
+        Ty::new_projection_from_args(tcx, item_def_id, item_args)
     }
 
     pub fn prohibit_generic_args<'a>(
@@ -1545,8 +1547,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         for segment in segments {
             // Only emit the first error to avoid overloading the user with error messages.
-            if let Some(b) = segment.args().bindings.first() {
-                return Err(prohibit_assoc_item_binding(self.tcx(), b, None));
+            if let Some(c) = segment.args().constraints.first() {
+                return Err(prohibit_assoc_item_constraint(self, c, None));
             }
         }
 
@@ -1806,7 +1808,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 // `AlwaysApplicable` impl needs a `T: ?Sized` bound for
                 // this to compile if we were to normalize here.
                 if forbid_generic && ty.has_param() {
-                    let mut err = tcx.dcx().struct_span_err(
+                    let mut err = self.dcx().struct_span_err(
                         path.span,
                         "generic `Self` types are currently not permitted in anonymous constants",
                     );
@@ -1818,7 +1820,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         err.span_note(impl_.self_ty.span, "not a concrete type");
                     }
                     let reported = err.emit();
-                    self.set_tainted_by_errors(reported);
                     Ty::new_error(tcx, reported)
                 } else {
                     ty
@@ -1830,19 +1831,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     path.segments[..path.segments.len() - 2].iter(),
                     GenericsArgsErrExtend::None,
                 );
-                // HACK: until we support `<Type as ~const Trait>`, assume all of them are.
-                let constness = if tcx.has_attr(tcx.parent(def_id), sym::const_trait) {
-                    ty::BoundConstness::ConstIfConst
-                } else {
-                    ty::BoundConstness::NotConst
-                };
                 self.lower_qpath(
                     span,
                     opt_self_ty,
                     def_id,
                     &path.segments[path.segments.len() - 2],
                     path.segments.last().unwrap(),
-                    constness,
+                    ty::BoundConstness::NotConst,
                 )
             }
             Res::PrimTy(prim_ty) => {
@@ -1865,7 +1860,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     .tcx()
                     .dcx()
                     .span_delayed_bug(path.span, "path with `Res::Err` but no error emitted");
-                self.set_tainted_by_errors(e);
                 Ty::new_error(self.tcx(), e)
             }
             Res::Def(..) => {
@@ -1876,7 +1870,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 );
                 Ty::new_error(
                     self.tcx(),
-                    self.tcx().dcx().span_delayed_bug(span, "incorrect resolution for `Self`"),
+                    self.dcx().span_delayed_bug(span, "incorrect resolution for `Self`"),
                 )
             }
             _ => span_bug!(span, "unexpected resolution: {:?}", path.res),
@@ -1914,7 +1908,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     ///
     /// Early-bound const parameters get lowered to [`ty::ConstKind::Param`]
     /// and late-bound ones to [`ty::ConstKind::Bound`].
-    pub(crate) fn lower_const_param(&self, hir_id: HirId, param_ty: Ty<'tcx>) -> Const<'tcx> {
+    pub(crate) fn lower_const_param(&self, hir_id: HirId) -> Const<'tcx> {
         let tcx = self.tcx();
         match tcx.named_bound_var(hir_id) {
             Some(rbv::ResolvedArg::EarlyBound(def_id)) => {
@@ -1924,12 +1918,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 let generics = tcx.generics_of(item_def_id);
                 let index = generics.param_def_id_to_index[&def_id];
                 let name = tcx.item_name(def_id);
-                ty::Const::new_param(tcx, ty::ParamConst::new(index, name), param_ty)
+                ty::Const::new_param(tcx, ty::ParamConst::new(index, name))
             }
             Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => {
-                ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index), param_ty)
+                ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index))
             }
-            Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar, param_ty),
+            Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar),
             arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", hir_id),
         }
     }
@@ -1949,7 +1943,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let sig_span = self.tcx().def_span(sig_id);
         let mut try_emit = |descr| {
             if emit {
-                self.tcx().dcx().emit_err(crate::errors::NotSupportedDelegation {
+                self.dcx().emit_err(crate::errors::NotSupportedDelegation {
                     span,
                     descr,
                     callee_span: sig_span,
@@ -1967,7 +1961,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
 
         let sig_generics = self.tcx().generics_of(sig_id);
-        let parent = self.tcx().parent(self.item_def_id());
+        let parent = self.tcx().local_parent(self.item_def_id());
         let parent_generics = self.tcx().generics_of(parent);
 
         let parent_is_trait = (self.tcx().def_kind(parent) == DefKind::Trait) as usize;
@@ -1999,14 +1993,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     ) -> Ty<'tcx> {
         if self.check_delegation_constraints(sig_id, span, idx == hir::InferDelegationKind::Output)
         {
-            let e = self.tcx().dcx().span_delayed_bug(span, "not supported delegation case");
-            self.set_tainted_by_errors(e);
+            let e = self.dcx().span_delayed_bug(span, "not supported delegation case");
             return Ty::new_error(self.tcx(), e);
         };
         let sig = self.tcx().fn_sig(sig_id);
         let sig_generics = self.tcx().generics_of(sig_id);
 
-        let parent = self.tcx().parent(self.item_def_id());
+        let parent = self.tcx().local_parent(self.item_def_id());
         let parent_def_kind = self.tcx().def_kind(parent);
 
         let sig = if let DefKind::Impl { .. } = parent_def_kind
@@ -2054,7 +2047,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             hir::TyKind::Slice(ty) => Ty::new_slice(tcx, self.lower_ty(ty)),
             hir::TyKind::Ptr(mt) => Ty::new_ptr(tcx, self.lower_ty(mt.ty), mt.mutbl),
             hir::TyKind::Ref(region, mt) => {
-                let r = self.lower_lifetime(region, None);
+                let r = self.lower_lifetime(region, RegionInferReason::Reference);
                 debug!(?r);
                 let t = self.lower_ty_common(mt.ty, true, false);
                 Ty::new_ref(tcx, r, t, mt.mutbl)
@@ -2145,7 +2138,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
             hir::TyKind::Array(ty, length) => {
                 let length = match length {
-                    hir::ArrayLen::Infer(inf) => self.ct_infer(tcx.types.usize, None, inf.span),
+                    hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span),
                     hir::ArrayLen::Body(constant) => {
                         ty::Const::from_anon_const(tcx, constant.def_id)
                     }
@@ -2165,7 +2158,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 let ty = self.lower_ty(ty);
                 let pat_ty = match pat.kind {
                     hir::PatKind::Wild => {
-                        let err = tcx.dcx().emit_err(WildPatTy { span: pat.span });
+                        let err = self.dcx().emit_err(WildPatTy { span: pat.span });
                         Ty::new_error(tcx, err)
                     }
                     hir::PatKind::Range(start, end, include_end) => {
@@ -2176,17 +2169,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                                 }
                                 _ => (expr, None),
                             };
-                            let c = match &expr.kind {
+                            let (c, c_ty) = match &expr.kind {
                                 hir::ExprKind::Lit(lit) => {
                                     let lit_input =
                                         LitToConstInput { lit: &lit.node, ty, neg: neg.is_some() };
-                                    match tcx.lit_to_const(lit_input) {
+                                    let ct = match tcx.lit_to_const(lit_input) {
                                         Ok(c) => c,
                                         Err(LitToConstError::Reported(err)) => {
-                                            ty::Const::new_error(tcx, err, ty)
+                                            ty::Const::new_error(tcx, err)
                                         }
                                         Err(LitToConstError::TypeError) => todo!(),
-                                    }
+                                    };
+                                    (ct, ty)
                                 }
 
                                 hir::ExprKind::Path(hir::QPath::Resolved(
@@ -2204,19 +2198,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                                         .type_of(def_id)
                                         .no_bound_vars()
                                         .expect("const parameter types cannot be generic");
-                                    self.lower_const_param(expr.hir_id, ty)
+                                    let ct = self.lower_const_param(expr.hir_id);
+                                    (ct, ty)
                                 }
 
                                 _ => {
                                     let err = tcx
                                         .dcx()
                                         .emit_err(crate::errors::NonConstRange { span: expr.span });
-                                    ty::Const::new_error(tcx, err, ty)
+                                    (ty::Const::new_error(tcx, err), Ty::new_error(tcx, err))
                                 }
                             };
-                            self.record_ty(expr.hir_id, c.ty(), expr.span);
+                            self.record_ty(expr.hir_id, c_ty, expr.span);
                             if let Some((id, span)) = neg {
-                                self.record_ty(id, c.ty(), span);
+                                self.record_ty(id, c_ty, span);
                             }
                             c
                         };
@@ -2283,7 +2278,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         &lifetimes[i]
                     )
                 };
-                self.lower_lifetime(lifetime, None).into()
+                self.lower_lifetime(lifetime, RegionInferReason::Param(&param)).into()
             } else {
                 tcx.mk_param_from_def(param)
             }
@@ -2291,7 +2286,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         debug!(?args);
 
         if in_trait {
-            Ty::new_projection(tcx, def_id, args)
+            Ty::new_projection_from_args(tcx, def_id, args)
         } else {
             Ty::new_opaque(tcx, def_id, args)
         }
@@ -2322,92 +2317,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let bound_vars = tcx.late_bound_vars(hir_id);
         debug!(?bound_vars);
 
-        // We proactively collect all the inferred type params to emit a single error per fn def.
-        let mut visitor = HirPlaceholderCollector::default();
-        let mut infer_replacements = vec![];
-
-        if let Some(generics) = generics {
-            walk_generics(&mut visitor, generics);
-        }
-
-        let input_tys: Vec<_> = decl
-            .inputs
-            .iter()
-            .enumerate()
-            .map(|(i, a)| {
-                if let hir::TyKind::Infer = a.kind
-                    && !self.allow_infer()
-                {
-                    if let Some(suggested_ty) =
-                        self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i))
-                    {
-                        infer_replacements.push((a.span, suggested_ty.to_string()));
-                        return Ty::new_error_with_message(
-                            self.tcx(),
-                            a.span,
-                            suggested_ty.to_string(),
-                        );
-                    }
-                }
-
-                // Only visit the type looking for `_` if we didn't fix the type above
-                visitor.visit_ty(a);
-                self.lower_arg_ty(a, None)
-            })
-            .collect();
-
-        let output_ty = match decl.output {
-            hir::FnRetTy::Return(output) => {
-                if let hir::TyKind::Infer = output.kind
-                    && !self.allow_infer()
-                    && let Some(suggested_ty) =
-                        self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, None)
-                {
-                    infer_replacements.push((output.span, suggested_ty.to_string()));
-                    Ty::new_error_with_message(self.tcx(), output.span, suggested_ty.to_string())
-                } else {
-                    visitor.visit_ty(output);
-                    self.lower_ty(output)
-                }
-            }
-            hir::FnRetTy::DefaultReturn(..) => tcx.types.unit,
-        };
+        let (input_tys, output_ty) = self.lower_fn_sig(decl, generics, hir_id, hir_ty);
 
         debug!(?output_ty);
 
         let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, safety, abi);
         let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars);
 
-        if !self.allow_infer() && !(visitor.0.is_empty() && infer_replacements.is_empty()) {
-            // We always collect the spans for placeholder types when evaluating `fn`s, but we
-            // only want to emit an error complaining about them if infer types (`_`) are not
-            // allowed. `allow_infer` gates this behavior. We check for the presence of
-            // `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`.
-
-            let mut diag = crate::collect::placeholder_type_error_diag(
-                tcx,
-                generics,
-                visitor.0,
-                infer_replacements.iter().map(|(s, _)| *s).collect(),
-                true,
-                hir_ty,
-                "function",
-            );
-
-            if !infer_replacements.is_empty() {
-                diag.multipart_suggestion(
-                    format!(
-                    "try replacing `_` with the type{} in the corresponding trait method signature",
-                    rustc_errors::pluralize!(infer_replacements.len()),
-                ),
-                    infer_replacements,
-                    Applicability::MachineApplicable,
-                );
-            }
-
-            self.set_tainted_by_errors(diag.emit());
-        }
-
         // Find any late-bound regions declared in return type that do
         // not appear in the arguments. These are not well-formed.
         //
@@ -2422,7 +2338,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         self.validate_late_bound_regions(late_bound_in_args, late_bound_in_ret, |br_name| {
             struct_span_code_err!(
-                tcx.dcx(),
+                self.dcx(),
                 decl.output.span(),
                 E0581,
                 "return type references {}, which is not constrained by the fn input types",
@@ -2437,7 +2353,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     /// corresponding function in the trait that the impl implements, if it exists.
     /// If arg_idx is Some, then it corresponds to an input type index, otherwise it
     /// corresponds to the return type.
-    fn suggest_trait_fn_ty_for_impl_fn_infer(
+    pub(super) fn suggest_trait_fn_ty_for_impl_fn_infer(
         &self,
         fn_hir_id: HirId,
         arg_idx: Option<usize>,
@@ -2473,11 +2389,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     }
 
     #[instrument(level = "trace", skip(self, generate_err))]
-    fn validate_late_bound_regions(
-        &self,
+    fn validate_late_bound_regions<'cx>(
+        &'cx self,
         constrained_regions: FxHashSet<ty::BoundRegionKind>,
         referenced_regions: FxHashSet<ty::BoundRegionKind>,
-        generate_err: impl Fn(&str) -> Diag<'tcx>,
+        generate_err: impl Fn(&str) -> Diag<'cx>,
     ) {
         for br in referenced_regions.difference(&constrained_regions) {
             let br_name = match *br {
@@ -2502,7 +2418,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 err.note("consider introducing a named lifetime parameter");
             }
 
-            self.set_tainted_by_errors(err.emit());
+            err.emit();
         }
     }
 
@@ -2543,7 +2459,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         // error.
         let r = derived_region_bounds[0];
         if derived_region_bounds[1..].iter().any(|r1| r != *r1) {
-            self.set_tainted_by_errors(tcx.dcx().emit_err(AmbiguousLifetimeBound { span }));
+            self.dcx().emit_err(AmbiguousLifetimeBound { span });
         }
         Some(r)
     }
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs
index 4f7a39d0250..aafadc7f9cb 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs
@@ -1,5 +1,7 @@
 use crate::bounds::Bounds;
-use crate::hir_ty_lowering::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds};
+use crate::hir_ty_lowering::{
+    GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds, RegionInferReason,
+};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_errors::{codes::*, struct_span_code_err};
 use rustc_hir as hir;
@@ -11,7 +13,7 @@ use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::{self, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable};
 use rustc_middle::ty::{DynKind, Upcast};
 use rustc_span::{ErrorGuaranteed, Span};
-use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
+use rustc_trait_selection::error_reporting::traits::report_object_safety_error;
 use rustc_trait_selection::traits::{self, hir_ty_lowering_object_safety_violations};
 
 use smallvec::{smallvec, SmallVec};
@@ -57,7 +59,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         let mut trait_bounds = vec![];
         let mut projection_bounds = vec![];
-        for (pred, span) in bounds.clauses() {
+        for (pred, span) in bounds.clauses(tcx) {
             let bound_pred = pred.kind();
             match bound_pred.skip_binder() {
                 ty::ClauseKind::Trait(trait_pred) => {
@@ -131,7 +133,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                             tcx.associated_items(pred.def_id())
                                 .in_definition_order()
                                 .filter(|item| item.kind == ty::AssocKind::Type)
-                                .filter(|item| !item.is_impl_trait_in_trait())
+                                .filter(|item| {
+                                    !item.is_impl_trait_in_trait() && !item.is_effects_desugaring
+                                })
                                 .map(|item| item.def_id),
                         );
                     }
@@ -141,9 +145,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         // `trait_object_dummy_self`, so check for that.
                         let references_self = match pred.skip_binder().term.unpack() {
                             ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
-                            ty::TermKind::Const(c) => {
-                                c.ty().walk().any(|arg| arg == dummy_self.into())
-                            }
+                            // FIXME(associated_const_equality): We should walk the const instead of not doing anything
+                            ty::TermKind::Const(_) => false,
                         };
 
                         // If the projection output contains `Self`, force the user to
@@ -233,7 +236,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                             Ty::new_misc_error(tcx).into()
                         } else if arg.walk().any(|arg| arg == dummy_self.into()) {
                             references_self = true;
-                            let guar = tcx.dcx().span_delayed_bug(
+                            let guar = self.dcx().span_delayed_bug(
                                 span,
                                 "trait object trait bounds reference `Self`",
                             );
@@ -259,8 +262,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
                 if references_self {
                     let def_id = i.bottom().0.def_id();
-                    let reported = struct_span_code_err!(
-                        tcx.dcx(),
+                    struct_span_code_err!(
+                        self.dcx(),
                         i.bottom().1,
                         E0038,
                         "the {} `{}` cannot be made into an object",
@@ -272,7 +275,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                             .error_msg(),
                     )
                     .emit();
-                    self.set_tainted_by_errors(reported);
                 }
 
                 ty::ExistentialTraitRef { def_id: trait_ref.def_id, args }
@@ -321,30 +323,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         // Use explicitly-specified region bound.
         let region_bound = if !lifetime.is_elided() {
-            self.lower_lifetime(lifetime, None)
+            self.lower_lifetime(lifetime, RegionInferReason::ObjectLifetimeDefault)
         } else {
             self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| {
                 if tcx.named_bound_var(lifetime.hir_id).is_some() {
-                    self.lower_lifetime(lifetime, None)
+                    self.lower_lifetime(lifetime, RegionInferReason::ObjectLifetimeDefault)
                 } else {
-                    self.re_infer(None, span).unwrap_or_else(|| {
-                        let err = struct_span_code_err!(
-                            tcx.dcx(),
-                            span,
-                            E0228,
-                            "the lifetime bound for this object type cannot be deduced \
-                             from context; please supply an explicit bound"
-                        );
-                        let e = if borrowed {
-                            // We will have already emitted an error E0106 complaining about a
-                            // missing named lifetime in `&dyn Trait`, so we elide this one.
-                            err.delay_as_bug()
+                    self.re_infer(
+                        span,
+                        if borrowed {
+                            RegionInferReason::ObjectLifetimeDefault
                         } else {
-                            err.emit()
-                        };
-                        self.set_tainted_by_errors(e);
-                        ty::Region::new_error(tcx, e)
-                    })
+                            RegionInferReason::BorrowedObjectLifetimeDefault
+                        },
+                    )
                 }
             })
         };
diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
index 10101aa046e..13993a1992b 100644
--- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
@@ -67,7 +67,7 @@ fn diagnostic_hir_wf_check<'tcx>(
     impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> {
         fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
             let infcx = self.tcx.infer_ctxt().build();
-            let ocx = ObligationCtxt::new(&infcx);
+            let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
             let tcx_ty = self.icx.lower_ty(ty);
             // This visitor can walk into binders, resulting in the `tcx_ty` to
@@ -158,7 +158,7 @@ fn diagnostic_hir_wf_check<'tcx>(
             },
             hir::Node::Field(field) => vec![field.ty],
             hir::Node::ForeignItem(ForeignItem {
-                kind: ForeignItemKind::Static(ty, _), ..
+                kind: ForeignItemKind::Static(ty, _, _), ..
             }) => vec![*ty],
             hir::Node::GenericParam(hir::GenericParam {
                 kind: hir::GenericParamKind::Type { default: Some(ty), .. },
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
index 002be61196a..5cc1ec71757 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
@@ -86,6 +86,8 @@ fn enforce_impl_params_are_constrained(
     let impl_predicates = tcx.predicates_of(impl_def_id);
     let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::instantiate_identity);
 
+    impl_trait_ref.error_reported()?;
+
     let mut input_parameters = cgp::parameters_for_impl(tcx, impl_self_ty, impl_trait_ref);
     cgp::identify_constrained_generic_params(
         tcx,
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index 6967cb4d9d0..5b8b6e98125 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -78,7 +78,7 @@ use rustc_middle::ty::trait_def::TraitSpecializationKind;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
 use rustc_middle::ty::{GenericArg, GenericArgs, GenericArgsRef};
 use rustc_span::{ErrorGuaranteed, Span};
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
+use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt;
 use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_trait_selection::traits::{self, translate_args_with_cause, wf, ObligationCtxt};
 
@@ -196,7 +196,7 @@ fn get_impl_args(
     impl2_node: Node,
 ) -> Result<(GenericArgsRef<'_>, GenericArgsRef<'_>), ErrorGuaranteed> {
     let infcx = &tcx.infer_ctxt().build();
-    let ocx = ObligationCtxt::new(infcx);
+    let ocx = ObligationCtxt::new_with_diagnostics(infcx);
     let param_env = tcx.param_env(impl1_def_id);
     let impl1_span = tcx.def_span(impl1_def_id);
     let assumed_wf_types = ocx.assumed_wf_types_and_report_errors(param_env, impl1_def_id)?;
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index d1e50e13894..dd7fbba753b 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -55,22 +55,24 @@ This API is completely unstable and subject to change.
 
 */
 
+// tidy-alphabetical-start
+#![allow(internal_features)]
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::potential_query_instability)]
 #![allow(rustc::untranslatable_diagnostic)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
-#![feature(rustdoc_internals)]
-#![allow(internal_features)]
 #![feature(control_flow_enum)]
 #![feature(if_let_guard)]
 #![feature(is_sorted)]
 #![feature(iter_intersperse)]
 #![feature(let_chains)]
 #![feature(never_type)]
-#![feature(lazy_cell)]
+#![feature(rustdoc_internals)]
 #![feature(slice_partition_dedup)]
 #![feature(try_blocks)]
+#![feature(unwrap_infallible)]
+// tidy-alphabetical-end
 
 #[macro_use]
 extern crate tracing;
@@ -90,7 +92,6 @@ mod errors;
 pub mod hir_wf_check;
 mod impl_wf_check;
 mod outlives;
-pub mod structured_errors;
 mod variance;
 
 use rustc_hir as hir;
@@ -150,8 +151,10 @@ pub fn provide(providers: &mut Providers) {
 pub fn check_crate(tcx: TyCtxt<'_>) {
     let _prof_timer = tcx.sess.timer("type_check_crate");
 
-    if tcx.features().rustc_attrs {
-        let _ = tcx.sess.time("outlives_testing", || outlives::test::test_inferred_outlives(tcx));
+    // FIXME(effects): remove once effects is implemented in old trait solver
+    // or if the next solver is stabilized.
+    if tcx.features().effects && !tcx.next_trait_solver_globally() {
+        tcx.dcx().emit_err(errors::EffectsWithoutNextSolver);
     }
 
     tcx.sess.time("coherence_checking", || {
@@ -168,11 +171,11 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
     });
 
     if tcx.features().rustc_attrs {
-        let _ = tcx.sess.time("variance_testing", || variance::test::test_variance(tcx));
-    }
-
-    if tcx.features().rustc_attrs {
-        let _ = collect::test_opaque_hidden_types(tcx);
+        tcx.sess.time("outlives_dumping", || outlives::dump::inferred_outlives(tcx));
+        tcx.sess.time("variance_dumping", || variance::dump::variances(tcx));
+        collect::dump::opaque_hidden_types(tcx);
+        collect::dump::predicates_and_item_bounds(tcx);
+        collect::dump::def_parents(tcx);
     }
 
     // Make sure we evaluate all static and (non-associated) const items, even if unused.
diff --git a/compiler/rustc_hir_analysis/src/outlives/dump.rs b/compiler/rustc_hir_analysis/src/outlives/dump.rs
new file mode 100644
index 00000000000..ab50d9e86ef
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/outlives/dump.rs
@@ -0,0 +1,29 @@
+use rustc_middle::bug;
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_span::sym;
+
+pub(crate) fn inferred_outlives(tcx: TyCtxt<'_>) {
+    for id in tcx.hir().items() {
+        if !tcx.has_attr(id.owner_id, sym::rustc_outlives) {
+            continue;
+        }
+
+        let preds = tcx.inferred_outlives_of(id.owner_id);
+        let mut preds: Vec<_> = preds
+            .iter()
+            .map(|(pred, _)| match pred.kind().skip_binder() {
+                ty::ClauseKind::RegionOutlives(p) => p.to_string(),
+                ty::ClauseKind::TypeOutlives(p) => p.to_string(),
+                err => bug!("unexpected clause {:?}", err),
+            })
+            .collect();
+        preds.sort();
+
+        let span = tcx.def_span(id.owner_id);
+        let mut err = tcx.dcx().struct_span_err(span, sym::rustc_outlives.as_str());
+        for pred in preds {
+            err.note(pred);
+        }
+        err.emit();
+    }
+}
diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
index 1de7a0f7bc7..bbfadbb5c30 100644
--- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
@@ -6,7 +6,7 @@ use super::utils::*;
 
 #[derive(Debug)]
 pub struct ExplicitPredicatesMap<'tcx> {
-    map: FxIndexMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>,
+    map: FxIndexMap<DefId, ty::EarlyBinder<'tcx, RequiredPredicates<'tcx>>>,
 }
 
 impl<'tcx> ExplicitPredicatesMap<'tcx> {
@@ -18,7 +18,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
         &mut self,
         tcx: TyCtxt<'tcx>,
         def_id: DefId,
-    ) -> &ty::EarlyBinder<RequiredPredicates<'tcx>> {
+    ) -> &ty::EarlyBinder<'tcx, RequiredPredicates<'tcx>> {
         self.map.entry(def_id).or_insert_with(|| {
             let predicates = if def_id.is_local() {
                 tcx.explicit_predicates_of(def_id)
diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
index e6c582667ba..af08f50f655 100644
--- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
@@ -15,7 +15,7 @@ use super::utils::*;
 ///     now be filled with inferred predicates.
 pub(super) fn infer_predicates(
     tcx: TyCtxt<'_>,
-) -> FxIndexMap<DefId, ty::EarlyBinder<RequiredPredicates<'_>>> {
+) -> FxIndexMap<DefId, ty::EarlyBinder<'_, RequiredPredicates<'_>>> {
     debug!("infer_predicates");
 
     let mut explicit_map = ExplicitPredicatesMap::new();
@@ -101,7 +101,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
     span: Span,
-    global_inferred_outlives: &FxIndexMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>,
+    global_inferred_outlives: &FxIndexMap<DefId, ty::EarlyBinder<'tcx, RequiredPredicates<'tcx>>>,
     required_predicates: &mut RequiredPredicates<'tcx>,
     explicit_map: &mut ExplicitPredicatesMap<'tcx>,
 ) {
@@ -322,7 +322,7 @@ fn check_inferred_predicates<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: DefId,
     args: ty::GenericArgsRef<'tcx>,
-    global_inferred_outlives: &FxIndexMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>,
+    global_inferred_outlives: &FxIndexMap<DefId, ty::EarlyBinder<'tcx, RequiredPredicates<'tcx>>>,
     required_predicates: &mut RequiredPredicates<'tcx>,
 ) {
     // Load the current set of inferred and explicit predicates from `global_inferred_outlives`
diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs
index 97fd7731b1e..1f74ebf99f1 100644
--- a/compiler/rustc_hir_analysis/src/outlives/mod.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs
@@ -5,10 +5,9 @@ use rustc_middle::ty::GenericArgKind;
 use rustc_middle::ty::{self, CratePredicatesMap, TyCtxt, Upcast};
 use rustc_span::Span;
 
+pub(crate) mod dump;
 mod explicit;
 mod implicit_infer;
-/// Code to write unit test for outlives.
-pub mod test;
 mod utils;
 
 pub fn provide(providers: &mut Providers) {
diff --git a/compiler/rustc_hir_analysis/src/outlives/test.rs b/compiler/rustc_hir_analysis/src/outlives/test.rs
deleted file mode 100644
index e9b6c679bd5..00000000000
--- a/compiler/rustc_hir_analysis/src/outlives/test.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-use rustc_middle::bug;
-use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::{symbol::sym, ErrorGuaranteed};
-
-pub fn test_inferred_outlives(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
-    let mut res = Ok(());
-    for id in tcx.hir().items() {
-        // For unit testing: check for a special "rustc_outlives"
-        // attribute and report an error with various results if found.
-        if tcx.has_attr(id.owner_id, sym::rustc_outlives) {
-            let predicates = tcx.inferred_outlives_of(id.owner_id);
-            let mut pred: Vec<String> = predicates
-                .iter()
-                .map(|(out_pred, _)| match out_pred.kind().skip_binder() {
-                    ty::ClauseKind::RegionOutlives(p) => p.to_string(),
-                    ty::ClauseKind::TypeOutlives(p) => p.to_string(),
-                    err => bug!("unexpected clause {:?}", err),
-                })
-                .collect();
-            pred.sort();
-
-            let span = tcx.def_span(id.owner_id);
-            let mut err = tcx.dcx().struct_span_err(span, "rustc_outlives");
-            for p in pred {
-                err.note(p);
-            }
-            res = Err(err.emit());
-        }
-    }
-    res
-}
diff --git a/compiler/rustc_hir_analysis/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs
index 5086c2af3f6..08015c28a26 100644
--- a/compiler/rustc_hir_analysis/src/outlives/utils.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs
@@ -1,9 +1,9 @@
 use rustc_data_structures::fx::FxIndexMap;
-use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
 use rustc_middle::ty::{self, Region, Ty, TyCtxt};
 use rustc_middle::ty::{GenericArg, GenericArgKind};
 use rustc_middle::{bug, span_bug};
 use rustc_span::Span;
+use rustc_type_ir::outlives::{push_outlives_components, Component};
 use smallvec::smallvec;
 
 /// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred
diff --git a/compiler/rustc_hir_analysis/src/structured_errors.rs b/compiler/rustc_hir_analysis/src/structured_errors.rs
deleted file mode 100644
index 5abfd25dd95..00000000000
--- a/compiler/rustc_hir_analysis/src/structured_errors.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-mod missing_cast_for_variadic_arg;
-mod sized_unsized_cast;
-mod wrong_number_of_generic_args;
-
-pub use self::{
-    missing_cast_for_variadic_arg::*, sized_unsized_cast::*, wrong_number_of_generic_args::*,
-};
-
-use rustc_errors::{Diag, ErrCode};
-use rustc_session::Session;
-
-pub trait StructuredDiag<'tcx> {
-    fn session(&self) -> &Session;
-
-    fn code(&self) -> ErrCode;
-
-    fn diagnostic(&self) -> Diag<'tcx> {
-        let err = self.diagnostic_common();
-
-        if self.session().teach(self.code()) {
-            self.diagnostic_extended(err)
-        } else {
-            self.diagnostic_regular(err)
-        }
-    }
-
-    fn diagnostic_common(&self) -> Diag<'tcx>;
-
-    fn diagnostic_regular(&self, err: Diag<'tcx>) -> Diag<'tcx> {
-        err
-    }
-
-    fn diagnostic_extended(&self, err: Diag<'tcx>) -> Diag<'tcx> {
-        err
-    }
-}
diff --git a/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs b/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs
deleted file mode 100644
index 0e78acbeae2..00000000000
--- a/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-use crate::{errors, structured_errors::StructuredDiag};
-use rustc_errors::{codes::*, Diag};
-use rustc_middle::ty::{Ty, TypeVisitableExt};
-use rustc_session::Session;
-use rustc_span::Span;
-
-pub struct MissingCastForVariadicArg<'tcx, 's> {
-    pub sess: &'tcx Session,
-    pub span: Span,
-    pub ty: Ty<'tcx>,
-    pub cast_ty: &'s str,
-}
-
-impl<'tcx> StructuredDiag<'tcx> for MissingCastForVariadicArg<'tcx, '_> {
-    fn session(&self) -> &Session {
-        self.sess
-    }
-
-    fn code(&self) -> ErrCode {
-        E0617
-    }
-
-    fn diagnostic_common(&self) -> Diag<'tcx> {
-        let (sugg_span, replace, help) =
-            if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.span) {
-                (Some(self.span), format!("{} as {}", snippet, self.cast_ty), None)
-            } else {
-                (None, "".to_string(), Some(()))
-            };
-
-        let mut err = self.sess.dcx().create_err(errors::PassToVariadicFunction {
-            span: self.span,
-            ty: self.ty,
-            cast_ty: self.cast_ty,
-            help,
-            replace,
-            sugg_span,
-        });
-
-        if self.ty.references_error() {
-            err.downgrade_to_delayed_bug();
-        }
-
-        err
-    }
-
-    fn diagnostic_extended(&self, mut err: Diag<'tcx>) -> Diag<'tcx> {
-        err.note(format!(
-            "certain types, like `{}`, must be casted before passing them to a \
-                variadic function, because of arcane ABI rules dictated by the C \
-                standard",
-            self.ty
-        ));
-
-        err
-    }
-}
diff --git a/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs b/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs
deleted file mode 100644
index 9e871ff9af0..00000000000
--- a/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-use crate::{errors, structured_errors::StructuredDiag};
-use rustc_errors::{codes::*, Diag};
-use rustc_middle::ty::{Ty, TypeVisitableExt};
-use rustc_session::Session;
-use rustc_span::Span;
-
-pub struct SizedUnsizedCast<'tcx> {
-    pub sess: &'tcx Session,
-    pub span: Span,
-    pub expr_ty: Ty<'tcx>,
-    pub cast_ty: String,
-}
-
-impl<'tcx> StructuredDiag<'tcx> for SizedUnsizedCast<'tcx> {
-    fn session(&self) -> &Session {
-        self.sess
-    }
-
-    fn code(&self) -> ErrCode {
-        E0607
-    }
-
-    fn diagnostic_common(&self) -> Diag<'tcx> {
-        let mut err = self.sess.dcx().create_err(errors::CastThinPointerToFatPointer {
-            span: self.span,
-            expr_ty: self.expr_ty,
-            cast_ty: self.cast_ty.to_owned(),
-        });
-
-        if self.expr_ty.references_error() {
-            err.downgrade_to_delayed_bug();
-        }
-
-        err
-    }
-
-    fn diagnostic_extended(&self, mut err: Diag<'tcx>) -> Diag<'tcx> {
-        err.help(
-            "Thin pointers are \"simple\" pointers: they are purely a reference to a
-memory address.
-
-Fat pointers are pointers referencing \"Dynamically Sized Types\" (also
-called DST). DST don't have a statically known size, therefore they can
-only exist behind some kind of pointers that contain additional
-information. Slices and trait objects are DSTs. In the case of slices,
-the additional information the fat pointer holds is their size.
-
-To fix this error, don't try to cast directly between thin and fat
-pointers.
-
-For more information about casts, take a look at The Book:
-https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions",
-        );
-        err
-    }
-}
diff --git a/compiler/rustc_hir_analysis/src/variance/dump.rs b/compiler/rustc_hir_analysis/src/variance/dump.rs
new file mode 100644
index 00000000000..1a17dabb677
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/variance/dump.rs
@@ -0,0 +1,32 @@
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::CRATE_DEF_ID;
+use rustc_middle::ty::TyCtxt;
+use rustc_span::symbol::sym;
+
+pub(crate) fn variances(tcx: TyCtxt<'_>) {
+    if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) {
+        for id in tcx.hir().items() {
+            let DefKind::OpaqueTy = tcx.def_kind(id.owner_id) else { continue };
+
+            let variances = tcx.variances_of(id.owner_id);
+
+            tcx.dcx().emit_err(crate::errors::VariancesOf {
+                span: tcx.def_span(id.owner_id),
+                variances: format!("{variances:?}"),
+            });
+        }
+    }
+
+    for id in tcx.hir().items() {
+        if !tcx.has_attr(id.owner_id, sym::rustc_variance) {
+            continue;
+        }
+
+        let variances = tcx.variances_of(id.owner_id);
+
+        tcx.dcx().emit_err(crate::errors::VariancesOf {
+            span: tcx.def_span(id.owner_id),
+            variances: format!("{variances:?}"),
+        });
+    }
+}
diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs
index 1977451f39e..29f96e27b64 100644
--- a/compiler/rustc_hir_analysis/src/variance/mod.rs
+++ b/compiler/rustc_hir_analysis/src/variance/mod.rs
@@ -22,8 +22,7 @@ mod constraints;
 /// Code to solve constraints and write out the results.
 mod solve;
 
-/// Code to write unit tests of variance.
-pub mod test;
+pub(crate) mod dump;
 
 /// Code for transforming variances.
 mod xform;
diff --git a/compiler/rustc_hir_analysis/src/variance/test.rs b/compiler/rustc_hir_analysis/src/variance/test.rs
deleted file mode 100644
index c211e1af046..00000000000
--- a/compiler/rustc_hir_analysis/src/variance/test.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-use rustc_hir::def::DefKind;
-use rustc_hir::def_id::CRATE_DEF_ID;
-use rustc_middle::ty::TyCtxt;
-use rustc_span::symbol::sym;
-use rustc_span::ErrorGuaranteed;
-
-use crate::errors;
-
-pub fn test_variance(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
-    let mut res = Ok(());
-    if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) {
-        for id in tcx.hir().items() {
-            if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) {
-                let variances_of = tcx.variances_of(id.owner_id);
-
-                res = Err(tcx.dcx().emit_err(errors::VariancesOf {
-                    span: tcx.def_span(id.owner_id),
-                    variances_of: format!("{variances_of:?}"),
-                }));
-            }
-        }
-    }
-
-    // For unit testing: check for a special "rustc_variance"
-    // attribute and report an error with various results if found.
-    for id in tcx.hir().items() {
-        if tcx.has_attr(id.owner_id, sym::rustc_variance) {
-            let variances_of = tcx.variances_of(id.owner_id);
-
-            res = Err(tcx.dcx().emit_err(errors::VariancesOf {
-                span: tcx.def_span(id.owner_id),
-                variances_of: format!("{variances_of:?}"),
-            }));
-        }
-    }
-    res
-}