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/astconv/generics.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/check/_match.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/callee.rs142
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs138
-rw-r--r--compiler/rustc_hir_analysis/src/check/coercion.rs13
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_method.rs1048
-rw-r--r--compiler/rustc_hir_analysis/src/check/demand.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/check/expr.rs29
-rw-r--r--compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs13
-rw-r--r--compiler/rustc_hir_analysis/src/check/fn_ctxt/checks.rs14
-rw-r--r--compiler/rustc_hir_analysis/src/check/fn_ctxt/mod.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs18
-rw-r--r--compiler/rustc_hir_analysis/src/check/inherited.rs36
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsicck.rs20
-rw-r--r--compiler/rustc_hir_analysis/src/check/method/probe.rs116
-rw-r--r--compiler/rustc_hir_analysis/src/check/method/suggest.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/op.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs75
-rw-r--r--compiler/rustc_hir_analysis/src/check/writeback.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs646
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/constrained_generic_params.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/expr_use_visitor.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/hir_wf_check.rs58
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs87
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs66
-rw-r--r--compiler/rustc_hir_analysis/src/mem_categorization.rs6
30 files changed, 1364 insertions, 1233 deletions
diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs
index b66e59d8ac6..47915b4bd4e 100644
--- a/compiler/rustc_hir_analysis/src/astconv/generics.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs
@@ -83,9 +83,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 Res::Def(DefKind::TyParam, src_def_id) => {
                     if let Some(param_local_id) = param.def_id.as_local() {
                         let param_name = tcx.hir().ty_param_name(param_local_id);
-                        let param_type = tcx.infer_ctxt().enter(|infcx| {
-                            infcx.resolve_numeric_literals_with_default(tcx.type_of(param.def_id))
-                        });
+                        let infcx = tcx.infer_ctxt().build();
+                        let param_type =
+                            infcx.resolve_numeric_literals_with_default(tcx.type_of(param.def_id));
                         if param_type.is_suggestable(tcx, false) {
                             err.span_suggestion(
                                 tcx.def_span(src_def_id),
diff --git a/compiler/rustc_hir_analysis/src/check/_match.rs b/compiler/rustc_hir_analysis/src/check/_match.rs
index 201927091a6..143508b785f 100644
--- a/compiler/rustc_hir_analysis/src/check/_match.rs
+++ b/compiler/rustc_hir_analysis/src/check/_match.rs
@@ -259,7 +259,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 err.help("consider adding an `else` block that evaluates to the expected type");
                 error = true;
             },
-            ret_reason.is_none(),
+            false,
         );
         error
     }
diff --git a/compiler/rustc_hir_analysis/src/check/callee.rs b/compiler/rustc_hir_analysis/src/check/callee.rs
index 080771844a4..f0a7c910906 100644
--- a/compiler/rustc_hir_analysis/src/check/callee.rs
+++ b/compiler/rustc_hir_analysis/src/check/callee.rs
@@ -1,8 +1,10 @@
+use super::method::probe::{IsSuggestion, Mode, ProbeScope};
 use super::method::MethodCallee;
 use super::{DefIdOrName, Expectation, FnCtxt, TupleArgumentsFlag};
 use crate::type_error_struct;
 
-use rustc_errors::{struct_span_err, Applicability, Diagnostic};
+use rustc_ast::util::parser::PREC_POSTFIX;
+use rustc_errors::{struct_span_err, Applicability, Diagnostic, StashKey};
 use rustc_hir as hir;
 use rustc_hir::def::{self, Namespace, Res};
 use rustc_hir::def_id::DefId;
@@ -60,6 +62,7 @@ pub fn check_legal_trait_for_method_call(
     }
 }
 
+#[derive(Debug)]
 enum CallStep<'tcx> {
     Builtin(Ty<'tcx>),
     DeferredClosure(LocalDefId, ty::FnSig<'tcx>),
@@ -188,6 +191,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 return None;
             }
 
+            ty::Error(_) => {
+                return None;
+            }
+
             _ => {}
         }
 
@@ -394,6 +401,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             ty::FnPtr(sig) => (sig, None),
             _ => {
+                if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = &callee_expr.kind
+                    && let [segment] = path.segments
+                    && let Some(mut diag) = self
+                        .tcx
+                        .sess
+                        .diagnostic()
+                        .steal_diagnostic(segment.ident.span, StashKey::CallIntoMethod)
+                {
+                    // Try suggesting `foo(a)` -> `a.foo()` if possible.
+                    if let Some(ty) =
+                        self.suggest_call_as_method(
+                            &mut diag,
+                            segment,
+                            arg_exprs,
+                            call_expr,
+                            expected
+                        )
+                    {
+                        diag.emit();
+                        return ty;
+                    } else {
+                        diag.emit();
+                    }
+                }
+
                 self.report_invalid_callee(call_expr, callee_expr, callee_ty, arg_exprs);
 
                 // This is the "default" function signature, used in case of error.
@@ -441,6 +473,105 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         fn_sig.output()
     }
 
+    /// Attempts to reinterpret `method(rcvr, args...)` as `rcvr.method(args...)`
+    /// and suggesting the fix if the method probe is successful.
+    fn suggest_call_as_method(
+        &self,
+        diag: &mut Diagnostic,
+        segment: &'tcx hir::PathSegment<'tcx>,
+        arg_exprs: &'tcx [hir::Expr<'tcx>],
+        call_expr: &'tcx hir::Expr<'tcx>,
+        expected: Expectation<'tcx>,
+    ) -> Option<Ty<'tcx>> {
+        if let [callee_expr, rest @ ..] = arg_exprs {
+            let callee_ty = self.check_expr(callee_expr);
+            // First, do a probe with `IsSuggestion(true)` to avoid emitting
+            // any strange errors. If it's successful, then we'll do a true
+            // method lookup.
+            let Ok(pick) = self
+            .probe_for_name(
+                call_expr.span,
+                Mode::MethodCall,
+                segment.ident,
+                IsSuggestion(true),
+                callee_ty,
+                call_expr.hir_id,
+                // We didn't record the in scope traits during late resolution
+                // so we need to probe AllTraits unfortunately
+                ProbeScope::AllTraits,
+            ) else {
+                return None;
+            };
+
+            let pick = self.confirm_method(
+                call_expr.span,
+                callee_expr,
+                call_expr,
+                callee_ty,
+                pick,
+                segment,
+            );
+            if pick.illegal_sized_bound.is_some() {
+                return None;
+            }
+
+            let up_to_rcvr_span = segment.ident.span.until(callee_expr.span);
+            let rest_span = callee_expr.span.shrink_to_hi().to(call_expr.span.shrink_to_hi());
+            let rest_snippet = if let Some(first) = rest.first() {
+                self.tcx
+                    .sess
+                    .source_map()
+                    .span_to_snippet(first.span.to(call_expr.span.shrink_to_hi()))
+            } else {
+                Ok(")".to_string())
+            };
+
+            if let Ok(rest_snippet) = rest_snippet {
+                let sugg = if callee_expr.precedence().order() >= PREC_POSTFIX {
+                    vec![
+                        (up_to_rcvr_span, "".to_string()),
+                        (rest_span, format!(".{}({rest_snippet}", segment.ident)),
+                    ]
+                } else {
+                    vec![
+                        (up_to_rcvr_span, "(".to_string()),
+                        (rest_span, format!(").{}({rest_snippet}", segment.ident)),
+                    ]
+                };
+                let self_ty = self.resolve_vars_if_possible(pick.callee.sig.inputs()[0]);
+                diag.multipart_suggestion(
+                    format!(
+                        "use the `.` operator to call the method `{}{}` on `{self_ty}`",
+                        self.tcx
+                            .associated_item(pick.callee.def_id)
+                            .trait_container(self.tcx)
+                            .map_or_else(
+                                || String::new(),
+                                |trait_def_id| self.tcx.def_path_str(trait_def_id) + "::"
+                            ),
+                        segment.ident
+                    ),
+                    sugg,
+                    Applicability::MaybeIncorrect,
+                );
+
+                // Let's check the method fully now
+                let return_ty = self.check_method_argument_types(
+                    segment.ident.span,
+                    call_expr,
+                    Ok(pick.callee),
+                    rest,
+                    TupleArgumentsFlag::DontTupleArguments,
+                    expected,
+                );
+
+                return Some(return_ty);
+            }
+        }
+
+        None
+    }
+
     fn report_invalid_callee(
         &self,
         call_expr: &'tcx hir::Expr<'tcx>,
@@ -459,10 +590,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 def::CtorOf::Struct => "struct",
                 def::CtorOf::Variant => "enum variant",
             };
-            let removal_span =
-                callee_expr.span.shrink_to_hi().to(call_expr.span.shrink_to_hi());
-            unit_variant =
-                Some((removal_span, descr, rustc_hir_pretty::qpath_to_string(qpath)));
+            let removal_span = callee_expr.span.shrink_to_hi().to(call_expr.span.shrink_to_hi());
+            unit_variant = Some((removal_span, descr, rustc_hir_pretty::qpath_to_string(qpath)));
         }
 
         let callee_ty = self.resolve_vars_if_possible(callee_ty);
@@ -525,7 +654,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) {
-            if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_expr, callee_ty)
+            if let Some((maybe_def, output_ty, _)) =
+                self.extract_callable_info(callee_expr, callee_ty)
                 && !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span)
             {
                 let descr = match maybe_def {
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 824144aeac0..77ab27266b2 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -2,7 +2,7 @@ use crate::check::intrinsicck::InlineAsmCtxt;
 
 use super::coercion::CoerceMany;
 use super::compare_method::check_type_bounds;
-use super::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl};
+use super::compare_method::{compare_impl_method, compare_ty_impl};
 use super::*;
 use rustc_attr as attr;
 use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
@@ -29,9 +29,8 @@ use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVE
 use rustc_span::symbol::sym;
 use rustc_span::{self, Span};
 use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::{self, ObligationCtxt};
-use rustc_ty_utils::representability::{self, Representability};
 
 use std::ops::ControlFlow;
 
@@ -78,7 +77,7 @@ pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ab
 /// * inherited: other fields inherited from the enclosing fn (if any)
 #[instrument(skip(inherited, body), level = "debug")]
 pub(super) fn check_fn<'a, 'tcx>(
-    inherited: &'a Inherited<'a, 'tcx>,
+    inherited: &'a Inherited<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     fn_sig: ty::FnSig<'tcx>,
     decl: &'tcx hir::FnDecl<'tcx>,
@@ -381,7 +380,7 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     let def = tcx.adt_def(def_id);
     let span = tcx.def_span(def_id);
     def.destructor(tcx); // force the destructor to be evaluated
-    check_representable(tcx, span, def_id);
+    let _ = tcx.representability(def_id);
 
     if def.repr().simd() {
         check_simd(tcx, span, def_id);
@@ -395,7 +394,7 @@ fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     let def = tcx.adt_def(def_id);
     let span = tcx.def_span(def_id);
     def.destructor(tcx); // force the destructor to be evaluated
-    check_representable(tcx, span, def_id);
+    let _ = tcx.representability(def_id);
     check_transparent(tcx, span, def);
     check_union_fields(tcx, span, def_id);
     check_packed(tcx, span, def);
@@ -708,10 +707,12 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
 /// check those cases in the `param_env` of that function, which may have
 /// bounds not on this opaque type:
 ///
-/// type X<T> = impl Clone
+/// ```ignore (illustrative)
+/// type X<T> = impl Clone;
 /// fn f<T: Clone>(t: T) -> X<T> {
 ///     t
 /// }
+/// ```
 ///
 /// Without this check the above code is incorrectly accepted: we would ICE if
 /// some tried, for example, to clone an `Option<X<&mut ()>>`.
@@ -732,52 +733,52 @@ fn check_opaque_meets_bounds<'tcx>(
     };
     let param_env = tcx.param_env(defining_use_anchor);
 
-    tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(defining_use_anchor)).enter(
-        move |infcx| {
-            let ocx = ObligationCtxt::new(&infcx);
-            let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
+    let infcx = tcx
+        .infer_ctxt()
+        .with_opaque_type_inference(DefiningAnchor::Bind(defining_use_anchor))
+        .build();
+    let ocx = ObligationCtxt::new(&infcx);
+    let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
 
-            let misc_cause = traits::ObligationCause::misc(span, hir_id);
+    let misc_cause = traits::ObligationCause::misc(span, hir_id);
 
-            match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_type) {
-                Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok),
-                Err(ty_err) => {
-                    tcx.sess.delay_span_bug(
-                        span,
-                        &format!("could not unify `{hidden_type}` with revealed type:\n{ty_err}"),
-                    );
-                }
-            }
+    match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_type) {
+        Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok),
+        Err(ty_err) => {
+            tcx.sess.delay_span_bug(
+                span,
+                &format!("could not unify `{hidden_type}` with revealed type:\n{ty_err}"),
+            );
+        }
+    }
 
-            // Additionally require the hidden type to be well-formed with only the generics of the opaque type.
-            // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
-            // hidden type is well formed even without those bounds.
-            let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_type.into()))
-                .to_predicate(tcx);
-            ocx.register_obligation(Obligation::new(misc_cause, param_env, predicate));
-
-            // Check that all obligations are satisfied by the implementation's
-            // version.
-            let errors = ocx.select_all_or_error();
-            if !errors.is_empty() {
-                infcx.report_fulfillment_errors(&errors, None, false);
-            }
-            match origin {
-                // Checked when type checking the function containing them.
-                hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
-                // Can have different predicates to their defining use
-                hir::OpaqueTyOrigin::TyAlias => {
-                    let outlives_environment = OutlivesEnvironment::new(param_env);
-                    infcx.check_region_obligations_and_report_errors(
-                        defining_use_anchor,
-                        &outlives_environment,
-                    );
-                }
-            }
-            // Clean up after ourselves
-            let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
-        },
-    );
+    // Additionally require the hidden type to be well-formed with only the generics of the opaque type.
+    // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
+    // hidden type is well formed even without those bounds.
+    let predicate =
+        ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_type.into())).to_predicate(tcx);
+    ocx.register_obligation(Obligation::new(misc_cause, param_env, predicate));
+
+    // Check that all obligations are satisfied by the implementation's
+    // version.
+    let errors = ocx.select_all_or_error();
+    if !errors.is_empty() {
+        infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+    }
+    match origin {
+        // Checked when type checking the function containing them.
+        hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
+        // Can have different predicates to their defining use
+        hir::OpaqueTyOrigin::TyAlias => {
+            let outlives_environment = OutlivesEnvironment::new(param_env);
+            infcx.check_region_obligations_and_report_errors(
+                defining_use_anchor,
+                &outlives_environment,
+            );
+        }
+    }
+    // Clean up after ourselves
+    let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
 }
 
 fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
@@ -1048,14 +1049,10 @@ fn check_impl_items_against_trait<'tcx>(
         let impl_item_full = tcx.hir().impl_item(impl_item.id);
         match impl_item_full.kind {
             hir::ImplItemKind::Const(..) => {
-                // Find associated const definition.
-                compare_const_impl(
-                    tcx,
-                    &ty_impl_item,
-                    impl_item.span,
-                    &ty_trait_item,
-                    impl_trait_ref,
-                );
+                let _ = tcx.compare_assoc_const_impl_item_with_trait_item((
+                    impl_item.id.def_id.def_id,
+                    ty_impl_item.trait_item_def_id.unwrap(),
+                ));
             }
             hir::ImplItemKind::Fn(..) => {
                 let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
@@ -1067,7 +1064,7 @@ fn check_impl_items_against_trait<'tcx>(
                     opt_trait_span,
                 );
             }
-            hir::ImplItemKind::TyAlias(impl_ty) => {
+            hir::ImplItemKind::Type(impl_ty) => {
                 let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
                 compare_ty_impl(
                     tcx,
@@ -1155,27 +1152,6 @@ fn check_impl_items_against_trait<'tcx>(
     }
 }
 
-/// Checks whether a type can be represented in memory. In particular, it
-/// identifies types that contain themselves without indirection through a
-/// pointer, which would mean their size is unbounded.
-pub(super) fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: LocalDefId) -> bool {
-    let rty = tcx.type_of(item_def_id);
-
-    // Check that it is possible to represent this type. This call identifies
-    // (1) types that contain themselves and (2) types that contain a different
-    // recursive type. It is only necessary to throw an error on those that
-    // contain themselves. For case 2, there must be an inner type that will be
-    // caught by case 1.
-    match representability::ty_is_representable(tcx, rty, sp, None) {
-        Representability::SelfRecursive(spans) => {
-            recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id(), spans);
-            return false;
-        }
-        Representability::Representable | Representability::ContainsRecursive => (),
-    }
-    true
-}
-
 pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
     let t = tcx.type_of(def_id);
     if let ty::Adt(def, substs) = t.kind()
