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.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs78
-rw-r--r--compiler/rustc_hir_analysis/src/check/callee.rs274
-rw-r--r--compiler/rustc_hir_analysis/src/check/cast.rs77
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs27
-rw-r--r--compiler/rustc_hir_analysis/src/check/demand.rs46
-rw-r--r--compiler/rustc_hir_analysis/src/check/expr.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs21
-rw-r--r--compiler/rustc_hir_analysis/src/check/fn_ctxt/checks.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs119
-rw-r--r--compiler/rustc_hir_analysis/src/check/generator_interior.rs20
-rw-r--r--compiler/rustc_hir_analysis/src/check/inherited.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs27
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsicck.rs32
-rw-r--r--compiler/rustc_hir_analysis/src/check/method/prelude2021.rs112
-rw-r--r--compiler/rustc_hir_analysis/src/check/method/probe.rs25
-rw-r--r--compiler/rustc_hir_analysis/src/check/method/suggest.rs54
-rw-r--r--compiler/rustc_hir_analysis/src/check/op.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/check/pat.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/check/upvar.rs26
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check_unused.rs20
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs23
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs1203
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs480
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs707
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs117
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs89
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/mem_categorization.rs3
30 files changed, 1942 insertions, 1683 deletions
diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs
index afac75de2d9..b66e59d8ac6 100644
--- a/compiler/rustc_hir_analysis/src/astconv/generics.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs
@@ -448,8 +448,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let infer_lifetimes =
             (gen_pos != GenericArgPosition::Type || infer_args) && !gen_args.has_lifetime_params();
 
-        if gen_pos != GenericArgPosition::Type && !gen_args.bindings.is_empty() {
-            Self::prohibit_assoc_ty_binding(tcx, gen_args.bindings[0].span);
+        if gen_pos != GenericArgPosition::Type && let Some(b) = gen_args.bindings.first() {
+            Self::prohibit_assoc_ty_binding(tcx, b.span);
         }
 
         let explicit_late_bound =
@@ -649,9 +649,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     LATE_BOUND_LIFETIME_ARGUMENTS,
                     args.args[0].hir_id(),
                     multispan,
-                    |lint| {
-                        lint.build(msg).emit();
-                    },
+                    msg,
+                    |lint| lint,
                 );
             }
 
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 244018ebbeb..6e373e41b4c 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -276,9 +276,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             item_segment.infer_args,
             None,
         );
-        let assoc_bindings = self.create_assoc_bindings_for_generic_args(item_segment.args());
-
-        if let Some(b) = assoc_bindings.first() {
+        if let Some(b) = item_segment.args().bindings.first() {
             Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
         }
 
@@ -605,8 +603,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             None,
         );
 
-        let assoc_bindings = self.create_assoc_bindings_for_generic_args(item_segment.args());
-        if let Some(b) = assoc_bindings.first() {
+        if let Some(b) = item_segment.args().bindings.first() {
             Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
         }
 
@@ -794,8 +791,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             trait_segment,
             is_impl,
         );
-        let assoc_bindings = self.create_assoc_bindings_for_generic_args(trait_segment.args());
-        if let Some(b) = assoc_bindings.first() {
+        if let Some(b) = trait_segment.args().bindings.first() {
             Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
         }
         ty::TraitRef::new(trait_def_id, substs)
@@ -1902,7 +1898,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         // Find the type of the associated item, and the trait where the associated
         // item is declared.
         let bound = match (&qself_ty.kind(), qself_res) {
-            (_, Res::SelfTy { trait_: Some(_), alias_to: Some((impl_def_id, _)) }) => {
+            (_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => {
                 // `Self` in an impl of a trait -- we have a concrete self type and a
                 // trait reference.
                 let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else {
@@ -1921,8 +1917,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
             (
                 &ty::Param(_),
-                Res::SelfTy { trait_: Some(param_did), alias_to: None }
-                | Res::Def(DefKind::TyParam, param_did),
+                Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did),
             ) => self.find_bound_for_assoc_item(param_did.expect_local(), assoc_ident, span)?,
             _ => {
                 let reported = if variant_resolution.is_some() {
@@ -2015,30 +2010,35 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         tcx.check_stability(item.def_id, Some(hir_ref_id), span, None);
 
         if let Some(variant_def_id) = variant_resolution {
-            tcx.struct_span_lint_hir(AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, |lint| {
-                let mut err = lint.build("ambiguous associated item");
-                let mut could_refer_to = |kind: DefKind, def_id, also| {
-                    let note_msg = format!(
-                        "`{}` could{} refer to the {} defined here",
-                        assoc_ident,
-                        also,
-                        kind.descr(def_id)
-                    );
-                    err.span_note(tcx.def_span(def_id), &note_msg);
-                };
+            tcx.struct_span_lint_hir(
+                AMBIGUOUS_ASSOCIATED_ITEMS,
+                hir_ref_id,
+                span,
+                "ambiguous associated item",
+                |lint| {
+                    let mut could_refer_to = |kind: DefKind, def_id, also| {
+                        let note_msg = format!(
+                            "`{}` could{} refer to the {} defined here",
+                            assoc_ident,
+                            also,
+                            kind.descr(def_id)
+                        );
+                        lint.span_note(tcx.def_span(def_id), &note_msg);
+                    };
 
-                could_refer_to(DefKind::Variant, variant_def_id, "");
-                could_refer_to(kind, item.def_id, " also");
+                    could_refer_to(DefKind::Variant, variant_def_id, "");
+                    could_refer_to(kind, item.def_id, " also");
 
-                err.span_suggestion(
-                    span,
-                    "use fully-qualified syntax",
-                    format!("<{} as {}>::{}", qself_ty, tcx.item_name(trait_did), assoc_ident),
-                    Applicability::MachineApplicable,
-                );
+                    lint.span_suggestion(
+                        span,
+                        "use fully-qualified syntax",
+                        format!("<{} as {}>::{}", qself_ty, tcx.item_name(trait_did), assoc_ident),
+                        Applicability::MachineApplicable,
+                    );
 
-                err.emit();
-            });
+                    lint
+                },
+            );
         }
         Ok((ty, kind, item.def_id))
     }
@@ -2208,8 +2208,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
         for segment in segments {
             // Only emit the first error to avoid overloading the user with error messages.
-            if let [binding, ..] = segment.args().bindings {
-                Self::prohibit_assoc_ty_binding(self.tcx(), binding.span);
+            if let Some(b) = segment.args().bindings.first() {
+                Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
                 return true;
             }
         }
@@ -2417,7 +2417,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 let index = generics.param_def_id_to_index[&def_id.to_def_id()];
                 tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id))
             }
-            Res::SelfTy { trait_: Some(_), alias_to: None } => {
+            Res::SelfTyParam { .. } => {
                 // `Self` in trait or type alias.
                 assert_eq!(opt_self_ty, None);
                 self.prohibit_generics(path.segments.iter(), |err| {
@@ -2432,7 +2432,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 });
                 tcx.types.self_param
             }
-            Res::SelfTy { trait_: _, alias_to: Some((def_id, forbid_generic)) } => {
+            Res::SelfTyAlias { alias_to: def_id, forbid_generic, .. } => {
                 // `Self` in impl (we know the concrete type).
                 assert_eq!(opt_self_ty, None);
                 // Try to evaluate any array length constants.
@@ -3084,15 +3084,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     BARE_TRAIT_OBJECTS,
                     self_ty.hir_id,
                     self_ty.span,
+                    msg,
                     |lint| {
-                        let mut diag = lint.build(msg);
-                        diag.multipart_suggestion_verbose(
+                        lint.multipart_suggestion_verbose(
                             "use `dyn`",
                             sugg,
                             Applicability::MachineApplicable,
                         );
-                        self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
-                        diag.emit();
+                        self.maybe_lint_blanket_trait_impl(&self_ty, lint);
+                        lint
                     },
                 );
             }
diff --git a/compiler/rustc_hir_analysis/src/check/callee.rs b/compiler/rustc_hir_analysis/src/check/callee.rs
index c82a31e65cf..080771844a4 100644
--- a/compiler/rustc_hir_analysis/src/check/callee.rs
+++ b/compiler/rustc_hir_analysis/src/check/callee.rs
@@ -394,140 +394,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             ty::FnPtr(sig) => (sig, None),
             _ => {
-                let mut unit_variant = None;
-                if let hir::ExprKind::Path(qpath) = &callee_expr.kind
-                    && let Res::Def(def::DefKind::Ctor(kind, def::CtorKind::Const), _)
-                        = self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id)
-                    // Only suggest removing parens if there are no arguments
-                    && arg_exprs.is_empty()
-                {
-                    let descr = match kind {
-                        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 callee_ty = self.resolve_vars_if_possible(callee_ty);
-                let mut err = type_error_struct!(
-                    self.tcx.sess,
-                    callee_expr.span,
-                    callee_ty,
-                    E0618,
-                    "expected function, found {}",
-                    match &unit_variant {
-                        Some((_, kind, path)) => format!("{kind} `{path}`"),
-                        None => format!("`{callee_ty}`"),
-                    }
-                );
-
-                self.identify_bad_closure_def_and_call(
-                    &mut err,
-                    call_expr.hir_id,
-                    &callee_expr.kind,
-                    callee_expr.span,
-                );
-
-                if let Some((removal_span, kind, path)) = &unit_variant {
-                    err.span_suggestion_verbose(
-                        *removal_span,
-                        &format!(
-                            "`{path}` is a unit {kind}, and does not take parentheses to be constructed",
-                        ),
-                        "",
-                        Applicability::MachineApplicable,
-                    );
-                }
-
-                let mut inner_callee_path = None;
-                let def = match callee_expr.kind {
-                    hir::ExprKind::Path(ref qpath) => {
-                        self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id)
-                    }
-                    hir::ExprKind::Call(ref inner_callee, _) => {
-                        // If the call spans more than one line and the callee kind is
-                        // itself another `ExprCall`, that's a clue that we might just be
-                        // missing a semicolon (Issue #51055)
-                        let call_is_multiline =
-                            self.tcx.sess.source_map().is_multiline(call_expr.span);
-                        if call_is_multiline {
-                            err.span_suggestion(
-                                callee_expr.span.shrink_to_hi(),
-                                "consider using a semicolon here",
-                                ";",
-                                Applicability::MaybeIncorrect,
-                            );
-                        }
-                        if let hir::ExprKind::Path(ref inner_qpath) = inner_callee.kind {
-                            inner_callee_path = Some(inner_qpath);
-                            self.typeck_results.borrow().qpath_res(inner_qpath, inner_callee.hir_id)
-                        } else {
-                            Res::Err
-                        }
-                    }
-                    _ => Res::Err,
-                };
-
-                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)
-                        && !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span)
-                    {
-                        let descr = match maybe_def {
-                            DefIdOrName::DefId(def_id) => self.tcx.def_kind(def_id).descr(def_id),
-                            DefIdOrName::Name(name) => name,
-                        };
-                        err.span_label(
-                            callee_expr.span,
-                            format!("this {descr} returns an unsized value `{output_ty}`, so it cannot be called")
-                        );
-                        if let DefIdOrName::DefId(def_id) = maybe_def
-                            && let Some(def_span) = self.tcx.hir().span_if_local(def_id)
-                        {
-                            err.span_label(def_span, "the callable type is defined here");
-                        }
-                    } else {
-                        err.span_label(call_expr.span, "call expression requires function");
-                    }
-                }
-
-                if let Some(span) = self.tcx.hir().res_span(def) {
-                    let callee_ty = callee_ty.to_string();
-                    let label = match (unit_variant, inner_callee_path) {
-                        (Some((_, kind, path)), _) => Some(format!("{kind} `{path}` defined here")),
-                        (_, Some(hir::QPath::Resolved(_, path))) => self
-                            .tcx
-                            .sess
-                            .source_map()
-                            .span_to_snippet(path.span)
-                            .ok()
-                            .map(|p| format!("`{p}` defined here returns `{callee_ty}`")),
-                        _ => {
-                            match def {
-                                // Emit a different diagnostic for local variables, as they are not
-                                // type definitions themselves, but rather variables *of* that type.
-                                Res::Local(hir_id) => Some(format!(
-                                    "`{}` has type `{}`",
-                                    self.tcx.hir().name(hir_id),
-                                    callee_ty
-                                )),
-                                Res::Def(kind, def_id) if kind.ns() == Some(Namespace::ValueNS) => {
-                                    Some(format!(
-                                        "`{}` defined here",
-                                        self.tcx.def_path_str(def_id),
-                                    ))
-                                }
-                                _ => Some(format!("`{callee_ty}` defined here")),
-                            }
-                        }
-                    };
-                    if let Some(label) = label {
-                        err.span_label(span, label);
-                    }
-                }
-                err.emit();
+                self.report_invalid_callee(call_expr, callee_expr, callee_ty, arg_exprs);
 
                 // This is the "default" function signature, used in case of error.
                 // In that case, we check each argument against "error" in order to
@@ -574,6 +441,145 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         fn_sig.output()
     }
 
+    fn report_invalid_callee(
+        &self,
+        call_expr: &'tcx hir::Expr<'tcx>,
+        callee_expr: &'tcx hir::Expr<'tcx>,
+        callee_ty: Ty<'tcx>,
+        arg_exprs: &'tcx [hir::Expr<'tcx>],
+    ) {
+        let mut unit_variant = None;
+        if let hir::ExprKind::Path(qpath) = &callee_expr.kind
+            && let Res::Def(def::DefKind::Ctor(kind, def::CtorKind::Const), _)
+                = self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id)
+            // Only suggest removing parens if there are no arguments
+            && arg_exprs.is_empty()
+        {
+            let descr = match kind {
+                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 callee_ty = self.resolve_vars_if_possible(callee_ty);
+        let mut err = type_error_struct!(
+            self.tcx.sess,
+            callee_expr.span,
+            callee_ty,
+            E0618,
+            "expected function, found {}",
+            match &unit_variant {
+                Some((_, kind, path)) => format!("{kind} `{path}`"),
+                None => format!("`{callee_ty}`"),
+            }
+        );
+
+        self.identify_bad_closure_def_and_call(
+            &mut err,
+            call_expr.hir_id,
+            &callee_expr.kind,
+            callee_expr.span,
+        );
+
+        if let Some((removal_span, kind, path)) = &unit_variant {
+            err.span_suggestion_verbose(
+                *removal_span,
+                &format!(
+                    "`{path}` is a unit {kind}, and does not take parentheses to be constructed",
+                ),
+                "",
+                Applicability::MachineApplicable,
+            );
+        }
+
+        let mut inner_callee_path = None;
+        let def = match callee_expr.kind {
+            hir::ExprKind::Path(ref qpath) => {
+                self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id)
+            }
+            hir::ExprKind::Call(ref inner_callee, _) => {
+                // If the call spans more than one line and the callee kind is
+                // itself another `ExprCall`, that's a clue that we might just be
+                // missing a semicolon (Issue #51055)
+                let call_is_multiline = self.tcx.sess.source_map().is_multiline(call_expr.span);
+                if call_is_multiline {
+                    err.span_suggestion(
+                        callee_expr.span.shrink_to_hi(),
+                        "consider using a semicolon here",
+                        ";",
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+                if let hir::ExprKind::Path(ref inner_qpath) = inner_callee.kind {
+                    inner_callee_path = Some(inner_qpath);
+                    self.typeck_results.borrow().qpath_res(inner_qpath, inner_callee.hir_id)
+                } else {
+                    Res::Err
+                }
+            }
+            _ => Res::Err,
+        };
+
+        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)
+                && !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span)
+            {
+                let descr = match maybe_def {
+                    DefIdOrName::DefId(def_id) => self.tcx.def_kind(def_id).descr(def_id),
+                    DefIdOrName::Name(name) => name,
+                };
+                err.span_label(
+                    callee_expr.span,
+                    format!("this {descr} returns an unsized value `{output_ty}`, so it cannot be called")
+                );
+                if let DefIdOrName::DefId(def_id) = maybe_def
+                    && let Some(def_span) = self.tcx.hir().span_if_local(def_id)
+                {
+                    err.span_label(def_span, "the callable type is defined here");
+                }
+            } else {
+                err.span_label(call_expr.span, "call expression requires function");
+            }
+        }
+
+        if let Some(span) = self.tcx.hir().res_span(def) {
+            let callee_ty = callee_ty.to_string();
+            let label = match (unit_variant, inner_callee_path) {
+                (Some((_, kind, path)), _) => Some(format!("{kind} `{path}` defined here")),
+                (_, Some(hir::QPath::Resolved(_, path))) => self
+                    .tcx
+                    .sess
+                    .source_map()
+                    .span_to_snippet(path.span)
+                    .ok()
+                    .map(|p| format!("`{p}` defined here returns `{callee_ty}`")),
+                _ => {
+                    match def {
+                        // Emit a different diagnostic for local variables, as they are not
+                        // type definitions themselves, but rather variables *of* that type.
+                        Res::Local(hir_id) => Some(format!(
+                            "`{}` has type `{}`",
+                            self.tcx.hir().name(hir_id),
+                            callee_ty
+                        )),
+                        Res::Def(kind, def_id) if kind.ns() == Some(Namespace::ValueNS) => {
+                            Some(format!("`{}` defined here", self.tcx.def_path_str(def_id),))
+                        }
+                        _ => Some(format!("`{callee_ty}` defined here")),
+                    }
+                }
+            };
+            if let Some(label) = label {
+                err.span_label(span, label);
+            }
+        }
+        err.emit();
+    }
+
     fn confirm_deferred_closure_call(
         &self,
         call_expr: &'tcx hir::Expr<'tcx>,
diff --git a/compiler/rustc_hir_analysis/src/check/cast.rs b/compiler/rustc_hir_analysis/src/check/cast.rs
index 81a979865ac..01badc133c9 100644
--- a/compiler/rustc_hir_analysis/src/check/cast.rs
+++ b/compiler/rustc_hir_analysis/src/check/cast.rs
@@ -33,7 +33,7 @@ use super::FnCtxt;
 use crate::hir::def_id::DefId;
 use crate::type_error_struct;
 use hir::def_id::LOCAL_CRATE;
-use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::{struct_span_err, Applicability, DelayDm, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode};
 use rustc_middle::mir::Mutability;
@@ -754,19 +754,25 @@ impl<'a, 'tcx> CastCheck<'tcx> {
         } else {
             ("", lint::builtin::TRIVIAL_CASTS)
         };
-        fcx.tcx.struct_span_lint_hir(lint, self.expr.hir_id, self.span, |err| {
-            err.build(&format!(
-                "trivial {}cast: `{}` as `{}`",
-                adjective,
-                fcx.ty_to_string(t_expr),
-                fcx.ty_to_string(t_cast)
-            ))
-            .help(&format!(
-                "cast can be replaced by coercion; this might \
-                                   require {type_asc_or}a temporary variable"
-            ))
-            .emit();
-        });
+        fcx.tcx.struct_span_lint_hir(
+            lint,
+            self.expr.hir_id,
+            self.span,
+            DelayDm(|| {
+                format!(
+                    "trivial {}cast: `{}` as `{}`",
+                    adjective,
+                    fcx.ty_to_string(t_expr),
+                    fcx.ty_to_string(t_cast)
+                )
+            }),
+            |lint| {
+                lint.help(format!(
+                    "cast can be replaced by coercion; this might \
+                     require {type_asc_or}a temporary variable"
+                ))
+            },
+        );
     }
 
     #[instrument(skip(fcx), level = "debug")]
@@ -1074,12 +1080,12 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 lint::builtin::CENUM_IMPL_DROP_CAST,
                 self.expr.hir_id,
                 self.span,
-                |err| {
-                    err.build(&format!(
-                        "cannot cast enum `{}` into integer `{}` because it implements `Drop`",
-                        self.expr_ty, self.cast_ty
-                    ))
-                    .emit();
+                DelayDm(|| format!(
+                    "cannot cast enum `{}` into integer `{}` because it implements `Drop`",
+                    self.expr_ty, self.cast_ty
+                )),
+                |lint| {
+                    lint
                 },
             );
         }
@@ -1090,12 +1096,11 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             lint::builtin::LOSSY_PROVENANCE_CASTS,
             self.expr.hir_id,
             self.span,
-            |err| {
-                let mut err = err.build(&format!(
+            DelayDm(|| format!(
                     "under strict provenance it is considered bad style to cast pointer `{}` to integer `{}`",
                     self.expr_ty, self.cast_ty
-                ));
-
+                )),
+            |lint| {
                 let msg = "use `.addr()` to obtain the address of a pointer";
 
                 let expr_prec = self.expr.precedence().order();
@@ -1114,9 +1119,9 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                         (cast_span, format!(").addr(){scalar_cast}")),
                     ];
 
-                    err.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
+                    lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
                 } else {
-                    err.span_suggestion(
+                    lint.span_suggestion(
                         cast_span,
                         msg,
                         format!(".addr(){scalar_cast}"),
@@ -1124,12 +1129,12 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                     );
                 }
 
-                err.help(
+                lint.help(
                     "if you can't comply with strict provenance and need to expose the pointer \
                     provenance you can use `.expose_addr()` instead"
                 );
 
-                err.emit();
+                lint
             },
         );
     }
@@ -1139,24 +1144,24 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             lint::builtin::FUZZY_PROVENANCE_CASTS,
             self.expr.hir_id,
             self.span,
-            |err| {
-                let mut err = err.build(&format!(
-                    "strict provenance disallows casting integer `{}` to pointer `{}`",
-                    self.expr_ty, self.cast_ty
-                ));
+            DelayDm(|| format!(
+                "strict provenance disallows casting integer `{}` to pointer `{}`",
+                self.expr_ty, self.cast_ty
+            )),
+            |lint| {
                 let msg = "use `.with_addr()` to adjust a valid pointer in the same allocation, to this address";
                 let suggestions = vec![
                     (self.expr_span.shrink_to_lo(), String::from("(...).with_addr(")),
                     (self.expr_span.shrink_to_hi().to(self.cast_span), String::from(")")),
                 ];
 
-                err.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
-                err.help(
+                lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
+                lint.help(
                     "if you can't comply with strict provenance and don't have a pointer with \
                     the correct provenance you can use `std::ptr::from_exposed_addr()` instead"
                  );
 
-                err.emit();
+                lint
             },
         );
     }
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index d82ee8f48c5..824144aeac0 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -48,9 +48,13 @@ pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ab
             .emit();
         }
         None => {
-            tcx.struct_span_lint_hir(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| {
-                lint.build("use of calling convention not supported on this target").emit();
-            });
+            tcx.struct_span_lint_hir(
+                UNSUPPORTED_CALLING_CONVENTIONS,
+                hir_id,
+                span,
+                "use of calling convention not supported on this target",
+                |lint| lint,
+            );
         }
     }
 
