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/check/check.rs56
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/check/entry.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs18
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs83
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs335
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs132
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs17
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs15
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs155
-rw-r--r--compiler/rustc_hir_analysis/src/hir_wf_check.rs14
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs2
16 files changed, 321 insertions, 552 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 32fec0604c0..f08a2451496 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -1,8 +1,9 @@
 use std::cell::LazyCell;
 use std::ops::ControlFlow;
 
-use rustc_abi::FieldIdx;
+use rustc_abi::{ExternAbi, FieldIdx};
 use rustc_attr_data_structures::ReprAttr::ReprPacked;
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_errors::codes::*;
 use rustc_errors::{EmissionGuarantee, MultiSpan};
@@ -12,7 +13,6 @@ use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
 use rustc_infer::traits::{Obligation, ObligationCauseCode};
 use rustc_lint_defs::builtin::{
     REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, UNSUPPORTED_CALLING_CONVENTIONS,
-    UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS,
 };
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
@@ -52,49 +52,22 @@ fn add_abi_diag_help<T: EmissionGuarantee>(abi: ExternAbi, diag: &mut Diag<'_, T
 }
 
 pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi) {
-    // FIXME: this should be checked earlier, e.g. in `rustc_ast_lowering`, to fix
-    // things like #86232.
+    // FIXME: This should be checked earlier, e.g. in `rustc_ast_lowering`, as this
+    // currently only guards function imports, function definitions, and function pointer types.
+    // Functions in trait declarations can still use "deprecated" ABIs without any warning.
 
     match AbiMap::from_target(&tcx.sess.target).canonize_abi(abi, false) {
         AbiMapping::Direct(..) => (),
+        // already erred in rustc_ast_lowering
         AbiMapping::Invalid => {
-            let mut err = struct_span_code_err!(
-                tcx.dcx(),
-                span,
-                E0570,
-                "`{abi}` is not a supported ABI for the current target",
-            );
-            add_abi_diag_help(abi, &mut err);
-            err.emit();
+            tcx.dcx().span_delayed_bug(span, format!("{abi} should be rejected in ast_lowering"));
         }
         AbiMapping::Deprecated(..) => {
             tcx.node_span_lint(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| {
-                lint.primary_message("use of calling convention not supported on this target");
-                add_abi_diag_help(abi, lint);
-            });
-        }
-    }
-}
-
-pub fn check_abi_fn_ptr(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi) {
-    // This is always an FCW, even for `AbiMapping::Invalid`, since we started linting later than
-    // in `check_abi` above.
-    match AbiMap::from_target(&tcx.sess.target).canonize_abi(abi, false) {
-        AbiMapping::Direct(..) => (),
-        // This is not a redundant match arm: these ABIs started linting after introducing
-        // UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS already existed and we want to
-        // avoid expanding the scope of that lint so it can move to a hard error sooner.
-        AbiMapping::Deprecated(..) => {
-            tcx.node_span_lint(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| {
-                lint.primary_message("use of calling convention not supported on this target");
-                add_abi_diag_help(abi, lint);
-            });
-        }
-        AbiMapping::Invalid => {
-            tcx.node_span_lint(UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS, hir_id, span, |lint| {
                 lint.primary_message(format!(
-                    "the calling convention {abi} is not supported on this target"
+                    "{abi} is not a supported ABI for the current target"
                 ));
+                add_abi_diag_help(abi, lint);
             });
         }
     }
@@ -103,7 +76,7 @@ pub fn check_abi_fn_ptr(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ex
 pub fn check_custom_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, fn_sig: FnSig<'_>, fn_sig_span: Span) {
     if fn_sig.abi == ExternAbi::Custom {
         // Function definitions that use `extern "custom"` must be naked functions.
-        if !tcx.has_attr(def_id, sym::naked) {
+        if !find_attr!(tcx.get_all_attrs(def_id), AttributeKind::Naked(_)) {
             tcx.dcx().emit_err(crate::errors::AbiCustomClothedFunction {
                 span: fn_sig_span,
                 naked_span: tcx.def_span(def_id).shrink_to_lo(),
@@ -339,7 +312,7 @@ fn check_opaque_meets_bounds<'tcx>(
     // here rather than using ReErased.
     let hidden_ty = tcx.type_of(def_id.to_def_id()).instantiate(tcx, args);
     let hidden_ty = fold_regions(tcx, hidden_ty, |re, _dbi| match re.kind() {
-        ty::ReErased => infcx.next_region_var(RegionVariableOrigin::MiscVariable(span)),
+        ty::ReErased => infcx.next_region_var(RegionVariableOrigin::Misc(span)),
         _ => re,
     });
 
@@ -867,6 +840,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
             let hir::ItemKind::ForeignMod { abi, items } = it.kind else {
                 return;
             };
+
             check_abi(tcx, it.hir_id(), it.span, abi);
 
             for item in items {
@@ -1384,7 +1358,11 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
                 ty::Tuple(list) => list.iter().try_for_each(|t| check_non_exhaustive(tcx, t)),
                 ty::Array(ty, _) => check_non_exhaustive(tcx, *ty),
                 ty::Adt(def, args) => {
-                    if !def.did().is_local() && !tcx.has_attr(def.did(), sym::rustc_pub_transparent)
+                    if !def.did().is_local()
+                        && !attrs::find_attr!(
+                            tcx.get_all_attrs(def.did()),
+                            AttributeKind::PubTransparent(_)
+                        )
                     {
                         let non_exhaustive = def.is_variant_list_non_exhaustive()
                             || def
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 47681a78ecc..372a383fb39 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -9,7 +9,7 @@ use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, pluralize, struct_
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::VisitorExt;
 use rustc_hir::{self as hir, AmbigArg, GenericParamKind, ImplItemKind, intravisit};
-use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
+use rustc_infer::infer::{self, BoundRegionConversionTime, InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::util;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::{
@@ -311,7 +311,7 @@ fn compare_method_predicate_entailment<'tcx>(
 
     let unnormalized_impl_sig = infcx.instantiate_binder_with_fresh_vars(
         impl_m_span,
-        infer::HigherRankedType,
+        BoundRegionConversionTime::HigherRankedType,
         tcx.fn_sig(impl_m.def_id).instantiate_identity(),
     );
 
@@ -518,7 +518,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
         param_env,
         infcx.instantiate_binder_with_fresh_vars(
             return_span,
-            infer::HigherRankedType,
+            BoundRegionConversionTime::HigherRankedType,
             tcx.fn_sig(impl_m.def_id).instantiate_identity(),
         ),
     );
diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs
index 3bad36da999..b556683e80a 100644
--- a/compiler/rustc_hir_analysis/src/check/entry.rs
+++ b/compiler/rustc_hir_analysis/src/check/entry.rs
@@ -1,14 +1,15 @@
 use std::ops::Not;
 
 use rustc_abi::ExternAbi;
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_hir as hir;
 use rustc_hir::Node;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::span_bug;
 use rustc_middle::ty::{self, TyCtxt, TypingMode};
 use rustc_session::config::EntryFnType;
+use rustc_span::Span;
 use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
-use rustc_span::{Span, sym};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
 
@@ -98,8 +99,10 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
         error = true;
     }
 
-    for attr in tcx.get_attrs(main_def_id, sym::track_caller) {
-        tcx.dcx().emit_err(errors::TrackCallerOnMain { span: attr.span(), annotated: main_span });
+    if let Some(attr_span) =
+        find_attr!(tcx.get_all_attrs(main_def_id), AttributeKind::TrackCaller(span) => *span)
+    {
+        tcx.dcx().emit_err(errors::TrackCallerOnMain { span: attr_span, annotated: main_span });
         error = true;
     }
 
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 5b8aa28102c..5cec3331bb1 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -72,8 +72,8 @@ pub mod wfcheck;
 
 use std::num::NonZero;
 
-pub use check::{check_abi, check_abi_fn_ptr, check_custom_abi};
-use rustc_abi::{ExternAbi, VariantIdx};
+pub use check::{check_abi, check_custom_abi};
+use rustc_abi::VariantIdx;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_errors::{Diag, ErrorGuaranteed, pluralize, struct_span_code_err};
 use rustc_hir::LangItem;
@@ -114,7 +114,15 @@ pub fn provide(providers: &mut Providers) {
 }
 
 fn adt_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::Destructor> {
-    tcx.calculate_dtor(def_id, always_applicable::check_drop_impl)
+    let dtor = tcx.calculate_dtor(def_id, always_applicable::check_drop_impl);
+    if dtor.is_none() && tcx.features().async_drop() {
+        if let Some(async_dtor) = adt_async_destructor(tcx, def_id) {
+            // When type has AsyncDrop impl, but doesn't have Drop impl, generate error
+            let span = tcx.def_span(async_dtor.impl_did);
+            tcx.dcx().emit_err(errors::AsyncDropWithoutSyncDrop { span });
+        }
+    }
+    dtor
 }
 
 fn adt_async_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::AsyncDestructor> {
@@ -303,9 +311,7 @@ fn default_body_is_unstable(
         reason: reason_str,
     });
 
-    let inject_span = item_did
-        .as_local()
-        .and_then(|id| tcx.crate_level_attribute_injection_span(tcx.local_def_id_to_hir_id(id)));
+    let inject_span = item_did.is_local().then(|| tcx.crate_level_attribute_injection_span());
     rustc_session::parse::add_feature_diagnostics_for_issue(
         &mut err,
         &tcx.sess,
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 20d0e87b7a7..89ce74879d8 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -11,7 +11,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{AmbigArg, ItemKind};
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
-use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
+use rustc_infer::infer::{self, InferCtxt, SubregionOrigin, TyCtxtInferExt};
 use rustc_lint_defs::builtin::SUPERTRAIT_ITEM_SHADOWING_DEFINITION;
 use rustc_macros::LintDiagnostic;
 use rustc_middle::mir::interpret::ErrorHandled;
@@ -231,7 +231,6 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<()
         item.name = ? tcx.def_path_str(def_id)
     );
     crate::collect::lower_item(tcx, item.item_id());
-    crate::collect::reject_placeholder_type_signatures_in_item(tcx, item);
 
     let res = match item.kind {
         // Right now we check that every default trait implementation
@@ -382,8 +381,6 @@ fn check_trait_item<'tcx>(
         _ => (None, trait_item.span),
     };
 
-    check_dyn_incompatible_self_trait_by_name(tcx, trait_item);
-
     // Check that an item definition in a subtrait is shadowing a supertrait item.
     lint_item_shadowing_supertrait_item(tcx, def_id);
 
@@ -741,7 +738,7 @@ fn ty_known_to_outlive<'tcx>(
         infcx.register_type_outlives_constraint_inner(infer::TypeOutlivesConstraint {
             sub_region: region,
             sup_type: ty,
-            origin: infer::RelateParamBound(DUMMY_SP, ty, None),
+            origin: SubregionOrigin::RelateParamBound(DUMMY_SP, ty, None),
         });
     })
 }
@@ -757,7 +754,11 @@ fn region_known_to_outlive<'tcx>(
     region_b: ty::Region<'tcx>,
 ) -> bool {
     test_region_obligations(tcx, id, param_env, wf_tys, |infcx| {
-        infcx.sub_regions(infer::RelateRegionParamBound(DUMMY_SP, None), region_b, region_a);
+        infcx.sub_regions(
+            SubregionOrigin::RelateRegionParamBound(DUMMY_SP, None),
+            region_b,
+            region_a,
+        );
     })
 }
 
@@ -832,70 +833,6 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GATArgsCollector<'tcx> {
     }
 }
 
-fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
-    match ty.kind {
-        hir::TyKind::TraitObject([trait_ref], ..) => match trait_ref.trait_ref.path.segments {
-            [s] => s.res.opt_def_id() == Some(trait_def_id.to_def_id()),
-            _ => false,
-        },
-        _ => false,
-    }
-}
-
-/// Detect when a dyn-incompatible trait is referring to itself in one of its associated items.
-///
-/// In such cases, suggest using `Self` instead.
-fn check_dyn_incompatible_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem<'_>) {
-    let (trait_ident, trait_def_id) =
-        match tcx.hir_node_by_def_id(tcx.hir_get_parent_item(item.hir_id()).def_id) {
-            hir::Node::Item(item) => match item.kind {
-                hir::ItemKind::Trait(_, _, ident, ..) => (ident, item.owner_id),
-                _ => return,
-            },
-            _ => return,
-        };
-    let mut trait_should_be_self = vec![];
-    match &item.kind {
-        hir::TraitItemKind::Const(ty, _) | hir::TraitItemKind::Type(_, Some(ty))
-            if could_be_self(trait_def_id.def_id, ty) =>
-        {
-            trait_should_be_self.push(ty.span)
-        }
-        hir::TraitItemKind::Fn(sig, _) => {
-            for ty in sig.decl.inputs {
-                if could_be_self(trait_def_id.def_id, ty) {
-                    trait_should_be_self.push(ty.span);
-                }
-            }
-            match sig.decl.output {
-                hir::FnRetTy::Return(ty) if could_be_self(trait_def_id.def_id, ty) => {
-                    trait_should_be_self.push(ty.span);
-                }
-                _ => {}
-            }
-        }
-        _ => {}
-    }
-    if !trait_should_be_self.is_empty() {
-        if tcx.is_dyn_compatible(trait_def_id) {
-            return;
-        }
-        let sugg = trait_should_be_self.iter().map(|span| (*span, "Self".to_string())).collect();
-        tcx.dcx()
-            .struct_span_err(
-                trait_should_be_self,
-                "associated item referring to unboxed trait object for its own trait",
-            )
-            .with_span_label(trait_ident.span, "in this trait")
-            .with_multipart_suggestion(
-                "you might have meant to use `Self` to refer to the implementing type",
-                sugg,
-                Applicability::MachineApplicable,
-            )
-            .emit();
-    }
-}
-
 fn lint_item_shadowing_supertrait_item<'tcx>(tcx: TyCtxt<'tcx>, trait_item_def_id: LocalDefId) {
     let item_name = tcx.item_name(trait_item_def_id.to_def_id());
     let trait_def_id = tcx.local_parent(trait_item_def_id);
@@ -1064,7 +1001,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
                     Ok(..) => Some(vec![(adt_const_params_feature_string, sym::adt_const_params)]),
                 };
                 if let Some(features) = may_suggest_feature {
-                    tcx.disabled_nightly_features(&mut diag, Some(param.hir_id), features);
+                    tcx.disabled_nightly_features(&mut diag, features);
                 }
 
                 Err(diag.emit())
@@ -1557,7 +1494,9 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
                     ty::ConstKind::Unevaluated(uv) => {
                         infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args)
                     }
-                    ty::ConstKind::Param(param_ct) => param_ct.find_ty_from_env(wfcx.param_env),
+                    ty::ConstKind::Param(param_ct) => {
+                        param_ct.find_const_ty_from_env(wfcx.param_env)
+                    }
                 };
 
                 let param_ty = tcx.type_of(param.def_id).instantiate_identity();
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 4779f4fb702..734c9c58c08 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -10,7 +10,7 @@ use rustc_hir as hir;
 use rustc_hir::ItemKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