@@ -1513,7 +1489,7 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L
 
     detect_discriminant_duplicate(tcx, def.discriminants(tcx).collect(), vs, sp);
 
-    check_representable(tcx, sp, def_id);
+    let _ = tcx.representability(def_id);
     check_transparent(tcx, sp, def);
 }
 
diff --git a/compiler/rustc_hir_analysis/src/check/coercion.rs b/compiler/rustc_hir_analysis/src/check/coercion.rs
index d738e563256..cf87fe3c510 100644
--- a/compiler/rustc_hir_analysis/src/check/coercion.rs
+++ b/compiler/rustc_hir_analysis/src/check/coercion.rs
@@ -61,7 +61,7 @@ use rustc_span::symbol::sym;
 use rustc_span::{self, BytePos, DesugaringKind, Span};
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
 
 use smallvec::{smallvec, SmallVec};
@@ -702,7 +702,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
 
                 // Object safety violations or miscellaneous.
                 Err(err) => {
-                    self.report_selection_error(obligation.clone(), &obligation, &err, false);
+                    self.err_ctxt().report_selection_error(
+                        obligation.clone(),
+                        &obligation,
+                        &err,
+                        false,
+                    );
                     // Treat this like an obligation and follow through
                     // with the unsizing - the lack of a coercion should
                     // be silent, as it causes a type mismatch later.
@@ -1549,7 +1554,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                         }
                     }
                     _ => {
-                        err = fcx.report_mismatched_types(
+                        err = fcx.err_ctxt().report_mismatched_types(
                             cause,
                             expected,
                             found,
@@ -1629,7 +1634,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
         expression: Option<&'tcx hir::Expr<'tcx>>,
         blk_id: Option<hir::HirId>,
     ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-        let mut err = fcx.report_mismatched_types(cause, expected, found, ty_err);
+        let mut err = fcx.err_ctxt().report_mismatched_types(cause, expected, found, ty_err);
 
         let mut pointing_at_return_type = false;
         let mut fn_output = None;
diff --git a/compiler/rustc_hir_analysis/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_method.rs
index ae98a8f6209..5e5dbedb4bd 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_method.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_method.rs
@@ -1,6 +1,6 @@
 use super::potentially_plural_count;
 use crate::errors::LifetimesOrBoundsMismatchOnTrait;
-use hir::def_id::DefId;
+use hir::def_id::{DefId, LocalDefId};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
 use rustc_hir as hir;
@@ -19,7 +19,7 @@ use rustc_middle::ty::{
 };
 use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
 use rustc_span::Span;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
+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,
@@ -215,224 +215,220 @@ fn compare_predicate_entailment<'tcx>(
     );
     let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
 
-    tcx.infer_ctxt().enter(|ref infcx| {
-        let ocx = ObligationCtxt::new(infcx);
+    let infcx = &tcx.infer_ctxt().build();
+    let ocx = ObligationCtxt::new(infcx);
 
-        debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds());
+    debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds());
 
-        let mut selcx = traits::SelectionContext::new(&infcx);
-        let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs);
-        for (predicate, span) in iter::zip(impl_m_own_bounds.predicates, impl_m_own_bounds.spans) {
-            let normalize_cause = traits::ObligationCause::misc(span, impl_m_hir_id);
-            let traits::Normalized { value: predicate, obligations } =
-                traits::normalize(&mut selcx, param_env, normalize_cause, predicate);
+    let mut selcx = traits::SelectionContext::new(&infcx);
+    let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs);
+    for (predicate, span) in iter::zip(impl_m_own_bounds.predicates, impl_m_own_bounds.spans) {
+        let normalize_cause = traits::ObligationCause::misc(span, impl_m_hir_id);
+        let traits::Normalized { value: predicate, obligations } =
+            traits::normalize(&mut selcx, param_env, normalize_cause, predicate);
 
-            ocx.register_obligations(obligations);
-            let cause = ObligationCause::new(
-                span,
-                impl_m_hir_id,
-                ObligationCauseCode::CompareImplItemObligation {
-                    impl_item_def_id: impl_m.def_id.expect_local(),
-                    trait_item_def_id: trait_m.def_id,
-                    kind: impl_m.kind,
-                },
-            );
-            ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate));
-        }
-
-        // We now need to check that the signature of the impl method is
-        // compatible with that of the trait method. We do this by
-        // checking that `impl_fty <: trait_fty`.
-        //
-        // FIXME. Unfortunately, this doesn't quite work right now because
-        // associated type normalization is not integrated into subtype
-        // checks. For the comparison to be valid, we need to
-        // normalize the associated types in the impl/trait methods
-        // first. However, because function types bind regions, just
-        // calling `normalize_associated_types_in` would have no effect on
-        // any associated types appearing in the fn arguments or return
-        // type.
-
-        // Compute placeholder form of impl and trait method tys.
-        let tcx = infcx.tcx;
-
-        let mut wf_tys = FxHashSet::default();
-
-        let impl_sig = infcx.replace_bound_vars_with_fresh_vars(
-            impl_m_span,
-            infer::HigherRankedType,
-            tcx.fn_sig(impl_m.def_id),
+        ocx.register_obligations(obligations);
+        let cause = ObligationCause::new(
+            span,
+            impl_m_hir_id,
+            ObligationCauseCode::CompareImplItemObligation {
+                impl_item_def_id: impl_m.def_id.expect_local(),
+                trait_item_def_id: trait_m.def_id,
+                kind: impl_m.kind,
+            },
         );
+        ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate));
+    }
 
-        let norm_cause = ObligationCause::misc(impl_m_span, impl_m_hir_id);
-        let impl_sig = ocx.normalize(norm_cause.clone(), param_env, impl_sig);
-        let impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig));
-        debug!("compare_impl_method: impl_fty={:?}", impl_fty);
-
-        let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs);
-        let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig);
-
-        // Next, add all inputs and output as well-formed tys. Importantly,
-        // we have to do this before normalization, since the normalized ty may
-        // not contain the input parameters. See issue #87748.
-        wf_tys.extend(trait_sig.inputs_and_output.iter());
-        let trait_sig = ocx.normalize(norm_cause, param_env, trait_sig);
-        // We also have to add the normalized trait signature
-        // as we don't normalize during implied bounds computation.
-        wf_tys.extend(trait_sig.inputs_and_output.iter());
-        let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
-
-        debug!("compare_impl_method: trait_fty={:?}", trait_fty);
-
-        // FIXME: We'd want to keep more accurate spans than "the method signature" when
-        // processing the comparison between the trait and impl fn, but we sadly lose them
-        // and point at the whole signature when a trait bound or specific input or output
-        // type would be more appropriate. In other places we have a `Vec<Span>`
-        // corresponding to their `Vec<Predicate>`, but we don't have that here.
-        // Fixing this would improve the output of test `issue-83765.rs`.
-        let mut result = infcx
-            .at(&cause, param_env)
-            .sup(trait_fty, impl_fty)
-            .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok));
-
-        // HACK(RPITIT): #101614. When we are trying to infer the hidden types for
-        // RPITITs, we need to equate the output tys instead of just subtyping. If
-        // we just use `sup` above, we'll end up `&'static str <: _#1t`, which causes
-        // us to infer `_#1t = #'_#2r str`, where `'_#2r` is unconstrained, which gets
-        // fixed up to `ReEmpty`, and which is certainly not what we want.
-        if trait_fty.has_infer_types() {
-            result = result.and_then(|()| {
-                infcx
-                    .at(&cause, param_env)
-                    .eq(trait_sig.output(), impl_sig.output())
-                    .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok))
-            });
-        }
+    // We now need to check that the signature of the impl method is
+    // compatible with that of the trait method. We do this by
+    // checking that `impl_fty <: trait_fty`.
+    //
+    // FIXME. Unfortunately, this doesn't quite work right now because
+    // associated type normalization is not integrated into subtype
+    // checks. For the comparison to be valid, we need to
+    // normalize the associated types in the impl/trait methods
+    // first. However, because function types bind regions, just
+    // calling `normalize_associated_types_in` would have no effect on
+    // any associated types appearing in the fn arguments or return
+    // type.
+
+    // Compute placeholder form of impl and trait method tys.
+    let tcx = infcx.tcx;
 
-        if let Err(terr) = result {
-            debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty);
+    let mut wf_tys = FxHashSet::default();
 
-            let (impl_err_span, trait_err_span) =
-                extract_spans_for_error_reporting(&infcx, terr, &cause, impl_m, trait_m);
+    let impl_sig = infcx.replace_bound_vars_with_fresh_vars(
+        impl_m_span,
+        infer::HigherRankedType,
+        tcx.fn_sig(impl_m.def_id),
+    );
 
-            cause.span = impl_err_span;
+    let norm_cause = ObligationCause::misc(impl_m_span, impl_m_hir_id);
+    let impl_sig = ocx.normalize(norm_cause.clone(), param_env, impl_sig);
+    let impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig));
+    debug!("compare_impl_method: impl_fty={:?}", impl_fty);
+
+    let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs);
+    let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig);
+
+    // Next, add all inputs and output as well-formed tys. Importantly,
+    // we have to do this before normalization, since the normalized ty may
+    // not contain the input parameters. See issue #87748.
+    wf_tys.extend(trait_sig.inputs_and_output.iter());
+    let trait_sig = ocx.normalize(norm_cause, param_env, trait_sig);
+    // We also have to add the normalized trait signature
+    // as we don't normalize during implied bounds computation.
+    wf_tys.extend(trait_sig.inputs_and_output.iter());
+    let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
+
+    debug!("compare_impl_method: trait_fty={:?}", trait_fty);
+
+    // FIXME: We'd want to keep more accurate spans than "the method signature" when
+    // processing the comparison between the trait and impl fn, but we sadly lose them
+    // and point at the whole signature when a trait bound or specific input or output
+    // type would be more appropriate. In other places we have a `Vec<Span>`
+    // corresponding to their `Vec<Predicate>`, but we don't have that here.
+    // Fixing this would improve the output of test `issue-83765.rs`.
+    let mut result = infcx
+        .at(&cause, param_env)
+        .sup(trait_fty, impl_fty)
+        .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok));
+
+    // HACK(RPITIT): #101614. When we are trying to infer the hidden types for
+    // RPITITs, we need to equate the output tys instead of just subtyping. If
+    // we just use `sup` above, we'll end up `&'static str <: _#1t`, which causes
+    // us to infer `_#1t = #'_#2r str`, where `'_#2r` is unconstrained, which gets
+    // fixed up to `ReEmpty`, and which is certainly not what we want.
+    if trait_fty.has_infer_types() {
+        result = result.and_then(|()| {
+            infcx
+                .at(&cause, param_env)
+                .eq(trait_sig.output(), impl_sig.output())
+                .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok))
+        });
+    }
 
-            let mut diag = struct_span_err!(
-                tcx.sess,
-                cause.span(),
-                E0053,
-                "method `{}` has an incompatible type for trait",
-                trait_m.name
-            );
-            match &terr {
-                TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
-                    if trait_m.fn_has_self_parameter =>
-                {
-                    let ty = trait_sig.inputs()[0];
-                    let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty())
-                    {
-                        ExplicitSelf::ByValue => "self".to_owned(),
-                        ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
-                        ExplicitSelf::ByReference(_, hir::Mutability::Mut) => {
-                            "&mut self".to_owned()
-                        }
-                        _ => format!("self: {ty}"),
-                    };
+    if let Err(terr) = result {
+        debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty);
 
-                    // When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
-                    // span points only at the type `Box<Self`>, but we want to cover the whole
-                    // argument pattern and type.
-                    let span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
-                        ImplItemKind::Fn(ref sig, body) => tcx
-                            .hir()
-                            .body_param_names(body)
-                            .zip(sig.decl.inputs.iter())
-                            .map(|(param, ty)| param.span.to(ty.span))
-                            .next()
-                            .unwrap_or(impl_err_span),
-                        _ => bug!("{:?} is not a method", impl_m),
-                    };
+        let (impl_err_span, trait_err_span) =
+            extract_spans_for_error_reporting(&infcx, terr, &cause, impl_m, trait_m);
+
+        cause.span = impl_err_span;
 
+        let mut diag = struct_span_err!(
+            tcx.sess,
+            cause.span(),
+            E0053,
+            "method `{}` has an incompatible type for trait",
+            trait_m.name
+        );
+        match &terr {
+            TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
+                if trait_m.fn_has_self_parameter =>
+            {
+                let ty = trait_sig.inputs()[0];
+                let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty()) {
+                    ExplicitSelf::ByValue => "self".to_owned(),
+                    ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
+                    ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
+                    _ => format!("self: {ty}"),
+                };
+
+                // When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
+                // span points only at the type `Box<Self`>, but we want to cover the whole
+                // argument pattern and type.
+                let span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
+                    ImplItemKind::Fn(ref sig, body) => tcx
+                        .hir()
+                        .body_param_names(body)
+                        .zip(sig.decl.inputs.iter())
+                        .map(|(param, ty)| param.span.to(ty.span))
+                        .next()
+                        .unwrap_or(impl_err_span),
+                    _ => bug!("{:?} is not a method", impl_m),
+                };
+
+                diag.span_suggestion(
+                    span,
+                    "change the self-receiver type to match the trait",
+                    sugg,
+                    Applicability::MachineApplicable,
+                );
+            }
+            TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {
+                if trait_sig.inputs().len() == *i {
+                    // Suggestion to change output type. We do not suggest in `async` functions
+                    // to avoid complex logic or incorrect output.
+                    match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
+                        ImplItemKind::Fn(ref sig, _)
+                            if sig.header.asyncness == hir::IsAsync::NotAsync =>
+                        {
+                            let msg = "change the output type to match the trait";
+                            let ap = Applicability::MachineApplicable;
+                            match sig.decl.output {
+                                hir::FnRetTy::DefaultReturn(sp) => {
+                                    let sugg = format!("-> {} ", trait_sig.output());
+                                    diag.span_suggestion_verbose(sp, msg, sugg, ap);
+                                }
+                                hir::FnRetTy::Return(hir_ty) => {
+                                    let sugg = trait_sig.output();
+                                    diag.span_suggestion(hir_ty.span, msg, sugg, ap);
+                                }
+                            };
+                        }
+                        _ => {}
+                    };
+                } else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
                     diag.span_suggestion(
-                        span,
-                        "change the self-receiver type to match the trait",
-                        sugg,
+                        impl_err_span,
+                        "change the parameter type to match the trait",
+                        trait_ty,
                         Applicability::MachineApplicable,
                     );
                 }
-                TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {
-                    if trait_sig.inputs().len() == *i {
-                        // Suggestion to change output type. We do not suggest in `async` functions
-                        // to avoid complex logic or incorrect output.
-                        match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
-                            ImplItemKind::Fn(ref sig, _)
-                                if sig.header.asyncness == hir::IsAsync::NotAsync =>
-                            {
-                                let msg = "change the output type to match the trait";
-                                let ap = Applicability::MachineApplicable;
-                                match sig.decl.output {
-                                    hir::FnRetTy::DefaultReturn(sp) => {
-                                        let sugg = format!("-> {} ", trait_sig.output());
-                                        diag.span_suggestion_verbose(sp, msg, sugg, ap);
-                                    }
-                                    hir::FnRetTy::Return(hir_ty) => {
-                                        let sugg = trait_sig.output();
-                                        diag.span_suggestion(hir_ty.span, msg, sugg, ap);
-                                    }
-                                };
-                            }
-                            _ => {}
-                        };
-                    } else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
-                        diag.span_suggestion(
-                            impl_err_span,
-                            "change the parameter type to match the trait",
-                            trait_ty,
-                            Applicability::MachineApplicable,
-                        );
-                    }
-                }
-                _ => {}
             }
+            _ => {}
+        }
 
-            infcx.note_type_err(
-                &mut diag,
-                &cause,
-                trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
-                Some(infer::ValuePairs::Terms(ExpectedFound {
-                    expected: trait_fty.into(),
-                    found: impl_fty.into(),
-                })),
-                terr,
-                false,
-                false,
-            );
+        infcx.err_ctxt().note_type_err(
+            &mut diag,
+            &cause,
+            trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
+            Some(infer::ValuePairs::Terms(ExpectedFound {
+                expected: trait_fty.into(),
+                found: impl_fty.into(),
+            })),
+            terr,
+            false,
+            false,
+        );
 
-            return Err(diag.emit());
-        }
+        return Err(diag.emit());
+    }
 
-        // Check that all obligations are satisfied by the implementation's
-        // version.
-        let errors = ocx.select_all_or_error();
-        if !errors.is_empty() {
-            let reported = infcx.report_fulfillment_errors(&errors, None, false);
-            return Err(reported);
-        }
+    // Check that all obligations are satisfied by the implementation's
+    // version.
+    let errors = ocx.select_all_or_error();
+    if !errors.is_empty() {
+        let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+        return Err(reported);
+    }
 