@@ -510,10 +514,10 @@ fn check_static_inhabited<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
             UNINHABITED_STATIC,
             tcx.hir().local_def_id_to_hir_id(def_id),
             span,
+            "static of uninhabited type",
             |lint| {
-                lint.build("static of uninhabited type")
+                lint
                 .note("uninhabited statics cannot be initialized, and any access would be an immediate error")
-                .emit();
             },
         );
     }
@@ -609,9 +613,12 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
         fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
             match arg.kind {
                 hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
-                    [PathSegment { res: Res::SelfTy { trait_: _, alias_to: impl_ref }, .. }] => {
-                        let impl_ty_name =
-                            impl_ref.map(|(def_id, _)| self.tcx.def_path_str(def_id));
+                    [PathSegment { res: Res::SelfTyParam { .. }, .. }] => {
+                        let impl_ty_name = None;
+                        self.selftys.push((path.span, impl_ty_name));
+                    }
+                    [PathSegment { res: Res::SelfTyAlias { alias_to: def_id, .. }, .. }] => {
+                        let impl_ty_name = Some(self.tcx.def_path_str(*def_id));
                         self.selftys.push((path.span, impl_ty_name));
                     }
                     _ => {}
@@ -1434,6 +1441,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
                 REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
                 tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()),
                 span,
+                "zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types",
                 |lint| {
                     let note = if non_exhaustive {
                         "is marked with `#[non_exhaustive]`"
@@ -1441,10 +1449,9 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
                         "contains private fields"
                     };
                     let field_ty = tcx.def_path_str_with_substs(def_id, substs);
-                    lint.build("zero-sized fields in repr(transparent) cannot contain external non-exhaustive types")
+                    lint
                         .note(format!("this {descr} contains `{field_ty}`, which {note}, \
                             and makes it not a breaking change to become non-zero-sized in the future."))
-                        .emit();
                 },
             )
         }
diff --git a/compiler/rustc_hir_analysis/src/check/demand.rs b/compiler/rustc_hir_analysis/src/check/demand.rs
index 264df8b914b..d396c801c09 100644
--- a/compiler/rustc_hir_analysis/src/check/demand.rs
+++ b/compiler/rustc_hir_analysis/src/check/demand.rs
@@ -32,17 +32,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         error: Option<TypeError<'tcx>>,
     ) {
         self.annotate_expected_due_to_let_ty(err, expr, error);
-        self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr);
-        self.suggest_compatible_variants(err, expr, expected, expr_ty);
-        self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty);
-        if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) {
-            return;
-        }
-        self.suggest_no_capture_closure(err, expected, expr_ty);
-        self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
-        self.suggest_missing_parentheses(err, expr);
-        self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected);
-        self.suggest_copied_or_cloned(err, expr, expr_ty, expected);
+
+        // Use `||` to give these suggestions a precedence
+        let _ = self.suggest_missing_parentheses(err, expr)
+            || self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr)
+            || self.suggest_compatible_variants(err, expr, expected, expr_ty)
+            || self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty)
+            || self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty)
+            || self.suggest_no_capture_closure(err, expected, expr_ty)
+            || self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty)
+            || self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected)
+            || self.suggest_copied_or_cloned(err, expr, expr_ty, expected)
+            || self.suggest_into(err, expr, expr_ty, expected);
+
         self.note_type_is_not_clone(err, expected, expr_ty, expr);
         self.note_need_for_fn_pointer(err, expected, expr_ty);
         self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
@@ -286,7 +288,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expr: &hir::Expr<'_>,
         expected: Ty<'tcx>,
         expr_ty: Ty<'tcx>,
-    ) {
+    ) -> bool {
         if let ty::Adt(expected_adt, substs) = expected.kind() {
             if let hir::ExprKind::Field(base, ident) = expr.kind {
                 let base_ty = self.typeck_results.borrow().expr_ty(base);
@@ -299,7 +301,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         "",
                         Applicability::MaybeIncorrect,
                     );
-                    return
+                    return true;
                 }
             }
 
@@ -338,7 +340,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             } else if self.tcx.is_diagnostic_item(sym::Option, expected_adt.did()) {
                                 vec!["None", "Some(())"]
                             } else {
-                                return;
+                                return false;
                             };
                             if let Some(indent) =
                                 self.tcx.sess.source_map().indentation_before(span.shrink_to_lo())
@@ -358,7 +360,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                     Applicability::MaybeIncorrect,
                                 );
                             }
-                            return;
+                            return true;
                         }
                     }
                 }
@@ -445,6 +447,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         suggestions_for(&**variant, *ctor_kind, *field_name),
                         Applicability::MaybeIncorrect,
                     );
+                    return true;
                 }
                 _ => {
                     // More than one matching variant.
@@ -460,9 +463,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         ),
                         Applicability::MaybeIncorrect,
                     );
+                    return true;
                 }
             }
         }
+
+        false
     }
 
     fn suggest_non_zero_new_unwrap(
@@ -471,19 +477,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expr: &hir::Expr<'_>,
         expected: Ty<'tcx>,
         expr_ty: Ty<'tcx>,
-    ) {
+    ) -> bool {
         let tcx = self.tcx;
         let (adt, unwrap) = match expected.kind() {
             // In case Option<NonZero*> is wanted, but * is provided, suggest calling new
             ty::Adt(adt, substs) if tcx.is_diagnostic_item(sym::Option, adt.did()) => {
                 // Unwrap option
-                let ty::Adt(adt, _) = substs.type_at(0).kind() else { return };
+                let ty::Adt(adt, _) = substs.type_at(0).kind() else { return false; };
 
                 (adt, "")
             }
             // In case NonZero* is wanted, but * is provided also add `.unwrap()` to satisfy types
             ty::Adt(adt, _) => (adt, ".unwrap()"),
-            _ => return,
+            _ => return false,
         };
 
         let map = [
@@ -502,7 +508,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let Some((s, _)) = map
             .iter()
             .find(|&&(s, t)| self.tcx.is_diagnostic_item(s, adt.did()) && self.can_coerce(expr_ty, t))
-            else { return };
+            else { return false; };
 
         let path = self.tcx.def_path_str(adt.non_enum_variant().def_id);
 
@@ -514,6 +520,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ],
             Applicability::MaybeIncorrect,
         );
+
+        true
     }
 
     pub fn get_conversion_methods(
diff --git a/compiler/rustc_hir_analysis/src/check/expr.rs b/compiler/rustc_hir_analysis/src/check/expr.rs
index 48a4f40780b..b9459887c46 100644
--- a/compiler/rustc_hir_analysis/src/check/expr.rs
+++ b/compiler/rustc_hir_analysis/src/check/expr.rs
@@ -41,6 +41,7 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
 use rustc_middle::ty::error::TypeError::FieldMisMatch;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, AdtKind, Ty, TypeVisitable};
+use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_session::parse::feature_err;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::lev_distance::find_best_match_for_name;
@@ -394,7 +395,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         if let Some(sp) =
                             tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp)
                         {
-                            tcx.sess.parse_sess.expr_parentheses_needed(&mut err, *sp);
+                            err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
                         }
                         err.emit();
                         oprnd_t = tcx.ty_error();
@@ -541,7 +542,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // been resolved or we errored. This is important as we can only check transmute
                 // on concrete types, but the output type may not be known yet (it would only
                 // be known if explicitly specified via turbofish).
-                self.deferred_transmute_checks.borrow_mut().push((from, to, expr.span));
+                self.deferred_transmute_checks.borrow_mut().push((from, to, expr.hir_id));
             }
             if !tcx.features().unsized_fn_params {
                 // We want to remove some Sized bounds from std functions,
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 4522678802b..e51e5280620 100644
--- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs
@@ -58,17 +58,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                 debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind);
 
-                self.tcx().struct_span_lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, |lint| {
-                    let msg = format!("unreachable {}", kind);
-                    lint.build(&msg)
-                        .span_label(span, &msg)
-                        .span_label(
+                let msg = format!("unreachable {}", kind);
+                self.tcx().struct_span_lint_hir(
+                    lint::builtin::UNREACHABLE_CODE,
+                    id,
+                    span,
+                    &msg,
+                    |lint| {
+                        lint.span_label(span, &msg).span_label(
                             orig_span,
                             custom_note
                                 .unwrap_or("any code following this expression is unreachable"),
                         )
-                        .emit();
-                })
+                    },
+                )
             }
         }
     }
@@ -88,14 +91,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         mutate_fulfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
     ) -> Ty<'tcx> {
         // No Infer()? Nothing needs doing.
-        if !ty.has_infer_types_or_consts() {
+        if !ty.has_non_region_infer() {
             debug!("no inference var, nothing needs doing");
             return ty;
         }
 
         // If `ty` is a type variable, see whether we already know what it is.
         ty = self.resolve_vars_if_possible(ty);
-        if !ty.has_infer_types_or_consts() {
+        if !ty.has_non_region_infer() {
             debug!(?ty);
             return ty;
         }
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 64e7fa1a42b..13e74021b9e 100644
--- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_analysis/src/check/fn_ctxt/checks.rs
@@ -50,8 +50,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(in super::super) fn check_transmutes(&self) {
         let mut deferred_transmute_checks = self.deferred_transmute_checks.borrow_mut();
         debug!("FnCtxt::check_transmutes: {} deferred checks", deferred_transmute_checks.len());
-        for (from, to, span) in deferred_transmute_checks.drain(..) {
-            self.check_transmute(span, from, to);
+        for (from, to, hir_id) in deferred_transmute_checks.drain(..) {
+            self.check_transmute(from, to, hir_id);
         }
     }
 
@@ -63,7 +63,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let get_operand_ty = |expr| {
                 let ty = self.typeck_results.borrow().expr_ty_adjusted(expr);
                 let ty = self.resolve_vars_if_possible(ty);
-                if ty.has_infer_types_or_consts() {
+                if ty.has_non_region_infer() {
                     assert!(self.is_tainted_by_errors());
                     self.tcx.ty_error()
                 } else {
@@ -1199,7 +1199,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 _ => bug!("unexpected type: {:?}", ty),
             },
             Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
-            | Res::SelfTy { .. } => match ty.kind() {
+            | Res::SelfTyParam { .. }
+            | Res::SelfTyAlias { .. } => match ty.kind() {
                 ty::Adt(adt, substs) if !adt.is_enum() => {
                     Some((adt.non_enum_variant(), adt.did(), substs))
                 }
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 c32d1309031..09890c55cd3 100644
--- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs
@@ -3,7 +3,7 @@ use crate::astconv::AstConv;
 use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
 
 use hir::def_id::DefId;
-use rustc_ast::util::parser::ExprPrecedence;
+use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
 use rustc_errors::{Applicability, Diagnostic, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind};
@@ -15,6 +15,7 @@ use rustc_infer::infer::{self, TyCtxtInferExt};
 use rustc_infer::traits::{self, StatementAsExpression};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Binder, IsSuggestable, ToPredicate, Ty};
+use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_trait_selection::infer::InferCtxtExt;
@@ -64,7 +65,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     /// When encountering an fn-like type, try accessing the output of the type
-    /// // and suggesting calling it if it satisfies a predicate (i.e. if the
+    /// and suggesting calling it if it satisfies a predicate (i.e. if the
     /// output has a method or a field):
     /// ```compile_fail,E0308
     /// fn foo(x: usize) -> usize { x }
@@ -138,7 +139,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 sugg,
                 applicability,
             );
-
             return true;
         }
         false
@@ -327,7 +327,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected: Ty<'tcx>,
         found: Ty<'tcx>,
         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
-    ) {
+    ) -> bool {
         let expr = expr.peel_blocks();
         if let Some((sp, msg, suggestion, applicability, verbose)) =
             self.check_ref(expr, found, expected)
@@ -337,12 +337,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             } else {
                 err.span_suggestion(sp, &msg, suggestion, applicability);
             }
+            return true;
+        } else if self.suggest_else_fn_with_closure(err, expr, found, expected)
+        {
+            return true;
         } else if self.suggest_fn_call(err, expr, found, |output| self.can_coerce(output, expected))
             && let ty::FnDef(def_id, ..) = &found.kind()
             && let Some(sp) = self.tcx.hir().span_if_local(*def_id)
         {
             err.span_label(sp, format!("{found} defined here"));
-        } else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
+            return true;
+        } else if self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
+            return true;
+        } else {
             let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
             if !methods.is_empty() {
                 let mut suggestions = methods.iter()
@@ -393,6 +400,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         suggestions,
                         Applicability::MaybeIncorrect,
                     );
+                    return true;
                 }
             } else if let ty::Adt(found_adt, found_substs) = found.kind()
                 && self.tcx.is_diagnostic_item(sym::Option, found_adt.did())
@@ -417,9 +425,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         format!(".map(|x| &*{}x)", "*".repeat(ref_cnt)),
                         Applicability::MaybeIncorrect,
                     );
+                    return true;
                 }
             }
         }
+
+        false
     }
 
     /// When encountering the expected boxed value allocated in the stack, suggest allocating it
@@ -430,13 +441,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expr: &hir::Expr<'_>,
         expected: Ty<'tcx>,
         found: Ty<'tcx>,
-    ) {
+    ) -> bool {
         if self.tcx.hir().is_inside_const_context(expr.hir_id) {
             // Do not suggest `Box::new` in const context.
-            return;
+            return false;
         }
         if !expected.is_box() || found.is_box() {
-            return;
+            return false;
         }
         let boxed_found = self.tcx.mk_box(found);
         if self.can_coerce(boxed_found, expected) {
@@ -454,6 +465,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                  https://doc.rust-lang.org/rust-by-example/std/box.html, and \
                  https://doc.rust-lang.org/std/boxed/index.html",
             );
+            true
+        } else {
+            false
         }
     }
 
@@ -464,7 +478,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         err: &mut Diagnostic,
         expected: Ty<'tcx>,
         found: Ty<'tcx>,
-    ) {
+    ) -> bool {
         if let (ty::FnPtr(_), ty::Closure(def_id, _)) = (expected.kind(), found.kind()) {
             if let Some(upvars) = self.tcx.upvars_mentioned(*def_id) {
                 // Report upto four upvars being captured to reduce the amount error messages
@@ -488,8 +502,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     multi_span,
                     "closures can only be coerced to `fn` types if they do not capture any variables"
                 );
+                return true;
             }
         }
+        false
     }
 
     /// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
@@ -891,11 +907,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         err: &mut Diagnostic,
         expr: &hir::Expr<'_>,
-    ) {
+    ) -> bool {
         let sp = self.tcx.sess.source_map().start_point(expr.span);
         if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) {
             // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
-            self.tcx.sess.parse_sess.expr_parentheses_needed(err, *sp);
+            err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
+            true
+        } else {
+            false
         }
     }
 
@@ -908,7 +927,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         mut expr: &hir::Expr<'_>,
         mut expr_ty: Ty<'tcx>,
         mut expected_ty: Ty<'tcx>,
-    ) {
+    ) -> bool {
         loop {
             match (&expr.kind, expr_ty.kind(), expected_ty.kind()) {
                 (
@@ -922,9 +941,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
                 (hir::ExprKind::Block(blk, _), _, _) => {
                     self.suggest_block_to_brackets(diag, *blk, expr_ty, expected_ty);
-                    break;
+                    break true;
                 }
-                _ => break,
+                _ => break false,
             }
         }
     }
@@ -935,11 +954,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expr: &hir::Expr<'_>,
         expr_ty: Ty<'tcx>,
         expected_ty: Ty<'tcx>,
-    ) {
-        let ty::Adt(adt_def, substs) = expr_ty.kind() else { return; };
-        let ty::Adt(expected_adt_def, expected_substs) = expected_ty.kind() else { return; };
+    ) -> bool {
+        let ty::Adt(adt_def, substs) = expr_ty.kind() else { return false; };
+        let ty::Adt(expected_adt_def, expected_substs) = expected_ty.kind() else { return false; };
         if adt_def != expected_adt_def {
-            return;
+            return false;
         }
 
         let mut suggest_copied_or_cloned = || {
@@ -958,6 +977,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         ".copied()",
                         Applicability::MachineApplicable,
                     );
+                    return true;
                 } else if let Some(clone_did) = self.tcx.lang_items().clone_trait()
                     && rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions(
                         self,
@@ -975,8 +995,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         ".cloned()",
                         Applicability::MachineApplicable,
                     );
+                    return true;
                 }
             }
+            false
         };
 
         if let Some(result_did) = self.tcx.get_diagnostic_item(sym::Result)
@@ -984,12 +1006,67 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // Check that the error types are equal
             && self.can_eq(self.param_env, substs.type_at(1), expected_substs.type_at(1)).is_ok()
         {
-            suggest_copied_or_cloned();
+            return suggest_copied_or_cloned();
         } else if let Some(option_did) = self.tcx.get_diagnostic_item(sym::Option)
             && adt_def.did() == option_did
         {
-            suggest_copied_or_cloned();
+            return suggest_copied_or_cloned();
+        }
+
+        false
+    }
+
+    pub(crate) fn suggest_into(
+        &self,
+        diag: &mut Diagnostic,
+        expr: &hir::Expr<'_>,
+        expr_ty: Ty<'tcx>,
+        expected_ty: Ty<'tcx>,
+    ) -> bool {
+        let expr = expr.peel_blocks();
+
+        // We have better suggestions for scalar interconversions...
+        if expr_ty.is_scalar() && expected_ty.is_scalar() {
+            return false;
+        }
+
+        // Don't suggest turning a block into another type (e.g. `{}.into()`)
+        if matches!(expr.kind, hir::ExprKind::Block(..)) {
+            return false;
+        }
+
+        // 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() {
+            return false;
+        }
+
+        if let Some(into_def_id) = self.tcx.get_diagnostic_item(sym::Into)
+            && self.predicate_must_hold_modulo_regions(&traits::Obligation::new(
+                self.misc(expr.span),
+                self.param_env,
+                ty::Binder::dummy(ty::TraitRef {
+                    def_id: into_def_id,
+                    substs: self.tcx.mk_substs_trait(expr_ty, &[expected_ty.into()]),
+                })
+                .to_poly_trait_predicate()
+                .to_predicate(self.tcx),
+            ))
+        {
+            let sugg = if expr.precedence().order() >= PREC_POSTFIX {
+                vec![(expr.span.shrink_to_hi(), ".into()".to_owned())]
+            } else {
+                vec![(expr.span.shrink_to_lo(), "(".to_owned()), (expr.span.shrink_to_hi(), ").into()".to_owned())]
+            };
+            diag.multipart_suggestion(
+                format!("call `Into::into` on this expression to convert `{expr_ty}` into `{expected_ty}`"),
+                sugg,
+                Applicability::MaybeIncorrect
+            );
+            return true;
         }
+
+        false
     }
 
     /// Suggest wrapping the block in square brackets instead of curly braces