-use rustc_infer::infer::{self, RegionResolutionError, TyCtxtInferExt};
+use rustc_infer::infer::{self, RegionResolutionError, SubregionOrigin, TyCtxtInferExt};
 use rustc_infer::traits::Obligation;
 use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
@@ -415,7 +415,7 @@ pub(crate) fn coerce_unsized_info<'tcx>(
     };
     let (source, target, trait_def_id, kind, field_span) = match (source.kind(), target.kind()) {
         (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
-            infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
+            infcx.sub_regions(SubregionOrigin::RelateObjectBound(span), r_b, r_a);
             let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
             let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
             check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ref(tcx, r_b, ty))
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 6e22ac5a28a..d7568554669 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -21,6 +21,7 @@ use std::ops::Bound;
 
 use rustc_abi::ExternAbi;
 use rustc_ast::Recovered;
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_data_structures::unord::UnordMap;
 use rustc_errors::{
@@ -28,22 +29,28 @@ use rustc_errors::{
 };
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_generics};
+use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt};
 use rustc_hir::{self as hir, GenericParamKind, HirId, Node, PreciseCapturingArgKind};
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::{DynCompatibilityViolation, ObligationCause};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::util::{Discr, IntTypeExt};
-use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypingMode, fold_regions};
+use rustc_middle::ty::{
+    self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt, TypingMode, fold_regions,
+};
 use rustc_middle::{bug, span_bug};
 use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
 use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName;
 use rustc_trait_selection::infer::InferCtxtExt;