-        // Finally, resolve all regions. This catches wily misuses of
-        // lifetime parameters.
-        let outlives_environment = OutlivesEnvironment::with_bounds(
-            param_env,
-            Some(infcx),
-            infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys),
-        );
-        infcx.check_region_obligations_and_report_errors(
-            impl_m.def_id.expect_local(),
-            &outlives_environment,
-        );
+    // Finally, resolve all regions. This catches wily misuses of
+    // lifetime parameters.
+    let outlives_environment = OutlivesEnvironment::with_bounds(
+        param_env,
+        Some(infcx),
+        infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys),
+    );
+    infcx.check_region_obligations_and_report_errors(
+        impl_m.def_id.expect_local(),
+        &outlives_environment,
+    );
 
-        Ok(())
-    })
+    Ok(())
 }
 
 pub fn collect_trait_impl_trait_tys<'tcx>(
@@ -465,125 +461,120 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
     let trait_to_placeholder_substs =
         impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_substs);
 
-    tcx.infer_ctxt().enter(|ref infcx| {
-        let ocx = ObligationCtxt::new(infcx);
-
-        let norm_cause = ObligationCause::misc(return_span, impl_m_hir_id);
-        let impl_return_ty = ocx.normalize(
-            norm_cause.clone(),
-            param_env,
-            infcx
-                .replace_bound_vars_with_fresh_vars(
-                    return_span,
-                    infer::HigherRankedType,
-                    tcx.fn_sig(impl_m.def_id),
-                )
-                .output(),
-        );
-
-        let mut collector =
-            ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_hir_id);
-        let unnormalized_trait_return_ty = tcx
-            .liberate_late_bound_regions(
-                impl_m.def_id,
-                tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs),
+    let infcx = &tcx.infer_ctxt().build();
+    let ocx = ObligationCtxt::new(infcx);
+
+    let norm_cause = ObligationCause::misc(return_span, impl_m_hir_id);
+    let impl_return_ty = ocx.normalize(
+        norm_cause.clone(),
+        param_env,
+        infcx
+            .replace_bound_vars_with_fresh_vars(
+                return_span,
+                infer::HigherRankedType,
+                tcx.fn_sig(impl_m.def_id),
             )
-            .output()
-            .fold_with(&mut collector);
-        let trait_return_ty =
-            ocx.normalize(norm_cause.clone(), param_env, unnormalized_trait_return_ty);
+            .output(),
+    );
 
-        let wf_tys = FxHashSet::from_iter([unnormalized_trait_return_ty, trait_return_ty]);
+    let mut collector = ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_hir_id);
+    let unnormalized_trait_return_ty = tcx
+        .liberate_late_bound_regions(
+            impl_m.def_id,
+            tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs),
+        )
+        .output()
+        .fold_with(&mut collector);
+    let trait_return_ty =
+        ocx.normalize(norm_cause.clone(), param_env, unnormalized_trait_return_ty);
 
-        match infcx.at(&cause, param_env).eq(trait_return_ty, impl_return_ty) {
-            Ok(infer::InferOk { value: (), obligations }) => {
-                ocx.register_obligations(obligations);
-            }
-            Err(terr) => {
-                let mut diag = struct_span_err!(
-                    tcx.sess,
-                    cause.span(),
-                    E0053,
-                    "method `{}` has an incompatible return type for trait",
-                    trait_m.name
-                );
-                let hir = tcx.hir();
-                infcx.note_type_err(
-                    &mut diag,
-                    &cause,
-                    hir.get_if_local(impl_m.def_id)
-                        .and_then(|node| node.fn_decl())
-                        .map(|decl| (decl.output.span(), "return type in trait".to_owned())),
-                    Some(infer::ValuePairs::Terms(ExpectedFound {
-                        expected: trait_return_ty.into(),
-                        found: impl_return_ty.into(),
-                    })),
-                    terr,
-                    false,
-                    false,
-                );
-                return Err(diag.emit());
-            }
-        }
+    let wf_tys = FxHashSet::from_iter([unnormalized_trait_return_ty, trait_return_ty]);
 
-        // Check that all obligations are satisfied by the implementation's
-        // RPITs.
-        let errors = ocx.select_all_or_error();
-        if !errors.is_empty() {
-            let reported = infcx.report_fulfillment_errors(&errors, None, false);
-            return Err(reported);
+    match infcx.at(&cause, param_env).eq(trait_return_ty, impl_return_ty) {
+        Ok(infer::InferOk { value: (), obligations }) => {
+            ocx.register_obligations(obligations);
         }
+        Err(terr) => {
+            let mut diag = struct_span_err!(
+                tcx.sess,
+                cause.span(),
+                E0053,
+                "method `{}` has an incompatible return type for trait",
+                trait_m.name
+            );
+            let hir = tcx.hir();
+            infcx.err_ctxt().note_type_err(
+                &mut diag,
+                &cause,
+                hir.get_if_local(impl_m.def_id)
+                    .and_then(|node| node.fn_decl())
+                    .map(|decl| (decl.output.span(), "return type in trait".to_owned())),
+                Some(infer::ValuePairs::Terms(ExpectedFound {
+                    expected: trait_return_ty.into(),
+                    found: impl_return_ty.into(),
+                })),
+                terr,
+                false,
+                false,
+            );
+            return Err(diag.emit());
+        }
+    }
 
-        // Finally, resolve all regions. This catches wily misuses of
-        // lifetime parameters.
-        let outlives_environment = OutlivesEnvironment::with_bounds(
-            param_env,
-            Some(infcx),
-            infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys),
-        );
-        infcx.check_region_obligations_and_report_errors(
-            impl_m.def_id.expect_local(),
-            &outlives_environment,
-        );
+    // Check that all obligations are satisfied by the implementation's
+    // RPITs.
+    let errors = ocx.select_all_or_error();
+    if !errors.is_empty() {
+        let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+        return Err(reported);
+    }
 
-        let mut collected_tys = FxHashMap::default();
-        for (def_id, (ty, substs)) in collector.types {
-            match infcx.fully_resolve(ty) {
-                Ok(ty) => {
-                    // `ty` contains free regions that we created earlier while liberating the
-                    // trait fn signature.  However, projection normalization expects `ty` to
-                    // contains `def_id`'s early-bound regions.
-                    let id_substs = InternalSubsts::identity_for_item(tcx, def_id);
-                    debug!(?id_substs, ?substs);
-                    let map: FxHashMap<ty::GenericArg<'tcx>, ty::GenericArg<'tcx>> = substs
-                        .iter()
-                        .enumerate()
-                        .map(|(index, arg)| (arg, id_substs[index]))
-                        .collect();
-                    debug!(?map);
-
-                    let ty = tcx.fold_regions(ty, |region, _| {
-                        if let ty::ReFree(_) = region.kind() {
-                            map[&region.into()].expect_region()
-                        } else {
-                            region
-                        }
-                    });
-                    debug!(%ty);
-                    collected_tys.insert(def_id, ty);
-                }
-                Err(err) => {
-                    tcx.sess.delay_span_bug(
-                        return_span,
-                        format!("could not fully resolve: {ty} => {err:?}"),
-                    );
-                    collected_tys.insert(def_id, tcx.ty_error());
-                }
+    // Finally, resolve all regions. This catches wily misuses of
+    // lifetime parameters.
+    let outlives_environment = OutlivesEnvironment::with_bounds(
+        param_env,
+        Some(infcx),
+        infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys),
+    );
+    infcx.check_region_obligations_and_report_errors(
+        impl_m.def_id.expect_local(),
+        &outlives_environment,
+    );
+
+    let mut collected_tys = FxHashMap::default();
+    for (def_id, (ty, substs)) in collector.types {
+        match infcx.fully_resolve(ty) {
+            Ok(ty) => {
+                // `ty` contains free regions that we created earlier while liberating the
+                // trait fn signature.  However, projection normalization expects `ty` to
+                // contains `def_id`'s early-bound regions.
+                let id_substs = InternalSubsts::identity_for_item(tcx, def_id);
+                debug!(?id_substs, ?substs);
+                let map: FxHashMap<ty::GenericArg<'tcx>, ty::GenericArg<'tcx>> =
+                    substs.iter().enumerate().map(|(index, arg)| (arg, id_substs[index])).collect();
+                debug!(?map);
+
+                let ty = tcx.fold_regions(ty, |region, _| {
+                    if let ty::ReFree(_) = region.kind() {
+                        map[&region.into()].expect_region()
+                    } else {
+                        region
+                    }
+                });
+                debug!(%ty);
+                collected_tys.insert(def_id, ty);
+            }
+            Err(err) => {
+                tcx.sess.delay_span_bug(
+                    return_span,
+                    format!("could not fully resolve: {ty} => {err:?}"),
+                );
+                collected_tys.insert(def_id, tcx.ty_error());
             }
         }
+    }
 
-        Ok(&*tcx.arena.alloc(collected_tys))
-    })
+    Ok(&*tcx.arena.alloc(collected_tys))
 }
 
 struct ImplTraitInTraitCollector<'a, 'tcx> {
@@ -712,8 +703,8 @@ fn check_region_bounds_on_impl_item<'tcx>(
 }
 
 #[instrument(level = "debug", skip(infcx))]
-fn extract_spans_for_error_reporting<'a, 'tcx>(
-    infcx: &infer::InferCtxt<'a, 'tcx>,
+fn extract_spans_for_error_reporting<'tcx>(
+    infcx: &infer::InferCtxt<'tcx>,
     terr: TypeError<'_>,
     cause: &ObligationCause<'tcx>,
     impl_m: &ty::AssocItem,
@@ -768,16 +759,15 @@ fn compare_self_type<'tcx>(
         let self_arg_ty = tcx.fn_sig(method.def_id).input(0);
         let param_env = ty::ParamEnv::reveal_all();
 
-        tcx.infer_ctxt().enter(|infcx| {
-            let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty);
-            let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty).is_ok();
-            match ExplicitSelf::determine(self_arg_ty, can_eq_self) {
-                ExplicitSelf::ByValue => "self".to_owned(),
-                ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
-                ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
-                _ => format!("self: {self_arg_ty}"),
-            }
-        })
+        let infcx = tcx.infer_ctxt().build();
+        let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty);
+        let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty).is_ok();
+        match ExplicitSelf::determine(self_arg_ty, can_eq_self) {
+            ExplicitSelf::ByValue => "self".to_owned(),
+            ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
+            ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
+            _ => format!("self: {self_arg_ty}"),
+        }
     };
 
     match (trait_m.fn_has_self_parameter, impl_m.fn_has_self_parameter) {
@@ -1300,114 +1290,114 @@ fn compare_generic_param_kinds<'tcx>(
     Ok(())
 }
 
-pub(crate) fn compare_const_impl<'tcx>(
+/// Use `tcx.compare_assoc_const_impl_item_with_trait_item` instead
+pub(crate) fn raw_compare_const_impl<'tcx>(
     tcx: TyCtxt<'tcx>,
-    impl_c: &ty::AssocItem,
-    impl_c_span: Span,
-    trait_c: &ty::AssocItem,
-    impl_trait_ref: ty::TraitRef<'tcx>,
-) {
+    (impl_const_item_def, trait_const_item_def): (LocalDefId, DefId),
+) -> Result<(), ErrorGuaranteed> {
+    let impl_const_item = tcx.associated_item(impl_const_item_def);
+    let trait_const_item = tcx.associated_item(trait_const_item_def);
+    let impl_trait_ref = tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap();
     debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
 
-    tcx.infer_ctxt().enter(|infcx| {
-        let param_env = tcx.param_env(impl_c.def_id);
-        let ocx = ObligationCtxt::new(&infcx);
-
-        // The below is for the most part highly similar to the procedure
-        // for methods above. It is simpler in many respects, especially
-        // because we shouldn't really have to deal with lifetimes or
-        // predicates. In fact some of this should probably be put into
-        // shared functions because of DRY violations...
-        let trait_to_impl_substs = impl_trait_ref.substs;
-
-        // Create a parameter environment that represents the implementation's
-        // method.
-        let impl_c_hir_id = tcx.hir().local_def_id_to_hir_id(impl_c.def_id.expect_local());
-
-        // Compute placeholder form of impl and trait const tys.
-        let impl_ty = tcx.type_of(impl_c.def_id);
-        let trait_ty = tcx.bound_type_of(trait_c.def_id).subst(tcx, trait_to_impl_substs);
-        let mut cause = ObligationCause::new(
-            impl_c_span,
-            impl_c_hir_id,
-            ObligationCauseCode::CompareImplItemObligation {
-                impl_item_def_id: impl_c.def_id.expect_local(),
-                trait_item_def_id: trait_c.def_id,
-                kind: impl_c.kind,
-            },
-        );
+    let impl_c_span = tcx.def_span(impl_const_item_def.to_def_id());
 
-        // There is no "body" here, so just pass dummy id.
-        let impl_ty = ocx.normalize(cause.clone(), param_env, impl_ty);
+    let infcx = tcx.infer_ctxt().build();
+    let param_env = tcx.param_env(impl_const_item_def.to_def_id());
+    let ocx = ObligationCtxt::new(&infcx);
 
-        debug!("compare_const_impl: impl_ty={:?}", impl_ty);
+    // The below is for the most part highly similar to the procedure
+    // for methods above. It is simpler in many respects, especially
+    // because we shouldn't really have to deal with lifetimes or
+    // predicates. In fact some of this should probably be put into
+    // shared functions because of DRY violations...
+    let trait_to_impl_substs = impl_trait_ref.substs;
 
-        let trait_ty = ocx.normalize(cause.clone(), param_env, trait_ty);
+    // Create a parameter environment that represents the implementation's
+    // method.
+    let impl_c_hir_id = tcx.hir().local_def_id_to_hir_id(impl_const_item_def);
 
-        debug!("compare_const_impl: trait_ty={:?}", trait_ty);
+    // Compute placeholder form of impl and trait const tys.
+    let impl_ty = tcx.type_of(impl_const_item_def.to_def_id());
+    let trait_ty = tcx.bound_type_of(trait_const_item_def).subst(tcx, trait_to_impl_substs);
+    let mut cause = ObligationCause::new(
+        impl_c_span,
+        impl_c_hir_id,
+        ObligationCauseCode::CompareImplItemObligation {
+            impl_item_def_id: impl_const_item_def,
+            trait_item_def_id: trait_const_item_def,
+            kind: impl_const_item.kind,
+        },
+    );
 
-        let err = infcx
-            .at(&cause, param_env)
-            .sup(trait_ty, impl_ty)
-            .map(|ok| ocx.register_infer_ok_obligations(ok));
+    // There is no "body" here, so just pass dummy id.
+    let impl_ty = ocx.normalize(cause.clone(), param_env, impl_ty);
 
-        if let Err(terr) = err {
-            debug!(
-                "checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
-                impl_ty, trait_ty
-            );
+    debug!("compare_const_impl: impl_ty={:?}", impl_ty);
 
-            // Locate the Span containing just the type of the offending impl
-            match tcx.hir().expect_impl_item(impl_c.def_id.expect_local()).kind {
-                ImplItemKind::Const(ref ty, _) => cause.span = ty.span,
-                _ => bug!("{:?} is not a impl const", impl_c),
-            }
+    let trait_ty = ocx.normalize(cause.clone(), param_env, trait_ty);
 
-            let mut diag = struct_span_err!(
-                tcx.sess,
-                cause.span,
-                E0326,
-                "implemented const `{}` has an incompatible type for trait",
-                trait_c.name
-            );
+    debug!("compare_const_impl: trait_ty={:?}", trait_ty);
 
-            let trait_c_span = trait_c.def_id.as_local().map(|trait_c_def_id| {
-                // Add a label to the Span containing just the type of the const
-                match tcx.hir().expect_trait_item(trait_c_def_id).kind {
-                    TraitItemKind::Const(ref ty, _) => ty.span,
-                    _ => bug!("{:?} is not a trait const", trait_c),
-                }
-            });
+    let err = infcx
+        .at(&cause, param_env)
+        .sup(trait_ty, impl_ty)
+        .map(|ok| ocx.register_infer_ok_obligations(ok));
 
-            infcx.note_type_err(
-                &mut diag,
-                &cause,
-                trait_c_span.map(|span| (span, "type in trait".to_owned())),
-                Some(infer::ValuePairs::Terms(ExpectedFound {
-                    expected: trait_ty.into(),
-                    found: impl_ty.into(),
-                })),
-                terr,
-                false,
-                false,
-            );
-            diag.emit();
-        }
+    if let Err(terr) = err {
+        debug!(
+            "checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
+            impl_ty, trait_ty
+        );
 
-        // Check that all obligations are satisfied by the implementation's
-        // version.
-        let errors = ocx.select_all_or_error();
-        if !errors.is_empty() {
-            infcx.report_fulfillment_errors(&errors, None, false);
-            return;
+        // Locate the Span containing just the type of the offending impl
+        match tcx.hir().expect_impl_item(impl_const_item_def).kind {
+            ImplItemKind::Const(ref ty, _) => cause.span = ty.span,
+            _ => bug!("{:?} is not a impl const", impl_const_item),
         }
 
-        let outlives_environment = OutlivesEnvironment::new(param_env);
-        infcx.check_region_obligations_and_report_errors(
-            impl_c.def_id.expect_local(),
-            &outlives_environment,
+        let mut diag = struct_span_err!(
+            tcx.sess,
+            cause.span,
+            E0326,
+            "implemented const `{}` has an incompatible type for trait",
+            trait_const_item.name
         );
-    });
+
+        let trait_c_span = trait_const_item_def.as_local().map(|trait_c_def_id| {
+            // Add a label to the Span containing just the type of the const
+            match tcx.hir().expect_trait_item(trait_c_def_id).kind {
+                TraitItemKind::Const(ref ty, _) => ty.span,
+                _ => bug!("{:?} is not a trait const", trait_const_item),
+            }
+        });
+
+        infcx.err_ctxt().note_type_err(
+            &mut diag,
+            &cause,
+            trait_c_span.map(|span| (span, "type in trait".to_owned())),
+            Some(infer::ValuePairs::Terms(ExpectedFound {
+                expected: trait_ty.into(),
+                found: impl_ty.into(),
+            })),
+            terr,
+            false,
+            false,
+        );
+        return Err(diag.emit());
+    };
+
+    // Check that all obligations are satisfied by the implementation's
+    // version.
+    let errors = ocx.select_all_or_error();
+    if !errors.is_empty() {
+        return Err(infcx.err_ctxt().report_fulfillment_errors(&errors, None, false));
+    }
+
+    // FIXME return `ErrorReported` if region obligations error?
+    let outlives_environment = OutlivesEnvironment::new(param_env);
+    infcx.check_region_obligations_and_report_errors(impl_const_item_def, &outlives_environment);
+    Ok(())
 }
 
 pub(crate) fn compare_ty_impl<'tcx>(
@@ -1488,52 +1478,50 @@ fn compare_type_predicate_entailment<'tcx>(
         hir::Constness::NotConst,
     );
     let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
-    tcx.infer_ctxt().enter(|infcx| {
-        let ocx = ObligationCtxt::new(&infcx);
+    let infcx = tcx.infer_ctxt().build();
+    let ocx = ObligationCtxt::new(&infcx);
 
-        debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds());
+    debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds());
 
-        let mut selcx = traits::SelectionContext::new(&infcx);
+    let mut selcx = traits::SelectionContext::new(&infcx);
 
-        assert_eq!(impl_ty_own_bounds.predicates.len(), impl_ty_own_bounds.spans.len());
-        for (span, predicate) in
-            std::iter::zip(impl_ty_own_bounds.spans, impl_ty_own_bounds.predicates)
-        {
-            let cause = ObligationCause::misc(span, impl_ty_hir_id);
-            let traits::Normalized { value: predicate, obligations } =
-                traits::normalize(&mut selcx, param_env, cause, predicate);
-
-            let cause = ObligationCause::new(
-                span,
-                impl_ty_hir_id,
-                ObligationCauseCode::CompareImplItemObligation {
-                    impl_item_def_id: impl_ty.def_id.expect_local(),
-                    trait_item_def_id: trait_ty.def_id,
-                    kind: impl_ty.kind,
-                },
-            );
-            ocx.register_obligations(obligations);
-            ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate));
-        }
-
-        // Check that all obligations are satisfied by the implementation's
-        // version.
-        let errors = ocx.select_all_or_error();
-        if !errors.is_empty() {
-            let reported = infcx.report_fulfillment_errors(&errors, None, false);
-            return Err(reported);
-        }
+    assert_eq!(impl_ty_own_bounds.predicates.len(), impl_ty_own_bounds.spans.len());
+    for (span, predicate) in std::iter::zip(impl_ty_own_bounds.spans, impl_ty_own_bounds.predicates)
+    {
+        let cause = ObligationCause::misc(span, impl_ty_hir_id);
+        let traits::Normalized { value: predicate, obligations } =
+            traits::normalize(&mut selcx, param_env, cause, predicate);
 
-        // Finally, resolve all regions. This catches wily misuses of
-        // lifetime parameters.
-        let outlives_environment = OutlivesEnvironment::new(param_env);
-        infcx.check_region_obligations_and_report_errors(
-            impl_ty.def_id.expect_local(),
-            &outlives_environment,
+        let cause = ObligationCause::new(
+            span,
+            impl_ty_hir_id,
+            ObligationCauseCode::CompareImplItemObligation {
+                impl_item_def_id: impl_ty.def_id.expect_local(),
+                trait_item_def_id: trait_ty.def_id,
+                kind: impl_ty.kind,
+            },
         );
+        ocx.register_obligations(obligations);
+        ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate));
+    }
+
+    // Check that all obligations are satisfied by the implementation's
+    // version.
+    let errors = ocx.select_all_or_error();
+    if !errors.is_empty() {
+        let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+        return Err(reported);
+    }
 