@@ -1121,7 +1198,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             } else {
                 err.span_suggestion_short(
                     span_semi,
-                    "remove this semicolon",
+                    "remove this semicolon to return this value",
                     "",
                     Applicability::MachineApplicable,
                 );
diff --git a/compiler/rustc_hir_analysis/src/check/generator_interior.rs b/compiler/rustc_hir_analysis/src/check/generator_interior.rs
index 254a19368bf..898419b5b23 100644
--- a/compiler/rustc_hir_analysis/src/check/generator_interior.rs
+++ b/compiler/rustc_hir_analysis/src/check/generator_interior.rs
@@ -6,7 +6,7 @@
 use self::drop_ranges::DropRanges;
 use super::FnCtxt;
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
-use rustc_errors::pluralize;
+use rustc_errors::{pluralize, DelayDm};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -610,33 +610,33 @@ fn check_must_not_suspend_def(
             rustc_session::lint::builtin::MUST_NOT_SUSPEND,
             hir_id,
             data.source_span,
-            |lint| {
-                let msg = format!(
+            DelayDm(|| {
+                format!(
                     "{}`{}`{} held across a suspend point, but should not be",
                     data.descr_pre,
                     tcx.def_path_str(def_id),
                     data.descr_post,
-                );
-                let mut err = lint.build(&msg);
-
+                )
+            }),
+            |lint| {
                 // add span pointing to the offending yield/await
-                err.span_label(data.yield_span, "the value is held across this suspend point");
+                lint.span_label(data.yield_span, "the value is held across this suspend point");
 
                 // Add optional reason note
                 if let Some(note) = attr.value_str() {
                     // FIXME(guswynn): consider formatting this better
-                    err.span_note(data.source_span, note.as_str());
+                    lint.span_note(data.source_span, note.as_str());
                 }
 
                 // Add some quick suggestions on what to do
                 // FIXME: can `drop` work as a suggestion here as well?
-                err.span_help(
+                lint.span_help(
                     data.source_span,
                     "consider using a block (`{ ... }`) \
                     to shrink the value's scope, ending before the suspend point",
                 );
 
-                err.emit();
+                lint
             },
         );
 
diff --git a/compiler/rustc_hir_analysis/src/check/inherited.rs b/compiler/rustc_hir_analysis/src/check/inherited.rs
index 37c830d4e38..2546227e138 100644
--- a/compiler/rustc_hir_analysis/src/check/inherited.rs
+++ b/compiler/rustc_hir_analysis/src/check/inherited.rs
@@ -55,7 +55,7 @@ pub struct Inherited<'a, 'tcx> {
 
     pub(super) deferred_cast_checks: RefCell<Vec<super::cast::CastCheck<'tcx>>>,
 
-    pub(super) deferred_transmute_checks: RefCell<Vec<(Ty<'tcx>, Ty<'tcx>, Span)>>,
+    pub(super) deferred_transmute_checks: RefCell<Vec<(Ty<'tcx>, Ty<'tcx>, hir::HirId)>>,
 
     pub(super) deferred_asm_checks: RefCell<Vec<(&'tcx hir::InlineAsm<'tcx>, hir::HirId)>>,
 
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index ae484b4feda..8be1cf04f8b 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -7,7 +7,8 @@ use crate::errors::{
 };
 use crate::require_same_types;
 
-use rustc_errors::struct_span_err;
+use hir::def_id::DefId;
+use rustc_errors::{struct_span_err, DiagnosticMessage};
 use rustc_hir as hir;
 use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::{self, TyCtxt};
@@ -61,8 +62,12 @@ fn equate_intrinsic_type<'tcx>(
 }
 
 /// Returns the unsafety of the given intrinsic.
-pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety {
-    match intrinsic {
+pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: DefId) -> hir::Unsafety {
+    let has_safe_attr = match tcx.has_attr(intrinsic_id, sym::rustc_safe_intrinsic) {
+        true => hir::Unsafety::Normal,
+        false => hir::Unsafety::Unsafe,
+    };
+    let is_in_list = match tcx.item_name(intrinsic_id) {
         // When adding a new intrinsic to this list,
         // it's usually worth updating that intrinsic's documentation
         // to note that it's safe to call, since
@@ -106,14 +111,26 @@ pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety {
         | sym::variant_count
         | sym::ptr_mask => hir::Unsafety::Normal,
         _ => hir::Unsafety::Unsafe,
+    };
+
+    if has_safe_attr != is_in_list {
+        tcx.sess.struct_span_err(
+            tcx.def_span(intrinsic_id),
+            DiagnosticMessage::Str(format!(
+                    "intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `{}`",
+                    tcx.item_name(intrinsic_id)
+        ))).emit();
     }
+
+    is_in_list
 }
 
 /// Remember to add all intrinsics here, in `compiler/rustc_codegen_llvm/src/intrinsic.rs`,
 /// and in `library/core/src/intrinsics.rs`.
 pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
     let param = |n| tcx.mk_ty_param(n, Symbol::intern(&format!("P{}", n)));
-    let intrinsic_name = tcx.item_name(it.def_id.to_def_id());
+    let intrinsic_id = it.def_id.to_def_id();
+    let intrinsic_name = tcx.item_name(intrinsic_id);
     let name_str = intrinsic_name.as_str();
 
     let bound_vars = tcx.mk_bound_variable_kinds(
@@ -160,7 +177,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
         };
         (n_tps, 0, inputs, output, hir::Unsafety::Unsafe)
     } else {
-        let unsafety = intrinsic_operation_unsafety(intrinsic_name);
+        let unsafety = intrinsic_operation_unsafety(tcx, intrinsic_id);
         let (n_tps, inputs, output) = match intrinsic_name {
             sym::abort => (0, Vec::new(), tcx.types.never),
             sym::unreachable => (0, Vec::new(), tcx.types.never),
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index d8fe63dbf08..4abc00cefb6 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
@@ -1,3 +1,4 @@
+use hir::HirId;
 use rustc_ast::InlineAsmTemplatePiece;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::struct_span_err;
@@ -6,7 +7,7 @@ use rustc_index::vec::Idx;
 use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
 use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitable, UintTy};
 use rustc_session::lint;
-use rustc_span::{Span, Symbol, DUMMY_SP};
+use rustc_span::{Symbol, DUMMY_SP};
 use rustc_target::abi::{Pointer, VariantIdx};
 use rustc_target::asm::{InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType};
 
@@ -40,11 +41,13 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
 }
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
-    pub fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'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 ty = self.resolve_vars_if_possible(ty);
-            let ty = self.tcx.normalize_erasing_regions(self.param_env, ty);
-            (SizeSkeleton::compute(ty, self.tcx, self.param_env), ty)
+            let ty = tcx.normalize_erasing_regions(self.param_env, ty);
+            (SizeSkeleton::compute(ty, tcx, self.param_env), ty)
         };
         let (sk_from, from) = convert(from);
         let (sk_to, to) = convert(to);
@@ -57,9 +60,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
             // Special-case transmuting from `typeof(function)` and
             // `Option<typeof(function)>` to present a clearer error.
-            let from = unpack_option_like(self.tcx, from);
-            if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer.size(&self.tcx) {
-                struct_span_err!(self.tcx.sess, span, E0591, "can't transmute zero-sized type")
+            let from = unpack_option_like(tcx, from);
+            if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer.size(&tcx) {
+                struct_span_err!(tcx.sess, span, E0591, "can't transmute zero-sized type")
                     .note(&format!("source type: {from}"))
                     .note(&format!("target type: {to}"))
                     .help("cast with `as` to a pointer instead")
@@ -83,7 +86,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         let mut err = struct_span_err!(
-            self.tcx.sess,
+            tcx.sess,
             span,
             E0512,
             "cannot transmute between types of different sizes, \
@@ -146,7 +149,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
         target_features: &FxHashSet<Symbol>,
     ) -> Option<InlineAsmType> {
         let ty = (self.get_operand_ty)(expr);
-        if ty.has_infer_types_or_consts() {
+        if ty.has_non_region_infer() {
             bug!("inference variable in asm operand ty: {:?} {:?}", expr, ty);
         }
         let asm_ty_isize = match self.tcx.sess.target.pointer_width {
@@ -328,17 +331,16 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                     lint::builtin::ASM_SUB_REGISTER,
                     expr.hir_id,
                     spans,
+                    "formatting may not be suitable for sub-register argument",
                     |lint| {
-                        let msg = "formatting may not be suitable for sub-register argument";
-                        let mut err = lint.build(msg);
-                        err.span_label(expr.span, "for this argument");
-                        err.help(&format!(
+                        lint.span_label(expr.span, "for this argument");
+                        lint.help(&format!(
                             "use `{{{idx}:{suggested_modifier}}}` to have the register formatted as `{suggested_result}`",
                         ));
-                        err.help(&format!(
+                        lint.help(&format!(
                             "or use `{{{idx}:{default_modifier}}}` to keep the default formatting of `{default_result}`",
                         ));
-                        err.emit();
+                        lint
                     },
                 );
             }
diff --git a/compiler/rustc_hir_analysis/src/check/method/prelude2021.rs b/compiler/rustc_hir_analysis/src/check/method/prelude2021.rs
index 392695cca68..ca4cdf5a0d0 100644
--- a/compiler/rustc_hir_analysis/src/check/method/prelude2021.rs
+++ b/compiler/rustc_hir_analysis/src/check/method/prelude2021.rs
@@ -82,14 +82,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 prelude_or_array_lint,
                 self_expr.hir_id,
                 self_expr.span,
+                format!("trait method `{}` will become ambiguous in Rust 2021", segment.ident.name),
                 |lint| {
                     let sp = self_expr.span;
 
-                    let mut lint = lint.build(&format!(
-                        "trait method `{}` will become ambiguous in Rust 2021",
-                        segment.ident.name
-                    ));
-
                     let derefs = "*".repeat(pick.autoderefs);
 
                     let autoref = match pick.autoref_or_ptr_adjustment {
@@ -133,7 +129,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         );
                     }
 
-                    lint.emit();
+                    lint
                 },
             );
         } else {
@@ -143,6 +139,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 prelude_or_array_lint,
                 call_expr.hir_id,
                 call_expr.span,
+                format!("trait method `{}` will become ambiguous in Rust 2021", segment.ident.name),
                 |lint| {
                     let sp = call_expr.span;
                     let trait_name = self.trait_path_or_bare_name(
@@ -151,11 +148,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         pick.item.container_id(self.tcx),
                     );
 
-                    let mut lint = lint.build(&format!(
-                        "trait method `{}` will become ambiguous in Rust 2021",
-                        segment.ident.name
-                    ));
-
                     let (self_adjusted, precise) = self.adjust_expr(pick, self_expr, sp);
                     if precise {
                         let args = args
@@ -202,7 +194,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         );
                     }
 
-                    lint.emit();
+                    lint
                 },
             );
         }
@@ -257,15 +249,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return;
         }
 
-        self.tcx.struct_span_lint_hir(RUST_2021_PRELUDE_COLLISIONS, expr_id, span, |lint| {
-            // "type" refers to either a type or, more likely, a trait from which
-            // the associated function or method is from.
-            let container_id = pick.item.container_id(self.tcx);
-            let trait_path = self.trait_path_or_bare_name(span, expr_id, container_id);
-            let trait_generics = self.tcx.generics_of(container_id);
-
-            let trait_name =
-                if trait_generics.params.len() <= trait_generics.has_self as usize {
+        self.tcx.struct_span_lint_hir(
+            RUST_2021_PRELUDE_COLLISIONS,
+            expr_id,
+            span,
+            format!(
+                "trait-associated function `{}` will become ambiguous in Rust 2021",
+                method_name.name
+            ),
+            |lint| {
+                // "type" refers to either a type or, more likely, a trait from which
+                // the associated function or method is from.
+                let container_id = pick.item.container_id(self.tcx);
+                let trait_path = self.trait_path_or_bare_name(span, expr_id, container_id);
+                let trait_generics = self.tcx.generics_of(container_id);
+
+                let trait_name = if trait_generics.params.len() <= trait_generics.has_self as usize
+                {
                     trait_path
                 } else {
                     let counts = trait_generics.own_counts();
@@ -282,44 +282,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     )
                 };
 
-            let mut lint = lint.build(&format!(
-                "trait-associated function `{}` will become ambiguous in Rust 2021",
-                method_name.name
-            ));
-
-            let mut self_ty_name = self_ty_span
-                .find_ancestor_inside(span)
-                .and_then(|span| self.sess().source_map().span_to_snippet(span).ok())
-                .unwrap_or_else(|| self_ty.to_string());
-
-            // Get the number of generics the self type has (if an Adt) unless we can determine that
-            // the user has written the self type with generics already which we (naively) do by looking
-            // for a "<" in `self_ty_name`.
-            if !self_ty_name.contains('<') {
-                if let Adt(def, _) = self_ty.kind() {
-                    let generics = self.tcx.generics_of(def.did());
-                    if !generics.params.is_empty() {
-                        let counts = generics.own_counts();
-                        self_ty_name += &format!(
-                            "<{}>",
-                            std::iter::repeat("'_")
-                                .take(counts.lifetimes)
-                                .chain(std::iter::repeat("_").take(counts.types + counts.consts))
-                                .collect::<Vec<_>>()
-                                .join(", ")
-                        );
+                let mut self_ty_name = self_ty_span
+                    .find_ancestor_inside(span)
+                    .and_then(|span| self.sess().source_map().span_to_snippet(span).ok())
+                    .unwrap_or_else(|| self_ty.to_string());
+
+                // Get the number of generics the self type has (if an Adt) unless we can determine that
+                // the user has written the self type with generics already which we (naively) do by looking
+                // for a "<" in `self_ty_name`.
+                if !self_ty_name.contains('<') {
+                    if let Adt(def, _) = self_ty.kind() {
+                        let generics = self.tcx.generics_of(def.did());
+                        if !generics.params.is_empty() {
+                            let counts = generics.own_counts();
+                            self_ty_name += &format!(
+                                "<{}>",
+                                std::iter::repeat("'_")
+                                    .take(counts.lifetimes)
+                                    .chain(
+                                        std::iter::repeat("_").take(counts.types + counts.consts)
+                                    )
+                                    .collect::<Vec<_>>()
+                                    .join(", ")
+                            );
+                        }
                     }
                 }
-            }
-            lint.span_suggestion(
-                span,
-                "disambiguate the associated function",
-                format!("<{} as {}>::{}", self_ty_name, trait_name, method_name.name,),
-                Applicability::MachineApplicable,
-            );
-
-            lint.emit();
-        });
+                lint.span_suggestion(
+                    span,
+                    "disambiguate the associated function",
+                    format!("<{} as {}>::{}", self_ty_name, trait_name, method_name.name,),
+                    Applicability::MachineApplicable,
+                );
+
+                lint
+            },
+        );
     }
 
     fn trait_path_or_bare_name(
diff --git a/compiler/rustc_hir_analysis/src/check/method/probe.rs b/compiler/rustc_hir_analysis/src/check/method/probe.rs
index 6cd7ced01a3..a761a93dea4 100644
--- a/compiler/rustc_hir_analysis/src/check/method/probe.rs
+++ b/compiler/rustc_hir_analysis/src/check/method/probe.rs
@@ -409,9 +409,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         lint::builtin::TYVAR_BEHIND_RAW_POINTER,
                         scope_expr_id,
                         span,
-                        |lint| {
-                            lint.build("type annotations needed").emit();
-                        },
+                        "type annotations needed",
+                        |lint| lint,
                     );
                 }
             } else {
@@ -1358,24 +1357,24 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         stable_pick: &Pick<'_>,
         unstable_candidates: &[(Candidate<'tcx>, Symbol)],
     ) {
+        let def_kind = stable_pick.item.kind.as_def_kind();
         self.tcx.struct_span_lint_hir(
             lint::builtin::UNSTABLE_NAME_COLLISIONS,
             self.scope_expr_id,
             self.span,
+            format!(
+                "{} {} with this name may be added to the standard library in the future",
+                def_kind.article(),
+                def_kind.descr(stable_pick.item.def_id),
+            ),
             |lint| {
-                let def_kind = stable_pick.item.kind.as_def_kind();
-                let mut diag = lint.build(&format!(
-                    "{} {} with this name may be added to the standard library in the future",
-                    def_kind.article(),
-                    def_kind.descr(stable_pick.item.def_id),
-                ));
                 match (stable_pick.item.kind, stable_pick.item.container) {
                     (ty::AssocKind::Fn, _) => {
                         // FIXME: This should be a `span_suggestion` instead of `help`
                         // However `self.span` only
                         // highlights the method name, so we can't use it. Also consider reusing
                         // the code from `report_method_error()`.
-                        diag.help(&format!(
+                        lint.help(&format!(
                             "call with fully qualified syntax `{}(...)` to keep using the current \
                              method",
                             self.tcx.def_path_str(stable_pick.item.def_id),
@@ -1383,7 +1382,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                     }
                     (ty::AssocKind::Const, ty::AssocItemContainer::TraitContainer) => {
                         let def_id = stable_pick.item.container_id(self.tcx);
-                        diag.span_suggestion(
+                        lint.span_suggestion(
                             self.span,
                             "use the fully qualified path to the associated const",
                             format!(
@@ -1399,7 +1398,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                 }
                 if self.tcx.sess.is_nightly_build() {
                     for (candidate, feature) in unstable_candidates {
-                        diag.help(&format!(
+                        lint.help(&format!(
                             "add `#![feature({})]` to the crate attributes to enable `{}`",
                             feature,
                             self.tcx.def_path_str(candidate.item.def_id),
@@ -1407,7 +1406,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                     }
                 }
 
-                diag.emit();
+                lint
             },
         );
     }
diff --git a/compiler/rustc_hir_analysis/src/check/method/suggest.rs b/compiler/rustc_hir_analysis/src/check/method/suggest.rs
index 0e82e4956c7..ad1084bd1b1 100644
--- a/compiler/rustc_hir_analysis/src/check/method/suggest.rs
+++ b/compiler/rustc_hir_analysis/src/check/method/suggest.rs
@@ -2324,6 +2324,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
+    /// issue #102320, for `unwrap_or` with closure as argument, suggest `unwrap_or_else`
+    /// FIXME: currently not working for suggesting `map_or_else`, see #102408
+    pub(crate) fn suggest_else_fn_with_closure(
+        &self,
+        err: &mut Diagnostic,
+        expr: &hir::Expr<'_>,
+        found: Ty<'tcx>,
+        expected: Ty<'tcx>,
+    ) -> bool {
+        let Some((_def_id_or_name, output, _inputs)) = self.extract_callable_info(expr, found)
+        else { return false; };
+
+        if !self.can_coerce(output, expected) {
+            return false;
+        }
+
+        let parent = self.tcx.hir().get_parent_node(expr.hir_id);
+        if  let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent) &&
+            let hir::ExprKind::MethodCall(
+                hir::PathSegment { ident: method_name, .. },
+                self_expr,
+                args,
+                ..,
+             ) = call_expr.kind &&
+            let Some(self_ty) = self.typeck_results.borrow().expr_ty_opt(self_expr) {
+            let new_name = Ident {
+                name: Symbol::intern(&format!("{}_else", method_name.as_str())),
+                span: method_name.span,
+            };
+            let probe = self.lookup_probe(
+                expr.span,
+                new_name,
+                self_ty,
+                self_expr,
+                ProbeScope::TraitsInScope,
+            );
+
+            // check the method arguments number
+            if let Ok(pick) = probe &&
+                let fn_sig = self.tcx.fn_sig(pick.item.def_id) &&
+                let fn_args = fn_sig.skip_binder().inputs() &&
+                fn_args.len() == args.len() + 1 {
+                err.span_suggestion_verbose(
+                    method_name.span.shrink_to_hi(),
+                    &format!("try calling `{}` instead", new_name.name.as_str()),
+                    "_else",
+                    Applicability::MaybeIncorrect,
+                );
+                return true;
+            }
+        }
+        false
+    }
+
     /// Checks whether there is a local type somewhere in the chain of
     /// autoderefs of `rcvr_ty`.
     fn type_derefs_to_local(
diff --git a/compiler/rustc_hir_analysis/src/check/op.rs b/compiler/rustc_hir_analysis/src/check/op.rs
index 4754717c29a..d876b1d20fe 100644
--- a/compiler/rustc_hir_analysis/src/check/op.rs
+++ b/compiler/rustc_hir_analysis/src/check/op.rs
@@ -13,6 +13,7 @@ use rustc_middle::ty::adjustment::{
 };
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable};
+use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
@@ -470,7 +471,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         // This has nothing here because it means we did string
                         // concatenation (e.g., "Hello " + "World!"). This means
                         // we don't want the note in the else clause to be emitted
-                    } else if lhs_ty.has_param_types_or_consts() {
+                    } else if lhs_ty.has_non_region_param() {
                         // Look for a TraitPredicate in the Fulfillment errors,
                         // and use it to generate a suggestion.
                         //
@@ -656,7 +657,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         format!("cannot apply unary operator `{}`", op.as_str()),
                     );
 
-                    if operand_ty.has_param_types_or_consts() {
+                    if operand_ty.has_non_region_param() {
                         let predicates = errors.iter().filter_map(|error| {
                             error.obligation.predicate.to_opt_poly_trait_pred()
                         });
@@ -677,7 +678,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         // If the previous expression was a block expression, suggest parentheses
                         // (turning this into a binary subtraction operation instead.)
                         // for example, `{2} - 2` -> `({2}) - 2` (see src\test\ui\parser\expr-as-stmt.rs)
-                        self.tcx.sess.parse_sess.expr_parentheses_needed(&mut err, *sp);
+                        err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
                     } else {
                         match actual.kind() {
                             Uint(_) if op == hir::UnOp::Neg => {
diff --git a/compiler/rustc_hir_analysis/src/check/pat.rs b/compiler/rustc_hir_analysis/src/check/pat.rs
index 8906b622b68..178326cfdc4 100644
--- a/compiler/rustc_hir_analysis/src/check/pat.rs
+++ b/compiler/rustc_hir_analysis/src/check/pat.rs
@@ -1790,10 +1790,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             &unmentioned_fields.iter().map(|(_, i)| i).collect::<Vec<_>>(),
         );
 
-        self.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, |build| {
-        let mut lint = build.build("some fields are not explicitly listed");
+        self.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, "some fields are not explicitly listed", |lint| {
         lint.span_label(pat.span, format!("field{} {} not listed", rustc_errors::pluralize!(unmentioned_fields.len()), joined_patterns));
-
         lint.help(
             "ensure that all fields are mentioned explicitly by adding the suggested fields",
         );
@@ -1801,7 +1799,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             "the pattern is of type `{}` and the `non_exhaustive_omitted_patterns` attribute was found",
             ty,
         ));
-        lint.emit();
+
+        lint
     });
     }
 
diff --git a/compiler/rustc_hir_analysis/src/check/upvar.rs b/compiler/rustc_hir_analysis/src/check/upvar.rs
index 0b207a6c0be..4f495641691 100644
--- a/compiler/rustc_hir_analysis/src/check/upvar.rs
+++ b/compiler/rustc_hir_analysis/src/check/upvar.rs
@@ -749,10 +749,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 lint::builtin::RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES,
                 closure_hir_id,
                 closure_head_span,
+                reasons.migration_message(),
                 |lint| {
-                    let mut diagnostics_builder = lint.build(
-                        &reasons.migration_message(),
-                    );
                     for NeededMigration { var_hir_id, diagnostics_info } in &need_migrations {
                         // Labels all the usage of the captured variable and why they are responsible
                         // for migration being needed
@@ -760,13 +758,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             match &lint_note.captures_info {
                                 UpvarMigrationInfo::CapturingPrecise { source_expr: Some(capture_expr_id), var_name: captured_name } => {
                                     let cause_span = self.tcx.hir().span(*capture_expr_id);
-                                    diagnostics_builder.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`",
+                                    lint.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`",
                                         self.tcx.hir().name(*var_hir_id),
                                         captured_name,
                                     ));
                                 }
                                 UpvarMigrationInfo::CapturingNothing { use_span } => {
-                                    diagnostics_builder.span_label(*use_span, format!("in Rust 2018, this causes the closure to capture `{}`, but in Rust 2021, it has no effect",
+                                    lint.span_label(*use_span, format!("in Rust 2018, this causes the closure to capture `{}`, but in Rust 2021, it has no effect",
                                         self.tcx.hir().name(*var_hir_id),
                                     ));
                                 }
@@ -781,13 +779,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                                 match &lint_note.captures_info {
                                     UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => {
-                                        diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure",
+                                        lint.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure",
                                             self.tcx.hir().name(*var_hir_id),
                                             captured_name,
                                         ));
                                     }
                                     UpvarMigrationInfo::CapturingNothing { use_span: _ } => {
-                                        diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{v}` is dropped here along with the closure, but in Rust 2021 `{v}` is not part of the closure",
+                                        lint.span_label(drop_location_span, format!("in Rust 2018, `{v}` is dropped here along with the closure, but in Rust 2021 `{v}` is not part of the closure",
                                             v = self.tcx.hir().name(*var_hir_id),
                                         ));
                                     }
@@ -800,7 +798,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 match &lint_note.captures_info {
                                     UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => {
                                         let var_name = self.tcx.hir().name(*var_hir_id);
-                                        diagnostics_builder.span_label(closure_head_span, format!("\
+                                        lint.span_label(closure_head_span, format!("\
                                         in Rust 2018, this closure implements {missing_trait} \
                                         as `{var_name}` implements {missing_trait}, but in Rust 2021, \
                                         this closure will no longer implement {missing_trait} \
@@ -814,7 +812,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             }
                         }
                     }
-                    diagnostics_builder.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>");
+                    lint.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>");
 
                     let diagnostic_msg = format!(
                         "add a dummy let to cause {} to be fully captured",
@@ -857,7 +855,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             // We take the indentation from the next non-empty line.
                             let line2 = lines.find(|line| !line.is_empty()).unwrap_or_default();
                             let indent = line2.split_once(|c: char| !c.is_whitespace()).unwrap_or_default().0;
-                            diagnostics_builder.span_suggestion(
+                            lint.span_suggestion(
                                 closure_body_span.with_lo(closure_body_span.lo() + BytePos::from_usize(line1.len())).shrink_to_lo(),
                                 &diagnostic_msg,
                                 format!("\n{indent}{migration_string};"),
@@ -868,7 +866,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             // braces, but with more than just the opening
                             // brace on the first line. We put the `let`
                             // directly after the `{`.
-                            diagnostics_builder.span_suggestion(
+                            lint.span_suggestion(
                                 closure_body_span.with_lo(closure_body_span.lo() + BytePos(1)).shrink_to_lo(),
                                 &diagnostic_msg,
                                 format!(" {migration_string};"),
@@ -877,7 +875,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         } else {
                             // This is a closure without braces around the body.
                             // We add braces to add the `let` before the body.
-                            diagnostics_builder.multipart_suggestion(
+                            lint.multipart_suggestion(
                                 &diagnostic_msg,
                                 vec![
                                     (closure_body_span.shrink_to_lo(), format!("{{ {migration_string}; ")),
@@ -887,7 +885,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             );
                         }
                     } else {
-                        diagnostics_builder.span_suggestion(
+                        lint.span_suggestion(
                             closure_span,
                             &diagnostic_msg,
                             migration_string,
@@ -895,7 +893,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         );
                     }
 
-                    diagnostics_builder.emit();
+                    lint
                 },
             );
         }
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 7965ec1b43f..d607f901420 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1428,9 +1428,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
             let substituted_pred = predicates.rebind(pred).subst(tcx, substs);
             // Don't check non-defaulted params, dependent defaults (including lifetimes)
             // or preds with multiple params.
-            if substituted_pred.has_param_types_or_consts()
-                || param_count.params.len() > 1
-                || has_region
+            if substituted_pred.has_non_region_param() || param_count.params.len() > 1 || has_region
             {
                 None
             } else if predicates.0.predicates.iter().any(|&(p, _)| p == substituted_pred) {
diff --git a/compiler/rustc_hir_analysis/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs
index 1d23ed92921..922833f8580 100644
--- a/compiler/rustc_hir_analysis/src/check_unused.rs
+++ b/compiler/rustc_hir_analysis/src/check_unused.rs
@@ -29,14 +29,18 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
             continue;
         }
         let hir::ItemKind::Use(path, _) = item.kind else { unreachable!() };
-        tcx.struct_span_lint_hir(lint::builtin::UNUSED_IMPORTS, item.hir_id(), path.span, |lint| {
-            let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) {
-                format!("unused import: `{}`", snippet)
-            } else {
-                "unused import".to_owned()
-            };
-            lint.build(&msg).emit();
-        });
+        let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) {
+            format!("unused import: `{}`", snippet)
+        } else {
+            "unused import".to_owned()
+        };
+        tcx.struct_span_lint_hir(
+            lint::builtin::UNUSED_IMPORTS,
+            item.hir_id(),
+            path.span,
+            msg,
+            |lint| lint,
+        );
     }
 
     unused_crates_lint(tcx);
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 7d15e5a7f3c..1307f74f210 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -2,7 +2,7 @@
 //! crate or pertains to a type defined in this crate.
 
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::struct_span_err;
+use rustc_errors::{struct_span_err, DelayDm};
 use rustc_errors::{Diagnostic, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_middle::ty::subst::GenericArgKind;
@@ -412,30 +412,31 @@ fn lint_auto_trait_impl<'tcx>(
         lint::builtin::SUSPICIOUS_AUTO_TRAIT_IMPLS,
         tcx.hir().local_def_id_to_hir_id(impl_def_id),
         tcx.def_span(impl_def_id),
-        |err| {
-            let item_span = tcx.def_span(self_type_did);
-            let self_descr = tcx.def_kind(self_type_did).descr(self_type_did);
-            let mut err = err.build(&format!(
+        DelayDm(|| {
+            format!(
                 "cross-crate traits with a default impl, like `{}`, \
                          should not be specialized",
                 tcx.def_path_str(trait_ref.def_id),
-            ));
+            )
+        }),
+        |lint| {
+            let item_span = tcx.def_span(self_type_did);
+            let self_descr = tcx.def_kind(self_type_did).descr(self_type_did);
             match arg {
                 ty::util::NotUniqueParam::DuplicateParam(arg) => {
-                    err.note(&format!("`{}` is mentioned multiple times", arg));
+                    lint.note(&format!("`{}` is mentioned multiple times", arg));
                 }
                 ty::util::NotUniqueParam::NotParam(arg) => {
-                    err.note(&format!("`{}` is not a generic parameter", arg));
+                    lint.note(&format!("`{}` is not a generic parameter", arg));
                 }
             }
-            err.span_note(
+            lint.span_note(
                 item_span,
                 &format!(
                     "try using the same sequence of generic parameters as the {} definition",
                     self_descr,
                 ),
-            );
-            err.emit();
+            )
         },
     );
 }
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index e7deae2b557..ab4b861b6cb 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -15,46 +15,40 @@
 //! crate as a kind of pass. This should eventually be factored away.
 
 use crate::astconv::AstConv;
-use crate::bounds::Bounds;
 use crate::check::intrinsic::intrinsic_operation_unsafety;
-use crate::constrained_generic_params as cgp;
 use crate::errors;
-use crate::middle::resolve_lifetime as rl;
 use rustc_ast as ast;
 use rustc_ast::{MetaItemKind, NestedMetaItem};
 use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
 use rustc_data_structures::captures::Captures;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey};
 use rustc_hir as hir;
-use rustc_hir::def::{CtorKind, DefKind};
+use rustc_hir::def::CtorKind;
 use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::weak_lang_items;
-use rustc_hir::{GenericParamKind, HirId, Node};
+use rustc_hir::{GenericParamKind, Node};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc_middle::mir::mono::Linkage;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::subst::InternalSubsts;
-use rustc_middle::ty::util::Discr;
-use rustc_middle::ty::util::IntTypeExt;
+use rustc_middle::ty::util::{Discr, IntTypeExt};
+use rustc_middle::ty::ReprOptions;
 use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, IsSuggestable, Ty, TyCtxt};
-use rustc_middle::ty::{ReprOptions, ToPredicate};
 use rustc_session::lint;
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::Span;
 use rustc_target::spec::{abi, SanitizerSet};
 use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
 use std::iter;
 
+mod generics_of;
 mod item_bounds;
+mod predicates_of;
 mod type_of;
 
-#[derive(Debug)]
-struct OnlySelfBounds(bool);
-
 ///////////////////////////////////////////////////////////////////////////
 // Main entry point
 
@@ -68,14 +62,15 @@ pub fn provide(providers: &mut Providers) {
         type_of: type_of::type_of,
         item_bounds: item_bounds::item_bounds,
         explicit_item_bounds: item_bounds::explicit_item_bounds,
-        generics_of,
-        predicates_of,
+        generics_of: generics_of::generics_of,
+        predicates_of: predicates_of::predicates_of,
         predicates_defined_on,
-        explicit_predicates_of,
-        super_predicates_of,
-        super_predicates_that_define_assoc_type,
-        trait_explicit_predicates_and_bounds,
-        type_param_predicates,
+        explicit_predicates_of: predicates_of::explicit_predicates_of,
+        super_predicates_of: predicates_of::super_predicates_of,
+        super_predicates_that_define_assoc_type:
+            predicates_of::super_predicates_that_define_assoc_type,
+        trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds,
+        type_param_predicates: predicates_of::type_param_predicates,
         trait_def,
         adt_def,
         fn_sig,
@@ -572,160 +567,6 @@ fn get_new_lifetime_name<'tcx>(
     (1..).flat_map(a_to_z_repeat_n).find(|lt| !existing_lifetimes.contains(lt.as_str())).unwrap()
 }
 
-/// Returns the predicates defined on `item_def_id` of the form
-/// `X: Foo` where `X` is the type parameter `def_id`.
-#[instrument(level = "trace", skip(tcx))]
-fn type_param_predicates(
-    tcx: TyCtxt<'_>,
-    (item_def_id, def_id, assoc_name): (DefId, LocalDefId, Ident),
-) -> ty::GenericPredicates<'_> {
-    use rustc_hir::*;
-
-    // In the AST, bounds can derive from two places. Either
-    // written inline like `<T: Foo>` or in a where-clause like
-    // `where T: Foo`.
-
-    let param_id = tcx.hir().local_def_id_to_hir_id(def_id);
-    let param_owner = tcx.hir().ty_param_owner(def_id);
-    let generics = tcx.generics_of(param_owner);
-    let index = generics.param_def_id_to_index[&def_id.to_def_id()];
-    let ty = tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id));
-
-    // Don't look for bounds where the type parameter isn't in scope.
-    let parent = if item_def_id == param_owner.to_def_id() {
-        None
-    } else {
-        tcx.generics_of(item_def_id).parent
-    };
-
-    let mut result = parent
-        .map(|parent| {
-            let icx = ItemCtxt::new(tcx, parent);
-            icx.get_type_parameter_bounds(DUMMY_SP, def_id.to_def_id(), assoc_name)
-        })
-        .unwrap_or_default();
-    let mut extend = None;
-
-    let item_hir_id = tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local());
-    let ast_generics = match tcx.hir().get(item_hir_id) {
-        Node::TraitItem(item) => &item.generics,
-
-        Node::ImplItem(item) => &item.generics,
-
-        Node::Item(item) => {
-            match item.kind {
-                ItemKind::Fn(.., ref generics, _)
-                | ItemKind::Impl(hir::Impl { ref generics, .. })
-                | ItemKind::TyAlias(_, ref generics)
-                | ItemKind::OpaqueTy(OpaqueTy {
-                    ref generics,
-                    origin: hir::OpaqueTyOrigin::TyAlias,
-                    ..
-                })
-                | ItemKind::Enum(_, ref generics)
-                | ItemKind::Struct(_, ref generics)
-                | ItemKind::Union(_, ref generics) => generics,
-                ItemKind::Trait(_, _, ref generics, ..) => {
-                    // Implied `Self: Trait` and supertrait bounds.
-                    if param_id == item_hir_id {
-                        let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id);
-                        extend =
-                            Some((identity_trait_ref.without_const().to_predicate(tcx), item.span));
-                    }
-                    generics
-                }
-                _ => return result,
-            }
-        }
-
-        Node::ForeignItem(item) => match item.kind {
-            ForeignItemKind::Fn(_, _, ref generics) => generics,
-            _ => return result,
-        },
-
-        _ => return result,
-    };
-
-    let icx = ItemCtxt::new(tcx, item_def_id);
-    let extra_predicates = extend.into_iter().chain(
-        icx.type_parameter_bounds_in_generics(
-            ast_generics,
-            param_id,
-            ty,
-            OnlySelfBounds(true),
-            Some(assoc_name),
-        )
-        .into_iter()
-        .filter(|(predicate, _)| match predicate.kind().skip_binder() {
-            ty::PredicateKind::Trait(data) => data.self_ty().is_param(index),
-            _ => false,
-        }),
-    );
-    result.predicates =
-        tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(extra_predicates));
-    result
-}
-
-impl<'tcx> ItemCtxt<'tcx> {
-    /// Finds bounds from `hir::Generics`. This requires scanning through the
-    /// AST. We do this to avoid having to convert *all* the bounds, which
-    /// would create artificial cycles. Instead, we can only convert the
-    /// bounds for a type parameter `X` if `X::Foo` is used.
-    #[instrument(level = "trace", skip(self, ast_generics))]
-    fn type_parameter_bounds_in_generics(
-        &self,
-        ast_generics: &'tcx hir::Generics<'tcx>,
-        param_id: hir::HirId,
-        ty: Ty<'tcx>,
-        only_self_bounds: OnlySelfBounds,
-        assoc_name: Option<Ident>,
-    ) -> Vec<(ty::Predicate<'tcx>, Span)> {
-        let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id();
-        trace!(?param_def_id);
-        ast_generics
-            .predicates
-            .iter()
-            .filter_map(|wp| match *wp {
-                hir::WherePredicate::BoundPredicate(ref bp) => Some(bp),
-                _ => None,
-            })
-            .flat_map(|bp| {
-                let bt = if bp.is_param_bound(param_def_id) {
-                    Some(ty)
-                } else if !only_self_bounds.0 {
-                    Some(self.to_ty(bp.bounded_ty))
-                } else {
-                    None
-                };
-                let bvars = self.tcx.late_bound_vars(bp.bounded_ty.hir_id);
-
-                bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b, bvars))).filter(
-                    |(_, b, _)| match assoc_name {
-                        Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
-                        None => true,
-                    },
-                )
-            })
-            .flat_map(|(bt, b, bvars)| predicates_from_bound(self, bt, b, bvars))
-            .collect()
-    }
-
-    #[instrument(level = "trace", skip(self))]
-    fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool {
-        match b {
-            hir::GenericBound::Trait(poly_trait_ref, _) => {
-                let trait_ref = &poly_trait_ref.trait_ref;
-                if let Some(trait_did) = trait_ref.trait_def_id() {
-                    self.tcx.trait_may_define_assoc_type(trait_did, assoc_name)
-                } else {
-                    false
-                }
-            }
-            _ => false,
-        }
-    }
-}
-
 fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
     let it = tcx.hir().item(item_id);
     debug!("convert: item {} with id {}", it.ident, it.hir_id());
@@ -1097,96 +938,6 @@ fn adt_def<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::AdtDef<'tcx> {
     tcx.alloc_adt_def(def_id.to_def_id(), kind, variants, repr)
 }
 
-/// Ensures that the super-predicates of the trait with a `DefId`
-/// of `trait_def_id` are converted and stored. This also ensures that
-/// the transitive super-predicates are converted.
-fn super_predicates_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> ty::GenericPredicates<'_> {
-    debug!("super_predicates(trait_def_id={:?})", trait_def_id);
-    tcx.super_predicates_that_define_assoc_type((trait_def_id, None))
-}
-
-/// Ensures that the super-predicates of the trait with a `DefId`
-/// of `trait_def_id` are converted and stored. This also ensures that
-/// the transitive super-predicates are converted.
-fn super_predicates_that_define_assoc_type(
-    tcx: TyCtxt<'_>,
-    (trait_def_id, assoc_name): (DefId, Option<Ident>),
-) -> ty::GenericPredicates<'_> {
-    debug!(
-        "super_predicates_that_define_assoc_type(trait_def_id={:?}, assoc_name={:?})",
-        trait_def_id, assoc_name
-    );
-    if trait_def_id.is_local() {
-        debug!("super_predicates_that_define_assoc_type: local trait_def_id={:?}", trait_def_id);
-        let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id.expect_local());
-
-        let Node::Item(item) = tcx.hir().get(trait_hir_id) else {
-            bug!("trait_node_id {} is not an item", trait_hir_id);
-        };
-
-        let (generics, bounds) = match item.kind {
-            hir::ItemKind::Trait(.., ref generics, ref supertraits, _) => (generics, supertraits),
-            hir::ItemKind::TraitAlias(ref generics, ref supertraits) => (generics, supertraits),
-            _ => span_bug!(item.span, "super_predicates invoked on non-trait"),
-        };
-
-        let icx = ItemCtxt::new(tcx, trait_def_id);
-
-        // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`.
-        let self_param_ty = tcx.types.self_param;
-        let superbounds1 = if let Some(assoc_name) = assoc_name {
-            <dyn AstConv<'_>>::compute_bounds_that_match_assoc_type(
-                &icx,
-                self_param_ty,
-                bounds,
-                assoc_name,
-            )
-        } else {
-            <dyn AstConv<'_>>::compute_bounds(&icx, self_param_ty, bounds)
-        };
-
-        let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
-
-        // Convert any explicit superbounds in the where-clause,
-        // e.g., `trait Foo where Self: Bar`.
-        // In the case of trait aliases, however, we include all bounds in the where-clause,
-        // so e.g., `trait Foo = where u32: PartialEq<Self>` would include `u32: PartialEq<Self>`
-        // as one of its "superpredicates".
-        let is_trait_alias = tcx.is_trait_alias(trait_def_id);
-        let superbounds2 = icx.type_parameter_bounds_in_generics(
-            generics,
-            item.hir_id(),
-            self_param_ty,
-            OnlySelfBounds(!is_trait_alias),
-            assoc_name,
-        );
-
-        // Combine the two lists to form the complete set of superbounds:
-        let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2));
-        debug!(?superbounds);
-
-        // Now require that immediate supertraits are converted,
-        // which will, in turn, reach indirect supertraits.
-        if assoc_name.is_none() {
-            // Now require that immediate supertraits are converted,
-            // which will, in turn, reach indirect supertraits.
-            for &(pred, span) in superbounds {
-                debug!("superbound: {:?}", pred);
-                if let ty::PredicateKind::Trait(bound) = pred.kind().skip_binder() {
-                    tcx.at(span).super_predicates_of(bound.def_id());
-                }
-            }
-        }
-
-        ty::GenericPredicates { parent: None, predicates: superbounds }
-    } else {
-        // if `assoc_name` is None, then the query should've been redirected to an
-        // external provider
-        assert!(assoc_name.is_some());
-        tcx.super_predicates_of(trait_def_id)
-    }
-}
-
 fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
     let item = tcx.hir().expect_item(def_id.expect_local());
 
@@ -1328,475 +1079,6 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
     )
 }
 
-fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<Span> {
-    struct LateBoundRegionsDetector<'tcx> {
-        tcx: TyCtxt<'tcx>,
-        outer_index: ty::DebruijnIndex,
-        has_late_bound_regions: Option<Span>,
-    }
-
-    impl<'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'tcx> {
-        fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
-            if self.has_late_bound_regions.is_some() {
-                return;
-            }
-            match ty.kind {
-                hir::TyKind::BareFn(..) => {
-                    self.outer_index.shift_in(1);
-                    intravisit::walk_ty(self, ty);
-                    self.outer_index.shift_out(1);
-                }
-                _ => intravisit::walk_ty(self, ty),
-            }
-        }
-
-        fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) {
-            if self.has_late_bound_regions.is_some() {
-                return;
-            }
-            self.outer_index.shift_in(1);
-            intravisit::walk_poly_trait_ref(self, tr);
-            self.outer_index.shift_out(1);
-        }
-
-        fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
-            if self.has_late_bound_regions.is_some() {
-                return;
-            }
-
-            match self.tcx.named_region(lt.hir_id) {
-                Some(rl::Region::Static | rl::Region::EarlyBound(..)) => {}
-                Some(rl::Region::LateBound(debruijn, _, _)) if debruijn < self.outer_index => {}
-                Some(rl::Region::LateBound(..) | rl::Region::Free(..)) | None => {
-                    self.has_late_bound_regions = Some(lt.span);
-                }
-            }
-        }
-    }
-
-    fn has_late_bound_regions<'tcx>(
-        tcx: TyCtxt<'tcx>,
-        generics: &'tcx hir::Generics<'tcx>,
-        decl: &'tcx hir::FnDecl<'tcx>,
-    ) -> Option<Span> {
-        let mut visitor = LateBoundRegionsDetector {
-            tcx,
-            outer_index: ty::INNERMOST,
-            has_late_bound_regions: None,
-        };
-        for param in generics.params {
-            if let GenericParamKind::Lifetime { .. } = param.kind {
-                if tcx.is_late_bound(param.hir_id) {
-                    return Some(param.span);
-                }
-            }
-        }
-        visitor.visit_fn_decl(decl);
-        visitor.has_late_bound_regions
-    }
-
-    match node {
-        Node::TraitItem(item) => match item.kind {
-            hir::TraitItemKind::Fn(ref sig, _) => {
-                has_late_bound_regions(tcx, &item.generics, sig.decl)
-            }
-            _ => None,
-        },
-        Node::ImplItem(item) => match item.kind {
-            hir::ImplItemKind::Fn(ref sig, _) => {
-                has_late_bound_regions(tcx, &item.generics, sig.decl)
-            }
-            _ => None,
-        },
-        Node::ForeignItem(item) => match item.kind {
-            hir::ForeignItemKind::Fn(fn_decl, _, ref generics) => {
-                has_late_bound_regions(tcx, generics, fn_decl)
-            }
-            _ => None,
-        },
-        Node::Item(item) => match item.kind {
-            hir::ItemKind::Fn(ref sig, .., ref generics, _) => {
-                has_late_bound_regions(tcx, generics, sig.decl)
-            }
-            _ => None,
-        },
-        _ => None,
-    }
-}
-
-struct AnonConstInParamTyDetector {
-    in_param_ty: bool,
-    found_anon_const_in_param_ty: bool,
-    ct: HirId,
-}
-
-impl<'v> Visitor<'v> for AnonConstInParamTyDetector {
-    fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) {
-        if let GenericParamKind::Const { ty, default: _ } = p.kind {
-            let prev = self.in_param_ty;
-            self.in_param_ty = true;
-            self.visit_ty(ty);
-            self.in_param_ty = prev;
-        }
-    }
-
-    fn visit_anon_const(&mut self, c: &'v hir::AnonConst) {
-        if self.in_param_ty && self.ct == c.hir_id {
-            self.found_anon_const_in_param_ty = true;
-        } else {
-            intravisit::walk_anon_const(self, c)
-        }
-    }
-}
-
-fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
-    use rustc_hir::*;
-
-    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-
-    let node = tcx.hir().get(hir_id);
-    let parent_def_id = match node {
-        Node::ImplItem(_)
-        | Node::TraitItem(_)
-        | Node::Variant(_)
-        | Node::Ctor(..)
-        | Node::Field(_) => {
-            let parent_id = tcx.hir().get_parent_item(hir_id);
-            Some(parent_id.to_def_id())
-        }
-        // FIXME(#43408) always enable this once `lazy_normalization` is
-        // stable enough and does not need a feature gate anymore.
-        Node::AnonConst(_) => {
-            let parent_def_id = tcx.hir().get_parent_item(hir_id);
-
-            let mut in_param_ty = false;
-            for (_parent, node) in tcx.hir().parent_iter(hir_id) {
-                if let Some(generics) = node.generics() {
-                    let mut visitor = AnonConstInParamTyDetector {
-                        in_param_ty: false,
-                        found_anon_const_in_param_ty: false,
-                        ct: hir_id,
-                    };
-
-                    visitor.visit_generics(generics);
-                    in_param_ty = visitor.found_anon_const_in_param_ty;
-                    break;
-                }
-            }
-
-            if in_param_ty {
-                // We do not allow generic parameters in anon consts if we are inside
-                // of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
-                None
-            } else if tcx.lazy_normalization() {
-                if let Some(param_id) = tcx.hir().opt_const_param_default_param_hir_id(hir_id) {
-                    // If the def_id we are calling generics_of on is an anon ct default i.e:
-                    //
-                    // struct Foo<const N: usize = { .. }>;
-                    //        ^^^       ^          ^^^^^^ def id of this anon const
-                    //        ^         ^ param_id
-                    //        ^ parent_def_id
-                    //
-                    // then we only want to return generics for params to the left of `N`. If we don't do that we
-                    // end up with that const looking like: `ty::ConstKind::Unevaluated(def_id, substs: [N#0])`.
-                    //
-                    // This causes ICEs (#86580) when building the substs for Foo in `fn foo() -> Foo { .. }` as
-                    // we substitute the defaults with the partially built substs when we build the substs. Subst'ing
-                    // the `N#0` on the unevaluated const indexes into the empty substs we're in the process of building.
-                    //
-                    // We fix this by having this function return the parent's generics ourselves and truncating the
-                    // generics to only include non-forward declared params (with the exception of the `Self` ty)
-                    //
-                    // For the above code example that means we want `substs: []`
-                    // For the following struct def we want `substs: [N#0]` when generics_of is called on
-                    // the def id of the `{ N + 1 }` anon const
-                    // struct Foo<const N: usize, const M: usize = { N + 1 }>;
-                    //
-                    // This has some implications for how we get the predicates available to the anon const
-                    // see `explicit_predicates_of` for more information on this
-                    let generics = tcx.generics_of(parent_def_id.to_def_id());
-                    let param_def = tcx.hir().local_def_id(param_id).to_def_id();
-                    let param_def_idx = generics.param_def_id_to_index[&param_def];
-                    // In the above example this would be .params[..N#0]
-                    let params = generics.params[..param_def_idx as usize].to_owned();
-                    let param_def_id_to_index =
-                        params.iter().map(|param| (param.def_id, param.index)).collect();
-
-                    return ty::Generics {
-                        // we set the parent of these generics to be our parent's parent so that we
-                        // dont end up with substs: [N, M, N] for the const default on a struct like this:
-                        // struct Foo<const N: usize, const M: usize = { ... }>;
-                        parent: generics.parent,
-                        parent_count: generics.parent_count,
-                        params,
-                        param_def_id_to_index,
-                        has_self: generics.has_self,
-                        has_late_bound_regions: generics.has_late_bound_regions,
-                    };
-                }
-
-                // HACK(eddyb) this provides the correct generics when
-                // `feature(generic_const_expressions)` is enabled, so that const expressions
-                // used with const generics, e.g. `Foo<{N+1}>`, can work at all.
-                //
-                // Note that we do not supply the parent generics when using
-                // `min_const_generics`.
-                Some(parent_def_id.to_def_id())
-            } else {
-                let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
-                match parent_node {
-                    // HACK(eddyb) this provides the correct generics for repeat
-                    // expressions' count (i.e. `N` in `[x; N]`), and explicit
-                    // `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`),
-                    // as they shouldn't be able to cause query cycle errors.
-                    Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
-                        if constant.hir_id() == hir_id =>
-                    {
-                        Some(parent_def_id.to_def_id())
-                    }
-                    Node::Variant(Variant { disr_expr: Some(ref constant), .. })
-                        if constant.hir_id == hir_id =>
-                    {
-                        Some(parent_def_id.to_def_id())
-                    }
-                    Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => {
-                        Some(tcx.typeck_root_def_id(def_id))
-                    }
-                    // Exclude `GlobalAsm` here which cannot have generics.
-                    Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
-                        if asm.operands.iter().any(|(op, _op_sp)| match op {
-                            hir::InlineAsmOperand::Const { anon_const }
-                            | hir::InlineAsmOperand::SymFn { anon_const } => {
-                                anon_const.hir_id == hir_id
-                            }
-                            _ => false,
-                        }) =>
-                    {
-                        Some(parent_def_id.to_def_id())
-                    }
-                    _ => None,
-                }
-            }
-        }
-        Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
-            Some(tcx.typeck_root_def_id(def_id))
-        }
-        Node::Item(item) => match item.kind {
-            ItemKind::OpaqueTy(hir::OpaqueTy {
-                origin:
-                    hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
-                in_trait,
-                ..
-            }) => {
-                if in_trait {
-                    assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn))
-                } else {
-                    assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn))
-                }
-                Some(fn_def_id.to_def_id())
-            }
-            ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
-                let parent_id = tcx.hir().get_parent_item(hir_id);
-                assert_ne!(parent_id, hir::CRATE_OWNER_ID);
-                debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_id);
-                // Opaque types are always nested within another item, and
-                // inherit the generics of the item.
-                Some(parent_id.to_def_id())
-            }
-            _ => None,
-        },
-        _ => None,
-    };
-
-    enum Defaults {
-        Allowed,
-        // See #36887
-        FutureCompatDisallowed,
-        Deny,
-    }
-
-    let no_generics = hir::Generics::empty();
-    let ast_generics = node.generics().unwrap_or(&no_generics);
-    let (opt_self, allow_defaults) = match node {
-        Node::Item(item) => {
-            match item.kind {
-                ItemKind::Trait(..) | ItemKind::TraitAlias(..) => {
-                    // Add in the self type parameter.
-                    //
-                    // Something of a hack: use the node id for the trait, also as
-                    // the node id for the Self type parameter.
-                    let opt_self = Some(ty::GenericParamDef {
-                        index: 0,
-                        name: kw::SelfUpper,
-                        def_id,
-                        pure_wrt_drop: false,
-                        kind: ty::GenericParamDefKind::Type {
-                            has_default: false,
-                            synthetic: false,
-                        },
-                    });
-
-                    (opt_self, Defaults::Allowed)
-                }
-                ItemKind::TyAlias(..)
-                | ItemKind::Enum(..)
-                | ItemKind::Struct(..)
-                | ItemKind::OpaqueTy(..)
-                | ItemKind::Union(..) => (None, Defaults::Allowed),
-                _ => (None, Defaults::FutureCompatDisallowed),
-            }
-        }
-
-        // GATs
-        Node::TraitItem(item) if matches!(item.kind, TraitItemKind::Type(..)) => {
-            (None, Defaults::Deny)
-        }
-        Node::ImplItem(item) if matches!(item.kind, ImplItemKind::TyAlias(..)) => {
-            (None, Defaults::Deny)
-        }
-
-        _ => (None, Defaults::FutureCompatDisallowed),
-    };
-
-    let has_self = opt_self.is_some();
-    let mut parent_has_self = false;
-    let mut own_start = has_self as u32;
-    let parent_count = parent_def_id.map_or(0, |def_id| {
-        let generics = tcx.generics_of(def_id);
-        assert!(!has_self);
-        parent_has_self = generics.has_self;
-        own_start = generics.count() as u32;
-        generics.parent_count + generics.params.len()
-    });
-
-    let mut params: Vec<_> = Vec::with_capacity(ast_generics.params.len() + has_self as usize);
-
-    if let Some(opt_self) = opt_self {
-        params.push(opt_self);
-    }
-
-    let early_lifetimes = early_bound_lifetimes_from_generics(tcx, ast_generics);
-    params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef {
-        name: param.name.ident().name,
-        index: own_start + i as u32,
-        def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
-        pure_wrt_drop: param.pure_wrt_drop,
-        kind: ty::GenericParamDefKind::Lifetime,
-    }));
-
-    // Now create the real type and const parameters.
-    let type_start = own_start - has_self as u32 + params.len() as u32;
-    let mut i = 0;
-
-    const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \
-    `struct`, `enum`, `type`, or `trait` definitions";
-
-    params.extend(ast_generics.params.iter().filter_map(|param| match param.kind {
-        GenericParamKind::Lifetime { .. } => None,
-        GenericParamKind::Type { ref default, synthetic, .. } => {
-            if default.is_some() {
-                match allow_defaults {
-                    Defaults::Allowed => {}
-                    Defaults::FutureCompatDisallowed
-                        if tcx.features().default_type_parameter_fallback => {}
-                    Defaults::FutureCompatDisallowed => {
-                        tcx.struct_span_lint_hir(
-                            lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
-                            param.hir_id,
-                            param.span,
-                            |lint| {
-                                lint.build(TYPE_DEFAULT_NOT_ALLOWED).emit();
-                            },
-                        );
-                    }
-                    Defaults::Deny => {
-                        tcx.sess.span_err(param.span, TYPE_DEFAULT_NOT_ALLOWED);
-                    }
-                }
-            }
-
-            let kind = ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic };
-
-            let param_def = ty::GenericParamDef {
-                index: type_start + i as u32,
-                name: param.name.ident().name,
-                def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
-                pure_wrt_drop: param.pure_wrt_drop,
-                kind,
-            };
-            i += 1;
-            Some(param_def)
-        }
-        GenericParamKind::Const { default, .. } => {
-            if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() {
-                tcx.sess.span_err(
-                    param.span,
-                    "defaults for const parameters are only allowed in \
-                    `struct`, `enum`, `type`, or `trait` definitions",
-                );
-            }
-
-            let param_def = ty::GenericParamDef {
-                index: type_start + i as u32,
-                name: param.name.ident().name,
-                def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
-                pure_wrt_drop: param.pure_wrt_drop,
-                kind: ty::GenericParamDefKind::Const { has_default: default.is_some() },
-            };
-            i += 1;
-            Some(param_def)
-        }
-    }));
-
-    // provide junk type parameter defs - the only place that
-    // cares about anything but the length is instantiation,
-    // and we don't do that for closures.
-    if let Node::Expr(&hir::Expr {
-        kind: hir::ExprKind::Closure(hir::Closure { movability: gen, .. }),
-        ..
-    }) = node
-    {
-        let dummy_args = if gen.is_some() {
-            &["<resume_ty>", "<yield_ty>", "<return_ty>", "<witness>", "<upvars>"][..]
-        } else {
-            &["<closure_kind>", "<closure_signature>", "<upvars>"][..]
-        };
-
-        params.extend(dummy_args.iter().enumerate().map(|(i, &arg)| ty::GenericParamDef {
-            index: type_start + i as u32,
-            name: Symbol::intern(arg),
-            def_id,
-            pure_wrt_drop: false,
-            kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
-        }));
-    }
-
-    // provide junk type parameter defs for const blocks.
-    if let Node::AnonConst(_) = node {
-        let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
-        if let Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) = parent_node {
-            params.push(ty::GenericParamDef {
-                index: type_start,
-                name: Symbol::intern("<const_ty>"),
-                def_id,
-                pure_wrt_drop: false,
-                kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
-            });
-        }
-    }
-
-    let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect();
-
-    ty::Generics {
-        parent: parent_def_id,
-        parent_count,
-        params,
-        param_def_id_to_index,
-        has_self: has_self || parent_has_self,
-        has_late_bound_regions: has_late_bound_regions(tcx, node),
-    }
-}
-
 fn are_suggestable_generic_args(generic_args: &[hir::GenericArg<'_>]) -> bool {
     generic_args.iter().any(|arg| match arg {
         hir::GenericArg::Type(ty) => is_suggestable_infer_ty(ty),
@@ -2093,450 +1375,6 @@ fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicate
     result
 }
 
-/// Returns a list of all type predicates (explicit and implicit) for the definition with
-/// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus
-/// `Self: Trait` predicates for traits.
-fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
-    let mut result = tcx.predicates_defined_on(def_id);
-
-    if tcx.is_trait(def_id) {
-        // For traits, add `Self: Trait` predicate. This is
-        // not part of the predicates that a user writes, but it
-        // is something that one must prove in order to invoke a
-        // method or project an associated type.
-        //
-        // In the chalk setup, this predicate is not part of the
-        // "predicates" for a trait item. But it is useful in
-        // rustc because if you directly (e.g.) invoke a trait
-        // method like `Trait::method(...)`, you must naturally
-        // prove that the trait applies to the types that were
-        // used, and adding the predicate into this list ensures
-        // that this is done.
-        //
-        // We use a DUMMY_SP here as a way to signal trait bounds that come
-        // from the trait itself that *shouldn't* be shown as the source of
-        // an obligation and instead be skipped. Otherwise we'd use
-        // `tcx.def_span(def_id);`
-
-        let constness = if tcx.has_attr(def_id, sym::const_trait) {
-            ty::BoundConstness::ConstIfConst
-        } else {
-            ty::BoundConstness::NotConst
-        };
-
-        let span = rustc_span::DUMMY_SP;
-        result.predicates =
-            tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
-                ty::TraitRef::identity(tcx, def_id).with_constness(constness).to_predicate(tcx),
-                span,
-            ))));
-    }
-    debug!("predicates_of(def_id={:?}) = {:?}", def_id, result);
-    result
-}
-
-/// Returns a list of user-specified type predicates for the definition with ID `def_id`.
-/// N.B., this does not include any implied/inferred constraints.
-#[instrument(level = "trace", skip(tcx), ret)]
-fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
-    use rustc_hir::*;
-
-    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-    let node = tcx.hir().get(hir_id);
-
-    let mut is_trait = None;
-    let mut is_default_impl_trait = None;
-
-    let icx = ItemCtxt::new(tcx, def_id);
-
-    const NO_GENERICS: &hir::Generics<'_> = hir::Generics::empty();
-
-    // We use an `IndexSet` to preserves order of insertion.
-    // Preserving the order of insertion is important here so as not to break UI tests.
-    let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default();
-
-    let ast_generics = match node {
-        Node::TraitItem(item) => item.generics,
-
-        Node::ImplItem(item) => item.generics,
-
-        Node::Item(item) => {
-            match item.kind {
-                ItemKind::Impl(ref impl_) => {
-                    if impl_.defaultness.is_default() {
-                        is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy);
-                    }
-                    &impl_.generics
-                }
-                ItemKind::Fn(.., ref generics, _)
-                | ItemKind::TyAlias(_, ref generics)
-                | ItemKind::Enum(_, ref generics)
-                | ItemKind::Struct(_, ref generics)
-                | ItemKind::Union(_, ref generics) => *generics,
-
-                ItemKind::Trait(_, _, ref generics, ..) => {
-                    is_trait = Some(ty::TraitRef::identity(tcx, def_id));
-                    *generics
-                }
-                ItemKind::TraitAlias(ref generics, _) => {
-                    is_trait = Some(ty::TraitRef::identity(tcx, def_id));
-                    *generics
-                }
-                ItemKind::OpaqueTy(OpaqueTy {
-                    origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
-                    ..
-                }) => {
-                    // return-position impl trait
-                    //
-                    // We don't inherit predicates from the parent here:
-                    // If we have, say `fn f<'a, T: 'a>() -> impl Sized {}`
-                    // then the return type is `f::<'static, T>::{{opaque}}`.
-                    //
-                    // If we inherited the predicates of `f` then we would
-                    // require that `T: 'static` to show that the return
-                    // type is well-formed.
-                    //
-                    // The only way to have something with this opaque type
-                    // is from the return type of the containing function,
-                    // which will ensure that the function's predicates
-                    // hold.
-                    return ty::GenericPredicates { parent: None, predicates: &[] };
-                }
-                ItemKind::OpaqueTy(OpaqueTy {
-                    ref generics,
-                    origin: hir::OpaqueTyOrigin::TyAlias,
-                    ..
-                }) => {
-                    // type-alias impl trait
-                    generics
-                }
-
-                _ => NO_GENERICS,
-            }
-        }
-
-        Node::ForeignItem(item) => match item.kind {
-            ForeignItemKind::Static(..) => NO_GENERICS,
-            ForeignItemKind::Fn(_, _, ref generics) => *generics,
-            ForeignItemKind::Type => NO_GENERICS,
-        },
-
-        _ => NO_GENERICS,
-    };
-
-    let generics = tcx.generics_of(def_id);
-    let parent_count = generics.parent_count as u32;
-    let has_own_self = generics.has_self && parent_count == 0;
-
-    // Below we'll consider the bounds on the type parameters (including `Self`)
-    // and the explicit where-clauses, but to get the full set of predicates
-    // on a trait we need to add in the supertrait bounds and bounds found on
-    // associated types.
-    if let Some(_trait_ref) = is_trait {
-        predicates.extend(tcx.super_predicates_of(def_id).predicates.iter().cloned());
-    }
-
-    // In default impls, we can assume that the self type implements
-    // the trait. So in:
-    //
-    //     default impl Foo for Bar { .. }
-    //
-    // we add a default where clause `Foo: Bar`. We do a similar thing for traits
-    // (see below). Recall that a default impl is not itself an impl, but rather a
-    // set of defaults that can be incorporated into another impl.
-    if let Some(trait_ref) = is_default_impl_trait {
-        predicates.insert((trait_ref.without_const().to_predicate(tcx), tcx.def_span(def_id)));
-    }
-
-    // Collect the region predicates that were declared inline as
-    // well. In the case of parameters declared on a fn or method, we
-    // have to be careful to only iterate over early-bound regions.
-    let mut index = parent_count
-        + has_own_self as u32
-        + early_bound_lifetimes_from_generics(tcx, ast_generics).count() as u32;
-
-    trace!(?predicates);
-    trace!(?ast_generics);
-
-    // Collect the predicates that were written inline by the user on each
-    // type parameter (e.g., `<T: Foo>`).
-    for param in ast_generics.params {
-        match param.kind {
-            // We already dealt with early bound lifetimes above.
-            GenericParamKind::Lifetime { .. } => (),
-            GenericParamKind::Type { .. } => {
-                let name = param.name.ident().name;
-                let param_ty = ty::ParamTy::new(index, name).to_ty(tcx);
-                index += 1;
-
-                let mut bounds = Bounds::default();
-                // Params are implicitly sized unless a `?Sized` bound is found
-                <dyn AstConv<'_>>::add_implicitly_sized(
-                    &icx,
-                    &mut bounds,
-                    &[],
-                    Some((param.hir_id, ast_generics.predicates)),
-                    param.span,
-                );
-                trace!(?bounds);
-                predicates.extend(bounds.predicates(tcx, param_ty));
-                trace!(?predicates);
-            }
-            GenericParamKind::Const { .. } => {
-                // Bounds on const parameters are currently not possible.
-                index += 1;
-            }
-        }
-    }
-
-    trace!(?predicates);
-    // Add in the bounds that appear in the where-clause.
-    for predicate in ast_generics.predicates {
-        match predicate {
-            hir::WherePredicate::BoundPredicate(bound_pred) => {
-                let ty = icx.to_ty(bound_pred.bounded_ty);
-                let bound_vars = icx.tcx.late_bound_vars(bound_pred.bounded_ty.hir_id);
-
-                // Keep the type around in a dummy predicate, in case of no bounds.
-                // That way, `where Ty:` is not a complete noop (see #53696) and `Ty`
-                // is still checked for WF.
-                if bound_pred.bounds.is_empty() {
-                    if let ty::Param(_) = ty.kind() {
-                        // This is a `where T:`, which can be in the HIR from the
-                        // transformation that moves `?Sized` to `T`'s declaration.
-                        // We can skip the predicate because type parameters are
-                        // trivially WF, but also we *should*, to avoid exposing
-                        // users who never wrote `where Type:,` themselves, to
-                        // compiler/tooling bugs from not handling WF predicates.
-                    } else {
-                        let span = bound_pred.bounded_ty.span;
-                        let predicate = ty::Binder::bind_with_vars(
-                            ty::PredicateKind::WellFormed(ty.into()),
-                            bound_vars,
-                        );
-                        predicates.insert((predicate.to_predicate(tcx), span));
-                    }
-                }
-
-                let mut bounds = Bounds::default();
-                <dyn AstConv<'_>>::add_bounds(
-                    &icx,
-                    ty,
-                    bound_pred.bounds.iter(),
-                    &mut bounds,
-                    bound_vars,
-                );
-                predicates.extend(bounds.predicates(tcx, ty));
-            }
-
-            hir::WherePredicate::RegionPredicate(region_pred) => {
-                let r1 = <dyn AstConv<'_>>::ast_region_to_region(&icx, &region_pred.lifetime, None);
-                predicates.extend(region_pred.bounds.iter().map(|bound| {
-                    let (r2, span) = match bound {
-                        hir::GenericBound::Outlives(lt) => {
-                            (<dyn AstConv<'_>>::ast_region_to_region(&icx, lt, None), lt.span)
-                        }
-                        _ => bug!(),
-                    };
-                    let pred = ty::Binder::dummy(ty::PredicateKind::RegionOutlives(
-                        ty::OutlivesPredicate(r1, r2),
-                    ))
-                    .to_predicate(icx.tcx);
-
-                    (pred, span)
-                }))
-            }
-
-            hir::WherePredicate::EqPredicate(..) => {
-                // FIXME(#20041)
-            }
-        }
-    }
-
-    if tcx.features().generic_const_exprs {
-        predicates.extend(const_evaluatable_predicates_of(tcx, def_id.expect_local()));
-    }
-
-    let mut predicates: Vec<_> = predicates.into_iter().collect();
-
-    // Subtle: before we store the predicates into the tcx, we
-    // sort them so that predicates like `T: Foo<Item=U>` come
-    // before uses of `U`.  This avoids false ambiguity errors
-    // in trait checking. See `setup_constraining_predicates`
-    // for details.
-    if let Node::Item(&Item { kind: ItemKind::Impl { .. }, .. }) = node {
-        let self_ty = tcx.type_of(def_id);
-        let trait_ref = tcx.impl_trait_ref(def_id);
-        cgp::setup_constraining_predicates(
-            tcx,
-            &mut predicates,
-            trait_ref,
-            &mut cgp::parameters_for_impl(self_ty, trait_ref),
-        );
-    }
-
-    ty::GenericPredicates {
-        parent: generics.parent,
-        predicates: tcx.arena.alloc_from_iter(predicates),
-    }
-}
-
-fn const_evaluatable_predicates_of<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def_id: LocalDefId,
-) -> FxIndexSet<(ty::Predicate<'tcx>, Span)> {
-    struct ConstCollector<'tcx> {
-        tcx: TyCtxt<'tcx>,
-        preds: FxIndexSet<(ty::Predicate<'tcx>, Span)>,
-    }
-
-    impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'tcx> {
-        fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
-            let def_id = self.tcx.hir().local_def_id(c.hir_id);
-            let ct = ty::Const::from_anon_const(self.tcx, def_id);
-            if let ty::ConstKind::Unevaluated(uv) = ct.kind() {
-                let span = self.tcx.hir().span(c.hir_id);
-                self.preds.insert((
-                    ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv))
-                        .to_predicate(self.tcx),
-                    span,
-                ));
-            }
-        }
-
-        fn visit_const_param_default(&mut self, _param: HirId, _ct: &'tcx hir::AnonConst) {
-            // Do not look into const param defaults,
-            // these get checked when they are actually instantiated.
-            //
-            // We do not want the following to error:
-            //
-            //     struct Foo<const N: usize, const M: usize = { N + 1 }>;
-            //     struct Bar<const N: usize>(Foo<N, 3>);
-        }
-    }
-
-    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-    let node = tcx.hir().get(hir_id);
-
-    let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() };
-    if let hir::Node::Item(item) = node && let hir::ItemKind::Impl(ref impl_) = item.kind {
-        if let Some(of_trait) = &impl_.of_trait {
-            debug!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id);
-            collector.visit_trait_ref(of_trait);
-        }
-
-        debug!("const_evaluatable_predicates_of({:?}): visit_self_ty", def_id);
-        collector.visit_ty(impl_.self_ty);
-    }
-
-    if let Some(generics) = node.generics() {
-        debug!("const_evaluatable_predicates_of({:?}): visit_generics", def_id);
-        collector.visit_generics(generics);
-    }
-
-    if let Some(fn_sig) = tcx.hir().fn_sig_by_hir_id(hir_id) {
-        debug!("const_evaluatable_predicates_of({:?}): visit_fn_decl", def_id);
-        collector.visit_fn_decl(fn_sig.decl);
-    }
-    debug!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.preds);
-
-    collector.preds
-}
-
-fn trait_explicit_predicates_and_bounds(
-    tcx: TyCtxt<'_>,
-    def_id: LocalDefId,
-) -> ty::GenericPredicates<'_> {
-    assert_eq!(tcx.def_kind(def_id), DefKind::Trait);
-    gather_explicit_predicates_of(tcx, def_id.to_def_id())
-}
-
-fn explicit_predicates_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::GenericPredicates<'tcx> {
-    let def_kind = tcx.def_kind(def_id);
-    if let DefKind::Trait = def_kind {
-        // Remove bounds on associated types from the predicates, they will be
-        // returned by `explicit_item_bounds`.
-        let predicates_and_bounds = tcx.trait_explicit_predicates_and_bounds(def_id.expect_local());
-        let trait_identity_substs = InternalSubsts::identity_for_item(tcx, def_id);
-
-        let is_assoc_item_ty = |ty: Ty<'tcx>| {
-            // For a predicate from a where clause to become a bound on an
-            // associated type:
-            // * It must use the identity substs of the item.
-            //     * Since any generic parameters on the item are not in scope,
-            //       this means that the item is not a GAT, and its identity
-            //       substs are the same as the trait's.
-            // * It must be an associated type for this trait (*not* a
-            //   supertrait).
-            if let ty::Projection(projection) = ty.kind() {
-                projection.substs == trait_identity_substs
-                    && tcx.associated_item(projection.item_def_id).container_id(tcx) == def_id
-            } else {
-                false
-            }
-        };
-
-        let predicates: Vec<_> = predicates_and_bounds
-            .predicates
-            .iter()
-            .copied()
-            .filter(|(pred, _)| match pred.kind().skip_binder() {
-                ty::PredicateKind::Trait(tr) => !is_assoc_item_ty(tr.self_ty()),
-                ty::PredicateKind::Projection(proj) => {
-                    !is_assoc_item_ty(proj.projection_ty.self_ty())
-                }
-                ty::PredicateKind::TypeOutlives(outlives) => !is_assoc_item_ty(outlives.0),
-                _ => true,
-            })
-            .collect();
-        if predicates.len() == predicates_and_bounds.predicates.len() {
-            predicates_and_bounds
-        } else {
-            ty::GenericPredicates {
-                parent: predicates_and_bounds.parent,
-                predicates: tcx.arena.alloc_slice(&predicates),
-            }
-        }
-    } else {
-        if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() {
-            let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-            if tcx.hir().opt_const_param_default_param_hir_id(hir_id).is_some() {
-                // In `generics_of` we set the generics' parent to be our parent's parent which means that
-                // we lose out on the predicates of our actual parent if we dont return those predicates here.
-                // (See comment in `generics_of` for more information on why the parent shenanigans is necessary)
-                //
-                // struct Foo<T, const N: usize = { <T as Trait>::ASSOC }>(T) where T: Trait;
-                //        ^^^                     ^^^^^^^^^^^^^^^^^^^^^^^ the def id we are calling
-                //        ^^^                                             explicit_predicates_of on
-                //        parent item we dont have set as the
-                //        parent of generics returned by `generics_of`
-                //
-                // In the above code we want the anon const to have predicates in its param env for `T: Trait`
-                let item_def_id = tcx.hir().get_parent_item(hir_id);
-                // In the above code example we would be calling `explicit_predicates_of(Foo)` here
-                return tcx.explicit_predicates_of(item_def_id);
-            }
-        }
-        gather_explicit_predicates_of(tcx, def_id)
-    }
-}
-
-/// Converts a specific `GenericBound` from the AST into a set of
-/// predicates that apply to the self type. A vector is returned
-/// because this can be anywhere from zero predicates (`T: ?Sized` adds no
-/// predicates) to one (`T: Foo`) to many (`T: Bar<X = i32>` adds `T: Bar`
-/// and `<T as Bar>::X == i32`).
-fn predicates_from_bound<'tcx>(
-    astconv: &dyn AstConv<'tcx>,
-    param_ty: Ty<'tcx>,
-    bound: &'tcx hir::GenericBound<'tcx>,
-    bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
-) -> Vec<(ty::Predicate<'tcx>, Span)> {
-    let mut bounds = Bounds::default();
-    astconv.add_bounds(param_ty, [bound].into_iter(), &mut bounds, bound_vars);
-    bounds.predicates(astconv.tcx(), param_ty).collect()
-}
-
 fn compute_sig_of_foreign_fn_decl<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: DefId,