-use rustc_trait_selection::traits::{ObligationCtxt, hir_ty_lowering_dyn_compatibility_violations};
+use rustc_trait_selection::traits::{
+    FulfillmentError, ObligationCtxt, hir_ty_lowering_dyn_compatibility_violations,
+};
 use tracing::{debug, instrument};
 
 use crate::errors;
-use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason};
+use crate::hir_ty_lowering::{
+    FeedConstTy, HirTyLowerer, InherentAssocCandidate, RegionInferReason,
+};
 
 pub(crate) mod dump;
 mod generics_of;
@@ -147,26 +154,7 @@ impl<'v> Visitor<'v> for HirPlaceholderCollector {
     }
 }
 
-/// If there are any placeholder types (`_`), emit an error explaining that this is not allowed
-/// and suggest adding type parameters in the appropriate place, taking into consideration any and
-/// all already existing generic type parameters to avoid suggesting a name that is already in use.
-pub(crate) fn placeholder_type_error<'tcx>(
-    cx: &dyn HirTyLowerer<'tcx>,
-    generics: Option<&hir::Generics<'_>>,
-    placeholder_types: Vec<Span>,
-    suggest: bool,
-    hir_ty: Option<&hir::Ty<'_>>,
-    kind: &'static str,
-) {
-    if placeholder_types.is_empty() {
-        return;
-    }
-
-    placeholder_type_error_diag(cx, generics, placeholder_types, vec![], suggest, hir_ty, kind)
-        .emit();
-}
-
-pub(crate) fn placeholder_type_error_diag<'cx, 'tcx>(
+fn placeholder_type_error_diag<'cx, 'tcx>(
     cx: &'cx dyn HirTyLowerer<'tcx>,
     generics: Option<&hir::Generics<'_>>,
     placeholder_types: Vec<Span>,
@@ -238,37 +226,6 @@ pub(crate) fn placeholder_type_error_diag<'cx, 'tcx>(
     err
 }
 
-pub(super) fn reject_placeholder_type_signatures_in_item<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    item: &'tcx hir::Item<'tcx>,
-) {
-    let (generics, suggest) = match &item.kind {
-        hir::ItemKind::Union(_, generics, _)
-        | hir::ItemKind::Enum(_, generics, _)
-        | hir::ItemKind::TraitAlias(_, generics, _)
-        | hir::ItemKind::Trait(_, _, _, generics, ..)
-        | hir::ItemKind::Impl(hir::Impl { generics, .. })
-        | hir::ItemKind::Struct(_, generics, _) => (generics, true),
-        hir::ItemKind::TyAlias(_, generics, _) => (generics, false),
-        // `static`, `fn` and `const` are handled elsewhere to suggest appropriate type.
-        _ => return,
-    };
-
-    let mut visitor = HirPlaceholderCollector::default();
-    visitor.visit_item(item);
-
-    let icx = ItemCtxt::new(tcx, item.owner_id.def_id);
-
-    placeholder_type_error(
-        icx.lowerer(),
-        Some(generics),
-        visitor.spans,
-        suggest && !visitor.may_contain_const_infer,
-        None,
-        item.kind.descr(),
-    );
-}
-
 ///////////////////////////////////////////////////////////////////////////
 // Utility types and common code for the above passes.
 
@@ -306,6 +263,54 @@ impl<'tcx> ItemCtxt<'tcx> {
             None => Ok(()),
         }
     }
+
+    fn report_placeholder_type_error(
+        &self,
+        placeholder_types: Vec<Span>,
+        infer_replacements: Vec<(Span, String)>,
+    ) -> ErrorGuaranteed {
+        let node = self.tcx.hir_node_by_def_id(self.item_def_id);
+        let generics = node.generics();
+        let kind_id = match node {
+            Node::GenericParam(_) | Node::WherePredicate(_) | Node::Field(_) => {
+                self.tcx.local_parent(self.item_def_id)
+            }
+            _ => self.item_def_id,
+        };
+        // FIXME: just invoke `tcx.def_descr` instead of going through the HIR
+        // Can also remove most `descr` methods then.
+        let kind = match self.tcx.hir_node_by_def_id(kind_id) {
+            Node::Item(it) => it.kind.descr(),
+            Node::ImplItem(it) => it.kind.descr(),
+            Node::TraitItem(it) => it.kind.descr(),
+            Node::ForeignItem(it) => it.kind.descr(),
+            Node::OpaqueTy(_) => "opaque type",
+            Node::Synthetic => self.tcx.def_descr(kind_id.into()),
+            node => todo!("{node:#?}"),
+        };
+        let mut diag = placeholder_type_error_diag(
+            self,
+            generics,
+            placeholder_types,
+            infer_replacements.iter().map(|&(span, _)| span).collect(),
+            false,
+            None,
+            kind,
+        );
+        if !infer_replacements.is_empty() {
+            diag.multipart_suggestion(
+                format!(
+                    "try replacing `_` with the type{} in the corresponding trait method \
+                        signature",
+                    rustc_errors::pluralize!(infer_replacements.len()),
+                ),
+                infer_replacements,
+                Applicability::MachineApplicable,
+            );
+        }
+
+        diag.emit()
+    }
 }
 
 impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