-        Ok(())
-    })
+    // Finally, resolve all regions. This catches wily misuses of
+    // lifetime parameters.
+    let outlives_environment = OutlivesEnvironment::new(param_env);
+    infcx.check_region_obligations_and_report_errors(
+        impl_ty.def_id.expect_local(),
+        &outlives_environment,
+    );
+
+    Ok(())
 }
 
 /// Validate that `ProjectionCandidate`s created for this associated type will
@@ -1693,94 +1681,94 @@ pub fn check_type_bounds<'tcx>(
     let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
     let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
 
-    tcx.infer_ctxt().enter(move |infcx| {
-        let ocx = ObligationCtxt::new(&infcx);
+    let infcx = tcx.infer_ctxt().build();
+    let ocx = ObligationCtxt::new(&infcx);
 
-        let assumed_wf_types =
-            ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty.def_id.expect_local());
+    let assumed_wf_types =
+        ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty.def_id.expect_local());
 
-        let mut selcx = traits::SelectionContext::new(&infcx);
-        let normalize_cause = ObligationCause::new(
-            impl_ty_span,
-            impl_ty_hir_id,
-            ObligationCauseCode::CheckAssociatedTypeBounds {
-                impl_item_def_id: impl_ty.def_id.expect_local(),
-                trait_item_def_id: trait_ty.def_id,
-            },
-        );
-        let mk_cause = |span: Span| {
-            let code = if span.is_dummy() {
-                traits::ItemObligation(trait_ty.def_id)
-            } else {
-                traits::BindingObligation(trait_ty.def_id, span)
-            };
-            ObligationCause::new(impl_ty_span, impl_ty_hir_id, code)
+    let mut selcx = traits::SelectionContext::new(&infcx);
+    let normalize_cause = ObligationCause::new(
+        impl_ty_span,
+        impl_ty_hir_id,
+        ObligationCauseCode::CheckAssociatedTypeBounds {
+            impl_item_def_id: impl_ty.def_id.expect_local(),
+            trait_item_def_id: trait_ty.def_id,
+        },
+    );
+    let mk_cause = |span: Span| {
+        let code = if span.is_dummy() {
+            traits::ItemObligation(trait_ty.def_id)
+        } else {
+            traits::BindingObligation(trait_ty.def_id, span)
         };
+        ObligationCause::new(impl_ty_span, impl_ty_hir_id, code)
+    };
 
-        let obligations = tcx
-            .bound_explicit_item_bounds(trait_ty.def_id)
-            .transpose_iter()
-            .map(|e| e.map_bound(|e| *e).transpose_tuple2())
-            .map(|(bound, span)| {
-                debug!(?bound);
-                // this is where opaque type is found
-                let concrete_ty_bound = bound.subst(tcx, rebased_substs);
-                debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
-
-                traits::Obligation::new(mk_cause(span.0), param_env, concrete_ty_bound)
-            })
-            .collect();
-        debug!("check_type_bounds: item_bounds={:?}", obligations);
-
-        for mut obligation in util::elaborate_obligations(tcx, obligations) {
-            let traits::Normalized { value: normalized_predicate, obligations } = traits::normalize(
-                &mut selcx,
-                normalize_param_env,
-                normalize_cause.clone(),
-                obligation.predicate,
-            );
-            debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate);
-            obligation.predicate = normalized_predicate;
+    let obligations = tcx
+        .bound_explicit_item_bounds(trait_ty.def_id)
+        .transpose_iter()
+        .map(|e| e.map_bound(|e| *e).transpose_tuple2())
+        .map(|(bound, span)| {
+            debug!(?bound);
+            // this is where opaque type is found
+            let concrete_ty_bound = bound.subst(tcx, rebased_substs);
+            debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
+
+            traits::Obligation::new(mk_cause(span.0), param_env, concrete_ty_bound)
+        })
+        .collect();
+    debug!("check_type_bounds: item_bounds={:?}", obligations);
+
+    for mut obligation in util::elaborate_obligations(tcx, obligations) {
+        let traits::Normalized { value: normalized_predicate, obligations } = traits::normalize(
+            &mut selcx,
+            normalize_param_env,
+            normalize_cause.clone(),
+            obligation.predicate,
+        );
+        debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate);
+        obligation.predicate = normalized_predicate;
 
-            ocx.register_obligations(obligations);
-            ocx.register_obligation(obligation);
-        }
-        // Check that all obligations are satisfied by the implementation's
-        // version.
-        let errors = ocx.select_all_or_error();
-        if !errors.is_empty() {
-            let reported = infcx.report_fulfillment_errors(&errors, None, false);
-            return Err(reported);
-        }
+        ocx.register_obligations(obligations);
+        ocx.register_obligation(obligation);
+    }
+    // Check that all obligations are satisfied by the implementation's
+    // version.
+    let errors = ocx.select_all_or_error();
+    if !errors.is_empty() {
+        let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+        return Err(reported);
+    }
 
-        // Finally, resolve all regions. This catches wily misuses of
-        // lifetime parameters.
-        let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_hir_id, assumed_wf_types);
-        let outlives_environment =
-            OutlivesEnvironment::with_bounds(param_env, Some(&infcx), implied_bounds);
+    // Finally, resolve all regions. This catches wily misuses of
+    // lifetime parameters.
+    let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_hir_id, assumed_wf_types);
+    let outlives_environment =
+        OutlivesEnvironment::with_bounds(param_env, Some(&infcx), implied_bounds);
 
-        infcx.check_region_obligations_and_report_errors(
-            impl_ty.def_id.expect_local(),
-            &outlives_environment,
-        );
+    infcx.check_region_obligations_and_report_errors(
+        impl_ty.def_id.expect_local(),
+        &outlives_environment,
+    );
 
-        let constraints = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
-        for (key, value) in constraints {
-            infcx
-                .report_mismatched_types(
-                    &ObligationCause::misc(
-                        value.hidden_type.span,
-                        tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local()),
-                    ),
-                    tcx.mk_opaque(key.def_id.to_def_id(), key.substs),
-                    value.hidden_type.ty,
-                    TypeError::Mismatch,
-                )
-                .emit();
-        }
+    let constraints = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+    for (key, value) in constraints {
+        infcx
+            .err_ctxt()
+            .report_mismatched_types(
+                &ObligationCause::misc(
+                    value.hidden_type.span,
+                    tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local()),
+                ),
+                tcx.mk_opaque(key.def_id.to_def_id(), key.substs),
+                value.hidden_type.ty,
+                TypeError::Mismatch,
+            )
+            .emit();
+    }
 
-        Ok(())
-    })
+    Ok(())
 }
 
 fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str {
diff --git a/compiler/rustc_hir_analysis/src/check/demand.rs b/compiler/rustc_hir_analysis/src/check/demand.rs
index d396c801c09..a5222c92331 100644
--- a/compiler/rustc_hir_analysis/src/check/demand.rs
+++ b/compiler/rustc_hir_analysis/src/check/demand.rs
@@ -79,7 +79,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.register_predicates(obligations);
                 None
             }
-            Err(e) => Some(self.report_mismatched_types(&cause, expected, actual, e)),
+            Err(e) => Some(self.err_ctxt().report_mismatched_types(&cause, expected, actual, e)),
         }
     }
 
@@ -109,7 +109,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.register_predicates(obligations);
                 None
             }
-            Err(e) => Some(self.report_mismatched_types(cause, expected, actual, e)),
+            Err(e) => Some(self.err_ctxt().report_mismatched_types(cause, expected, actual, e)),
         }
     }
 
@@ -153,7 +153,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let expr = expr.peel_drop_temps();
         let cause = self.misc(expr.span);
         let expr_ty = self.resolve_vars_with_obligations(checked_ty);
-        let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e.clone());
+        let mut err = self.err_ctxt().report_mismatched_types(&cause, expected, expr_ty, e.clone());
 
         let is_insufficiently_polymorphic =
             matches!(e, TypeError::RegionsInsufficientlyPolymorphic(..));
diff --git a/compiler/rustc_hir_analysis/src/check/expr.rs b/compiler/rustc_hir_analysis/src/check/expr.rs
index b9459887c46..375c13d922b 100644
--- a/compiler/rustc_hir_analysis/src/check/expr.rs
+++ b/compiler/rustc_hir_analysis/src/check/expr.rs
@@ -1045,6 +1045,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let rhs_ty = self.check_expr(&rhs);
             let (applicability, eq) = if self.can_coerce(rhs_ty, lhs_ty) {
                 (Applicability::MachineApplicable, true)
+            } else if let ExprKind::Binary(
+                Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. },
+                _,
+                rhs_expr,
+            ) = lhs.kind
+            {
+                let actual_lhs_ty = self.check_expr(&rhs_expr);
+                (Applicability::MaybeIncorrect, self.can_coerce(rhs_ty, actual_lhs_ty))
             } else {
                 (Applicability::MaybeIncorrect, false)
             };
@@ -1067,9 +1075,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             if eq {
                 err.span_suggestion_verbose(
-                    span,
+                    span.shrink_to_hi(),
                     "you might have meant to compare for equality",
-                    "==",
+                    '=',
                     applicability,
                 );
             }
@@ -1641,13 +1649,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                     Err(_) => {
                                         // This should never happen, since we're just subtyping the
                                         // remaining_fields, but it's fine to emit this, I guess.
-                                        self.report_mismatched_types(
-                                            &cause,
-                                            target_ty,
-                                            fru_ty,
-                                            FieldMisMatch(variant.name, ident.name),
-                                        )
-                                        .emit();
+                                        self.err_ctxt()
+                                            .report_mismatched_types(
+                                                &cause,
+                                                target_ty,
+                                                fru_ty,
+                                                FieldMisMatch(variant.name, ident.name),
+                                            )
+                                            .emit();
                                     }
                                 }
                             }
@@ -1934,7 +1943,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             self.set_tainted_by_errors();
             return;
         }
-        let mut err = self.type_error_struct_with_diag(
+        let mut err = self.err_ctxt().type_error_struct_with_diag(
             field.ident.span,
             |actual| match ty.kind() {
                 ty::Adt(adt, ..) if adt.is_enum() => struct_span_err!(
diff --git a/compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs b/compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs
index e51e5280620..d140c3a0989 100644
--- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs
@@ -32,7 +32,7 @@ use rustc_span::hygiene::DesugaringKind;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::{
     self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt,
 };
@@ -615,7 +615,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         if !errors.is_empty() {
             self.adjust_fulfillment_errors_for_expr_obligation(&mut errors);
-            self.report_fulfillment_errors(&errors, self.inh.body_id, false);
+            self.err_ctxt().report_fulfillment_errors(&errors, self.inh.body_id, false);
         }
     }
 
@@ -629,7 +629,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         if !result.is_empty() {
             mutate_fulfillment_errors(&mut result);
             self.adjust_fulfillment_errors_for_expr_obligation(&mut result);
-            self.report_fulfillment_errors(&result, self.inh.body_id, fallback_has_occurred);
+            self.err_ctxt().report_fulfillment_errors(
+                &result,
+                self.inh.body_id,
+                fallback_has_occurred,
+            );
         }
     }
 
@@ -1466,7 +1470,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ty
         } else {
             if !self.is_tainted_by_errors() {
-                self.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282, true)
+                self.err_ctxt()
+                    .emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282, true)
                     .emit();
             }
             let err = self.tcx.ty_error();