@@ -2544,7 +1382,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
     abi: abi::Abi,
 ) -> ty::PolyFnSig<'tcx> {
     let unsafety = if abi == abi::Abi::RustIntrinsic {
-        intrinsic_operation_unsafety(tcx.item_name(def_id))
+        intrinsic_operation_unsafety(tcx, def_id)
     } else {
         hir::Unsafety::Unsafe
     };
@@ -3229,11 +2067,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
                     lint::builtin::INLINE_NO_SANITIZE,
                     hir_id,
                     no_sanitize_span,
-                    |lint| {
-                        lint.build("`no_sanitize` will have no effect after inlining")
-                            .span_note(inline_span, "inlining requested here")
-                            .emit();
-                    },
+                    "`no_sanitize` will have no effect after inlining",
+                    |lint| lint.span_note(inline_span, "inlining requested here"),
                 )
             }
         }
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
new file mode 100644
index 00000000000..7ffacbecf5f
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -0,0 +1,480 @@
+use crate::middle::resolve_lifetime as rl;
+use hir::{
+    intravisit::{self, Visitor},
+    GenericParamKind, HirId, Node,
+};
+use rustc_hir as hir;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::DefId;
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_session::lint;
+use rustc_span::symbol::{kw, Symbol};
+use rustc_span::Span;
+
+pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
+    use rustc_hir::*;
+
+    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+
+    let node = tcx.hir().get(hir_id);
+    let parent_def_id = match node {
+        Node::ImplItem(_)
+        | Node::TraitItem(_)
+        | Node::Variant(_)
+        | Node::Ctor(..)
+        | Node::Field(_) => {
+            let parent_id = tcx.hir().get_parent_item(hir_id);
+            Some(parent_id.to_def_id())
+        }
+        // FIXME(#43408) always enable this once `lazy_normalization` is
+        // stable enough and does not need a feature gate anymore.
+        Node::AnonConst(_) => {
+            let parent_def_id = tcx.hir().get_parent_item(hir_id);
+
+            let mut in_param_ty = false;
+            for (_parent, node) in tcx.hir().parent_iter(hir_id) {
+                if let Some(generics) = node.generics() {
+                    let mut visitor = AnonConstInParamTyDetector {
+                        in_param_ty: false,
+                        found_anon_const_in_param_ty: false,
+                        ct: hir_id,
+                    };
+
+                    visitor.visit_generics(generics);
+                    in_param_ty = visitor.found_anon_const_in_param_ty;
+                    break;
+                }
+            }
+
+            if in_param_ty {
+                // We do not allow generic parameters in anon consts if we are inside
+                // of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
+                None
+            } else if tcx.lazy_normalization() {
+                if let Some(param_id) = tcx.hir().opt_const_param_default_param_hir_id(hir_id) {
+                    // If the def_id we are calling generics_of on is an anon ct default i.e:
+                    //
+                    // struct Foo<const N: usize = { .. }>;
+                    //        ^^^       ^          ^^^^^^ def id of this anon const
+                    //        ^         ^ param_id
+                    //        ^ parent_def_id
+                    //
+                    // then we only want to return generics for params to the left of `N`. If we don't do that we
+                    // end up with that const looking like: `ty::ConstKind::Unevaluated(def_id, substs: [N#0])`.
+                    //
+                    // This causes ICEs (#86580) when building the substs for Foo in `fn foo() -> Foo { .. }` as
+                    // we substitute the defaults with the partially built substs when we build the substs. Subst'ing
+                    // the `N#0` on the unevaluated const indexes into the empty substs we're in the process of building.
+                    //
+                    // We fix this by having this function return the parent's generics ourselves and truncating the
+                    // generics to only include non-forward declared params (with the exception of the `Self` ty)
+                    //
+                    // For the above code example that means we want `substs: []`
+                    // For the following struct def we want `substs: [N#0]` when generics_of is called on
+                    // the def id of the `{ N + 1 }` anon const
+                    // struct Foo<const N: usize, const M: usize = { N + 1 }>;
+                    //
+                    // This has some implications for how we get the predicates available to the anon const
+                    // see `explicit_predicates_of` for more information on this
+                    let generics = tcx.generics_of(parent_def_id.to_def_id());
+                    let param_def = tcx.hir().local_def_id(param_id).to_def_id();
+                    let param_def_idx = generics.param_def_id_to_index[&param_def];
+                    // In the above example this would be .params[..N#0]
+                    let params = generics.params[..param_def_idx as usize].to_owned();
+                    let param_def_id_to_index =
+                        params.iter().map(|param| (param.def_id, param.index)).collect();
+
+                    return ty::Generics {
+                        // we set the parent of these generics to be our parent's parent so that we
+                        // dont end up with substs: [N, M, N] for the const default on a struct like this:
+                        // struct Foo<const N: usize, const M: usize = { ... }>;
+                        parent: generics.parent,
+                        parent_count: generics.parent_count,
+                        params,
+                        param_def_id_to_index,
+                        has_self: generics.has_self,
+                        has_late_bound_regions: generics.has_late_bound_regions,
+                    };
+                }
+
+                // HACK(eddyb) this provides the correct generics when
+                // `feature(generic_const_expressions)` is enabled, so that const expressions
+                // used with const generics, e.g. `Foo<{N+1}>`, can work at all.
+                //
+                // Note that we do not supply the parent generics when using
+                // `min_const_generics`.
+                Some(parent_def_id.to_def_id())
+            } else {
+                let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
+                match parent_node {
+                    // HACK(eddyb) this provides the correct generics for repeat
+                    // expressions' count (i.e. `N` in `[x; N]`), and explicit
+                    // `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`),
+                    // as they shouldn't be able to cause query cycle errors.
+                    Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
+                        if constant.hir_id() == hir_id =>
+                    {
+                        Some(parent_def_id.to_def_id())
+                    }
+                    Node::Variant(Variant { disr_expr: Some(ref constant), .. })
+                        if constant.hir_id == hir_id =>
+                    {
+                        Some(parent_def_id.to_def_id())
+                    }
+                    Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => {
+                        Some(tcx.typeck_root_def_id(def_id))
+                    }
+                    // Exclude `GlobalAsm` here which cannot have generics.
+                    Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
+                        if asm.operands.iter().any(|(op, _op_sp)| match op {
+                            hir::InlineAsmOperand::Const { anon_const }
+                            | hir::InlineAsmOperand::SymFn { anon_const } => {
+                                anon_const.hir_id == hir_id
+                            }
+                            _ => false,
+                        }) =>
+                    {
+                        Some(parent_def_id.to_def_id())
+                    }
+                    _ => None,
+                }
+            }
+        }
+        Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
+            Some(tcx.typeck_root_def_id(def_id))
+        }
+        Node::Item(item) => match item.kind {
+            ItemKind::OpaqueTy(hir::OpaqueTy {
+                origin:
+                    hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
+                in_trait,
+                ..
+            }) => {
+                if in_trait {
+                    assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn))
+                } else {
+                    assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn))
+                }
+                Some(fn_def_id.to_def_id())
+            }
+            ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
+                let parent_id = tcx.hir().get_parent_item(hir_id);
+                assert_ne!(parent_id, hir::CRATE_OWNER_ID);
+                debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_id);
+                // Opaque types are always nested within another item, and
+                // inherit the generics of the item.
+                Some(parent_id.to_def_id())
+            }
+            _ => None,
+        },
+        _ => None,
+    };
+
+    enum Defaults {
+        Allowed,
+        // See #36887
+        FutureCompatDisallowed,
+        Deny,
+    }
+
+    let no_generics = hir::Generics::empty();
+    let ast_generics = node.generics().unwrap_or(&no_generics);
+    let (opt_self, allow_defaults) = match node {
+        Node::Item(item) => {
+            match item.kind {
+                ItemKind::Trait(..) | ItemKind::TraitAlias(..) => {
+                    // Add in the self type parameter.
+                    //
+                    // Something of a hack: use the node id for the trait, also as
+                    // the node id for the Self type parameter.
+                    let opt_self = Some(ty::GenericParamDef {
+                        index: 0,
+                        name: kw::SelfUpper,
+                        def_id,
+                        pure_wrt_drop: false,
+                        kind: ty::GenericParamDefKind::Type {
+                            has_default: false,
+                            synthetic: false,
+                        },
+                    });
+
+                    (opt_self, Defaults::Allowed)
+                }
+                ItemKind::TyAlias(..)
+                | ItemKind::Enum(..)
+                | ItemKind::Struct(..)
+                | ItemKind::OpaqueTy(..)
+                | ItemKind::Union(..) => (None, Defaults::Allowed),
+                _ => (None, Defaults::FutureCompatDisallowed),
+            }
+        }
+
+        // GATs
+        Node::TraitItem(item) if matches!(item.kind, TraitItemKind::Type(..)) => {
+            (None, Defaults::Deny)
+        }
+        Node::ImplItem(item) if matches!(item.kind, ImplItemKind::TyAlias(..)) => {
+            (None, Defaults::Deny)
+        }
+
+        _ => (None, Defaults::FutureCompatDisallowed),
+    };
+
+    let has_self = opt_self.is_some();
+    let mut parent_has_self = false;
+    let mut own_start = has_self as u32;
+    let parent_count = parent_def_id.map_or(0, |def_id| {
+        let generics = tcx.generics_of(def_id);
+        assert!(!has_self);
+        parent_has_self = generics.has_self;
+        own_start = generics.count() as u32;
+        generics.parent_count + generics.params.len()
+    });
+
+    let mut params: Vec<_> = Vec::with_capacity(ast_generics.params.len() + has_self as usize);
+
+    if let Some(opt_self) = opt_self {
+        params.push(opt_self);
+    }
+
+    let early_lifetimes = super::early_bound_lifetimes_from_generics(tcx, ast_generics);
+    params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef {
+        name: param.name.ident().name,
+        index: own_start + i as u32,
+        def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
+        pure_wrt_drop: param.pure_wrt_drop,
+        kind: ty::GenericParamDefKind::Lifetime,
+    }));
+
+    // Now create the real type and const parameters.
+    let type_start = own_start - has_self as u32 + params.len() as u32;
+    let mut i = 0;
+
+    const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \
+    `struct`, `enum`, `type`, or `trait` definitions";
+
+    params.extend(ast_generics.params.iter().filter_map(|param| match param.kind {
+        GenericParamKind::Lifetime { .. } => None,
+        GenericParamKind::Type { ref default, synthetic, .. } => {
+            if default.is_some() {
+                match allow_defaults {
+                    Defaults::Allowed => {}
+                    Defaults::FutureCompatDisallowed
+                        if tcx.features().default_type_parameter_fallback => {}
+                    Defaults::FutureCompatDisallowed => {
+                        tcx.struct_span_lint_hir(
+                            lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
+                            param.hir_id,
+                            param.span,
+                            TYPE_DEFAULT_NOT_ALLOWED,
+                            |lint| lint,
+                        );
+                    }
+                    Defaults::Deny => {
+                        tcx.sess.span_err(param.span, TYPE_DEFAULT_NOT_ALLOWED);
+                    }
+                }
+            }
+
+            let kind = ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic };
+
+            let param_def = ty::GenericParamDef {
+                index: type_start + i as u32,
+                name: param.name.ident().name,
+                def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
+                pure_wrt_drop: param.pure_wrt_drop,
+                kind,
+            };
+            i += 1;
+            Some(param_def)
+        }
+        GenericParamKind::Const { default, .. } => {
+            if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() {
+                tcx.sess.span_err(
+                    param.span,
+                    "defaults for const parameters are only allowed in \
+                    `struct`, `enum`, `type`, or `trait` definitions",
+                );
+            }
+
+            let param_def = ty::GenericParamDef {
+                index: type_start + i as u32,
+                name: param.name.ident().name,
+                def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
+                pure_wrt_drop: param.pure_wrt_drop,
+                kind: ty::GenericParamDefKind::Const { has_default: default.is_some() },
+            };
+            i += 1;
+            Some(param_def)
+        }
+    }));
+
+    // provide junk type parameter defs - the only place that
+    // cares about anything but the length is instantiation,
+    // and we don't do that for closures.
+    if let Node::Expr(&hir::Expr {
+        kind: hir::ExprKind::Closure(hir::Closure { movability: gen, .. }),
+        ..
+    }) = node
+    {
+        let dummy_args = if gen.is_some() {
+            &["<resume_ty>", "<yield_ty>", "<return_ty>", "<witness>", "<upvars>"][..]
+        } else {
+            &["<closure_kind>", "<closure_signature>", "<upvars>"][..]
+        };
+
+        params.extend(dummy_args.iter().enumerate().map(|(i, &arg)| ty::GenericParamDef {
+            index: type_start + i as u32,
+            name: Symbol::intern(arg),
+            def_id,
+            pure_wrt_drop: false,
+            kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
+        }));
+    }
+
+    // provide junk type parameter defs for const blocks.
+    if let Node::AnonConst(_) = node {
+        let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
+        if let Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) = parent_node {
+            params.push(ty::GenericParamDef {
+                index: type_start,
+                name: Symbol::intern("<const_ty>"),
+                def_id,
+                pure_wrt_drop: false,
+                kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
+            });
+        }
+    }
+
+    let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect();
+
+    ty::Generics {
+        parent: parent_def_id,
+        parent_count,
+        params,
+        param_def_id_to_index,
+        has_self: has_self || parent_has_self,
+        has_late_bound_regions: has_late_bound_regions(tcx, node),
+    }
+}
+
+fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<Span> {
+    struct LateBoundRegionsDetector<'tcx> {
+        tcx: TyCtxt<'tcx>,
+        outer_index: ty::DebruijnIndex,
+        has_late_bound_regions: Option<Span>,
+    }
+
+    impl<'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'tcx> {
+        fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
+            if self.has_late_bound_regions.is_some() {
+                return;
+            }
+            match ty.kind {
+                hir::TyKind::BareFn(..) => {
+                    self.outer_index.shift_in(1);
+                    intravisit::walk_ty(self, ty);
+                    self.outer_index.shift_out(1);
+                }
+                _ => intravisit::walk_ty(self, ty),
+            }
+        }
+
+        fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) {
+            if self.has_late_bound_regions.is_some() {
+                return;
+            }
+            self.outer_index.shift_in(1);
+            intravisit::walk_poly_trait_ref(self, tr);
+            self.outer_index.shift_out(1);
+        }
+
+        fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
+            if self.has_late_bound_regions.is_some() {
+                return;
+            }
+
+            match self.tcx.named_region(lt.hir_id) {
+                Some(rl::Region::Static | rl::Region::EarlyBound(..)) => {}
+                Some(rl::Region::LateBound(debruijn, _, _)) if debruijn < self.outer_index => {}
+                Some(rl::Region::LateBound(..) | rl::Region::Free(..)) | None => {
+                    self.has_late_bound_regions = Some(lt.span);
+                }
+            }
+        }
+    }
+
+    fn has_late_bound_regions<'tcx>(
+        tcx: TyCtxt<'tcx>,
+        generics: &'tcx hir::Generics<'tcx>,
+        decl: &'tcx hir::FnDecl<'tcx>,
+    ) -> Option<Span> {
+        let mut visitor = LateBoundRegionsDetector {
+            tcx,
+            outer_index: ty::INNERMOST,
+            has_late_bound_regions: None,
+        };
+        for param in generics.params {
+            if let GenericParamKind::Lifetime { .. } = param.kind {
+                if tcx.is_late_bound(param.hir_id) {
+                    return Some(param.span);
+                }
+            }
+        }
+        visitor.visit_fn_decl(decl);
+        visitor.has_late_bound_regions
+    }
+
+    match node {
+        Node::TraitItem(item) => match item.kind {
+            hir::TraitItemKind::Fn(ref sig, _) => {
+                has_late_bound_regions(tcx, &item.generics, sig.decl)
+            }
+            _ => None,
+        },
+        Node::ImplItem(item) => match item.kind {
+            hir::ImplItemKind::Fn(ref sig, _) => {
+                has_late_bound_regions(tcx, &item.generics, sig.decl)
+            }
+            _ => None,
+        },
+        Node::ForeignItem(item) => match item.kind {
+            hir::ForeignItemKind::Fn(fn_decl, _, ref generics) => {
+                has_late_bound_regions(tcx, generics, fn_decl)
+            }
+            _ => None,
+        },
+        Node::Item(item) => match item.kind {
+            hir::ItemKind::Fn(ref sig, .., ref generics, _) => {
+                has_late_bound_regions(tcx, generics, sig.decl)
+            }
+            _ => None,
+        },
+        _ => None,
+    }
+}
+
+struct AnonConstInParamTyDetector {
+    in_param_ty: bool,
+    found_anon_const_in_param_ty: bool,
+    ct: HirId,
+}
+
+impl<'v> Visitor<'v> for AnonConstInParamTyDetector {
+    fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) {
+        if let GenericParamKind::Const { ty, default: _ } = p.kind {
+            let prev = self.in_param_ty;
+            self.in_param_ty = true;
+            self.visit_ty(ty);
+            self.in_param_ty = prev;
+        }
+    }
+
+    fn visit_anon_const(&mut self, c: &'v hir::AnonConst) {
+        if self.in_param_ty && self.ct == c.hir_id {
+            self.found_anon_const_in_param_ty = true;
+        } else {
+            intravisit::walk_anon_const(self, c)
+        }
+    }
+}
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
new file mode 100644
index 00000000000..db8f8de68f2
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -0,0 +1,707 @@
+use crate::astconv::AstConv;
+use crate::bounds::Bounds;
+use crate::collect::ItemCtxt;
+use crate::constrained_generic_params as cgp;
+use hir::{HirId, Node};
+use rustc_data_structures::fx::FxIndexSet;
+use rustc_hir as hir;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::intravisit::{self, Visitor};
+use rustc_middle::ty::subst::InternalSubsts;
+use rustc_middle::ty::ToPredicate;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::symbol::{sym, Ident};
+use rustc_span::{Span, DUMMY_SP};
+
+#[derive(Debug)]
+struct OnlySelfBounds(bool);
+
+/// Returns a list of all type predicates (explicit and implicit) for the definition with
+/// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus
+/// `Self: Trait` predicates for traits.
+pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
+    let mut result = tcx.predicates_defined_on(def_id);
+
+    if tcx.is_trait(def_id) {
+        // For traits, add `Self: Trait` predicate. This is
+        // not part of the predicates that a user writes, but it
+        // is something that one must prove in order to invoke a
+        // method or project an associated type.
+        //
+        // In the chalk setup, this predicate is not part of the
+        // "predicates" for a trait item. But it is useful in
+        // rustc because if you directly (e.g.) invoke a trait
+        // method like `Trait::method(...)`, you must naturally
+        // prove that the trait applies to the types that were
+        // used, and adding the predicate into this list ensures
+        // that this is done.
+        //
+        // We use a DUMMY_SP here as a way to signal trait bounds that come
+        // from the trait itself that *shouldn't* be shown as the source of
+        // an obligation and instead be skipped. Otherwise we'd use
+        // `tcx.def_span(def_id);`
+
+        let constness = if tcx.has_attr(def_id, sym::const_trait) {
+            ty::BoundConstness::ConstIfConst
+        } else {
+            ty::BoundConstness::NotConst
+        };
+
+        let span = rustc_span::DUMMY_SP;
+        result.predicates =
+            tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
+                ty::TraitRef::identity(tcx, def_id).with_constness(constness).to_predicate(tcx),
+                span,
+            ))));
+    }
+    debug!("predicates_of(def_id={:?}) = {:?}", def_id, result);
+    result
+}
+
+/// Returns a list of user-specified type predicates for the definition with ID `def_id`.
+/// N.B., this does not include any implied/inferred constraints.
+#[instrument(level = "trace", skip(tcx), ret)]
+fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
+    use rustc_hir::*;
+
+    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+    let node = tcx.hir().get(hir_id);
+
+    let mut is_trait = None;
+    let mut is_default_impl_trait = None;
+
+    let icx = ItemCtxt::new(tcx, def_id);
+
+    const NO_GENERICS: &hir::Generics<'_> = hir::Generics::empty();
+
+    // We use an `IndexSet` to preserves order of insertion.
+    // Preserving the order of insertion is important here so as not to break UI tests.
+    let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default();
+
+    let ast_generics = match node {
+        Node::TraitItem(item) => item.generics,
+
+        Node::ImplItem(item) => item.generics,
+
+        Node::Item(item) => {
+            match item.kind {
+                ItemKind::Impl(ref impl_) => {
+                    if impl_.defaultness.is_default() {
+                        is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy);
+                    }
+                    &impl_.generics
+                }
+                ItemKind::Fn(.., ref generics, _)
+                | ItemKind::TyAlias(_, ref generics)
+                | ItemKind::Enum(_, ref generics)
+                | ItemKind::Struct(_, ref generics)
+                | ItemKind::Union(_, ref generics) => *generics,
+
+                ItemKind::Trait(_, _, ref generics, ..) => {
+                    is_trait = Some(ty::TraitRef::identity(tcx, def_id));
+                    *generics
+                }
+                ItemKind::TraitAlias(ref generics, _) => {
+                    is_trait = Some(ty::TraitRef::identity(tcx, def_id));
+                    *generics
+                }
+                ItemKind::OpaqueTy(OpaqueTy {
+                    origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
+                    ..
+                }) => {
+                    // return-position impl trait
+                    //
+                    // We don't inherit predicates from the parent here:
+                    // If we have, say `fn f<'a, T: 'a>() -> impl Sized {}`
+                    // then the return type is `f::<'static, T>::{{opaque}}`.
+                    //
+                    // If we inherited the predicates of `f` then we would
+                    // require that `T: 'static` to show that the return
+                    // type is well-formed.
+                    //
+                    // The only way to have something with this opaque type
+                    // is from the return type of the containing function,
+                    // which will ensure that the function's predicates
+                    // hold.
+                    return ty::GenericPredicates { parent: None, predicates: &[] };
+                }
+                ItemKind::OpaqueTy(OpaqueTy {
+                    ref generics,
+                    origin: hir::OpaqueTyOrigin::TyAlias,
+                    ..
+                }) => {
+                    // type-alias impl trait
+                    generics
+                }
+
+                _ => NO_GENERICS,
+            }
+        }
+
+        Node::ForeignItem(item) => match item.kind {
+            ForeignItemKind::Static(..) => NO_GENERICS,
+            ForeignItemKind::Fn(_, _, ref generics) => *generics,
+            ForeignItemKind::Type => NO_GENERICS,
+        },
+
+        _ => NO_GENERICS,
+    };
+
+    let generics = tcx.generics_of(def_id);
+    let parent_count = generics.parent_count as u32;
+    let has_own_self = generics.has_self && parent_count == 0;
+
+    // Below we'll consider the bounds on the type parameters (including `Self`)
+    // and the explicit where-clauses, but to get the full set of predicates
+    // on a trait we need to add in the supertrait bounds and bounds found on
+    // associated types.
+    if let Some(_trait_ref) = is_trait {
+        predicates.extend(tcx.super_predicates_of(def_id).predicates.iter().cloned());
+    }
+
+    // In default impls, we can assume that the self type implements
+    // the trait. So in:
+    //
+    //     default impl Foo for Bar { .. }
+    //
+    // we add a default where clause `Foo: Bar`. We do a similar thing for traits
+    // (see below). Recall that a default impl is not itself an impl, but rather a
+    // set of defaults that can be incorporated into another impl.
+    if let Some(trait_ref) = is_default_impl_trait {
+        predicates.insert((trait_ref.without_const().to_predicate(tcx), tcx.def_span(def_id)));
+    }
+
+    // Collect the region predicates that were declared inline as
+    // well. In the case of parameters declared on a fn or method, we
+    // have to be careful to only iterate over early-bound regions.
+    let mut index = parent_count
+        + has_own_self as u32
+        + super::early_bound_lifetimes_from_generics(tcx, ast_generics).count() as u32;
+
+    trace!(?predicates);
+    trace!(?ast_generics);
+
+    // Collect the predicates that were written inline by the user on each
+    // type parameter (e.g., `<T: Foo>`).
+    for param in ast_generics.params {
+        match param.kind {
+            // We already dealt with early bound lifetimes above.
+            GenericParamKind::Lifetime { .. } => (),
+            GenericParamKind::Type { .. } => {
+                let name = param.name.ident().name;
+                let param_ty = ty::ParamTy::new(index, name).to_ty(tcx);
+                index += 1;
+
+                let mut bounds = Bounds::default();
+                // Params are implicitly sized unless a `?Sized` bound is found
+                <dyn AstConv<'_>>::add_implicitly_sized(
+                    &icx,
+                    &mut bounds,
+                    &[],
+                    Some((param.hir_id, ast_generics.predicates)),
+                    param.span,
+                );
+                trace!(?bounds);
+                predicates.extend(bounds.predicates(tcx, param_ty));
+                trace!(?predicates);
+            }
+            GenericParamKind::Const { .. } => {
+                // Bounds on const parameters are currently not possible.
+                index += 1;
+            }
+        }
+    }
+
+    trace!(?predicates);
+    // Add in the bounds that appear in the where-clause.
+    for predicate in ast_generics.predicates {
+        match predicate {
+            hir::WherePredicate::BoundPredicate(bound_pred) => {
+                let ty = icx.to_ty(bound_pred.bounded_ty);
+                let bound_vars = icx.tcx.late_bound_vars(bound_pred.hir_id);
+
+                // Keep the type around in a dummy predicate, in case of no bounds.
+                // That way, `where Ty:` is not a complete noop (see #53696) and `Ty`
+                // is still checked for WF.
+                if bound_pred.bounds.is_empty() {
+                    if let ty::Param(_) = ty.kind() {
+                        // This is a `where T:`, which can be in the HIR from the
+                        // transformation that moves `?Sized` to `T`'s declaration.
+                        // We can skip the predicate because type parameters are
+                        // trivially WF, but also we *should*, to avoid exposing
+                        // users who never wrote `where Type:,` themselves, to
+                        // compiler/tooling bugs from not handling WF predicates.
+                    } else {
+                        let span = bound_pred.bounded_ty.span;
+                        let predicate = ty::Binder::bind_with_vars(
+                            ty::PredicateKind::WellFormed(ty.into()),
+                            bound_vars,
+                        );
+                        predicates.insert((predicate.to_predicate(tcx), span));
+                    }
+                }
+
+                let mut bounds = Bounds::default();
+                <dyn AstConv<'_>>::add_bounds(
+                    &icx,
+                    ty,
+                    bound_pred.bounds.iter(),
+                    &mut bounds,
+                    bound_vars,
+                );
+                predicates.extend(bounds.predicates(tcx, ty));
+            }
+
+            hir::WherePredicate::RegionPredicate(region_pred) => {
+                let r1 = <dyn AstConv<'_>>::ast_region_to_region(&icx, &region_pred.lifetime, None);
+                predicates.extend(region_pred.bounds.iter().map(|bound| {
+                    let (r2, span) = match bound {
+                        hir::GenericBound::Outlives(lt) => {
+                            (<dyn AstConv<'_>>::ast_region_to_region(&icx, lt, None), lt.span)
+                        }
+                        _ => bug!(),
+                    };
+                    let pred = ty::Binder::dummy(ty::PredicateKind::RegionOutlives(
+                        ty::OutlivesPredicate(r1, r2),
+                    ))
+                    .to_predicate(icx.tcx);
+
+                    (pred, span)
+                }))
+            }
+
+            hir::WherePredicate::EqPredicate(..) => {
+                // FIXME(#20041)
+            }
+        }
+    }
+
+    if tcx.features().generic_const_exprs {
+        predicates.extend(const_evaluatable_predicates_of(tcx, def_id.expect_local()));
+    }
+
+    let mut predicates: Vec<_> = predicates.into_iter().collect();
+
+    // Subtle: before we store the predicates into the tcx, we
+    // sort them so that predicates like `T: Foo<Item=U>` come
+    // before uses of `U`.  This avoids false ambiguity errors
+    // in trait checking. See `setup_constraining_predicates`
+    // for details.
+    if let Node::Item(&Item { kind: ItemKind::Impl { .. }, .. }) = node {
+        let self_ty = tcx.type_of(def_id);
+        let trait_ref = tcx.impl_trait_ref(def_id);
+        cgp::setup_constraining_predicates(
+            tcx,
+            &mut predicates,
+            trait_ref,
+            &mut cgp::parameters_for_impl(self_ty, trait_ref),
+        );
+    }
+
+    ty::GenericPredicates {
+        parent: generics.parent,
+        predicates: tcx.arena.alloc_from_iter(predicates),
+    }
+}
+
+fn const_evaluatable_predicates_of<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+) -> FxIndexSet<(ty::Predicate<'tcx>, Span)> {
+    struct ConstCollector<'tcx> {
+        tcx: TyCtxt<'tcx>,
+        preds: FxIndexSet<(ty::Predicate<'tcx>, Span)>,
+    }
+
+    impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'tcx> {
+        fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
+            let def_id = self.tcx.hir().local_def_id(c.hir_id);
+            let ct = ty::Const::from_anon_const(self.tcx, def_id);
+            if let ty::ConstKind::Unevaluated(uv) = ct.kind() {
+                let span = self.tcx.hir().span(c.hir_id);
+                self.preds.insert((
+                    ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv))
+                        .to_predicate(self.tcx),
+                    span,
+                ));
+            }
+        }
+
+        fn visit_const_param_default(&mut self, _param: HirId, _ct: &'tcx hir::AnonConst) {
+            // Do not look into const param defaults,
+            // these get checked when they are actually instantiated.
+            //
+            // We do not want the following to error:
+            //
+            //     struct Foo<const N: usize, const M: usize = { N + 1 }>;
+            //     struct Bar<const N: usize>(Foo<N, 3>);
+        }
+    }
+
+    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+    let node = tcx.hir().get(hir_id);
+
+    let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() };
+    if let hir::Node::Item(item) = node && let hir::ItemKind::Impl(ref impl_) = item.kind {
+        if let Some(of_trait) = &impl_.of_trait {
+            debug!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id);
+            collector.visit_trait_ref(of_trait);
+        }
+
+        debug!("const_evaluatable_predicates_of({:?}): visit_self_ty", def_id);
+        collector.visit_ty(impl_.self_ty);
+    }
+
+    if let Some(generics) = node.generics() {
+        debug!("const_evaluatable_predicates_of({:?}): visit_generics", def_id);
+        collector.visit_generics(generics);
+    }
+
+    if let Some(fn_sig) = tcx.hir().fn_sig_by_hir_id(hir_id) {
+        debug!("const_evaluatable_predicates_of({:?}): visit_fn_decl", def_id);
+        collector.visit_fn_decl(fn_sig.decl);
+    }
+    debug!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.preds);
+
+    collector.preds
+}
+
+pub(super) fn trait_explicit_predicates_and_bounds(
+    tcx: TyCtxt<'_>,
+    def_id: LocalDefId,
+) -> ty::GenericPredicates<'_> {
+    assert_eq!(tcx.def_kind(def_id), DefKind::Trait);
+    gather_explicit_predicates_of(tcx, def_id.to_def_id())
+}
+
+pub(super) fn explicit_predicates_of<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: DefId,
+) -> ty::GenericPredicates<'tcx> {
+    let def_kind = tcx.def_kind(def_id);
+    if let DefKind::Trait = def_kind {
+        // Remove bounds on associated types from the predicates, they will be
+        // returned by `explicit_item_bounds`.
+        let predicates_and_bounds = tcx.trait_explicit_predicates_and_bounds(def_id.expect_local());
+        let trait_identity_substs = InternalSubsts::identity_for_item(tcx, def_id);
+
+        let is_assoc_item_ty = |ty: Ty<'tcx>| {
+            // For a predicate from a where clause to become a bound on an
+            // associated type:
+            // * It must use the identity substs of the item.
+            //     * Since any generic parameters on the item are not in scope,
+            //       this means that the item is not a GAT, and its identity
+            //       substs are the same as the trait's.
+            // * It must be an associated type for this trait (*not* a
+            //   supertrait).
+            if let ty::Projection(projection) = ty.kind() {
+                projection.substs == trait_identity_substs
+                    && tcx.associated_item(projection.item_def_id).container_id(tcx) == def_id
+            } else {
+                false
+            }
+        };
+
+        let predicates: Vec<_> = predicates_and_bounds
+            .predicates
+            .iter()
+            .copied()
+            .filter(|(pred, _)| match pred.kind().skip_binder() {
+                ty::PredicateKind::Trait(tr) => !is_assoc_item_ty(tr.self_ty()),
+                ty::PredicateKind::Projection(proj) => {
+                    !is_assoc_item_ty(proj.projection_ty.self_ty())
+                }
+                ty::PredicateKind::TypeOutlives(outlives) => !is_assoc_item_ty(outlives.0),
+                _ => true,
+            })
+            .collect();
+        if predicates.len() == predicates_and_bounds.predicates.len() {
+            predicates_and_bounds
+        } else {
+            ty::GenericPredicates {
+                parent: predicates_and_bounds.parent,
+                predicates: tcx.arena.alloc_slice(&predicates),
+            }
+        }
+    } else {
+        if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() {
+            let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+            if tcx.hir().opt_const_param_default_param_hir_id(hir_id).is_some() {
+                // In `generics_of` we set the generics' parent to be our parent's parent which means that
+                // we lose out on the predicates of our actual parent if we dont return those predicates here.
+                // (See comment in `generics_of` for more information on why the parent shenanigans is necessary)
+                //
+                // struct Foo<T, const N: usize = { <T as Trait>::ASSOC }>(T) where T: Trait;
+                //        ^^^                     ^^^^^^^^^^^^^^^^^^^^^^^ the def id we are calling
+                //        ^^^                                             explicit_predicates_of on
+                //        parent item we dont have set as the
+                //        parent of generics returned by `generics_of`
+                //
+                // In the above code we want the anon const to have predicates in its param env for `T: Trait`
+                let item_def_id = tcx.hir().get_parent_item(hir_id);
+                // In the above code example we would be calling `explicit_predicates_of(Foo)` here
+                return tcx.explicit_predicates_of(item_def_id);
+            }
+        }
+        gather_explicit_predicates_of(tcx, def_id)
+    }
+}
+
+/// Ensures that the super-predicates of the trait with a `DefId`
+/// of `trait_def_id` are converted and stored. This also ensures that
+/// the transitive super-predicates are converted.
+pub(super) fn super_predicates_of(
+    tcx: TyCtxt<'_>,
+    trait_def_id: DefId,
+) -> ty::GenericPredicates<'_> {
+    tcx.super_predicates_that_define_assoc_type((trait_def_id, None))
+}
+
+/// Ensures that the super-predicates of the trait with a `DefId`
+/// of `trait_def_id` are converted and stored. This also ensures that
+/// the transitive super-predicates are converted.
+pub(super) fn super_predicates_that_define_assoc_type(
+    tcx: TyCtxt<'_>,
+    (trait_def_id, assoc_name): (DefId, Option<Ident>),
+) -> ty::GenericPredicates<'_> {
+    if trait_def_id.is_local() {
+        debug!("local trait");
+        let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id.expect_local());
+
+        let Node::Item(item) = tcx.hir().get(trait_hir_id) else {
+            bug!("trait_node_id {} is not an item", trait_hir_id);
+        };
+
+        let (generics, bounds) = match item.kind {
+            hir::ItemKind::Trait(.., ref generics, ref supertraits, _) => (generics, supertraits),
+            hir::ItemKind::TraitAlias(ref generics, ref supertraits) => (generics, supertraits),
+            _ => span_bug!(item.span, "super_predicates invoked on non-trait"),
+        };
+
+        let icx = ItemCtxt::new(tcx, trait_def_id);
+
+        // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`.
+        let self_param_ty = tcx.types.self_param;
+        let superbounds1 = if let Some(assoc_name) = assoc_name {
+            <dyn AstConv<'_>>::compute_bounds_that_match_assoc_type(
+                &icx,
+                self_param_ty,
+                bounds,
+                assoc_name,
+            )
+        } else {
+            <dyn AstConv<'_>>::compute_bounds(&icx, self_param_ty, bounds)
+        };
+
+        let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
+
+        // Convert any explicit superbounds in the where-clause,
+        // e.g., `trait Foo where Self: Bar`.
+        // In the case of trait aliases, however, we include all bounds in the where-clause,
+        // so e.g., `trait Foo = where u32: PartialEq<Self>` would include `u32: PartialEq<Self>`
+        // as one of its "superpredicates".
+        let is_trait_alias = tcx.is_trait_alias(trait_def_id);
+        let superbounds2 = icx.type_parameter_bounds_in_generics(
+            generics,
+            item.hir_id(),
+            self_param_ty,
+            OnlySelfBounds(!is_trait_alias),
+            assoc_name,
+        );
+
+        // Combine the two lists to form the complete set of superbounds:
+        let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2));
+        debug!(?superbounds);
+
+        // Now require that immediate supertraits are converted,
+        // which will, in turn, reach indirect supertraits.
+        if assoc_name.is_none() {
+            // Now require that immediate supertraits are converted,
+            // which will, in turn, reach indirect supertraits.
+            for &(pred, span) in superbounds {
+                debug!("superbound: {:?}", pred);
+                if let ty::PredicateKind::Trait(bound) = pred.kind().skip_binder() {
+                    tcx.at(span).super_predicates_of(bound.def_id());
+                }
+            }
+        }
+
+        ty::GenericPredicates { parent: None, predicates: superbounds }
+    } else {
+        // if `assoc_name` is None, then the query should've been redirected to an
+        // external provider
+        assert!(assoc_name.is_some());
+        tcx.super_predicates_of(trait_def_id)
+    }
+}
+
+/// Returns the predicates defined on `item_def_id` of the form
+/// `X: Foo` where `X` is the type parameter `def_id`.
+#[instrument(level = "trace", skip(tcx))]
+pub(super) fn type_param_predicates(
+    tcx: TyCtxt<'_>,
+    (item_def_id, def_id, assoc_name): (DefId, LocalDefId, Ident),
+) -> ty::GenericPredicates<'_> {
+    use rustc_hir::*;
+
+    // In the AST, bounds can derive from two places. Either
+    // written inline like `<T: Foo>` or in a where-clause like
+    // `where T: Foo`.
+
+    let param_id = tcx.hir().local_def_id_to_hir_id(def_id);
+    let param_owner = tcx.hir().ty_param_owner(def_id);
+    let generics = tcx.generics_of(param_owner);
+    let index = generics.param_def_id_to_index[&def_id.to_def_id()];
+    let ty = tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id));
+
+    // Don't look for bounds where the type parameter isn't in scope.
+    let parent = if item_def_id == param_owner.to_def_id() {
+        None
+    } else {
+        tcx.generics_of(item_def_id).parent
+    };
+
+    let mut result = parent
+        .map(|parent| {
+            let icx = ItemCtxt::new(tcx, parent);
+            icx.get_type_parameter_bounds(DUMMY_SP, def_id.to_def_id(), assoc_name)
+        })
+        .unwrap_or_default();
+    let mut extend = None;
+
+    let item_hir_id = tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local());
+    let ast_generics = match tcx.hir().get(item_hir_id) {
+        Node::TraitItem(item) => &item.generics,
+
+        Node::ImplItem(item) => &item.generics,
+
+        Node::Item(item) => {
+            match item.kind {
+                ItemKind::Fn(.., ref generics, _)
+                | ItemKind::Impl(hir::Impl { ref generics, .. })
+                | ItemKind::TyAlias(_, ref generics)
+                | ItemKind::OpaqueTy(OpaqueTy {
+                    ref generics,
+                    origin: hir::OpaqueTyOrigin::TyAlias,
+                    ..
+                })
+                | ItemKind::Enum(_, ref generics)
+                | ItemKind::Struct(_, ref generics)
+                | ItemKind::Union(_, ref generics) => generics,
+                ItemKind::Trait(_, _, ref generics, ..) => {
+                    // Implied `Self: Trait` and supertrait bounds.
+                    if param_id == item_hir_id {
+                        let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id);
+                        extend =
+                            Some((identity_trait_ref.without_const().to_predicate(tcx), item.span));
+                    }
+                    generics
+                }
+                _ => return result,
+            }
+        }
+
+        Node::ForeignItem(item) => match item.kind {
+            ForeignItemKind::Fn(_, _, ref generics) => generics,
+            _ => return result,
+        },
+
+        _ => return result,
+    };
+
+    let icx = ItemCtxt::new(tcx, item_def_id);
+    let extra_predicates = extend.into_iter().chain(
+        icx.type_parameter_bounds_in_generics(
+            ast_generics,
+            param_id,
+            ty,
+            OnlySelfBounds(true),
+            Some(assoc_name),
+        )
+        .into_iter()
+        .filter(|(predicate, _)| match predicate.kind().skip_binder() {
+            ty::PredicateKind::Trait(data) => data.self_ty().is_param(index),
+            _ => false,
+        }),
+    );
+    result.predicates =
+        tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(extra_predicates));
+    result
+}
+
+impl<'tcx> ItemCtxt<'tcx> {
+    /// Finds bounds from `hir::Generics`. This requires scanning through the
+    /// AST. We do this to avoid having to convert *all* the bounds, which
+    /// would create artificial cycles. Instead, we can only convert the
+    /// bounds for a type parameter `X` if `X::Foo` is used.
+    #[instrument(level = "trace", skip(self, ast_generics))]
+    fn type_parameter_bounds_in_generics(
+        &self,
+        ast_generics: &'tcx hir::Generics<'tcx>,
+        param_id: hir::HirId,
+        ty: Ty<'tcx>,
+        only_self_bounds: OnlySelfBounds,
+        assoc_name: Option<Ident>,
+    ) -> Vec<(ty::Predicate<'tcx>, Span)> {
+        let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id();
+        trace!(?param_def_id);
+        ast_generics
+            .predicates
+            .iter()
+            .filter_map(|wp| match *wp {
+                hir::WherePredicate::BoundPredicate(ref bp) => Some(bp),
+                _ => None,
+            })
+            .flat_map(|bp| {
+                let bt = if bp.is_param_bound(param_def_id) {
+                    Some(ty)
+                } else if !only_self_bounds.0 {
+                    Some(self.to_ty(bp.bounded_ty))
+                } else {
+                    None
+                };
+                let bvars = self.tcx.late_bound_vars(bp.hir_id);
+
+                bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b, bvars))).filter(
+                    |(_, b, _)| match assoc_name {
+                        Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
+                        None => true,
+                    },
+                )
+            })
+            .flat_map(|(bt, b, bvars)| predicates_from_bound(self, bt, b, bvars))
+            .collect()
+    }
+
+    #[instrument(level = "trace", skip(self))]
+    fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool {
+        match b {
+            hir::GenericBound::Trait(poly_trait_ref, _) => {
+                let trait_ref = &poly_trait_ref.trait_ref;
+                if let Some(trait_did) = trait_ref.trait_def_id() {
+                    self.tcx.trait_may_define_assoc_type(trait_did, assoc_name)
+                } else {
+                    false
+                }
+            }
+            _ => false,
+        }
+    }
+}
+
+/// Converts a specific `GenericBound` from the AST into a set of
+/// predicates that apply to the self type. A vector is returned
+/// because this can be anywhere from zero predicates (`T: ?Sized` adds no
+/// predicates) to one (`T: Foo`) to many (`T: Bar<X = i32>` adds `T: Bar`
+/// and `<T as Bar>::X == i32`).
+fn predicates_from_bound<'tcx>(
+    astconv: &dyn AstConv<'tcx>,
+    param_ty: Ty<'tcx>,
+    bound: &'tcx hir::GenericBound<'tcx>,
+    bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
+) -> Vec<(ty::Predicate<'tcx>, Span)> {
+    let mut bounds = Bounds::default();
+    astconv.add_bounds(param_ty, [bound].into_iter(), &mut bounds, bound_vars);
+    bounds.predicates(astconv.tcx(), param_ty).collect()
+}
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 24fb0b1fd26..f8a62c84910 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -333,7 +333,12 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                     find_opaque_ty_constraints_for_tait(tcx, def_id)
                 }
                 // Opaque types desugared from `impl Trait`.