@@ -339,10 +344,14 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
     }
 
     fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
+        if !self.tcx.dcx().has_stashed_diagnostic(span, StashKey::ItemNoType) {
+            self.report_placeholder_type_error(vec![span], vec![]);
+        }
         Ty::new_error_with_message(self.tcx(), span, "bad placeholder type")
     }
 
     fn ct_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> {
+        self.report_placeholder_type_error(vec![span], vec![]);
         ty::Const::new_error_with_message(self.tcx(), span, "bad placeholder constant")
     }
 
@@ -364,6 +373,58 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
         self.tcx.at(span).type_param_predicates((self.item_def_id, def_id, assoc_ident))
     }
 
+    #[instrument(level = "debug", skip(self, _span), ret)]
+    fn select_inherent_assoc_candidates(
+        &self,
+        _span: Span,
+        self_ty: Ty<'tcx>,
+        candidates: Vec<InherentAssocCandidate>,
+    ) -> (Vec<InherentAssocCandidate>, Vec<FulfillmentError<'tcx>>) {
+        assert!(!self_ty.has_infer());
+
+        // We don't just call the normal normalization routine here as we can't provide the
+        // correct `ParamEnv` and it would be wrong to invoke arbitrary trait solving under
+        // the wrong `ParamEnv`. Expanding free aliases doesn't need a `ParamEnv` so we do
+        // this just to make resolution a little bit smarter.
+        let self_ty = self.tcx.expand_free_alias_tys(self_ty);
+        debug!("select_inherent_assoc_candidates: self_ty={:?}", self_ty);
+
+        let candidates = candidates
+            .into_iter()
+            .filter(|&InherentAssocCandidate { impl_, .. }| {
+                let impl_ty = self.tcx().type_of(impl_).instantiate_identity();
+
+                // See comment on doing this operation for `self_ty`
+                let impl_ty = self.tcx.expand_free_alias_tys(impl_ty);
+                debug!("select_inherent_assoc_candidates: impl_ty={:?}", impl_ty);
+
+                // We treat parameters in the self ty as rigid and parameters in the impl ty as infers
+                // because it allows `impl<T> Foo<T>` to unify with `Foo<u8>::IAT`, while also disallowing
+                // `Foo<T>::IAT` from unifying with `impl Foo<u8>`.
+                //
+                // We don't really care about a depth limit here because we're only working with user-written
+                // types and if they wrote a type that would take hours to walk then that's kind of on them. On
+                // the other hand the default depth limit is relatively low and could realistically be hit by
+                // users in normal cases.
+                //
+                // `DeepRejectCtxt` leads to slightly worse IAT resolution than real type equality in cases
+                // where the `impl_ty` has repeated uses of generic parameters. E.g. `impl<T> Foo<T, T>` would
+                // be considered a valid candidate when resolving `Foo<u8, u16>::IAT`.
+                //
+                // Not replacing escaping bound vars in `self_ty` with placeholders also leads to slightly worse
+                // resolution, but it probably won't come up in practice and it would be backwards compatible
+                // to switch over to doing that.
+                ty::DeepRejectCtxt::relate_rigid_infer(self.tcx).types_may_unify_with_depth(
+                    self_ty,
+                    impl_ty,
+                    usize::MAX,
+                )
+            })
+            .collect();
+
+        (candidates, vec![])
+    }
+
     fn lower_assoc_item_path(
         &self,
         span: Span,
@@ -465,18 +526,13 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
     fn lower_fn_sig(
         &self,
         decl: &hir::FnDecl<'tcx>,
-        generics: Option<&hir::Generics<'_>>,
+        _generics: Option<&hir::Generics<'_>>,
         hir_id: rustc_hir::HirId,
-        hir_ty: Option<&hir::Ty<'_>>,
+        _hir_ty: Option<&hir::Ty<'_>>,
     ) -> (Vec<Ty<'tcx>>, Ty<'tcx>) {
         let tcx = self.tcx();
-        // We proactively collect all the inferred type params to emit a single error per fn def.
-        let mut visitor = HirPlaceholderCollector::default();
-        let mut infer_replacements = vec![];
 
-        if let Some(generics) = generics {
-            walk_generics(&mut visitor, generics);
-        }
+        let mut infer_replacements = vec![];
 
         let input_tys = decl
             .inputs
@@ -492,8 +548,6 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
                     }
                 }
 
-                // Only visit the type looking for `_` if we didn't fix the type above
-                visitor.visit_ty_unambig(a);
                 self.lowerer().lower_ty(a)
             })
             .collect();
@@ -507,42 +561,15 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
                     infer_replacements.push((output.span, suggested_ty.to_string()));
                     Ty::new_error_with_message(tcx, output.span, suggested_ty.to_string())
                 } else {
-                    visitor.visit_ty_unambig(output);
                     self.lower_ty(output)
                 }
             }
             hir::FnRetTy::DefaultReturn(..) => tcx.types.unit,
         };
 
-        if !(visitor.spans.is_empty() && infer_replacements.is_empty()) {
-            // We check for the presence of
-            // `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`.
-
-            let mut diag = crate::collect::placeholder_type_error_diag(
-                self,
-                generics,
-                visitor.spans,
-                infer_replacements.iter().map(|(s, _)| *s).collect(),
-                !visitor.may_contain_const_infer,
-                hir_ty,
-                "function",
-            );
-
-            if !infer_replacements.is_empty() {
-                diag.multipart_suggestion(
-                    format!(
-                        "try replacing `_` with the type{} in the corresponding trait method \
-                         signature",
-                        rustc_errors::pluralize!(infer_replacements.len()),
-                    ),
-                    infer_replacements,
-                    Applicability::MachineApplicable,
-                );
-            }
-
-            diag.emit();
+        if !infer_replacements.is_empty() {
+            self.report_placeholder_type_error(vec![], infer_replacements);
         }
-
         (input_tys, output_ty)
     }
 
@@ -593,7 +620,6 @@ pub(super) fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
     let it = tcx.hir_item(item_id);
     debug!(item = ?it.kind.ident(), id = %it.hir_id());
     let def_id = item_id.owner_id.def_id;