diff --git a/compiler/rustc_hir_analysis/src/check/fn_ctxt/checks.rs b/compiler/rustc_hir_analysis/src/check/fn_ctxt/checks.rs
index 13e74021b9e..285db90a9df 100644
--- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_analysis/src/check/fn_ctxt/checks.rs
@@ -650,7 +650,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     if tys.len() == 1 {
                         // A tuple wrap suggestion actually occurs within,
                         // so don't do anything special here.
-                        err = self.report_and_explain_type_error(
+                        err = self.err_ctxt().report_and_explain_type_error(
                             TypeTrace::types(
                                 &self.misc(*lo),
                                 true,
@@ -742,7 +742,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let cause = &self.misc(provided_span);
                 let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
                 if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308(_)) {
-                    self.report_and_explain_type_error(trace, *e).emit();
+                    self.err_ctxt().report_and_explain_type_error(trace, *e).emit();
                     return true;
                 }
                 false
@@ -766,7 +766,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let (provided_ty, provided_arg_span) = provided_arg_tys[*provided_idx];
             let cause = &self.misc(provided_arg_span);
             let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
-            let mut err = self.report_and_explain_type_error(trace, *err);
+            let mut err = self.err_ctxt().report_and_explain_type_error(trace, *err);
             self.emit_coerce_suggestions(
                 &mut err,
                 &provided_args[*provided_idx],
@@ -840,7 +840,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         let cause = &self.misc(provided_span);
                         let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
                         if let Some(e) = error {
-                            self.note_type_err(
+                            self.err_ctxt().note_type_err(
                                 &mut err,
                                 &trace.cause,
                                 None,
@@ -1474,7 +1474,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         &mut |err| {
                             if let Some(expected_ty) = expected.only_has_type(self) {
                                 if !self.consider_removing_semicolon(blk, expected_ty, err) {
-                                    self.consider_returning_binding(blk, expected_ty, err);
+                                    self.err_ctxt().consider_returning_binding(
+                                        blk,
+                                        expected_ty,
+                                        err,
+                                    );
                                 }
                                 if expected_ty == self.tcx.types.bool {
                                     // If this is caused by a missing `let` in a `while let`,
diff --git a/compiler/rustc_hir_analysis/src/check/fn_ctxt/mod.rs b/compiler/rustc_hir_analysis/src/check/fn_ctxt/mod.rs
index d929a3e6548..51f4cb7e0eb 100644
--- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/fn_ctxt/mod.rs
@@ -13,6 +13,7 @@ use crate::check::{Diverges, EnclosingBreakables, Inherited, UnsafetyState};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer;
+use rustc_infer::infer::error_reporting::TypeErrCtxt;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
 use rustc_middle::ty::subst::GenericArgKind;
@@ -117,7 +118,7 @@ pub struct FnCtxt<'a, 'tcx> {
 
     pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>,
 
-    pub(super) inh: &'a Inherited<'a, 'tcx>,
+    pub(super) inh: &'a Inherited<'tcx>,
 
     /// True if the function or closure's return type is known before
     /// entering the function/closure, i.e. if the return type is
@@ -131,7 +132,7 @@ pub struct FnCtxt<'a, 'tcx> {
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn new(
-        inh: &'a Inherited<'a, 'tcx>,
+        inh: &'a Inherited<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
         body_id: hir::HirId,
     ) -> FnCtxt<'a, 'tcx> {
@@ -168,13 +169,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self.tcx.sess
     }
 
+    /// Creates an `TypeErrCtxt` with a reference to the in-progress
+    /// `TypeckResults` which is used for diagnostics.
+    /// Use [`InferCtxt::err_ctxt`] to start one without a `TypeckResults`.
+    ///
+    /// [`InferCtxt::err_ctxt`]: infer::InferCtxt::err_ctxt
+    pub fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> {
+        TypeErrCtxt { infcx: &self.infcx, typeck_results: Some(self.typeck_results.borrow()) }
+    }
+
     pub fn errors_reported_since_creation(&self) -> bool {
         self.tcx.sess.err_count() > self.err_count_on_creation
     }
 }
 
 impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
-    type Target = Inherited<'a, 'tcx>;
+    type Target = Inherited<'tcx>;
     fn deref(&self) -> &Self::Target {
         &self.inh
     }
diff --git a/compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs
index 09890c55cd3..7a40def177a 100644
--- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs
@@ -876,18 +876,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars));
             let ty = self.normalize_associated_types_in(expr.span, ty);
             let ty = match self.tcx.asyncness(fn_id.owner) {
-                hir::IsAsync::Async => self
-                    .tcx
-                    .infer_ctxt()
-                    .enter(|infcx| {
-                        infcx.get_impl_future_output_ty(ty).unwrap_or_else(|| {
+                hir::IsAsync::Async => {
+                    let infcx = self.tcx.infer_ctxt().build();
+                    infcx
+                        .get_impl_future_output_ty(ty)
+                        .unwrap_or_else(|| {
                             span_bug!(
                                 fn_decl.output.span(),
                                 "failed to get output type of async function"
                             )
                         })
-                    })
-                    .skip_binder(),
+                        .skip_binder()
+                }
                 hir::IsAsync::NotAsync => ty,
             };
             if self.can_coerce(found, ty) {
@@ -1037,7 +1037,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // We'll later suggest `.as_ref` when noting the type error,
         // so skip if we will suggest that instead.
-        if self.should_suggest_as_ref(expected_ty, expr_ty).is_some() {
+        if self.err_ctxt().should_suggest_as_ref(expected_ty, expr_ty).is_some() {
             return false;
         }
 
@@ -1187,7 +1187,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected_ty: Ty<'tcx>,
         err: &mut Diagnostic,
     ) -> bool {
-        if let Some((span_semi, boxed)) = self.could_remove_semicolon(blk, expected_ty) {
+        if let Some((span_semi, boxed)) = self.err_ctxt().could_remove_semicolon(blk, expected_ty) {
             if let StatementAsExpression::NeedsBoxing = boxed {
                 err.span_suggestion_verbose(
                     span_semi,
diff --git a/compiler/rustc_hir_analysis/src/check/inherited.rs b/compiler/rustc_hir_analysis/src/check/inherited.rs
index 2546227e138..0fb7651b3a1 100644
--- a/compiler/rustc_hir_analysis/src/check/inherited.rs
+++ b/compiler/rustc_hir_analysis/src/check/inherited.rs
@@ -6,7 +6,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::HirIdMap;
 use rustc_infer::infer;
-use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
+use rustc_infer::infer::{DefiningAnchor, InferCtxt, InferOk, TyCtxtInferExt};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -29,10 +29,10 @@ use std::ops::Deref;
 /// Here, the function `foo()` and the closure passed to
 /// `bar()` will each have their own `FnCtxt`, but they will
 /// share the inherited fields.
-pub struct Inherited<'a, 'tcx> {
-    pub(super) infcx: InferCtxt<'a, 'tcx>,
+pub struct Inherited<'tcx> {
+    pub(super) infcx: InferCtxt<'tcx>,
 
-    pub(super) typeck_results: &'a RefCell<ty::TypeckResults<'tcx>>,
+    pub(super) typeck_results: RefCell<ty::TypeckResults<'tcx>>,
 
     pub(super) locals: RefCell<HirIdMap<super::LocalTy<'tcx>>>,
 
@@ -70,22 +70,23 @@ pub struct Inherited<'a, 'tcx> {
     pub(super) diverging_type_vars: RefCell<FxHashSet<Ty<'tcx>>>,
 }
 
-impl<'a, 'tcx> Deref for Inherited<'a, 'tcx> {
-    type Target = InferCtxt<'a, 'tcx>;
+impl<'tcx> Deref for Inherited<'tcx> {
+    type Target = InferCtxt<'tcx>;
     fn deref(&self) -> &Self::Target {
         &self.infcx
     }
 }
 
 /// A temporary returned by `Inherited::build(...)`. This is necessary
-/// for multiple `InferCtxt` to share the same `in_progress_typeck_results`
+/// for multiple `InferCtxt` to share the same `typeck_results`
 /// without using `Rc` or something similar.
 pub struct InheritedBuilder<'tcx> {
     infcx: infer::InferCtxtBuilder<'tcx>,
     def_id: LocalDefId,
+    typeck_results: RefCell<ty::TypeckResults<'tcx>>,
 }
 
-impl<'tcx> Inherited<'_, 'tcx> {
+impl<'tcx> Inherited<'tcx> {
     pub fn build(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> InheritedBuilder<'tcx> {
         let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner;
 
@@ -93,7 +94,7 @@ impl<'tcx> Inherited<'_, 'tcx> {
             infcx: tcx
                 .infer_ctxt()
                 .ignoring_regions()
-                .with_fresh_in_progress_typeck_results(hir_owner)
+                .with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id))
                 .with_normalize_fn_sig_for_diagnostic(Lrc::new(move |infcx, fn_sig| {
                     if fn_sig.has_escaping_bound_vars() {
                         return fn_sig;
@@ -117,26 +118,29 @@ impl<'tcx> Inherited<'_, 'tcx> {
                     })
                 })),
             def_id,
+            typeck_results: RefCell::new(ty::TypeckResults::new(hir_owner)),
         }
     }
 }
 
 impl<'tcx> InheritedBuilder<'tcx> {
-    pub fn enter<F, R>(&mut self, f: F) -> R
+    pub fn enter<F, R>(mut self, f: F) -> R
     where
-        F: for<'a> FnOnce(Inherited<'a, 'tcx>) -> R,
+        F: FnOnce(&Inherited<'tcx>) -> R,
     {
         let def_id = self.def_id;
-        self.infcx.enter(|infcx| f(Inherited::new(infcx, def_id)))
+        f(&Inherited::new(self.infcx.build(), def_id, self.typeck_results))
     }
 }
 
-impl<'a, 'tcx> Inherited<'a, 'tcx> {
-    fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self {
+impl<'tcx> Inherited<'tcx> {
+    fn new(
+        infcx: InferCtxt<'tcx>,
+        def_id: LocalDefId,
+        typeck_results: RefCell<ty::TypeckResults<'tcx>>,
+    ) -> Self {
         let tcx = infcx.tcx;
         let body_id = tcx.hir().maybe_body_owned_by(def_id);
-        let typeck_results =
-            infcx.in_progress_typeck_results.expect("building `FnCtxt` without typeck results");
 
         Inherited {
             typeck_results,
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index 4abc00cefb6..25228f424cd 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
@@ -44,13 +44,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) {
         let tcx = self.tcx;
         let span = tcx.hir().span(hir_id);
-        let convert = |ty: Ty<'tcx>| {
+        let normalize = |ty| {
             let ty = self.resolve_vars_if_possible(ty);
-            let ty = tcx.normalize_erasing_regions(self.param_env, ty);
-            (SizeSkeleton::compute(ty, tcx, self.param_env), ty)
+            self.tcx.normalize_erasing_regions(self.param_env, ty)
         };
-        let (sk_from, from) = convert(from);
-        let (sk_to, to) = convert(to);
+        let from = normalize(from);
+        let to = normalize(to);
+        trace!(?from, ?to);
+
+        // Transmutes that are only changing lifetimes are always ok.
+        if from == to {
+            return;
+        }
+
+        let skel = |ty| SizeSkeleton::compute(ty, tcx, self.param_env);
+        let sk_from = skel(from);
+        let sk_to = skel(to);
+        trace!(?sk_from, ?sk_to);
 
         // Check for same size using the skeletons.
         if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) {
diff --git a/compiler/rustc_hir_analysis/src/check/method/probe.rs b/compiler/rustc_hir_analysis/src/check/method/probe.rs
index a761a93dea4..ba078ad0abb 100644
--- a/compiler/rustc_hir_analysis/src/check/method/probe.rs
+++ b/compiler/rustc_hir_analysis/src/check/method/probe.rs
@@ -472,69 +472,65 @@ fn method_autoderef_steps<'tcx>(
 ) -> MethodAutoderefStepsResult<'tcx> {
     debug!("method_autoderef_steps({:?})", goal);
 
-    tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &goal, |ref infcx, goal, inference_vars| {
-        let ParamEnvAnd { param_env, value: self_ty } = goal;
-
-        let mut autoderef =
-            Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty, DUMMY_SP)
-                .include_raw_pointers()
-                .silence_errors();
-        let mut reached_raw_pointer = false;
-        let mut steps: Vec<_> = autoderef
-            .by_ref()
-            .map(|(ty, d)| {
-                let step = CandidateStep {
-                    self_ty: infcx.make_query_response_ignoring_pending_obligations(
-                        inference_vars.clone(),
-                        ty,
-                    ),
-                    autoderefs: d,
-                    from_unsafe_deref: reached_raw_pointer,
-                    unsize: false,
-                };
-                if let ty::RawPtr(_) = ty.kind() {
-                    // all the subsequent steps will be from_unsafe_deref
-                    reached_raw_pointer = true;
-                }
-                step
-            })
-            .collect();
-
-        let final_ty = autoderef.final_ty(true);
-        let opt_bad_ty = match final_ty.kind() {
-            ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy {
-                reached_raw_pointer,
-                ty: infcx
-                    .make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
-            }),
-            ty::Array(elem_ty, _) => {
-                let dereferences = steps.len() - 1;
-
-                steps.push(CandidateStep {
-                    self_ty: infcx.make_query_response_ignoring_pending_obligations(
-                        inference_vars,
-                        infcx.tcx.mk_slice(*elem_ty),
-                    ),
-                    autoderefs: dereferences,
-                    // this could be from an unsafe deref if we had
-                    // a *mut/const [T; N]
-                    from_unsafe_deref: reached_raw_pointer,
-                    unsize: true,
-                });
-
-                None
+    let (ref infcx, goal, inference_vars) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &goal);
+    let ParamEnvAnd { param_env, value: self_ty } = goal;
+
+    let mut autoderef =
+        Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty, DUMMY_SP)
+            .include_raw_pointers()
+            .silence_errors();
+    let mut reached_raw_pointer = false;
+    let mut steps: Vec<_> = autoderef
+        .by_ref()
+        .map(|(ty, d)| {
+            let step = CandidateStep {
+                self_ty: infcx
+                    .make_query_response_ignoring_pending_obligations(inference_vars.clone(), ty),
+                autoderefs: d,
+                from_unsafe_deref: reached_raw_pointer,
+                unsize: false,
+            };
+            if let ty::RawPtr(_) = ty.kind() {
+                // all the subsequent steps will be from_unsafe_deref
+                reached_raw_pointer = true;
             }
-            _ => None,
-        };
-
-        debug!("method_autoderef_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty);
+            step
+        })
+        .collect();
+
+    let final_ty = autoderef.final_ty(true);
+    let opt_bad_ty = match final_ty.kind() {
+        ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy {
+            reached_raw_pointer,
+            ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
+        }),
+        ty::Array(elem_ty, _) => {
+            let dereferences = steps.len() - 1;
+
+            steps.push(CandidateStep {
+                self_ty: infcx.make_query_response_ignoring_pending_obligations(
+                    inference_vars,
+                    infcx.tcx.mk_slice(*elem_ty),
+                ),
+                autoderefs: dereferences,
+                // this could be from an unsafe deref if we had
+                // a *mut/const [T; N]
+                from_unsafe_deref: reached_raw_pointer,
+                unsize: true,
+            });
 
-        MethodAutoderefStepsResult {
-            steps: tcx.arena.alloc_from_iter(steps),
-            opt_bad_ty: opt_bad_ty.map(|ty| &*tcx.arena.alloc(ty)),
-            reached_recursion_limit: autoderef.reached_recursion_limit(),
+            None
         }
-    })
+        _ => None,
+    };
+
+    debug!("method_autoderef_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty);
+
+    MethodAutoderefStepsResult {
+        steps: tcx.arena.alloc_from_iter(steps),
+        opt_bad_ty: opt_bad_ty.map(|ty| &*tcx.arena.alloc(ty)),
+        reached_recursion_limit: autoderef.reached_recursion_limit(),
+    }
 }
 
 impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
diff --git a/compiler/rustc_hir_analysis/src/check/method/suggest.rs b/compiler/rustc_hir_analysis/src/check/method/suggest.rs
index ad1084bd1b1..e276c4f7d84 100644
--- a/compiler/rustc_hir_analysis/src/check/method/suggest.rs
+++ b/compiler/rustc_hir_analysis/src/check/method/suggest.rs
@@ -22,7 +22,7 @@ use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef};
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Symbol;
 use rustc_span::{lev_distance, source_map, ExpnKind, FileName, MacroKind, Span};
-use rustc_trait_selection::traits::error_reporting::on_unimplemented::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::on_unimplemented::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_trait_selection::traits::{
     FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedNote,
@@ -855,8 +855,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                             // Avoid crashing.
                                             return (None, None);
                                         }
-                                        let OnUnimplementedNote { message, label, .. } =
-                                            self.on_unimplemented_note(trait_ref, &obligation);
+                                        let OnUnimplementedNote { message, label, .. } = self
+                                            .err_ctxt()
+                                            .on_unimplemented_note(trait_ref, &obligation);
                                         (message, label)
                                     })
                                     .unwrap_or((None, None))
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 593a9776bde..331bd7e26c8 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -123,7 +123,6 @@ use rustc_span::{self, BytePos, Span, Symbol};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits;
-use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error;
 use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
 use std::cell::RefCell;
 use std::num::NonZeroU32;
@@ -251,6 +250,7 @@ pub fn provide(providers: &mut Providers) {
         check_mod_item_types,
         region_scope_tree,
         collect_trait_impl_trait_tys,
+        compare_assoc_const_impl_item_with_trait_item: compare_method::raw_compare_const_impl,
         ..*providers
     };
 }
diff --git a/compiler/rustc_hir_analysis/src/check/op.rs b/compiler/rustc_hir_analysis/src/check/op.rs
index d876b1d20fe..5e498a92ec2 100644
--- a/compiler/rustc_hir_analysis/src/check/op.rs
+++ b/compiler/rustc_hir_analysis/src/check/op.rs
@@ -18,7 +18,7 @@ use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 use rustc_trait_selection::infer::InferCtxtExt;
-use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::{FulfillmentError, TraitEngine, TraitEngineExt};
 use rustc_type_ir::sty::TyKind::*;
 
@@ -512,7 +512,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                         _ => None,
                                     };
 
-                                    self.suggest_restricting_param_bound(
+                                    self.err_ctxt().suggest_restricting_param_bound(
                                         &mut err,
                                         trait_pred,
                                         output_associated_item,
@@ -662,7 +662,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             error.obligation.predicate.to_opt_poly_trait_pred()
                         });
                         for pred in predicates {
-                            self.suggest_restricting_param_bound(
+                            self.err_ctxt().suggest_restricting_param_bound(
                                 &mut err,
                                 pred,
                                 None,
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index d607f901420..0bd45bb1c91 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -22,7 +22,7 @@ use rustc_session::parse::feature_err;
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_trait_selection::autoderef::Autoderef;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
 use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_trait_selection::traits::{
@@ -91,29 +91,28 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
 {
     let param_env = tcx.param_env(body_def_id);
     let body_id = tcx.hir().local_def_id_to_hir_id(body_def_id);
-    tcx.infer_ctxt().enter(|ref infcx| {
-        let ocx = ObligationCtxt::new(infcx);
+    let infcx = &tcx.infer_ctxt().build();
+    let ocx = ObligationCtxt::new(infcx);
 
-        let assumed_wf_types = ocx.assumed_wf_types(param_env, span, body_def_id);
+    let assumed_wf_types = ocx.assumed_wf_types(param_env, span, body_def_id);
 
-        let mut wfcx = WfCheckingCtxt { ocx, span, body_id, param_env };
+    let mut wfcx = WfCheckingCtxt { ocx, span, body_id, param_env };
 
-        if !tcx.features().trivial_bounds {
-            wfcx.check_false_global_bounds()
-        }
-        f(&mut wfcx);
-        let errors = wfcx.select_all_or_error();
-        if !errors.is_empty() {
-            infcx.report_fulfillment_errors(&errors, None, false);
-            return;
-        }
+    if !tcx.features().trivial_bounds {
+        wfcx.check_false_global_bounds()
+    }
+    f(&mut wfcx);
+    let errors = wfcx.select_all_or_error();
+    if !errors.is_empty() {
+        infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+        return;
+    }
 
-        let implied_bounds = infcx.implied_bounds_tys(param_env, body_id, assumed_wf_types);
-        let outlives_environment =
-            OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
+    let implied_bounds = infcx.implied_bounds_tys(param_env, body_id, assumed_wf_types);
+    let outlives_environment =
+        OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
 
-        infcx.check_region_obligations_and_report_errors(body_def_id, &outlives_environment);
-    })
+    infcx.check_region_obligations_and_report_errors(body_def_id, &outlives_environment);
 }
 
 fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) {
@@ -699,29 +698,28 @@ fn resolve_regions_with_wf_tys<'tcx>(
     id: hir::HirId,
     param_env: ty::ParamEnv<'tcx>,
     wf_tys: &FxHashSet<Ty<'tcx>>,
-    add_constraints: impl for<'a> FnOnce(&'a InferCtxt<'a, 'tcx>, &'a RegionBoundPairs<'tcx>),
+    add_constraints: impl for<'a> FnOnce(&'a InferCtxt<'tcx>, &'a RegionBoundPairs<'tcx>),
 ) -> bool {
     // Unfortunately, we have to use a new `InferCtxt` each call, because
     // region constraints get added and solved there and we need to test each
     // call individually.
-    tcx.infer_ctxt().enter(|infcx| {
-        let outlives_environment = OutlivesEnvironment::with_bounds(
-            param_env,
-            Some(&infcx),
-            infcx.implied_bounds_tys(param_env, id, wf_tys.clone()),
-        );
-        let region_bound_pairs = outlives_environment.region_bound_pairs();
+    let infcx = tcx.infer_ctxt().build();
+    let outlives_environment = OutlivesEnvironment::with_bounds(
+        param_env,
+        Some(&infcx),
+        infcx.implied_bounds_tys(param_env, id, wf_tys.clone()),
+    );
+    let region_bound_pairs = outlives_environment.region_bound_pairs();
 
-        add_constraints(&infcx, region_bound_pairs);
+    add_constraints(&infcx, region_bound_pairs);
 
-        let errors = infcx.resolve_regions(&outlives_environment);
+    let errors = infcx.resolve_regions(&outlives_environment);
 
-        debug!(?errors, "errors");
+    debug!(?errors, "errors");
 
-        // If we were able to prove that the type outlives the region without
-        // an error, it must be because of the implied or explicit bounds...
-        errors.is_empty()
-    })
+    // If we were able to prove that the type outlives the region without
+    // an error, it must be because of the implied or explicit bounds...
+    errors.is_empty()
 }
 
 /// TypeVisitor that looks for uses of GATs like
@@ -839,7 +837,7 @@ fn check_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) {
     let (method_sig, span) = match impl_item.kind {
         hir::ImplItemKind::Fn(ref sig, _) => (Some(sig), impl_item.span),
         // Constrain binding and overflow error spans to `<Ty>` in `type foo = <Ty>`.
-        hir::ImplItemKind::TyAlias(ty) if ty.span != DUMMY_SP => (None, ty.span),
+        hir::ImplItemKind::Type(ty) if ty.span != DUMMY_SP => (None, ty.span),
         _ => (None, impl_item.span),
     };
 
@@ -1677,7 +1675,7 @@ fn receiver_is_valid<'tcx>(
     // `self: Self` is always valid.
     if can_eq_self(receiver_ty) {
         if let Err(err) = wfcx.equate_types(&cause, wfcx.param_env, self_ty, receiver_ty) {
-            infcx.report_mismatched_types(&cause, self_ty, receiver_ty, err).emit();
+            infcx.err_ctxt().report_mismatched_types(&cause, self_ty, receiver_ty, err).emit();
         }
         return true;
     }
@@ -1709,7 +1707,10 @@ fn receiver_is_valid<'tcx>(
                 if let Err(err) =
                     wfcx.equate_types(&cause, wfcx.param_env, self_ty, potential_self_ty)
                 {
-                    infcx.report_mismatched_types(&cause, self_ty, potential_self_ty, err).emit();
+                    infcx
+                        .err_ctxt()
+                        .report_mismatched_types(&cause, self_ty, potential_self_ty, err)
+                        .emit();
                 }
 
                 break;
diff --git a/compiler/rustc_hir_analysis/src/check/writeback.rs b/compiler/rustc_hir_analysis/src/check/writeback.rs
index 680dbf7037f..3583769b7cd 100644
--- a/compiler/rustc_hir_analysis/src/check/writeback.rs
+++ b/compiler/rustc_hir_analysis/src/check/writeback.rs
@@ -700,7 +700,7 @@ impl Locatable for hir::HirId {
 /// unresolved types and so forth.
 struct Resolver<'cx, 'tcx> {
     tcx: TyCtxt<'tcx>,
-    infcx: &'cx InferCtxt<'cx, 'tcx>,
+    infcx: &'cx InferCtxt<'tcx>,
     span: &'cx dyn Locatable,
     body: &'tcx hir::Body<'tcx>,
 
@@ -720,6 +720,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
     fn report_error(&self, p: impl Into<ty::GenericArg<'tcx>>) {
         if !self.tcx.sess.has_errors().is_some() {
             self.infcx
+                .err_ctxt()
                 .emit_inference_failure_err(
                     Some(self.body.id()),
                     self.span.to_span(self.tcx),
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index d4eb826f0b4..b6c91d425df 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -12,7 +12,7 @@ use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
 use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitable};
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
 use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError};
 use rustc_trait_selection::traits::predicate_for_trait_def;
 use rustc_trait_selection::traits::{self, ObligationCause};
@@ -108,43 +108,42 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
                 // why this field does not implement Copy. This is useful because sometimes
                 // it is not immediately clear why Copy is not implemented for a field, since
                 // all we point at is the field itself.
-                tcx.infer_ctxt().ignoring_regions().enter(|infcx| {
-                    for error in traits::fully_solve_bound(
-                        &infcx,
-                        traits::ObligationCause::dummy_with_span(field_ty_span),
-                        param_env,
-                        ty,
-                        tcx.lang_items().copy_trait().unwrap(),
-                    ) {
-                        let error_predicate = error.obligation.predicate;
-                        // Only note if it's not the root obligation, otherwise it's trivial and
-                        // should be self-explanatory (i.e. a field literally doesn't implement Copy).
-
-                        // FIXME: This error could be more descriptive, especially if the error_predicate
-                        // contains a foreign type or if it's a deeply nested type...
-                        if error_predicate != error.root_obligation.predicate {
-                            errors
-                                .entry((ty.to_string(), error_predicate.to_string()))
-                                .or_default()
-                                .push(error.obligation.cause.span);
-                        }
-                        if let ty::PredicateKind::Trait(ty::TraitPredicate {
-                            trait_ref,
-                            polarity: ty::ImplPolarity::Positive,
-                            ..
-                        }) = error_predicate.kind().skip_binder()
-                        {
-                            let ty = trait_ref.self_ty();
-                            if let ty::Param(_) = ty.kind() {
-                                bounds.push((
-                                    format!("{ty}"),
-                                    trait_ref.print_only_trait_path().to_string(),
-                                    Some(trait_ref.def_id),
-                                ));
-                            }
+                let infcx = tcx.infer_ctxt().ignoring_regions().build();
+                for error in traits::fully_solve_bound(
+                    &infcx,
+                    traits::ObligationCause::dummy_with_span(field_ty_span),
+                    param_env,
+                    ty,
+                    tcx.lang_items().copy_trait().unwrap(),
+                ) {
+                    let error_predicate = error.obligation.predicate;
+                    // Only note if it's not the root obligation, otherwise it's trivial and
+                    // should be self-explanatory (i.e. a field literally doesn't implement Copy).
+
+                    // FIXME: This error could be more descriptive, especially if the error_predicate
+                    // contains a foreign type or if it's a deeply nested type...
+                    if error_predicate != error.root_obligation.predicate {
+                        errors
+                            .entry((ty.to_string(), error_predicate.to_string()))
+                            .or_default()
+                            .push(error.obligation.cause.span);
+                    }
+                    if let ty::PredicateKind::Trait(ty::TraitPredicate {
+                        trait_ref,
+                        polarity: ty::ImplPolarity::Positive,
+                        ..
+                    }) = error_predicate.kind().skip_binder()
+                    {
+                        let ty = trait_ref.self_ty();
+                        if let ty::Param(_) = ty.kind() {
+                            bounds.push((
+                                format!("{ty}"),
+                                trait_ref.print_only_trait_path().to_string(),
+                                Some(trait_ref.def_id),
+                            ));
                         }
                     }
-                });
+                }
             }
             for ((ty, error_predicate), spans) in errors {
                 let span: MultiSpan = spans.into();
@@ -205,91 +204,89 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did:
 
     let create_err = |msg: &str| struct_span_err!(tcx.sess, span, E0378, "{}", msg);
 
-    tcx.infer_ctxt().enter(|infcx| {
-        let cause = ObligationCause::misc(span, impl_hir_id);
-
-        use rustc_type_ir::sty::TyKind::*;
-        match (source.kind(), target.kind()) {
-            (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
-                if infcx.at(&cause, param_env).eq(r_a, *r_b).is_ok() && mutbl_a == *mutbl_b => {}
-            (&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => (),
-            (&Adt(def_a, substs_a), &Adt(def_b, substs_b))
-                if def_a.is_struct() && def_b.is_struct() =>
-            {
-                if def_a != def_b {
-                    let source_path = tcx.def_path_str(def_a.did());
-                    let target_path = tcx.def_path_str(def_b.did());
-
-                    create_err(&format!(
-                        "the trait `DispatchFromDyn` may only be implemented \
-                                for a coercion between structures with the same \
-                                definition; expected `{}`, found `{}`",
-                        source_path, target_path,
-                    ))
-                    .emit();
+    let infcx = tcx.infer_ctxt().build();
+    let cause = ObligationCause::misc(span, impl_hir_id);
+
+    use rustc_type_ir::sty::TyKind::*;
+    match (source.kind(), target.kind()) {
+        (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
+            if infcx.at(&cause, param_env).eq(r_a, *r_b).is_ok() && mutbl_a == *mutbl_b => {}
+        (&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => (),
+        (&Adt(def_a, substs_a), &Adt(def_b, substs_b))
+            if def_a.is_struct() && def_b.is_struct() =>
+        {
+            if def_a != def_b {
+                let source_path = tcx.def_path_str(def_a.did());
+                let target_path = tcx.def_path_str(def_b.did());
+
+                create_err(&format!(
+                    "the trait `DispatchFromDyn` may only be implemented \
+                            for a coercion between structures with the same \
+                            definition; expected `{}`, found `{}`",
+                    source_path, target_path,
+                ))
+                .emit();
 
-                    return;
-                }
+                return;
+            }
 
-                if def_a.repr().c() || def_a.repr().packed() {
-                    create_err(
-                        "structs implementing `DispatchFromDyn` may not have \
-                             `#[repr(packed)]` or `#[repr(C)]`",
-                    )
-                    .emit();
-                }
+            if def_a.repr().c() || def_a.repr().packed() {
+                create_err(
+                    "structs implementing `DispatchFromDyn` may not have \
+                         `#[repr(packed)]` or `#[repr(C)]`",
+                )
+                .emit();
+            }
 
-                let fields = &def_a.non_enum_variant().fields;
+            let fields = &def_a.non_enum_variant().fields;
 
-                let coerced_fields = fields
-                    .iter()
-                    .filter(|field| {
-                        let ty_a = field.ty(tcx, substs_a);
-                        let ty_b = field.ty(tcx, substs_b);
+            let coerced_fields = fields
+                .iter()
+                .filter(|field| {
+                    let ty_a = field.ty(tcx, substs_a);
+                    let ty_b = field.ty(tcx, substs_b);
 
-                        if let Ok(layout) = tcx.layout_of(param_env.and(ty_a)) {
-                            if layout.is_zst() && layout.align.abi.bytes() == 1 {
-                                // ignore ZST fields with alignment of 1 byte
-                                return false;
-                            }
+                    if let Ok(layout) = tcx.layout_of(param_env.and(ty_a)) {
+                        if layout.is_zst() && layout.align.abi.bytes() == 1 {
+                            // ignore ZST fields with alignment of 1 byte
+                            return false;
                         }
+                    }
 
-                        if let Ok(ok) = infcx.at(&cause, param_env).eq(ty_a, ty_b) {
-                            if ok.obligations.is_empty() {
-                                create_err(
-                                    "the trait `DispatchFromDyn` may only be implemented \
-                                     for structs containing the field being coerced, \
-                                     ZST fields with 1 byte alignment, and nothing else",
-                                )
-                                .note(&format!(
-                                    "extra field `{}` of type `{}` is not allowed",
-                                    field.name, ty_a,
-                                ))
-                                .emit();
-
-                                return false;
-                            }
+                    if let Ok(ok) = infcx.at(&cause, param_env).eq(ty_a, ty_b) {
+                        if ok.obligations.is_empty() {
+                            create_err(
+                                "the trait `DispatchFromDyn` may only be implemented \
+                                 for structs containing the field being coerced, \
+                                 ZST fields with 1 byte alignment, and nothing else",
+                            )
+                            .note(&format!(
+                                "extra field `{}` of type `{}` is not allowed",
+                                field.name, ty_a,
+                            ))
+                            .emit();
+
+                            return false;
                         }
+                    }
 
-                        return true;
-                    })
-                    .collect::<Vec<_>>();
+                    return true;
+                })
+                .collect::<Vec<_>>();
 
-                if coerced_fields.is_empty() {
-                    create_err(
-                        "the trait `DispatchFromDyn` may only be implemented \
-                            for a coercion between structures with a single field \
-                            being coerced, none found",
-                    )
-                    .emit();
-                } else if coerced_fields.len() > 1 {
-                    create_err(
-                        "implementing the `DispatchFromDyn` trait requires multiple coercions",
-                    )
+            if coerced_fields.is_empty() {
+                create_err(
+                    "the trait `DispatchFromDyn` may only be implemented \
+                        for a coercion between structures with a single field \
+                        being coerced, none found",
+                )
+                .emit();
+            } else if coerced_fields.len() > 1 {
+                create_err("implementing the `DispatchFromDyn` trait requires multiple coercions")
                     .note(
                         "the trait `DispatchFromDyn` may only be implemented \
-                                for a coercion between structures with a single field \
-                                being coerced",
+                            for a coercion between structures with a single field \
+                            being coerced",
                     )
                     .note(&format!(
                         "currently, {} fields need coercions: {}",
@@ -308,39 +305,38 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did:
                             .join(", ")
                     ))
                     .emit();
-                } else {
-                    let errors = traits::fully_solve_obligations(
-                        &infcx,
-                        coerced_fields.into_iter().map(|field| {
-                            predicate_for_trait_def(
-                                tcx,
-                                param_env,
-                                cause.clone(),
-                                dispatch_from_dyn_trait,
-                                0,
-                                field.ty(tcx, substs_a),
-                                &[field.ty(tcx, substs_b).into()],
-                            )
-                        }),
-                    );
-                    if !errors.is_empty() {
-                        infcx.report_fulfillment_errors(&errors, None, false);
-                    }
-
-                    // Finally, resolve all regions.
-                    let outlives_env = OutlivesEnvironment::new(param_env);
-                    infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env);
+            } else {
+                let errors = traits::fully_solve_obligations(
+                    &infcx,
+                    coerced_fields.into_iter().map(|field| {
+                        predicate_for_trait_def(
+                            tcx,
+                            param_env,
+                            cause.clone(),
+                            dispatch_from_dyn_trait,
+                            0,
+                            field.ty(tcx, substs_a),
+                            &[field.ty(tcx, substs_b).into()],
+                        )
+                    }),
+                );
+                if !errors.is_empty() {
+                    infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
                 }
-            }
-            _ => {
-                create_err(
-                    "the trait `DispatchFromDyn` may only be implemented \
-                        for a coercion between structures",
-                )
-                .emit();
+
+                // Finally, resolve all regions.
+                let outlives_env = OutlivesEnvironment::new(param_env);
+                infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env);
             }
         }
-    })
+        _ => {
+            create_err(
+                "the trait `DispatchFromDyn` may only be implemented \
+                    for a coercion between structures",
+            )
+            .emit();
+        }
+    }
 }
 
 pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedInfo {
@@ -369,220 +365,208 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
 
     debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);
 
-    tcx.infer_ctxt().enter(|infcx| {
-        let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
-        let cause = ObligationCause::misc(span, impl_hir_id);
-        let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
-                           mt_b: ty::TypeAndMut<'tcx>,
-                           mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| {
-            if (mt_a.mutbl, mt_b.mutbl) == (hir::Mutability::Not, hir::Mutability::Mut) {
-                infcx
-                    .report_mismatched_types(
-                        &cause,
-                        mk_ptr(mt_b.ty),
-                        target,
-                        ty::error::TypeError::Mutability,
-                    )
-                    .emit();
-            }
-            (mt_a.ty, mt_b.ty, unsize_trait, None)
-        };
-        let (source, target, trait_def_id, kind) = match (source.kind(), target.kind()) {
-            (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
-                infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
-                let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
-                let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
-                check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty))
-            }
+    let infcx = tcx.infer_ctxt().build();
+    let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
+    let cause = ObligationCause::misc(span, impl_hir_id);
+    let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
+                       mt_b: ty::TypeAndMut<'tcx>,
+                       mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| {
+        if (mt_a.mutbl, mt_b.mutbl) == (hir::Mutability::Not, hir::Mutability::Mut) {
+            infcx
+                .err_ctxt()
+                .report_mismatched_types(
+                    &cause,
+                    mk_ptr(mt_b.ty),
+                    target,
+                    ty::error::TypeError::Mutability,
+                )
+                .emit();
+        }
+        (mt_a.ty, mt_b.ty, unsize_trait, None)
+    };
+    let (source, target, trait_def_id, kind) = match (source.kind(), target.kind()) {
+        (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
+            infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
+            let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
+            let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
+            check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty))
+        }
 
-            (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(mt_b)) => {
-                let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
-                check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
-            }
+        (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(mt_b)) => {
+            let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
+            check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
+        }
+
+        (&ty::RawPtr(mt_a), &ty::RawPtr(mt_b)) => check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty)),
 
-            (&ty::RawPtr(mt_a), &ty::RawPtr(mt_b)) => {
-                check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
+        (&ty::Adt(def_a, substs_a), &ty::Adt(def_b, substs_b))
+            if def_a.is_struct() && def_b.is_struct() =>
+        {
+            if def_a != def_b {
+                let source_path = tcx.def_path_str(def_a.did());
+                let target_path = tcx.def_path_str(def_b.did());
+                struct_span_err!(
+                    tcx.sess,
+                    span,
+                    E0377,
+                    "the trait `CoerceUnsized` may only be implemented \
+                           for a coercion between structures with the same \
+                           definition; expected `{}`, found `{}`",
+                    source_path,
+                    target_path
+                )
+                .emit();
+                return err_info;
             }
 
-            (&ty::Adt(def_a, substs_a), &ty::Adt(def_b, substs_b))
-                if def_a.is_struct() && def_b.is_struct() =>
-            {
-                if def_a != def_b {
-                    let source_path = tcx.def_path_str(def_a.did());
-                    let target_path = tcx.def_path_str(def_b.did());
-                    struct_span_err!(
-                        tcx.sess,
-                        span,
-                        E0377,
-                        "the trait `CoerceUnsized` may only be implemented \
-                               for a coercion between structures with the same \
-                               definition; expected `{}`, found `{}`",
-                        source_path,
-                        target_path
-                    )
-                    .emit();
-                    return err_info;
-                }
+            // Here we are considering a case of converting
+            // `S<P0...Pn>` to S<Q0...Qn>`. As an example, let's imagine a struct `Foo<T, U>`,
+            // which acts like a pointer to `U`, but carries along some extra data of type `T`:
+            //
+            //     struct Foo<T, U> {
+            //         extra: T,
+            //         ptr: *mut U,
+            //     }
+            //
+            // We might have an impl that allows (e.g.) `Foo<T, [i32; 3]>` to be unsized
+            // to `Foo<T, [i32]>`. That impl would look like:
+            //
+            //   impl<T, U: Unsize<V>, V> CoerceUnsized<Foo<T, V>> for Foo<T, U> {}
+            //
+            // Here `U = [i32; 3]` and `V = [i32]`. At runtime,
+            // when this coercion occurs, we would be changing the
+            // field `ptr` from a thin pointer of type `*mut [i32;
+            // 3]` to a fat pointer of type `*mut [i32]` (with
+            // extra data `3`).  **The purpose of this check is to
+            // make sure that we know how to do this conversion.**
+            //
+            // To check if this impl is legal, we would walk down
+            // the fields of `Foo` and consider their types with
+            // both substitutes. We are looking to find that
+            // exactly one (non-phantom) field has changed its
+            // type, which we will expect to be the pointer that
+            // is becoming fat (we could probably generalize this
+            // to multiple thin pointers of the same type becoming
+            // fat, but we don't). In this case:
+            //
+            // - `extra` has type `T` before and type `T` after
+            // - `ptr` has type `*mut U` before and type `*mut V` after
+            //
+            // Since just one field changed, we would then check
+            // that `*mut U: CoerceUnsized<*mut V>` is implemented
+            // (in other words, that we know how to do this
+            // conversion). This will work out because `U:
+            // Unsize<V>`, and we have a builtin rule that `*mut
+            // U` can be coerced to `*mut V` if `U: Unsize<V>`.
+            let fields = &def_a.non_enum_variant().fields;
+            let diff_fields = fields
+                .iter()
+                .enumerate()
+                .filter_map(|(i, f)| {
+                    let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
+
+                    if tcx.type_of(f.did).is_phantom_data() {
+                        // Ignore PhantomData fields
+                        return None;
+                    }
 
-                // Here we are considering a case of converting
-                // `S<P0...Pn>` to S<Q0...Qn>`. As an example, let's imagine a struct `Foo<T, U>`,
-                // which acts like a pointer to `U`, but carries along some extra data of type `T`:
-                //
-                //     struct Foo<T, U> {
-                //         extra: T,
-                //         ptr: *mut U,
-                //     }
-                //
-                // We might have an impl that allows (e.g.) `Foo<T, [i32; 3]>` to be unsized
-                // to `Foo<T, [i32]>`. That impl would look like:
-                //
-                //   impl<T, U: Unsize<V>, V> CoerceUnsized<Foo<T, V>> for Foo<T, U> {}
-                //
-                // Here `U = [i32; 3]` and `V = [i32]`. At runtime,
-                // when this coercion occurs, we would be changing the
-                // field `ptr` from a thin pointer of type `*mut [i32;
-                // 3]` to a fat pointer of type `*mut [i32]` (with
-                // extra data `3`).  **The purpose of this check is to
-                // make sure that we know how to do this conversion.**
-                //
-                // To check if this impl is legal, we would walk down
-                // the fields of `Foo` and consider their types with
-                // both substitutes. We are looking to find that
-                // exactly one (non-phantom) field has changed its
-                // type, which we will expect to be the pointer that
-                // is becoming fat (we could probably generalize this
-                // to multiple thin pointers of the same type becoming
-                // fat, but we don't). In this case:
-                //
-                // - `extra` has type `T` before and type `T` after
-                // - `ptr` has type `*mut U` before and type `*mut V` after
-                //
-                // Since just one field changed, we would then check
-                // that `*mut U: CoerceUnsized<*mut V>` is implemented
-                // (in other words, that we know how to do this
-                // conversion). This will work out because `U:
-                // Unsize<V>`, and we have a builtin rule that `*mut
-                // U` can be coerced to `*mut V` if `U: Unsize<V>`.
-                let fields = &def_a.non_enum_variant().fields;
-                let diff_fields = fields
-                    .iter()
-                    .enumerate()
-                    .filter_map(|(i, f)| {
-                        let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
-
-                        if tcx.type_of(f.did).is_phantom_data() {
-                            // Ignore PhantomData fields
+                    // Ignore fields that aren't changed; it may
+                    // be that we could get away with subtyping or
+                    // something more accepting, but we use
+                    // equality because we want to be able to
+                    // perform this check without computing
+                    // variance where possible. (This is because
+                    // we may have to evaluate constraint
+                    // expressions in the course of execution.)
+                    // See e.g., #41936.
+                    if let Ok(ok) = infcx.at(&cause, param_env).eq(a, b) {
+                        if ok.obligations.is_empty() {
                             return None;
                         }
+                    }
 
-                        // Ignore fields that aren't changed; it may
-                        // be that we could get away with subtyping or
-                        // something more accepting, but we use
-                        // equality because we want to be able to
-                        // perform this check without computing
-                        // variance where possible. (This is because
-                        // we may have to evaluate constraint
-                        // expressions in the course of execution.)
-                        // See e.g., #41936.
-                        if let Ok(ok) = infcx.at(&cause, param_env).eq(a, b) {
-                            if ok.obligations.is_empty() {
-                                return None;
-                            }
-                        }
+                    // Collect up all fields that were significantly changed
+                    // i.e., those that contain T in coerce_unsized T -> U
+                    Some((i, a, b))
+                })
+                .collect::<Vec<_>>();
 
-                        // Collect up all fields that were significantly changed
-                        // i.e., those that contain T in coerce_unsized T -> U
-                        Some((i, a, b))
-                    })
-                    .collect::<Vec<_>>();
-
-                if diff_fields.is_empty() {
-                    struct_span_err!(
-                        tcx.sess,
-                        span,
-                        E0374,
-                        "the trait `CoerceUnsized` may only be implemented \
-                               for a coercion between structures with one field \
-                               being coerced, none found"
-                    )
-                    .emit();
-                    return err_info;
-                } else if diff_fields.len() > 1 {
-                    let item = tcx.hir().expect_item(impl_did);
-                    let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(ref t), .. }) =
-                        item.kind
-                    {
+            if diff_fields.is_empty() {
+                struct_span_err!(
+                    tcx.sess,
+                    span,
+                    E0374,
+                    "the trait `CoerceUnsized` may only be implemented \
+                           for a coercion between structures with one field \
+                           being coerced, none found"
+                )
+                .emit();
+                return err_info;
+            } else if diff_fields.len() > 1 {
+                let item = tcx.hir().expect_item(impl_did);
+                let span =
+                    if let ItemKind::Impl(hir::Impl { of_trait: Some(ref t), .. }) = item.kind {
                         t.path.span
                     } else {
                         tcx.def_span(impl_did)
                     };
 
-                    struct_span_err!(
-                        tcx.sess,
-                        span,
-                        E0375,
-                        "implementing the trait \
-                                                    `CoerceUnsized` requires multiple \
-                                                    coercions"
-                    )
-                    .note(
-                        "`CoerceUnsized` may only be implemented for \
-                              a coercion between structures with one field being coerced",
-                    )
-                    .note(&format!(
-                        "currently, {} fields need coercions: {}",
-                        diff_fields.len(),
-                        diff_fields
-                            .iter()
-                            .map(|&(i, a, b)| {
-                                format!("`{}` (`{}` to `{}`)", fields[i].name, a, b)
-                            })
-                            .collect::<Vec<_>>()
-                            .join(", ")
-                    ))
-                    .span_label(span, "requires multiple coercions")
-                    .emit();
-                    return err_info;
-                }
-
-                let (i, a, b) = diff_fields[0];
-                let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
-                (a, b, coerce_unsized_trait, Some(kind))
-            }
-
-            _ => {
                 struct_span_err!(
                     tcx.sess,
                     span,
-                    E0376,
-                    "the trait `CoerceUnsized` may only be implemented \
-                           for a coercion between structures"
+                    E0375,
+                    "implementing the trait \
+                                                `CoerceUnsized` requires multiple \
+                                                coercions"
+                )
+                .note(
+                    "`CoerceUnsized` may only be implemented for \
+                          a coercion between structures with one field being coerced",
                 )
+                .note(&format!(
+                    "currently, {} fields need coercions: {}",
+                    diff_fields.len(),
+                    diff_fields
+                        .iter()
+                        .map(|&(i, a, b)| { format!("`{}` (`{}` to `{}`)", fields[i].name, a, b) })
+                        .collect::<Vec<_>>()
+                        .join(", ")
+                ))
+                .span_label(span, "requires multiple coercions")
                 .emit();
                 return err_info;
             }
-        };
-
-        // Register an obligation for `A: Trait<B>`.
-        let cause = traits::ObligationCause::misc(span, impl_hir_id);
-        let predicate = predicate_for_trait_def(
-            tcx,
-            param_env,
-            cause,
-            trait_def_id,
-            0,
-            source,
-            &[target.into()],
-        );
-        let errors = traits::fully_solve_obligation(&infcx, predicate);
-        if !errors.is_empty() {
-            infcx.report_fulfillment_errors(&errors, None, false);
+
+            let (i, a, b) = diff_fields[0];
+            let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
+            (a, b, coerce_unsized_trait, Some(kind))
         }
 
-        // Finally, resolve all regions.
-        let outlives_env = OutlivesEnvironment::new(param_env);
-        infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env);
+        _ => {
+            struct_span_err!(
+                tcx.sess,
+                span,
+                E0376,
+                "the trait `CoerceUnsized` may only be implemented \
+                       for a coercion between structures"
+            )
+            .emit();
+            return err_info;
+        }
+    };
+
+    // Register an obligation for `A: Trait<B>`.
+    let cause = traits::ObligationCause::misc(span, impl_hir_id);
+    let predicate =
+        predicate_for_trait_def(tcx, param_env, cause, trait_def_id, 0, source, &[target.into()]);
+    let errors = traits::fully_solve_obligation(&infcx, predicate);
+    if !errors.is_empty() {
+        infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+    }
+
+    // Finally, resolve all regions.
+    let outlives_env = OutlivesEnvironment::new(param_env);
+    infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env);
 
-        CoerceUnsizedInfo { custom_kind: kind }
-    })
+    CoerceUnsizedInfo { custom_kind: kind }
 }
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index ab4b861b6cb..6976c5a0edb 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -738,7 +738,7 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
         hir::ImplItemKind::Fn(..) => {
             tcx.ensure().fn_sig(def_id);
         }
-        hir::ImplItemKind::TyAlias(_) => {
+        hir::ImplItemKind::Type(_) => {
             // Account for `type T = _;`
             let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_impl_item(impl_item);
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 7ffacbecf5f..707fd6c7527 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -213,7 +213,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
         Node::TraitItem(item) if matches!(item.kind, TraitItemKind::Type(..)) => {
             (None, Defaults::Deny)
         }
-        Node::ImplItem(item) if matches!(item.kind, ImplItemKind::TyAlias(..)) => {
+        Node::ImplItem(item) if matches!(item.kind, ImplItemKind::Type(..)) => {
             (None, Defaults::Deny)
         }
 
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index f8a62c84910..1b7ed60929d 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -284,7 +284,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                     icx.to_ty(ty)
                 }
             }
-            ImplItemKind::TyAlias(ty) => {
+            ImplItemKind::Type(ty) => {
                 if tcx.impl_trait_ref(tcx.hir().get_parent_item(hir_id)).is_none() {
                     check_feature_inherent_assoc_ty(tcx, item.span);
                 }
@@ -493,8 +493,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                         },
                         def_id.to_def_id(),
                     );
-                    if let Some(assoc_item) = assoc_item {
-                        tcx.type_of(tcx.generics_of(assoc_item.def_id).params[idx].def_id)
+                    if let Some(param)
+                        = assoc_item.map(|item| &tcx.generics_of(item.def_id).params[idx]).filter(|param| param.kind.is_ty_or_const())
+                    {
+                        tcx.type_of(param.def_id)
                     } else {
                         // FIXME(associated_const_equality): add a useful error message here.
                         tcx.ty_error_with_message(
diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
index 8428e466406..213b89fc784 100644
--- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
+++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
@@ -114,9 +114,9 @@ pub fn identify_constrained_generic_params<'tcx>(
 /// ```
 /// The impl's predicates are collected from left to right. Ignoring
 /// the implicit `Sized` bounds, these are
-///   * T: Debug
-///   * U: Iterator
-///   * <U as Iterator>::Item = T -- a desugared ProjectionPredicate
+///   * `T: Debug`
+///   * `U: Iterator`
+///   * `<U as Iterator>::Item = T` -- a desugared ProjectionPredicate
 ///
 /// When we, for example, try to go over the trait-reference
 /// `IntoIter<u32> as Trait`, we substitute the impl parameters with fresh
@@ -132,12 +132,16 @@ pub fn identify_constrained_generic_params<'tcx>(
 ///
 /// We *do* have to be somewhat careful when projection targets contain
 /// projections themselves, for example in
+///
+/// ```ignore (illustrative)
 ///     impl<S,U,V,W> Trait for U where
 /// /* 0 */   S: Iterator<Item = U>,
 /// /* - */   U: Iterator,
 /// /* 1 */   <U as Iterator>::Item: ToOwned<Owned=(W,<V as Iterator>::Item)>
 /// /* 2 */   W: Iterator<Item = V>
 /// /* 3 */   V: Debug
+/// ```
+///
 /// we have to evaluate the projections in the order I wrote them:
 /// `V: Debug` requires `V` to be evaluated. The only projection that
 /// *determines* `V` is 2 (1 contains it, but *does not determine it*,
diff --git a/compiler/rustc_hir_analysis/src/expr_use_visitor.rs b/compiler/rustc_hir_analysis/src/expr_use_visitor.rs
index f483342b445..cbc3769901d 100644
--- a/compiler/rustc_hir_analysis/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_analysis/src/expr_use_visitor.rs
@@ -134,7 +134,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
     /// - `typeck_results` --- typeck results for the code being analyzed
     pub fn new(
         delegate: &'a mut (dyn Delegate<'tcx> + 'a),
-        infcx: &'a InferCtxt<'a, 'tcx>,
+        infcx: &'a InferCtxt<'tcx>,
         body_owner: LocalDefId,
         param_env: ty::ParamEnv<'tcx>,
         typeck_results: &'a ty::TypeckResults<'tcx>,
diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
index 7b080dc2942..b0fdfcf38a6 100644
--- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
@@ -64,38 +64,36 @@ fn diagnostic_hir_wf_check<'tcx>(
 
     impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> {
         fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
-            self.tcx.infer_ctxt().enter(|infcx| {
-                let tcx_ty =
-                    self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx });
-                let cause = traits::ObligationCause::new(
-                    ty.span,
-                    self.hir_id,
-                    traits::ObligationCauseCode::WellFormed(None),
-                );
-                let errors = traits::fully_solve_obligation(
-                    &infcx,
-                    traits::Obligation::new(
-                        cause,
-                        self.param_env,
-                        ty::Binder::dummy(ty::PredicateKind::WellFormed(tcx_ty.into()))
-                            .to_predicate(self.tcx),
-                    ),
-                );
-                if !errors.is_empty() {
-                    debug!("Wf-check got errors for {:?}: {:?}", ty, errors);
-                    for error in errors {
-                        if error.obligation.predicate == self.predicate {
-                            // Save the cause from the greatest depth - this corresponds
-                            // to picking more-specific types (e.g. `MyStruct<u8>`)
-                            // over less-specific types (e.g. `Option<MyStruct<u8>>`)
-                            if self.depth >= self.cause_depth {
-                                self.cause = Some(error.obligation.cause);
-                                self.cause_depth = self.depth
-                            }
+            let infcx = self.tcx.infer_ctxt().build();
+            let tcx_ty = self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx });
+            let cause = traits::ObligationCause::new(
+                ty.span,
+                self.hir_id,
+                traits::ObligationCauseCode::WellFormed(None),
+            );
+            let errors = traits::fully_solve_obligation(
+                &infcx,
+                traits::Obligation::new(
+                    cause,
+                    self.param_env,
+                    ty::Binder::dummy(ty::PredicateKind::WellFormed(tcx_ty.into()))
+                        .to_predicate(self.tcx),
+                ),
+            );
+            if !errors.is_empty() {
+                debug!("Wf-check got errors for {:?}: {:?}", ty, errors);
+                for error in errors {
+                    if error.obligation.predicate == self.predicate {
+                        // Save the cause from the greatest depth - this corresponds
+                        // to picking more-specific types (e.g. `MyStruct<u8>`)
+                        // over less-specific types (e.g. `Option<MyStruct<u8>>`)
+                        if self.depth >= self.cause_depth {
+                            self.cause = Some(error.obligation.cause);
+                            self.cause_depth = self.depth
                         }
                     }
                 }
-            });
+            }
             self.depth += 1;
             intravisit::walk_ty(self, ty);
             self.depth -= 1;
@@ -119,7 +117,7 @@ fn diagnostic_hir_wf_check<'tcx>(
     let ty = match loc {
         WellFormedLoc::Ty(_) => match hir.get(hir_id) {
             hir::Node::ImplItem(item) => match item.kind {
-                hir::ImplItemKind::TyAlias(ty) => Some(ty),
+                hir::ImplItemKind::Type(ty) => Some(ty),
                 hir::ImplItemKind::Const(ty, _) => Some(ty),
                 ref item => bug!("Unexpected ImplItem {:?}", item),
             },
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 5bebd7dee09..e806e94879d 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
@@ -77,7 +77,7 @@ use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
 use rustc_span::Span;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
 use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_trait_selection::traits::{self, translate_substs, wf, ObligationCtxt};
 
@@ -130,8 +130,10 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node
 ///
 /// Example
 ///
+/// ```ignore (illustrative)
 /// impl<A, B> Foo<A> for B { /* impl2 */ }
 /// impl<C> Foo<Vec<C>> for C { /* impl1 */ }
+/// ```
 ///
 /// Would return `S1 = [C]` and `S2 = [Vec<C>, C]`.
 fn get_impl_substs<'tcx>(
@@ -139,34 +141,33 @@ fn get_impl_substs<'tcx>(
     impl1_def_id: LocalDefId,
     impl2_node: Node,
 ) -> Option<(SubstsRef<'tcx>, SubstsRef<'tcx>)> {
-    tcx.infer_ctxt().enter(|ref infcx| {
-        let ocx = ObligationCtxt::new(infcx);
-        let param_env = tcx.param_env(impl1_def_id);
-        let impl1_hir_id = tcx.hir().local_def_id_to_hir_id(impl1_def_id);
+    let infcx = &tcx.infer_ctxt().build();
+    let ocx = ObligationCtxt::new(infcx);
+    let param_env = tcx.param_env(impl1_def_id);
+    let impl1_hir_id = tcx.hir().local_def_id_to_hir_id(impl1_def_id);
 
-        let assumed_wf_types =
-            ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id);
+    let assumed_wf_types =
+        ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id);
 
-        let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id.to_def_id());
-        let impl2_substs =
-            translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node);
+    let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id.to_def_id());
+    let impl2_substs =
+        translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node);
 
-        let errors = ocx.select_all_or_error();
-        if !errors.is_empty() {
-            ocx.infcx.report_fulfillment_errors(&errors, None, false);
-            return None;
-        }
+    let errors = ocx.select_all_or_error();
+    if !errors.is_empty() {
+        ocx.infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+        return None;
+    }
 
-        let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_hir_id, assumed_wf_types);
-        let outlives_env = OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
-        infcx.check_region_obligations_and_report_errors(impl1_def_id, &outlives_env);
-        let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
-            let span = tcx.def_span(impl1_def_id);
-            tcx.sess.emit_err(SubstsOnOverriddenImpl { span });
-            return None;
-        };
-        Some((impl1_substs, impl2_substs))
-    })
+    let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_hir_id, assumed_wf_types);
+    let outlives_env = OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
+    infcx.check_region_obligations_and_report_errors(impl1_def_id, &outlives_env);
+    let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
+        let span = tcx.def_span(impl1_def_id);
+        tcx.sess.emit_err(SubstsOnOverriddenImpl { span });
+        return None;
+    };
+    Some((impl1_substs, impl2_substs))
 }
 
 /// Returns a list of all of the unconstrained subst of the given impl.
@@ -226,13 +227,17 @@ fn unconstrained_parent_impl_substs<'tcx>(
 ///
 /// For example forbid the following:
 ///
+/// ```ignore (illustrative)
 /// impl<A> Tr for A { }
 /// impl<B> Tr for (B, B) { }
+/// ```
 ///
 /// Note that only consider the unconstrained parameters of the base impl:
 ///
+/// ```ignore (illustrative)
 /// impl<S, I: IntoIterator<Item = S>> Tr<S> for I { }
 /// impl<T> Tr<T> for Vec<T> { }
+/// ```
 ///
 /// The substs for the parent impl here are `[T, Vec<T>]`, which repeats `T`,
 /// but `S` is constrained in the parent impl, so `parent_substs` is only
@@ -257,8 +262,10 @@ fn check_duplicate_params<'tcx>(
 ///
 /// For example forbid the following:
 ///
+/// ```ignore (illustrative)
 /// impl<A> Tr for A { }
 /// impl Tr for &'static i32 { }
+/// ```
 fn check_static_lifetimes<'tcx>(
     tcx: TyCtxt<'tcx>,
     parent_substs: &Vec<GenericArg<'tcx>>,
@@ -344,23 +351,21 @@ fn check_predicates<'tcx>(
 
     // Include the well-formed predicates of the type parameters of the impl.
     for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().substs {
-        tcx.infer_ctxt().enter(|ref infcx| {
-            let obligations = wf::obligations(
-                infcx,
-                tcx.param_env(impl1_def_id),
-                tcx.hir().local_def_id_to_hir_id(impl1_def_id),
-                0,
-                arg,
-                span,
-            )
-            .unwrap();
+        let infcx = &tcx.infer_ctxt().build();
+        let obligations = wf::obligations(
+            infcx,
+            tcx.param_env(impl1_def_id),
+            tcx.hir().local_def_id_to_hir_id(impl1_def_id),
+            0,
+            arg,
+            span,
+        )
+        .unwrap();
 
-            assert!(!obligations.needs_infer());
-            impl2_predicates.extend(
-                traits::elaborate_obligations(tcx, obligations)
-                    .map(|obligation| obligation.predicate),
-            )
-        })
+        assert!(!obligations.needs_infer());
+        impl2_predicates.extend(
+            traits::elaborate_obligations(tcx, obligations).map(|obligation| obligation.predicate),
+        )
     }
     impl2_predicates.extend(
         traits::elaborate_predicates_with_span(tcx, always_applicable_traits)
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index d31b9b7ae46..b7d9fc8a2fe 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -110,7 +110,7 @@ use rustc_middle::util;
 use rustc_session::config::EntryFnType;
 use rustc_span::{symbol::sym, Span, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
 
 use std::iter;
@@ -141,24 +141,23 @@ fn require_same_types<'tcx>(
     expected: Ty<'tcx>,
     actual: Ty<'tcx>,
 ) -> bool {
-    tcx.infer_ctxt().enter(|ref infcx| {
-        let param_env = ty::ParamEnv::empty();
-        let errors = match infcx.at(cause, param_env).eq(expected, actual) {
-            Ok(InferOk { obligations, .. }) => traits::fully_solve_obligations(infcx, obligations),
-            Err(err) => {
-                infcx.report_mismatched_types(cause, expected, actual, err).emit();
-                return false;
-            }
-        };
+    let infcx = &tcx.infer_ctxt().build();
+    let param_env = ty::ParamEnv::empty();
+    let errors = match infcx.at(cause, param_env).eq(expected, actual) {
+        Ok(InferOk { obligations, .. }) => traits::fully_solve_obligations(infcx, obligations),
+        Err(err) => {
+            infcx.err_ctxt().report_mismatched_types(cause, expected, actual, err).emit();
+            return false;
+        }
+    };
 
-        match &errors[..] {
-            [] => true,
-            errors => {
-                infcx.report_fulfillment_errors(errors, None, false);
-                false
-            }
+    match &errors[..] {
+        [] => true,
+        errors => {
+            infcx.err_ctxt().report_fulfillment_errors(errors, None, false);
+            false
         }
-    })
+    }
 }
 
 fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
@@ -305,23 +304,22 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
             error = true;
         }
         let return_ty = return_ty.skip_binder();
-        tcx.infer_ctxt().enter(|infcx| {
-            // Main should have no WC, so empty param env is OK here.
-            let param_env = ty::ParamEnv::empty();
-            let cause = traits::ObligationCause::new(
-                return_ty_span,
-                main_diagnostics_hir_id,
-                ObligationCauseCode::MainFunctionType,
-            );
-            let ocx = traits::ObligationCtxt::new(&infcx);
-            let norm_return_ty = ocx.normalize(cause.clone(), param_env, return_ty);
-            ocx.register_bound(cause, param_env, norm_return_ty, term_did);
-            let errors = ocx.select_all_or_error();
-            if !errors.is_empty() {
-                infcx.report_fulfillment_errors(&errors, None, false);
-                error = true;
-            }
-        });
+        let infcx = tcx.infer_ctxt().build();
+        // Main should have no WC, so empty param env is OK here.
+        let param_env = ty::ParamEnv::empty();
+        let cause = traits::ObligationCause::new(
+            return_ty_span,
+            main_diagnostics_hir_id,
+            ObligationCauseCode::MainFunctionType,
+        );
+        let ocx = traits::ObligationCtxt::new(&infcx);
+        let norm_return_ty = ocx.normalize(cause.clone(), param_env, return_ty);
+        ocx.register_bound(cause, param_env, norm_return_ty, term_did);
+        let errors = ocx.select_all_or_error();
+        if !errors.is_empty() {
+            infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+            error = true;
+        }
         // now we can take the return type of the given main function
         expected_return_type = main_fnsig.output();
     } else {
diff --git a/compiler/rustc_hir_analysis/src/mem_categorization.rs b/compiler/rustc_hir_analysis/src/mem_categorization.rs
index 46b49647836..b62c5b5e077 100644
--- a/compiler/rustc_hir_analysis/src/mem_categorization.rs
+++ b/compiler/rustc_hir_analysis/src/mem_categorization.rs
@@ -92,7 +92,7 @@ impl HirNode for hir::Pat<'_> {
 #[derive(Clone)]
 pub(crate) struct MemCategorizationContext<'a, 'tcx> {
     pub(crate) typeck_results: &'a ty::TypeckResults<'tcx>,
-    infcx: &'a InferCtxt<'a, 'tcx>,
+    infcx: &'a InferCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     body_owner: LocalDefId,
     upvars: Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>>,
@@ -103,7 +103,7 @@ pub(crate) type McResult<T> = Result<T, ()>;
 impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
     /// Creates a `MemCategorizationContext`.
     pub(crate) fn new(
-        infcx: &'a InferCtxt<'a, 'tcx>,
+        infcx: &'a InferCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
         body_owner: LocalDefId,
         typeck_results: &'a ty::TypeckResults<'tcx>,
@@ -184,7 +184,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
     ///   modes #42640) may look like `Some(x)` but in fact have
     ///   implicit deref patterns attached (e.g., it is really
     ///   `&Some(x)`). In that case, we return the "outermost" type
-    ///   (e.g., `&Option<T>).
+    ///   (e.g., `&Option<T>`).
     pub(crate) fn pat_ty_adjusted(&self, pat: &hir::Pat<'_>) -> McResult<Ty<'tcx>> {
         // Check for implicit `&` types wrapping the pattern; note
         // that these are never attached to binding patterns, so