-                ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner), in_trait, .. }) => {
+                ItemKind::OpaqueTy(OpaqueTy {
+                    origin:
+                        hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner),
+                    in_trait,
+                    ..
+                }) => {
                     if in_trait {
                         span_bug!(item.span, "impl-trait in trait has no default")
                     } else {
@@ -378,7 +383,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
 
         Node::Field(field) => icx.to_ty(field.ty),
 
-        Node::Expr(&Expr { kind: ExprKind::Closure{..}, .. }) => tcx.typeck(def_id).node_type(hir_id),
+        Node::Expr(&Expr { kind: ExprKind::Closure { .. }, .. }) => {
+            tcx.typeck(def_id).node_type(hir_id)
+        }
 
         Node::AnonConst(_) if let Some(param) = tcx.opt_const_param_of(def_id) => {
             // We defer to `type_of` of the corresponding parameter
@@ -410,40 +417,91 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                 | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
                     if asm.operands.iter().any(|(op, _op_sp)| match op {
                         hir::InlineAsmOperand::Const { anon_const }
-                        | hir::InlineAsmOperand::SymFn { anon_const } => anon_const.hir_id == hir_id,
+                        | hir::InlineAsmOperand::SymFn { anon_const } => {
+                            anon_const.hir_id == hir_id
+                        }
                         _ => false,
                     }) =>
                 {
                     tcx.typeck(def_id).node_type(hir_id)
                 }
 
-                Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => tcx
-                    .adt_def(tcx.hir().get_parent_item(hir_id))
-                    .repr()
-                    .discr_type()
-                    .to_ty(tcx),
+                Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => {
+                    tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx)
+                }
 
-                Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, ..  })
-                    if let Node::TraitRef(trait_ref) = tcx.hir().get(
-                        tcx.hir().get_parent_node(binding_id)
-                    ) =>
+                Node::TypeBinding(
+                    binding @ &TypeBinding {
+                        hir_id: binding_id,
+                        kind: TypeBindingKind::Equality { term: Term::Const(ref e) },
+                        ..
+                    },
+                ) if let Node::TraitRef(trait_ref) =
+                    tcx.hir().get(tcx.hir().get_parent_node(binding_id))
+                    && e.hir_id == hir_id =>
                 {
-                  let Some(trait_def_id) = trait_ref.trait_def_id() else {
-                    return tcx.ty_error_with_message(DUMMY_SP, "Could not find trait");
-                  };
-                  let assoc_items = tcx.associated_items(trait_def_id);
-                  let assoc_item = assoc_items.find_by_name_and_kind(
-                    tcx, binding.ident, ty::AssocKind::Const, def_id.to_def_id(),
-                  );
-                  if let Some(assoc_item) = assoc_item {
-                    tcx.type_of(assoc_item.def_id)
-                  } else {
-                      // FIXME(associated_const_equality): add a useful error message here.
-                      tcx.ty_error_with_message(
-                        DUMMY_SP,
-                        "Could not find associated const on trait",
-                    )
-                  }
+                    let Some(trait_def_id) = trait_ref.trait_def_id() else {
+                        return tcx.ty_error_with_message(DUMMY_SP, "Could not find trait");
+                    };
+                    let assoc_items = tcx.associated_items(trait_def_id);
+                    let assoc_item = assoc_items.find_by_name_and_kind(
+                        tcx,
+                        binding.ident,
+                        ty::AssocKind::Const,
+                        def_id.to_def_id(),
+                    );
+                    if let Some(assoc_item) = assoc_item {
+                        tcx.type_of(assoc_item.def_id)
+                    } else {
+                        // FIXME(associated_const_equality): add a useful error message here.
+                        tcx.ty_error_with_message(
+                            DUMMY_SP,
+                            "Could not find associated const on trait",
+                        )
+                    }
+                }
+
+                Node::TypeBinding(
+                    binding @ &TypeBinding { hir_id: binding_id, gen_args, ref kind, .. },
+                ) if let Node::TraitRef(trait_ref) =
+                    tcx.hir().get(tcx.hir().get_parent_node(binding_id))
+                    && let Some((idx, _)) =
+                        gen_args.args.iter().enumerate().find(|(_, arg)| {
+                            if let GenericArg::Const(ct) = arg {
+                                ct.value.hir_id == hir_id
+                            } else {
+                                false
+                            }
+                        }) =>
+                {
+                    let Some(trait_def_id) = trait_ref.trait_def_id() else {
+                        return tcx.ty_error_with_message(DUMMY_SP, "Could not find trait");
+                    };
+                    let assoc_items = tcx.associated_items(trait_def_id);
+                    let assoc_item = assoc_items.find_by_name_and_kind(
+                        tcx,
+                        binding.ident,
+                        match kind {
+                            // I think `<A: T>` type bindings requires that `A` is a type
+                            TypeBindingKind::Constraint { .. }
+                            | TypeBindingKind::Equality { term: Term::Ty(..) } => {
+                                ty::AssocKind::Type
+                            }
+                            TypeBindingKind::Equality { term: Term::Const(..) } => {
+                                ty::AssocKind::Const
+                            }
+                        },
+                        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)
+                    } else {
+                        // FIXME(associated_const_equality): add a useful error message here.
+                        tcx.ty_error_with_message(
+                            DUMMY_SP,
+                            "Could not find associated const on trait",
+                        )
+                    }
                 }
 
                 Node::GenericParam(&GenericParam {
@@ -452,8 +510,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                     ..
                 }) if ct.hir_id == hir_id => tcx.type_of(tcx.hir().local_def_id(param_hir_id)),
 