-    let icx = ItemCtxt::new(tcx, def_id);
 
     match &it.kind {
         // These don't define types.
@@ -619,16 +645,6 @@ pub(super) fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
                     }
                     hir::ForeignItemKind::Static(..) => {
                         tcx.ensure_ok().codegen_fn_attrs(item.owner_id);
-                        let mut visitor = HirPlaceholderCollector::default();
-                        visitor.visit_foreign_item(item);
-                        placeholder_type_error(
-                            icx.lowerer(),
-                            None,
-                            visitor.spans,
-                            false,
-                            None,
-                            "static variable",
-                        );
                     }
                     _ => (),
                 }
@@ -682,22 +698,10 @@ pub(super) fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
             tcx.ensure_ok().predicates_of(def_id);
         }
 
-        hir::ItemKind::Static(_, _, ty, _) | hir::ItemKind::Const(_, _, ty, _) => {
+        hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => {
             tcx.ensure_ok().generics_of(def_id);
             tcx.ensure_ok().type_of(def_id);
             tcx.ensure_ok().predicates_of(def_id);
-            if !ty.is_suggestable_infer_ty() {
-                let mut visitor = HirPlaceholderCollector::default();
-                visitor.visit_item(it);
-                placeholder_type_error(
-                    icx.lowerer(),
-                    None,
-                    visitor.spans,
-                    false,
-                    None,
-                    it.kind.descr(),
-                );
-            }
         }
 
         hir::ItemKind::Fn { .. } => {
@@ -714,7 +718,6 @@ pub(crate) fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId)
     let trait_item = tcx.hir_trait_item(trait_item_id);
     let def_id = trait_item_id.owner_id;
     tcx.ensure_ok().generics_of(def_id);
-    let icx = ItemCtxt::new(tcx, def_id.def_id);
 
     match trait_item.kind {
         hir::TraitItemKind::Fn(..) => {
@@ -723,58 +726,19 @@ pub(crate) fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId)
             tcx.ensure_ok().fn_sig(def_id);
         }
 
-        hir::TraitItemKind::Const(ty, body_id) => {
+        hir::TraitItemKind::Const(..) => {
             tcx.ensure_ok().type_of(def_id);
-            if !tcx.dcx().has_stashed_diagnostic(ty.span, StashKey::ItemNoType)
-                && !(ty.is_suggestable_infer_ty() && body_id.is_some())
-            {
-                // Account for `const C: _;`.
-                let mut visitor = HirPlaceholderCollector::default();
-                visitor.visit_trait_item(trait_item);
-                placeholder_type_error(
-                    icx.lowerer(),
-                    None,
-                    visitor.spans,
-                    false,
-                    None,
-                    "associated constant",
-                );
-            }
         }
 
         hir::TraitItemKind::Type(_, Some(_)) => {
             tcx.ensure_ok().item_bounds(def_id);
             tcx.ensure_ok().item_self_bounds(def_id);
             tcx.ensure_ok().type_of(def_id);
-            // Account for `type T = _;`.
-            let mut visitor = HirPlaceholderCollector::default();
-            visitor.visit_trait_item(trait_item);
-            placeholder_type_error(
-                icx.lowerer(),
-                None,
-                visitor.spans,
-                false,
-                None,
-                "associated type",
-            );
         }
 
         hir::TraitItemKind::Type(_, None) => {
             tcx.ensure_ok().item_bounds(def_id);
             tcx.ensure_ok().item_self_bounds(def_id);
-            // #74612: Visit and try to find bad placeholders
-            // even if there is no concrete type.
-            let mut visitor = HirPlaceholderCollector::default();
-            visitor.visit_trait_item(trait_item);
-
-            placeholder_type_error(
-                icx.lowerer(),
-                None,
-                visitor.spans,
-                false,
-                None,
-                "associated type",
-            );
         }
     };
 
@@ -787,41 +751,13 @@ pub(super) fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
     tcx.ensure_ok().type_of(def_id);
     tcx.ensure_ok().predicates_of(def_id);
     let impl_item = tcx.hir_impl_item(impl_item_id);
-    let icx = ItemCtxt::new(tcx, def_id.def_id);
     match impl_item.kind {
         hir::ImplItemKind::Fn(..) => {
             tcx.ensure_ok().codegen_fn_attrs(def_id);
             tcx.ensure_ok().fn_sig(def_id);
         }
-        hir::ImplItemKind::Type(_) => {
-            // Account for `type T = _;`
-            let mut visitor = HirPlaceholderCollector::default();
-            visitor.visit_impl_item(impl_item);
-
-            placeholder_type_error(
-                icx.lowerer(),
-                None,
-                visitor.spans,
-                false,
-                None,
-                "associated type",
-            );
-        }
-        hir::ImplItemKind::Const(ty, _) => {
-            // Account for `const T: _ = ..;`
-            if !ty.is_suggestable_infer_ty() {
-                let mut visitor = HirPlaceholderCollector::default();
-                visitor.visit_impl_item(impl_item);
-                placeholder_type_error(
-                    icx.lowerer(),
-                    None,
-                    visitor.spans,
-                    false,
-                    None,
-                    "associated constant",
-                );
-            }
-        }
+        hir::ImplItemKind::Type(_) => {}
+        hir::ImplItemKind::Const(..) => {}
     }
 }
 
@@ -1093,22 +1029,11 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
     let rustc_coinductive = tcx.has_attr(def_id, sym::rustc_coinductive);
     let is_fundamental = tcx.has_attr(def_id, sym::fundamental);
 