-                x =>
-                  tcx.ty_error_with_message(
+                x => tcx.ty_error_with_message(
                     DUMMY_SP,
                     &format!("unexpected const parent in type_of(): {x:?}"),
                 ),
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 44df47e2fa0..d891171b824 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1,4 +1,5 @@
-//! Errors emitted by typeck.
+//! Errors emitted by `hir_analysis`.
+
 use rustc_errors::IntoDiagnostic;
 use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler};
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
@@ -6,18 +7,18 @@ use rustc_middle::ty::Ty;
 use rustc_span::{symbol::Ident, Span, Symbol};
 
 #[derive(Diagnostic)]
-#[diag(typeck::field_multiply_specified_in_initializer, code = "E0062")]
+#[diag(hir_analysis::field_multiply_specified_in_initializer, code = "E0062")]
 pub struct FieldMultiplySpecifiedInInitializer {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(typeck::previous_use_label)]
+    #[label(hir_analysis::previous_use_label)]
     pub prev_span: Span,
     pub ident: Ident,
 }
 
 #[derive(Diagnostic)]
-#[diag(typeck::unrecognized_atomic_operation, code = "E0092")]
+#[diag(hir_analysis::unrecognized_atomic_operation, code = "E0092")]
 pub struct UnrecognizedAtomicOperation<'a> {
     #[primary_span]
     #[label]
@@ -26,7 +27,7 @@ pub struct UnrecognizedAtomicOperation<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(typeck::wrong_number_of_generic_arguments_to_intrinsic, code = "E0094")]
+#[diag(hir_analysis::wrong_number_of_generic_arguments_to_intrinsic, code = "E0094")]
 pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> {
     #[primary_span]
     #[label]
@@ -37,7 +38,7 @@ pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(typeck::unrecognized_intrinsic_function, code = "E0093")]
+#[diag(hir_analysis::unrecognized_intrinsic_function, code = "E0093")]
 pub struct UnrecognizedIntrinsicFunction {
     #[primary_span]
     #[label]
@@ -46,19 +47,19 @@ pub struct UnrecognizedIntrinsicFunction {
 }
 
 #[derive(Diagnostic)]
-#[diag(typeck::lifetimes_or_bounds_mismatch_on_trait, code = "E0195")]
+#[diag(hir_analysis::lifetimes_or_bounds_mismatch_on_trait, code = "E0195")]
 pub struct LifetimesOrBoundsMismatchOnTrait {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(typeck::generics_label)]
+    #[label(hir_analysis::generics_label)]
     pub generics_span: Option<Span>,
     pub item_kind: &'static str,
     pub ident: Ident,
 }
 
 #[derive(Diagnostic)]