-    // FIXME: We could probably do way better attribute validation here.
-    let mut skip_array_during_method_dispatch = false;
-    let mut skip_boxed_slice_during_method_dispatch = false;
-    for attr in tcx.get_attrs(def_id, sym::rustc_skip_during_method_dispatch) {
-        if let Some(lst) = attr.meta_item_list() {
-            for item in lst {
-                if let Some(ident) = item.ident() {
-                    match ident.as_str() {
-                        "array" => skip_array_during_method_dispatch = true,
-                        "boxed_slice" => skip_boxed_slice_during_method_dispatch = true,
-                        _ => (),
-                    }
-                }
-            }
-        }
-    }
+    let [skip_array_during_method_dispatch, skip_boxed_slice_during_method_dispatch] = find_attr!(
+        tcx.get_all_attrs(def_id),
+        AttributeKind::SkipDuringMethodDispatch { array, boxed_slice, span:_ } => [*array, *boxed_slice]
+    )
+    .unwrap_or([false; 2]);
 
     let specialization_kind = if tcx.has_attr(def_id, sym::rustc_unsafe_specialization_marker) {
         ty::trait_def::TraitSpecializationKind::Marker
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index d45f0475e99..95743f9a63e 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -2177,84 +2177,80 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
     /// Walk the generics of the item for a trait bound whose self type
     /// corresponds to the expected res, and return the trait def id.
     fn for_each_trait_bound_on_res(&self, expected_res: Res) -> impl Iterator<Item = DefId> {
-        std::iter::from_coroutine(
-            #[coroutine]
-            move || {
-                let mut scope = self.scope;
-                loop {
-                    let hir_id = match *scope {
-                        Scope::Binder { hir_id, .. } => Some(hir_id),
-                        Scope::Root { opt_parent_item: Some(parent_def_id) } => {
-                            Some(self.tcx.local_def_id_to_hir_id(parent_def_id))
-                        }
-                        Scope::Body { .. }
-                        | Scope::ObjectLifetimeDefault { .. }
-                        | Scope::Supertrait { .. }
-                        | Scope::TraitRefBoundary { .. }
-                        | Scope::LateBoundary { .. }
-                        | Scope::Opaque { .. }
-                        | Scope::Root { opt_parent_item: None } => None,
-                    };
+        gen move {
+            let mut scope = self.scope;
+            loop {
+                let hir_id = match *scope {
+                    Scope::Binder { hir_id, .. } => Some(hir_id),
+                    Scope::Root { opt_parent_item: Some(parent_def_id) } => {
+                        Some(self.tcx.local_def_id_to_hir_id(parent_def_id))
+                    }
+                    Scope::Body { .. }
+                    | Scope::ObjectLifetimeDefault { .. }
+                    | Scope::Supertrait { .. }
+                    | Scope::TraitRefBoundary { .. }
+                    | Scope::LateBoundary { .. }
+                    | Scope::Opaque { .. }
+                    | Scope::Root { opt_parent_item: None } => None,
+                };
 
-                    if let Some(hir_id) = hir_id {
-                        let node = self.tcx.hir_node(hir_id);
-                        // If this is a `Self` bound in a trait, yield the trait itself.
-                        // Specifically, we don't need to look at any supertraits since
-                        // we already do that in `BoundVarContext::supertrait_hrtb_vars`.
-                        if let Res::SelfTyParam { trait_: _ } = expected_res
-                            && let hir::Node::Item(item) = node
-                            && let hir::ItemKind::Trait(..) = item.kind
-                        {
-                            // Yield the trait's def id. Supertraits will be
-                            // elaborated from that.
-                            yield item.owner_id.def_id.to_def_id();
-                        } else if let Some(generics) = node.generics() {
-                            for pred in generics.predicates {
-                                let hir::WherePredicateKind::BoundPredicate(pred) = pred.kind
-                                else {
-                                    continue;
-                                };
-                                let hir::TyKind::Path(hir::QPath::Resolved(None, bounded_path)) =
-                                    pred.bounded_ty.kind
-                                else {
-                                    continue;
-                                };
-                                // Match the expected res.
-                                if bounded_path.res != expected_res {
-                                    continue;
-                                }
-                                for pred in pred.bounds {
-                                    match pred {
-                                        hir::GenericBound::Trait(poly_trait_ref) => {
-                                            if let Some(def_id) =
-                                                poly_trait_ref.trait_ref.trait_def_id()
-                                            {
-                                                yield def_id;
-                                            }
+                if let Some(hir_id) = hir_id {
+                    let node = self.tcx.hir_node(hir_id);
+                    // If this is a `Self` bound in a trait, yield the trait itself.
+                    // Specifically, we don't need to look at any supertraits since
+                    // we already do that in `BoundVarContext::supertrait_hrtb_vars`.
+                    if let Res::SelfTyParam { trait_: _ } = expected_res
+                        && let hir::Node::Item(item) = node
+                        && let hir::ItemKind::Trait(..) = item.kind
+                    {
+                        // Yield the trait's def id. Supertraits will be
+                        // elaborated from that.
+                        yield item.owner_id.def_id.to_def_id();
+                    } else if let Some(generics) = node.generics() {
+                        for pred in generics.predicates {
+                            let hir::WherePredicateKind::BoundPredicate(pred) = pred.kind else {
+                                continue;
+                            };
+                            let hir::TyKind::Path(hir::QPath::Resolved(None, bounded_path)) =
+                                pred.bounded_ty.kind
+                            else {
+                                continue;
+                            };
+                            // Match the expected res.
+                            if bounded_path.res != expected_res {
+                                continue;
+                            }
+                            for pred in pred.bounds {
+                                match pred {
+                                    hir::GenericBound::Trait(poly_trait_ref) => {
+                                        if let Some(def_id) =
+                                            poly_trait_ref.trait_ref.trait_def_id()
+                                        {
+                                            yield def_id;
                                         }
-                                        hir::GenericBound::Outlives(_)
-                                        | hir::GenericBound::Use(_, _) => {}
                                     }
+                                    hir::GenericBound::Outlives(_)
+                                    | hir::GenericBound::Use(_, _) => {}
                                 }
                             }
                         }
                     }
+                }
 
-                    match *scope {
-                        Scope::Binder { s, .. }
-                        | Scope::Body { s, .. }
-                        | Scope::ObjectLifetimeDefault { s, .. }
-                        | Scope::Supertrait { s, .. }
-                        | Scope::TraitRefBoundary { s }
-                        | Scope::LateBoundary { s, .. }
-                        | Scope::Opaque { s, .. } => {
-                            scope = s;
-                        }
-                        Scope::Root { .. } => break,
+                match *scope {
+                    Scope::Binder { s, .. }
+                    | Scope::Body { s, .. }
+                    | Scope::ObjectLifetimeDefault { s, .. }
+                    | Scope::Supertrait { s, .. }
+                    | Scope::TraitRefBoundary { s }
+                    | Scope::LateBoundary { s, .. }
+                    | Scope::Opaque { s, .. } => {
+                        scope = s;
                     }
+                    Scope::Root { .. } => break,
                 }
-            },
-        )
+            }
+        }
     }
 }
 
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 141d96b57e5..902a2e15dff 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -452,13 +452,6 @@ fn infer_placeholder_type<'tcx>(
             if let Some(ty) = node.ty() {
                 visitor.visit_ty_unambig(ty);
             }
-            // If we have just one span, let's try to steal a const `_` feature error.
-            let try_steal_span = if !tcx.features().generic_arg_infer() && visitor.spans.len() == 1
-            {
-                visitor.spans.first().copied()
-            } else {
-                None
-            };
             // If we didn't find any infer tys, then just fallback to `span`.
             if visitor.spans.is_empty() {
                 visitor.spans.push(span);
@@ -489,15 +482,7 @@ fn infer_placeholder_type<'tcx>(
                 }
             }
 
-            if let Some(try_steal_span) = try_steal_span {
-                cx.dcx().try_steal_replace_and_emit_err(
-                    try_steal_span,
-                    StashKey::UnderscoreForArrayLengths,
-                    diag,
-                )
-            } else {
-                diag.emit()
-            }
+            diag.emit()
         });
     Ty::new_error(tcx, guar)
 }
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 8de2aec95a7..c920e25ad37 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -127,6 +127,7 @@ pub(crate) enum AssocItemNotFoundSugg<'a> {
     SimilarInOtherTrait {
         #[primary_span]
         span: Span,
+        trait_name: &'a str,
         assoc_kind: &'static str,
         suggested_name: Symbol,
     },
@@ -1712,3 +1713,11 @@ pub(crate) struct AbiCustomClothedFunction {
     )]
     pub naked_span: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_async_drop_without_sync_drop)]
+#[help]
+pub(crate) struct AsyncDropWithoutSyncDrop {
+    #[primary_span]
+    pub span: Span,
+}
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
index ebeb3b58208..82e5f65476f 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
@@ -18,7 +18,7 @@ pub(crate) fn validate_cmse_abi<'tcx>(
     fn_sig: ty::PolyFnSig<'tcx>,
 ) {
     match abi {
-        ExternAbi::CCmseNonSecureCall => {
+        ExternAbi::CmseNonSecureCall => {
             let hir_node = tcx.hir_node(hir_id);
             let hir::Node::Ty(hir::Ty {
                 span: bare_fn_span,
@@ -38,7 +38,7 @@ pub(crate) fn validate_cmse_abi<'tcx>(
                     dcx,
                     span,
                     E0781,
-                    "the `\"C-cmse-nonsecure-call\"` ABI is only allowed on function pointers"
+                    "the `\"cmse-nonsecure-call\"` ABI is only allowed on function pointers"
                 )
                 .emit();
                 return;
@@ -78,7 +78,7 @@ pub(crate) fn validate_cmse_abi<'tcx>(
                 }
             };
         }
-        ExternAbi::CCmseNonSecureEntry => {
+        ExternAbi::CmseNonSecureEntry => {
             let hir_node = tcx.hir_node(hir_id);
             let Some(hir::FnSig { decl, span: fn_sig_span, .. }) = hir_node.fn_sig() else {
                 // might happen when this ABI is used incorrectly. That will be handled elsewhere
@@ -203,11 +203,11 @@ fn should_emit_generic_error<'tcx>(abi: ExternAbi, layout_err: &'tcx LayoutError
     match layout_err {
         TooGeneric(ty) => {
             match abi {
-                ExternAbi::CCmseNonSecureCall => {
+                ExternAbi::CmseNonSecureCall => {
                     // prevent double reporting of this error
                     !ty.is_impl_trait()
                 }
-                ExternAbi::CCmseNonSecureEntry => true,
+                ExternAbi::CmseNonSecureEntry => true,
                 _ => bug!("invalid ABI: {abi}"),
             }
         }
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index 1cda6dff21e..f211137ddd6 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -26,6 +26,7 @@ use rustc_trait_selection::traits::{
 use smallvec::SmallVec;
 use tracing::debug;
 
+use super::InherentAssocCandidate;
 use crate::errors::{
     self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams,
     ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits,
@@ -308,6 +309,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         // change the associated item.
                         err.sugg = Some(errors::AssocItemNotFoundSugg::SimilarInOtherTrait {
                             span: assoc_ident.span,
+                            trait_name: &trait_name,
                             assoc_kind: assoc_kind_str,
                             suggested_name,
                         });
@@ -793,7 +795,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         &self,
         name: Ident,
         self_ty: Ty<'tcx>,
-        candidates: Vec<(DefId, (DefId, DefId))>,
+        candidates: Vec<InherentAssocCandidate>,
         fulfillment_errors: Vec<FulfillmentError<'tcx>>,
         span: Span,
         assoc_tag: ty::AssocTag,
@@ -827,8 +829,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             let type_candidates = candidates
                 .iter()
                 .take(limit)
-                .map(|&(impl_, _)| {
-                    format!("- `{}`", tcx.at(span).type_of(impl_).instantiate_identity())
+                .map(|cand| {
+                    format!("- `{}`", tcx.at(span).type_of(cand.impl_).instantiate_identity())
                 })
                 .collect::<Vec<_>>()
                 .join("\n");
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
index 3a26b8331f8..8c7c3750865 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
@@ -8,7 +8,7 @@ use rustc_middle::ty::{
     self, GenericArgsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty,
 };
 use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS;
-use rustc_span::{kw, sym};
+use rustc_span::kw;
 use smallvec::SmallVec;
 use tracing::{debug, instrument};
 
@@ -258,19 +258,6 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
                             GenericParamDefKind::Const { .. },
                             _,
                         ) => {
-                            if let GenericParamDefKind::Const { .. } = param.kind
-                                && let GenericArg::Infer(inf) = arg
-                                && !tcx.features().generic_arg_infer()
-                            {
-                                rustc_session::parse::feature_err(
-                                    tcx.sess,
-                                    sym::generic_arg_infer,
-                                    inf.span,
-                                    "const arguments cannot yet be inferred with `_`",
-                                )
-                                .emit();
-                            }
-
                             // We lower to an infer even when the feature gate is not enabled
                             // as it is useful for diagnostics to be able to see a `ConstKind::Infer`
                             args.push(ctx.provided_kind(&args, param, arg));
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index bf407cbaccb..baf3b9b5bc9 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -33,13 +33,14 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::{self as hir, AnonConst, GenericArg, GenericArgs, HirId};
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
-use rustc_infer::traits::{DynCompatibilityViolation, ObligationCause};
+use rustc_infer::traits::DynCompatibilityViolation;
+use rustc_macros::{TypeFoldable, TypeVisitable};
 use rustc_middle::middle::stability::AllowUnstable;
 use rustc_middle::mir::interpret::LitToConstInput;
 use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
 use rustc_middle::ty::{
-    self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt,
-    TypeVisitableExt, TypingMode, Upcast, fold_regions,
+    self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt,
+    TypingMode, Upcast, fold_regions,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
@@ -47,10 +48,10 @@ use rustc_session::parse::feature_err;
 use rustc_span::{DUMMY_SP, Ident, Span, kw, sym};
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::wf::object_region_bounds;
-use rustc_trait_selection::traits::{self, ObligationCtxt};
+use rustc_trait_selection::traits::{self, FulfillmentError};
 use tracing::{debug, instrument};
 
-use crate::check::check_abi_fn_ptr;
+use crate::check::check_abi;
 use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation};
 use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint};
 use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
@@ -99,6 +100,13 @@ pub enum RegionInferReason<'a> {
     OutlivesBound,
 }
 
+#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Debug)]
+pub struct InherentAssocCandidate {
+    pub impl_: DefId,
+    pub assoc_item: DefId,
+    pub scope: DefId,
+}
+
 /// A context which can lower type-system entities from the [HIR][hir] to
 /// the [`rustc_middle::ty`] representation.
 ///
@@ -148,6 +156,13 @@ pub trait HirTyLowerer<'tcx> {
         assoc_ident: Ident,
     ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]>;
 
+    fn select_inherent_assoc_candidates(
+        &self,
+        span: Span,
+        self_ty: Ty<'tcx>,
+        candidates: Vec<InherentAssocCandidate>,
+    ) -> (Vec<InherentAssocCandidate>, Vec<FulfillmentError<'tcx>>);
+
     /// Lower a path to an associated item (of a trait) to a projection.
     ///
     /// This method has to be defined by the concrete lowering context because
@@ -1449,48 +1464,32 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             .filter_map(|&impl_| {
                 let (item, scope) =
                     self.probe_assoc_item_unchecked(name, assoc_tag, block, impl_)?;
-                Some((impl_, (item.def_id, scope)))
+                Some(InherentAssocCandidate { impl_, assoc_item: item.def_id, scope })
             })
             .collect();
 
-        if candidates.is_empty() {
-            return Ok(None);
-        }
-
-        //
-        // Select applicable inherent associated type candidates modulo regions.
-        //
-
-        // In contexts that have no inference context, just make a new one.
-        // We do need a local variable to store it, though.
-        let infcx = match self.infcx() {
-            Some(infcx) => infcx,
-            None => {
-                assert!(!self_ty.has_infer());
-                &tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis())
-            }
-        };
+        let (applicable_candidates, fulfillment_errors) =
+            self.select_inherent_assoc_candidates(span, self_ty, candidates.clone());
 
-        // FIXME(inherent_associated_types): Acquiring the ParamEnv this early leads to cycle errors
-        // when inside of an ADT (#108491) or where clause.
-        let param_env = tcx.param_env(block.owner);
+        let InherentAssocCandidate { impl_, assoc_item, scope: def_scope } =
+            match &applicable_candidates[..] {
+                &[] => Err(self.report_unresolved_inherent_assoc_item(
+                    name,
+                    self_ty,
+                    candidates,
+                    fulfillment_errors,
+                    span,
+                    assoc_tag,
+                )),
 
-        let mut universes = if self_ty.has_escaping_bound_vars() {
-            vec![None; self_ty.outer_exclusive_binder().as_usize()]
-        } else {
-            vec![]
-        };
+                &[applicable_candidate] => Ok(applicable_candidate),
 
-        let (impl_, (assoc_item, def_scope)) = crate::traits::with_replaced_escaping_bound_vars(
-            infcx,
-            &mut universes,
-            self_ty,
-            |self_ty| {
-                self.select_inherent_assoc_candidates(
-                    infcx, name, span, self_ty, param_env, candidates, assoc_tag,
-                )
-            },
-        )?;
+                &[_, ..] => Err(self.report_ambiguous_inherent_assoc_item(
+                    name,
+                    candidates.into_iter().map(|cand| cand.assoc_item).collect(),
+                    span,
+                )),
+            }?;
 
         self.check_assoc_item(assoc_item, name, def_scope, block, span);
 
@@ -1507,78 +1506,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         Ok(Some((assoc_item, args)))
     }
 
-    fn select_inherent_assoc_candidates(
-        &self,
-        infcx: &InferCtxt<'tcx>,
-        name: Ident,
-        span: Span,
-        self_ty: Ty<'tcx>,
-        param_env: ParamEnv<'tcx>,
-        candidates: Vec<(DefId, (DefId, DefId))>,
-        assoc_tag: ty::AssocTag,
-    ) -> Result<(DefId, (DefId, DefId)), ErrorGuaranteed> {
-        let tcx = self.tcx();
-        let mut fulfillment_errors = Vec::new();
-
-        let applicable_candidates: Vec<_> = candidates
-            .iter()
-            .copied()
-            .filter(|&(impl_, _)| {
-                infcx.probe(|_| {
-                    let ocx = ObligationCtxt::new_with_diagnostics(infcx);
-                    let self_ty = ocx.normalize(&ObligationCause::dummy(), param_env, self_ty);
-
-                    let impl_args = infcx.fresh_args_for_item(span, impl_);
-                    let impl_ty = tcx.type_of(impl_).instantiate(tcx, impl_args);
-                    let impl_ty = ocx.normalize(&ObligationCause::dummy(), param_env, impl_ty);
-
-                    // Check that the self types can be related.
-                    if ocx.eq(&ObligationCause::dummy(), param_env, impl_ty, self_ty).is_err() {
-                        return false;
-                    }
-
-                    // Check whether the impl imposes obligations we have to worry about.
-                    let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_args);
-                    let impl_bounds =
-                        ocx.normalize(&ObligationCause::dummy(), param_env, impl_bounds);
-                    let impl_obligations = traits::predicates_for_generics(
-                        |_, _| ObligationCause::dummy(),
-                        param_env,
-                        impl_bounds,
-                    );
-                    ocx.register_obligations(impl_obligations);
-
-                    let mut errors = ocx.select_where_possible();
-                    if !errors.is_empty() {
-                        fulfillment_errors.append(&mut errors);
-                        return false;
-                    }
-
-                    true
-                })
-            })
-            .collect();
-
-        match &applicable_candidates[..] {
-            &[] => Err(self.report_unresolved_inherent_assoc_item(
-                name,
-                self_ty,
-                candidates,
-                fulfillment_errors,
-                span,
-                assoc_tag,
-            )),
-
-            &[applicable_candidate] => Ok(applicable_candidate),
-
-            &[_, ..] => Err(self.report_ambiguous_inherent_assoc_item(
-                name,
-                applicable_candidates.into_iter().map(|(_, (candidate, _))| candidate).collect(),
-                span,
-            )),
-        }
-    }
-
     /// Given name and kind search for the assoc item in the provided scope and check if it's accessible[^1].
     ///
     /// [^1]: I.e., accessible in the provided scope wrt. visibility and stability.
@@ -2733,7 +2660,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         if let hir::Node::Ty(hir::Ty { kind: hir::TyKind::BareFn(bare_fn_ty), span, .. }) =
             tcx.hir_node(hir_id)
         {
-            check_abi_fn_ptr(tcx, hir_id, *span, bare_fn_ty.abi);
+            check_abi(tcx, hir_id, *span, bare_fn_ty.abi);
         }
 
         // reject function types that violate cmse ABI requirements
diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
index 4633f3951a7..fef0dbf2ece 100644
--- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
@@ -1,7 +1,8 @@
+use rustc_hir::def::DefKind;
 use rustc_hir::intravisit::{self, Visitor, VisitorExt};
 use rustc_hir::{self as hir, AmbigArg, ForeignItem, ForeignItemKind};
 use rustc_infer::infer::TyCtxtInferExt;
-use rustc_infer::traits::{ObligationCause, WellFormedLoc};
+use rustc_infer::traits::{ObligationCause, ObligationCauseCode, WellFormedLoc};
 use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, TypingMode, fold_regions};
@@ -107,6 +108,17 @@ fn diagnostic_hir_wf_check<'tcx>(
                     // over less-specific types (e.g. `Option<MyStruct<u8>>`)
                     if self.depth >= self.cause_depth {
                         self.cause = Some(error.obligation.cause);
+                        if let hir::TyKind::TraitObject(..) = ty.kind {
+                            if let DefKind::AssocTy | DefKind::AssocConst | DefKind::AssocFn =
+                                self.tcx.def_kind(self.def_id)
+                            {
+                                self.cause = Some(ObligationCause::new(
+                                    ty.span,
+                                    self.def_id,
+                                    ObligationCauseCode::DynCompatible(ty.span),
+                                ));
+                            }
+                        }
                         self.cause_depth = self.depth
                     }
                 }
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 7c8c9425a03..76ab2e57a1b 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -62,8 +62,8 @@ This API is completely unstable and subject to change.
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
 #![feature(assert_matches)]
-#![feature(coroutines)]
 #![feature(debug_closure_helpers)]
+#![feature(gen_blocks)]
 #![feature(if_let_guard)]
 #![feature(iter_from_coroutine)]
 #![feature(iter_intersperse)]