-#[diag(typeck::drop_impl_on_wrong_item, code = "E0120")]
+#[diag(hir_analysis::drop_impl_on_wrong_item, code = "E0120")]
 pub struct DropImplOnWrongItem {
     #[primary_span]
     #[label]
@@ -66,18 +67,18 @@ pub struct DropImplOnWrongItem {
 }
 
 #[derive(Diagnostic)]
-#[diag(typeck::field_already_declared, code = "E0124")]
+#[diag(hir_analysis::field_already_declared, code = "E0124")]
 pub struct FieldAlreadyDeclared {
     pub field_name: Ident,
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(typeck::previous_decl_label)]
+    #[label(hir_analysis::previous_decl_label)]
     pub prev_span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(typeck::copy_impl_on_type_with_dtor, code = "E0184")]
+#[diag(hir_analysis::copy_impl_on_type_with_dtor, code = "E0184")]
 pub struct CopyImplOnTypeWithDtor {
     #[primary_span]
     #[label]
@@ -85,14 +86,14 @@ pub struct CopyImplOnTypeWithDtor {
 }
 
 #[derive(Diagnostic)]
-#[diag(typeck::multiple_relaxed_default_bounds, code = "E0203")]
+#[diag(hir_analysis::multiple_relaxed_default_bounds, code = "E0203")]
 pub struct MultipleRelaxedDefaultBounds {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(typeck::copy_impl_on_non_adt, code = "E0206")]
+#[diag(hir_analysis::copy_impl_on_non_adt, code = "E0206")]
 pub struct CopyImplOnNonAdt {
     #[primary_span]
     #[label]
@@ -100,23 +101,23 @@ pub struct CopyImplOnNonAdt {
 }
 
 #[derive(Diagnostic)]
-#[diag(typeck::trait_object_declared_with_no_traits, code = "E0224")]
+#[diag(hir_analysis::trait_object_declared_with_no_traits, code = "E0224")]
 pub struct TraitObjectDeclaredWithNoTraits {
     #[primary_span]
     pub span: Span,
-    #[label(typeck::alias_span)]
+    #[label(hir_analysis::alias_span)]
     pub trait_alias_span: Option<Span>,
 }
 
 #[derive(Diagnostic)]
-#[diag(typeck::ambiguous_lifetime_bound, code = "E0227")]
+#[diag(hir_analysis::ambiguous_lifetime_bound, code = "E0227")]
 pub struct AmbiguousLifetimeBound {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(typeck::assoc_type_binding_not_allowed, code = "E0229")]
+#[diag(hir_analysis::assoc_type_binding_not_allowed, code = "E0229")]
 pub struct AssocTypeBindingNotAllowed {
     #[primary_span]
     #[label]
@@ -124,14 +125,14 @@ pub struct AssocTypeBindingNotAllowed {
 }
 
 #[derive(Diagnostic)]
-#[diag(typeck::functional_record_update_on_non_struct, code = "E0436")]
+#[diag(hir_analysis::functional_record_update_on_non_struct, code = "E0436")]
 pub struct FunctionalRecordUpdateOnNonStruct {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(typeck::typeof_reserved_keyword_used, code = "E0516")]
+#[diag(hir_analysis::typeof_reserved_keyword_used, code = "E0516")]
 pub struct TypeofReservedKeywordUsed<'tcx> {
     pub ty: Ty<'tcx>,
     #[primary_span]
@@ -142,25 +143,25 @@ pub struct TypeofReservedKeywordUsed<'tcx> {
 }
 
 #[derive(Diagnostic)]
-#[diag(typeck::return_stmt_outside_of_fn_body, code = "E0572")]
+#[diag(hir_analysis::return_stmt_outside_of_fn_body, code = "E0572")]
 pub struct ReturnStmtOutsideOfFnBody {
     #[primary_span]
     pub span: Span,
-    #[label(typeck::encl_body_label)]
+    #[label(hir_analysis::encl_body_label)]
     pub encl_body_span: Option<Span>,
-    #[label(typeck::encl_fn_label)]
+    #[label(hir_analysis::encl_fn_label)]
     pub encl_fn_span: Option<Span>,
 }
 
 #[derive(Diagnostic)]
-#[diag(typeck::yield_expr_outside_of_generator, code = "E0627")]
+#[diag(hir_analysis::yield_expr_outside_of_generator, code = "E0627")]
 pub struct YieldExprOutsideOfGenerator {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(typeck::struct_expr_non_exhaustive, code = "E0639")]
+#[diag(hir_analysis::struct_expr_non_exhaustive, code = "E0639")]
 pub struct StructExprNonExhaustive {
     #[primary_span]
     pub span: Span,
@@ -168,26 +169,26 @@ pub struct StructExprNonExhaustive {
 }
 
 #[derive(Diagnostic)]
-#[diag(typeck::method_call_on_unknown_type, code = "E0699")]
+#[diag(hir_analysis::method_call_on_unknown_type, code = "E0699")]
 pub struct MethodCallOnUnknownType {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(typeck::value_of_associated_struct_already_specified, code = "E0719")]
+#[diag(hir_analysis::value_of_associated_struct_already_specified, code = "E0719")]
 pub struct ValueOfAssociatedStructAlreadySpecified {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(typeck::previous_bound_label)]
+    #[label(hir_analysis::previous_bound_label)]
     pub prev_span: Span,
     pub item_name: Ident,
     pub def_path: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(typeck::address_of_temporary_taken, code = "E0745")]
+#[diag(hir_analysis::address_of_temporary_taken, code = "E0745")]
 pub struct AddressOfTemporaryTaken {
     #[primary_span]
     #[label]
@@ -197,7 +198,7 @@ pub struct AddressOfTemporaryTaken {
 #[derive(Subdiagnostic)]
 pub enum AddReturnTypeSuggestion {
     #[suggestion(
-        typeck::add_return_type_add,
+        hir_analysis::add_return_type_add,
         code = "-> {found} ",
         applicability = "machine-applicable"
     )]
@@ -207,7 +208,7 @@ pub enum AddReturnTypeSuggestion {
         found: String,
     },
     #[suggestion(
-        typeck::add_return_type_missing_here,
+        hir_analysis::add_return_type_missing_here,
         code = "-> _ ",
         applicability = "has-placeholders"
     )]
@@ -219,12 +220,12 @@ pub enum AddReturnTypeSuggestion {
 
 #[derive(Subdiagnostic)]
 pub enum ExpectedReturnTypeLabel<'tcx> {
-    #[label(typeck::expected_default_return_type)]
+    #[label(hir_analysis::expected_default_return_type)]
     Unit {
         #[primary_span]
         span: Span,
     },
-    #[label(typeck::expected_return_type)]
+    #[label(hir_analysis::expected_return_type)]
     Other {
         #[primary_span]
         span: Span,
@@ -233,7 +234,7 @@ pub enum ExpectedReturnTypeLabel<'tcx> {
 }
 
 #[derive(Diagnostic)]
-#[diag(typeck::unconstrained_opaque_type)]
+#[diag(hir_analysis::unconstrained_opaque_type)]
 #[note]
 pub struct UnconstrainedOpaqueType {
     #[primary_span]
@@ -254,7 +255,7 @@ impl<'a> IntoDiagnostic<'a> for MissingTypeParams {
     fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
         let mut err = handler.struct_span_err_with_code(
             self.span,
-            rustc_errors::fluent::typeck::missing_type_params,
+            rustc_errors::fluent::hir_analysis::missing_type_params,
             error_code!(E0393),
         );
         err.set_arg("parameterCount", self.missing_type_params.len());
@@ -267,7 +268,7 @@ impl<'a> IntoDiagnostic<'a> for MissingTypeParams {
                 .join(", "),
         );
 
-        err.span_label(self.def_span, rustc_errors::fluent::typeck::label);
+        err.span_label(self.def_span, rustc_errors::fluent::hir_analysis::label);
 
         let mut suggested = false;
         // Don't suggest setting the type params if there are some already: the order is
@@ -282,7 +283,7 @@ impl<'a> IntoDiagnostic<'a> for MissingTypeParams {
                 // least we can clue them to the correct syntax `Iterator<Type>`.
                 err.span_suggestion(
                     self.span,
-                    rustc_errors::fluent::typeck::suggestion,
+                    rustc_errors::fluent::hir_analysis::suggestion,
                     format!(
                         "{}<{}>",
                         snippet,
@@ -298,16 +299,16 @@ impl<'a> IntoDiagnostic<'a> for MissingTypeParams {
             }
         }
         if !suggested {
-            err.span_label(self.span, rustc_errors::fluent::typeck::no_suggestion_label);
+            err.span_label(self.span, rustc_errors::fluent::hir_analysis::no_suggestion_label);
         }
 
-        err.note(rustc_errors::fluent::typeck::note);
+        err.note(rustc_errors::fluent::hir_analysis::note);
         err
     }
 }
 
 #[derive(Diagnostic)]
-#[diag(typeck::manual_implementation, code = "E0183")]
+#[diag(hir_analysis::manual_implementation, code = "E0183")]
 #[help]
 pub struct ManualImplementation {
     #[primary_span]
@@ -317,21 +318,21 @@ pub struct ManualImplementation {
 }
 
 #[derive(Diagnostic)]
-#[diag(typeck::substs_on_overridden_impl)]
+#[diag(hir_analysis::substs_on_overridden_impl)]
 pub struct SubstsOnOverriddenImpl {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(typeck::unused_extern_crate)]
+#[diag(hir_analysis::unused_extern_crate)]
 pub struct UnusedExternCrate {
     #[suggestion(applicability = "machine-applicable", code = "")]
     pub span: Span,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(typeck::extern_crate_not_idiomatic)]
+#[diag(hir_analysis::extern_crate_not_idiomatic)]
 pub struct ExternCrateNotIdiomatic {
     #[suggestion_short(applicability = "machine-applicable", code = "{suggestion_code}")]
     pub span: Span,
@@ -340,7 +341,7 @@ pub struct ExternCrateNotIdiomatic {
 }
 
 #[derive(Diagnostic)]
-#[diag(typeck::expected_used_symbol)]
+#[diag(hir_analysis::expected_used_symbol)]
 pub struct ExpectedUsedSymbol {
     #[primary_span]
     pub span: Span,
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 1859473166a..d31b9b7ae46 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -70,7 +70,7 @@ This API is completely unstable and subject to change.
 #![feature(once_cell)]
 #![feature(slice_partition_dedup)]
 #![feature(try_blocks)]
-#![feature(is_some_with)]
+#![feature(is_some_and)]
 #![feature(type_alias_impl_trait)]
 #![recursion_limit = "256"]
 
diff --git a/compiler/rustc_hir_analysis/src/mem_categorization.rs b/compiler/rustc_hir_analysis/src/mem_categorization.rs
index 39610e3ae38..46b49647836 100644
--- a/compiler/rustc_hir_analysis/src/mem_categorization.rs
+++ b/compiler/rustc_hir_analysis/src/mem_categorization.rs
@@ -560,7 +560,8 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
             Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _)
             | Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
             | Res::SelfCtor(..)
-            | Res::SelfTy { .. } => {
+            | Res::SelfTyParam { .. }
+            | Res::SelfTyAlias { .. } => {
                 // Structs and Unions have only have one variant.
                 Ok(VariantIdx::new(0))
             }