about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBoxy <rust@boxyuwu.dev>2025-04-24 10:49:06 +0100
committerBoxy <rust@boxyuwu.dev>2025-06-17 14:18:34 +0100
commit442862bc78b24f6019e4f3e32cfe2380dd480f26 (patch)
treeb03b8571e0ca2dd7f2ae77a682762755665ce91f
parent55d436467c351b56253deeba209ae2553d1c243f (diff)
downloadrust-442862bc78b24f6019e4f3e32cfe2380dd480f26.tar.gz
rust-442862bc78b24f6019e4f3e32cfe2380dd480f26.zip
Don't build `ParamEnv` and do trait solving in `ItemCtxt`s
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs70
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs151
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs76
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/mod.rs10
-rw-r--r--compiler/rustc_type_ir/src/fast_reject.rs7
-rw-r--r--tests/crashes/136678.rs18
-rw-r--r--tests/crashes/138131.rs9
-rw-r--r--tests/ui/associated-inherent-types/bound_vars_in_args.rs23
-rw-r--r--tests/ui/associated-inherent-types/bound_vars_in_args.stderr37
-rw-r--r--tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.stderr33
-rw-r--r--tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-where-predicate.rs16
-rw-r--r--tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-where-predicate.stderr37
-rw-r--r--tests/ui/associated-inherent-types/candidate-with-alias-2.rs26
-rw-r--r--tests/ui/associated-inherent-types/candidate-with-alias-2.stderr20
-rw-r--r--tests/ui/associated-inherent-types/candidate-with-alias.rs27
-rw-r--r--tests/ui/associated-inherent-types/iat-in-where-bound.rs14
-rw-r--r--tests/ui/associated-inherent-types/iat-inside-of-adt.rs (renamed from tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.rs)9
-rw-r--r--tests/ui/associated-inherent-types/inhabited-predicates.rs (renamed from tests/crashes/125879.rs)7
-rw-r--r--tests/ui/associated-inherent-types/inhabited-predicates.stderr27
-rw-r--r--tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-1.rs23
-rw-r--r--tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-2.rs29
-rw-r--r--tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-2.stderr20
-rw-r--r--tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-3.rs27
-rw-r--r--tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.rs2
-rw-r--r--tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr18
-rw-r--r--tests/ui/associated-inherent-types/really_deep_self_ty_mismatch.rs26
-rw-r--r--tests/ui/const-generics/mgca/unresolved-iac-1.rs11
-rw-r--r--tests/ui/const-generics/mgca/unresolved-iac-1.stderr16
-rw-r--r--tests/ui/const-generics/mgca/unresolved-iac-2.rs14
-rw-r--r--tests/ui/const-generics/mgca/unresolved-iac-2.stderr15
31 files changed, 576 insertions, 249 deletions
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 6e22ac5a28a..fd8c702a76b 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -34,16 +34,22 @@ 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;
@@ -364,6 +370,64 @@ 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 seems dubious 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);
+
+        // We make an infcx and replace any escaping vars with placeholders so that IAT res
+        // with type/const bound vars in arguments is slightly smarter. `for<T> <Foo<T>>::IAT`
+        // would otherwise unify with `impl Foo<u8>` when ideally we would not.
+        let infcx = self.tcx().infer_ctxt().build(TypingMode::non_body_analysis());
+        let mut universes = if self_ty.has_escaping_bound_vars() {
+            vec![None; self_ty.outer_exclusive_binder().as_usize()]
+        } else {
+            vec![]
+        };
+        let candidates =
+            rustc_trait_selection::traits::with_replaced_escaping_bound_vars(
+                &infcx,
+                &mut universes,
+                self_ty,
+                |self_ty| {
+                    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.
+                            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,
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 45fee0fa402..f62e149191d 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,
@@ -742,7 +743,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,
@@ -776,8 +777,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/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index bf407cbaccb..b99f7b44661 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,7 +48,7 @@ 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;
@@ -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.
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index e979798a402..d8efb0aac4d 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -12,7 +12,9 @@ use hir::def_id::CRATE_DEF_ID;
 use rustc_errors::DiagCtxtHandle;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::{self as hir, HirId, ItemLocalMap};
-use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, RegionInferReason};
+use rustc_hir_analysis::hir_ty_lowering::{
+    HirTyLowerer, InherentAssocCandidate, RegionInferReason,
+};
 use rustc_infer::infer;
 use rustc_infer::traits::{DynCompatibilityViolation, Obligation};
 use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt};
@@ -20,7 +22,9 @@ use rustc_session::Session;
 use rustc_span::{self, DUMMY_SP, ErrorGuaranteed, Ident, Span, sym};
 use rustc_trait_selection::error_reporting::TypeErrCtxt;
 use rustc_trait_selection::error_reporting::infer::sub_relations::SubRelations;
-use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt};
+use rustc_trait_selection::traits::{
+    self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt,
+};
 
 use crate::coercion::DynamicCoerceMany;
 use crate::fallback::DivergingFallbackBehavior;
@@ -310,6 +314,74 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
         ))
     }
 
+    fn select_inherent_assoc_candidates(
+        &self,
+        span: Span,
+        self_ty: Ty<'tcx>,
+        candidates: Vec<InherentAssocCandidate>,
+    ) -> (Vec<InherentAssocCandidate>, Vec<FulfillmentError<'tcx>>) {
+        let tcx = self.tcx();
+        let infcx = &self.infcx;
+
+        let mut universes = if self_ty.has_escaping_bound_vars() {
+            vec![None; self_ty.outer_exclusive_binder().as_usize()]
+        } else {
+            vec![]
+        };
+
+        let mut fulfillment_errors = vec![];
+        let candidates =
+            traits::with_replaced_escaping_bound_vars(infcx, &mut universes, self_ty, |self_ty| {
+                candidates
+                    .into_iter()
+                    .filter(|&InherentAssocCandidate { impl_, .. }| {
+                        infcx.probe(|_| {
+                            let ocx = ObligationCtxt::new_with_diagnostics(self);
+                            let self_ty =
+                                ocx.normalize(&ObligationCause::dummy(), self.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(), self.param_env, impl_ty);
+
+                            // Check that the self types can be related.
+                            if ocx
+                                .eq(&ObligationCause::dummy(), self.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(),
+                                self.param_env,
+                                impl_bounds,
+                            );
+                            let impl_obligations = traits::predicates_for_generics(
+                                |_, _| ObligationCause::dummy(),
+                                self.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()
+            });
+
+        (candidates, fulfillment_errors)
+    }
+
     fn lower_assoc_item_path(
         &self,
         span: Span,
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
index d8bab58545f..2a336cc21f4 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
@@ -127,7 +127,9 @@ impl<'tcx> Ty<'tcx> {
                 InhabitedPredicate::True
             }
             Never => InhabitedPredicate::False,
-            Param(_) | Alias(ty::Projection | ty::Free, _) => InhabitedPredicate::GenericType(self),
+            Param(_) | Alias(ty::Inherent | ty::Projection | ty::Free, _) => {
+                InhabitedPredicate::GenericType(self)
+            }
             Alias(ty::Opaque, alias_ty) => {
                 match alias_ty.def_id.as_local() {
                     // Foreign opaque is considered inhabited.
@@ -139,12 +141,6 @@ impl<'tcx> Ty<'tcx> {
                     }
                 }
             }
-            // FIXME(inherent_associated_types): Most likely we can just map to `GenericType` like above.
-            // However it's unclear if the args passed to `InhabitedPredicate::instantiate` are of the correct
-            // format, i.e. don't contain parent args. If you hit this case, please verify this beforehand.
-            Alias(ty::Inherent, _) => {
-                bug!("unimplemented: inhabitedness checking for inherent projections")
-            }
             Tuple(tys) if tys.is_empty() => InhabitedPredicate::True,
             // use a query for more complex cases
             Adt(..) | Array(..) | Tuple(_) => tcx.inhabited_predicate_type(self),
diff --git a/compiler/rustc_type_ir/src/fast_reject.rs b/compiler/rustc_type_ir/src/fast_reject.rs
index fa5e8d43702..a5d461c57cd 100644
--- a/compiler/rustc_type_ir/src/fast_reject.rs
+++ b/compiler/rustc_type_ir/src/fast_reject.rs
@@ -240,6 +240,13 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_
         self.types_may_unify_inner(lhs, rhs, Self::STARTING_DEPTH)
     }
 
+    pub fn types_may_unify_with_depth(self, lhs: I::Ty, rhs: I::Ty, depth_limit: usize) -> bool {
+        if lhs == rhs {
+            return true;
+        }
+        self.types_may_unify_inner(lhs, rhs, depth_limit)
+    }
+
     fn args_may_unify_inner(
         self,
         obligation_args: I::GenericArgs,
diff --git a/tests/crashes/136678.rs b/tests/crashes/136678.rs
deleted file mode 100644
index e7d7de23bfe..00000000000
--- a/tests/crashes/136678.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-//@ known-bug: #136678
-#![feature(inherent_associated_types)]
-#![feature(generic_const_exprs)]
-#![allow(incomplete_features)]
-
-struct B<const A: usize>;
-
-struct Test<const A: usize>;
-
-impl<const A: usize> Test<A> {
-    type B = B<{ A }>;
-
-    fn test(a: Self::B) -> Self::B {
-        a
-    }
-}
-
-pub fn main() {}
diff --git a/tests/crashes/138131.rs b/tests/crashes/138131.rs
index f400c02de8d..d0f91b74840 100644
--- a/tests/crashes/138131.rs
+++ b/tests/crashes/138131.rs
@@ -1,12 +1,15 @@
 //@ known-bug: #138131
-#![feature(min_generic_const_args)]
-#![feature(inherent_associated_types)]
+
+#![feature(min_generic_const_args, generic_const_items)]
+
+const BAR<'a>: usize = 10;
+
 struct Foo<'a> {
     x: &'a (),
 }
 
 impl<'a> Foo<'a> {
-    fn foo(_: [u8; Foo::X]) {}
+    fn foo(_: [u8; BAR]) {}
 }
 
 fn main() {}
diff --git a/tests/ui/associated-inherent-types/bound_vars_in_args.rs b/tests/ui/associated-inherent-types/bound_vars_in_args.rs
new file mode 100644
index 00000000000..276e3cf1da0
--- /dev/null
+++ b/tests/ui/associated-inherent-types/bound_vars_in_args.rs
@@ -0,0 +1,23 @@
+#![feature(non_lifetime_binders, inherent_associated_types)]
+#![expect(incomplete_features)]
+
+// Test that we can resolve to the right IAT when the self type
+// contains a bound type.
+
+struct Foo<T: ?Sized>(T);
+
+impl Foo<[u8]> {
+    type IAT = u8;
+}
+
+impl<T: Sized> Foo<T> {
+    type IAT = u8;
+}
+
+struct Bar
+//~^ ERROR: the size for values of type `T` cannot be known at compilation time
+//~| ERROR: the size for values of type `T` cannot be known at compilation time
+where
+    for<T> Foo<T>::IAT: Sized;
+
+fn main() {}
diff --git a/tests/ui/associated-inherent-types/bound_vars_in_args.stderr b/tests/ui/associated-inherent-types/bound_vars_in_args.stderr
new file mode 100644
index 00000000000..108f1e531af
--- /dev/null
+++ b/tests/ui/associated-inherent-types/bound_vars_in_args.stderr
@@ -0,0 +1,37 @@
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> $DIR/bound_vars_in_args.rs:17:1
+   |
+LL | struct Bar
+   | ^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `T`
+note: required by a bound in `Foo<T>::IAT`
+  --> $DIR/bound_vars_in_args.rs:13:9
+   |
+LL | impl<T: Sized> Foo<T> {
+   |         ^^^^^ required by this bound in `Foo<T>::IAT`
+LL |     type IAT = u8;
+   |          --- required by a bound in this associated type
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> $DIR/bound_vars_in_args.rs:17:1
+   |
+LL | / struct Bar
+LL | |
+LL | |
+LL | | where
+LL | |     for<T> Foo<T>::IAT: Sized;
+   | |______________________________^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `T`
+note: required by a bound in `Foo<T>::IAT`
+  --> $DIR/bound_vars_in_args.rs:13:9
+   |
+LL | impl<T: Sized> Foo<T> {
+   |         ^^^^^ required by this bound in `Foo<T>::IAT`
+LL |     type IAT = u8;
+   |          --- required by a bound in this associated type
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.stderr b/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.stderr
deleted file mode 100644
index 7f8ed898525..00000000000
--- a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.stderr
+++ /dev/null
@@ -1,33 +0,0 @@
-error[E0391]: cycle detected when computing predicates of `Foo`
-  --> $DIR/cycle-iat-inside-of-adt.rs:7:1
-   |
-LL | struct Foo {
-   | ^^^^^^^^^^
-   |
-note: ...which requires computing inferred outlives-predicates of `Foo`...
-  --> $DIR/cycle-iat-inside-of-adt.rs:7:1
-   |
-LL | struct Foo {
-   | ^^^^^^^^^^
-   = note: ...which requires computing the inferred outlives-predicates for items in this crate...
-note: ...which requires computing type of `Foo::bar`...
-  --> $DIR/cycle-iat-inside-of-adt.rs:8:5
-   |
-LL |     bar: Self::Bar,
-   |     ^^^^^^^^^^^^^^
-note: ...which requires computing normalized predicates of `Foo`...
-  --> $DIR/cycle-iat-inside-of-adt.rs:7:1
-   |
-LL | struct Foo {
-   | ^^^^^^^^^^
-   = note: ...which again requires computing predicates of `Foo`, completing the cycle
-note: cycle used when checking that `Foo` is well-formed
-  --> $DIR/cycle-iat-inside-of-adt.rs:7:1
-   |
-LL | struct Foo {
-   | ^^^^^^^^^^
-   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-where-predicate.rs b/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-where-predicate.rs
deleted file mode 100644
index 902094b9862..00000000000
--- a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-where-predicate.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-//@ known-bug: unknown
-
-#![feature(inherent_associated_types)]
-#![allow(incomplete_features)]
-
-// FIXME(inherent_associated_types): This shouldn't lead to a cycle error.
-
-fn user<T>() where S<T>::P: std::fmt::Debug {}
-
-struct S<T>;
-
-impl<T: Copy> S<T> {
-    type P = ();
-}
-
-fn main() {}
diff --git a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-where-predicate.stderr b/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-where-predicate.stderr
deleted file mode 100644
index e97a5df9d49..00000000000
--- a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-where-predicate.stderr
+++ /dev/null
@@ -1,37 +0,0 @@
-error[E0391]: cycle detected when computing predicates of `user`
-  --> $DIR/cycle-iat-inside-of-where-predicate.rs:8:1
-   |
-LL | fn user<T>() where S<T>::P: std::fmt::Debug {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: ...which requires computing explicit predicates of `user`...
-  --> $DIR/cycle-iat-inside-of-where-predicate.rs:8:1
-   |
-LL | fn user<T>() where S<T>::P: std::fmt::Debug {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires computing normalized predicates of `user`...
-  --> $DIR/cycle-iat-inside-of-where-predicate.rs:8:1
-   |
-LL | fn user<T>() where S<T>::P: std::fmt::Debug {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which again requires computing predicates of `user`, completing the cycle
-note: cycle used when checking that `user` is well-formed
-  --> $DIR/cycle-iat-inside-of-where-predicate.rs:8:1
-   |
-LL | fn user<T>() where S<T>::P: std::fmt::Debug {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
-
-error[E0392]: type parameter `T` is never used
-  --> $DIR/cycle-iat-inside-of-where-predicate.rs:10:10
-   |
-LL | struct S<T>;
-   |          ^ unused type parameter
-   |
-   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
-   = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0391, E0392.
-For more information about an error, try `rustc --explain E0391`.
diff --git a/tests/ui/associated-inherent-types/candidate-with-alias-2.rs b/tests/ui/associated-inherent-types/candidate-with-alias-2.rs
new file mode 100644
index 00000000000..d7be825a9c2
--- /dev/null
+++ b/tests/ui/associated-inherent-types/candidate-with-alias-2.rs
@@ -0,0 +1,26 @@
+#![feature(inherent_associated_types)]
+#![expect(incomplete_features)]
+
+trait Identity {
+    type Assoc;
+}
+impl<T> Identity for T {
+    type Assoc = T;
+}
+
+struct Foo<T>(T);
+impl Foo<<u8 as Identity>::Assoc> {
+    type Inherent = u8;
+}
+impl Foo<<u16 as Identity>::Assoc> {
+    type Inherent = u32;
+}
+
+struct Bar {
+    field: <Foo<u8>>::Inherent,
+    //~^ ERROR: multiple applicable items in scope
+}
+
+fn main() {
+    Bar { field: 10_u8 };
+}
diff --git a/tests/ui/associated-inherent-types/candidate-with-alias-2.stderr b/tests/ui/associated-inherent-types/candidate-with-alias-2.stderr
new file mode 100644
index 00000000000..335e35a9577
--- /dev/null
+++ b/tests/ui/associated-inherent-types/candidate-with-alias-2.stderr
@@ -0,0 +1,20 @@
+error[E0034]: multiple applicable items in scope
+  --> $DIR/candidate-with-alias-2.rs:20:23
+   |
+LL |     field: <Foo<u8>>::Inherent,
+   |                       ^^^^^^^^ multiple `Inherent` found
+   |
+note: candidate #1 is defined in an impl for the type `Foo<<u8 as Identity>::Assoc>`
+  --> $DIR/candidate-with-alias-2.rs:13:5
+   |
+LL |     type Inherent = u8;
+   |     ^^^^^^^^^^^^^
+note: candidate #2 is defined in an impl for the type `Foo<<u16 as Identity>::Assoc>`
+  --> $DIR/candidate-with-alias-2.rs:16:5
+   |
+LL |     type Inherent = u32;
+   |     ^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0034`.
diff --git a/tests/ui/associated-inherent-types/candidate-with-alias.rs b/tests/ui/associated-inherent-types/candidate-with-alias.rs
new file mode 100644
index 00000000000..d4dd002a774
--- /dev/null
+++ b/tests/ui/associated-inherent-types/candidate-with-alias.rs
@@ -0,0 +1,27 @@
+//@ check-pass
+
+#![feature(inherent_associated_types)]
+#![expect(incomplete_features)]
+
+trait Identity {
+    type Assoc;
+}
+impl<T> Identity for T {
+    type Assoc = T;
+}
+
+struct Foo<T>(T);
+impl Foo<<u8 as Identity>::Assoc> {
+    type Inherent = u8;
+}
+impl Foo<u16> {
+    type Inherent = u32;
+}
+
+struct Bar {
+    field: <Foo<u8>>::Inherent,
+}
+
+fn main() {
+    Bar { field: 10_u8 };
+}
diff --git a/tests/ui/associated-inherent-types/iat-in-where-bound.rs b/tests/ui/associated-inherent-types/iat-in-where-bound.rs
new file mode 100644
index 00000000000..3b8b95eec9a
--- /dev/null
+++ b/tests/ui/associated-inherent-types/iat-in-where-bound.rs
@@ -0,0 +1,14 @@
+//@ check-pass
+
+#![feature(inherent_associated_types)]
+#![allow(incomplete_features)]
+
+fn user<T: Copy>() where S<T>::P: std::fmt::Debug {}
+
+struct S<T>(T);
+
+impl<T: Copy> S<T> {
+    type P = ();
+}
+
+fn main() {}
diff --git a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.rs b/tests/ui/associated-inherent-types/iat-inside-of-adt.rs
index 64168cb8c14..3d88016d0f8 100644
--- a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.rs
+++ b/tests/ui/associated-inherent-types/iat-inside-of-adt.rs
@@ -1,8 +1,7 @@
-//@ known-bug: #108491
+//@ check-pass
 
 #![feature(inherent_associated_types)]
 #![allow(incomplete_features)]
-// FIXME(inherent_associated_types): This should pass.
 
 struct Foo {
     bar: Self::Bar,
@@ -11,4 +10,8 @@ impl Foo {
     pub type Bar = usize;
 }
 
-fn main() {}
+fn main() {
+    Foo {
+        bar: 10_usize,
+    };
+}
diff --git a/tests/crashes/125879.rs b/tests/ui/associated-inherent-types/inhabited-predicates.rs
index 4318842e455..2b041d4e1be 100644
--- a/tests/crashes/125879.rs
+++ b/tests/ui/associated-inherent-types/inhabited-predicates.rs
@@ -1,8 +1,10 @@
-//@ known-bug: rust-lang/rust#125879
+//@ check-pass
+
 #![feature(inherent_associated_types)]
-#![allow(incomplete_features)]
+#![expect(incomplete_features)]
 
 pub type PubAlias0 = PubTy::PrivAssocTy;
+//~^ WARN: associated type `PubTy::PrivAssocTy` is more private than the item `PubAlias0`
 
 pub struct PubTy;
 impl PubTy {
@@ -10,6 +12,7 @@ impl PubTy {
 }
 
 pub struct S(pub PubAlias0);
+//~^ WARN: associated type `PubTy::PrivAssocTy` is more private than the item `S::0`
 
 pub unsafe fn foo(a: S) -> S {
     a
diff --git a/tests/ui/associated-inherent-types/inhabited-predicates.stderr b/tests/ui/associated-inherent-types/inhabited-predicates.stderr
new file mode 100644
index 00000000000..e43cd034e67
--- /dev/null
+++ b/tests/ui/associated-inherent-types/inhabited-predicates.stderr
@@ -0,0 +1,27 @@
+warning: associated type `PubTy::PrivAssocTy` is more private than the item `PubAlias0`
+  --> $DIR/inhabited-predicates.rs:6:1
+   |
+LL | pub type PubAlias0 = PubTy::PrivAssocTy;
+   | ^^^^^^^^^^^^^^^^^^ type alias `PubAlias0` is reachable at visibility `pub`
+   |
+note: but associated type `PubTy::PrivAssocTy` is only usable at visibility `pub(crate)`
+  --> $DIR/inhabited-predicates.rs:11:5
+   |
+LL |     type PrivAssocTy = ();
+   |     ^^^^^^^^^^^^^^^^
+   = note: `#[warn(private_interfaces)]` on by default
+
+warning: associated type `PubTy::PrivAssocTy` is more private than the item `S::0`
+  --> $DIR/inhabited-predicates.rs:14:14
+   |
+LL | pub struct S(pub PubAlias0);
+   |              ^^^^^^^^^^^^^ field `S::0` is reachable at visibility `pub`
+   |
+note: but associated type `PubTy::PrivAssocTy` is only usable at visibility `pub(crate)`
+  --> $DIR/inhabited-predicates.rs:11:5
+   |
+LL |     type PrivAssocTy = ();
+   |     ^^^^^^^^^^^^^^^^
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-1.rs b/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-1.rs
new file mode 100644
index 00000000000..7723ee9c58d
--- /dev/null
+++ b/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-1.rs
@@ -0,0 +1,23 @@
+//@ check-pass
+
+#![feature(inherent_associated_types)]
+#![expect(incomplete_features)]
+
+// Test that when resolving an IAT we select candidates based
+// off whether the self type matches not just the name of the IAT
+
+struct Foo<T>(T);
+impl Foo<u8> {
+    type Inherent = u8;
+}
+impl Foo<u16> {
+    type Inherent = u32;
+}
+
+struct Bar {
+    field: <Foo<u16>>::Inherent,
+}
+
+fn main() {
+    Bar { field: 10_u32 };
+}
diff --git a/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-2.rs b/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-2.rs
new file mode 100644
index 00000000000..b942c303d3e
--- /dev/null
+++ b/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-2.rs
@@ -0,0 +1,29 @@
+#![feature(inherent_associated_types)]
+#![expect(incomplete_features)]
+
+// Test that when we have an unnormalized projection we don't normalize it
+// to determine which IAT to resolve to.
+
+struct Foo<T>(T);
+impl Foo<u8> {
+    type Inherent = u16;
+}
+impl Foo<u16> {
+    type Inherent = u32;
+}
+
+struct Bar {
+    field: <Foo<<u8 as Identity>::This>>::Inherent,
+    //~^ ERROR: multiple applicable items in scope
+}
+
+trait Identity {
+    type This;
+}
+impl<T> Identity for T { type This = T; }
+
+fn main() {
+    Bar {
+        field: 1_u16,
+    };
+}
diff --git a/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-2.stderr b/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-2.stderr
new file mode 100644
index 00000000000..df8c124f77f
--- /dev/null
+++ b/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-2.stderr
@@ -0,0 +1,20 @@
+error[E0034]: multiple applicable items in scope
+  --> $DIR/multiple-candidates-in-adt-field-2.rs:16:43
+   |
+LL |     field: <Foo<<u8 as Identity>::This>>::Inherent,
+   |                                           ^^^^^^^^ multiple `Inherent` found
+   |
+note: candidate #1 is defined in an impl for the type `Foo<u8>`
+  --> $DIR/multiple-candidates-in-adt-field-2.rs:9:5
+   |
+LL |     type Inherent = u16;
+   |     ^^^^^^^^^^^^^
+note: candidate #2 is defined in an impl for the type `Foo<u16>`
+  --> $DIR/multiple-candidates-in-adt-field-2.rs:12:5
+   |
+LL |     type Inherent = u32;
+   |     ^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0034`.
diff --git a/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-3.rs b/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-3.rs
new file mode 100644
index 00000000000..4c5b382463d
--- /dev/null
+++ b/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-3.rs
@@ -0,0 +1,27 @@
+//@ check-pass
+
+#![feature(inherent_associated_types, lazy_type_alias)]
+#![expect(incomplete_features)]
+
+// Test that we *do* normalize free aliases in order to resolve
+// between multiple IAT candidates
+
+type Free = u8;
+
+struct Foo<T>(T);
+impl Foo<u8> {
+    type Assoc = u16;
+}
+impl Foo<u16> {
+    type Assoc = u32;
+}
+
+struct Bar {
+    field: <Foo<Free>>::Assoc,
+}
+
+fn main() {
+    Bar {
+        field: 1_u16,
+    };
+}
diff --git a/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.rs b/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.rs
index c205cb800d2..337fd8fa00c 100644
--- a/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.rs
+++ b/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.rs
@@ -27,5 +27,5 @@ impl S<()> {
 fn main() {
     let _: S::<bool>::Pr = ();
     //[shadowed]~^ ERROR associated type `Pr` not found
-    //[uncovered]~^^ ERROR ambiguous associated type
+    //[uncovered]~^^ ERROR associated type `Pr` not found
 }
diff --git a/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr b/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr
index 3e914e0538d..f35158c5b41 100644
--- a/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr
+++ b/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr
@@ -1,15 +1,15 @@
-error[E0223]: ambiguous associated type
-  --> $DIR/not-found-self-type-differs-shadowing-trait-item.rs:28:12
+error[E0220]: associated type `Pr` not found for `S<bool>` in the current scope
+  --> $DIR/not-found-self-type-differs-shadowing-trait-item.rs:28:23
    |
+LL | struct S<T>(T);
+   | ----------- associated type `Pr` not found for this struct
+...
 LL |     let _: S::<bool>::Pr = ();
-   |            ^^^^^^^^^^^^^
-   |
-help: use fully-qualified syntax
-   |
-LL -     let _: S::<bool>::Pr = ();
-LL +     let _: <S<bool> as Tr>::Pr = ();
+   |                       ^^ associated item not found in `S<bool>`
    |
+   = note: the associated type was found for
+           
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0223`.
+For more information about this error, try `rustc --explain E0220`.
diff --git a/tests/ui/associated-inherent-types/really_deep_self_ty_mismatch.rs b/tests/ui/associated-inherent-types/really_deep_self_ty_mismatch.rs
new file mode 100644
index 00000000000..eac33f631bb
--- /dev/null
+++ b/tests/ui/associated-inherent-types/really_deep_self_ty_mismatch.rs
@@ -0,0 +1,26 @@
+//@ check-pass
+
+#![feature(inherent_associated_types)]
+#![expect(incomplete_features)]
+
+// Test that IAT resolution doesn't bail out when the self type is
+// very nested.
+
+struct Foo<T>(T);
+#[rustfmt::skip]
+impl Foo<Foo<Foo<Foo<Foo<Foo<Foo<Foo<Foo<Foo<Foo<u8>>>>>>>>>>> {
+    type Inherent = u16;
+}
+#[rustfmt::skip]
+impl Foo<Foo<Foo<Foo<Foo<Foo<Foo<Foo<Foo<Foo<Foo<u16>>>>>>>>>>> {
+    type Inherent = u32;
+}
+
+#[rustfmt::skip]
+struct Bar {
+    field: <Foo<Foo<Foo<Foo<Foo<Foo<Foo<Foo<Foo<Foo<Foo<u8>>>>>>>>>>>>::Inherent,
+}
+
+fn main() {
+    Bar { field: 1_u16 };
+}
diff --git a/tests/ui/const-generics/mgca/unresolved-iac-1.rs b/tests/ui/const-generics/mgca/unresolved-iac-1.rs
new file mode 100644
index 00000000000..a0700aa5b65
--- /dev/null
+++ b/tests/ui/const-generics/mgca/unresolved-iac-1.rs
@@ -0,0 +1,11 @@
+#![feature(min_generic_const_args)]
+#![feature(inherent_associated_types)]
+#![expect(incomplete_features)]
+
+struct A(Box<[u8; Box::b]>);
+//~^ ERROR: associated constant `b` not found for
+
+impl A {
+  fn c(self) { self.0.d() }
+}
+fn main() {}
diff --git a/tests/ui/const-generics/mgca/unresolved-iac-1.stderr b/tests/ui/const-generics/mgca/unresolved-iac-1.stderr
new file mode 100644
index 00000000000..4bf1191e786
--- /dev/null
+++ b/tests/ui/const-generics/mgca/unresolved-iac-1.stderr
@@ -0,0 +1,16 @@
+error[E0220]: associated constant `b` not found for `Box<{type error}, {type error}>` in the current scope
+  --> $DIR/unresolved-iac-1.rs:5:24
+   |
+LL |   struct A(Box<[u8; Box::b]>);
+   |                          ^ associated item not found in `Box<{type error}, {type error}>`
+  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+  ::: $SRC_DIR/alloc/src/boxed.rs:LL:COL
+   |
+   = note: associated constant `b` not found for this struct
+   |
+   = note: the associated constant was found for
+           
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0220`.
diff --git a/tests/ui/const-generics/mgca/unresolved-iac-2.rs b/tests/ui/const-generics/mgca/unresolved-iac-2.rs
new file mode 100644
index 00000000000..72bb5d7f627
--- /dev/null
+++ b/tests/ui/const-generics/mgca/unresolved-iac-2.rs
@@ -0,0 +1,14 @@
+#![feature(min_generic_const_args)]
+#![feature(inherent_associated_types)]
+#![expect(incomplete_features)]
+
+struct Foo<'a> {
+    x: &'a (),
+}
+
+impl<'a> Foo<'a> {
+    fn foo(_: [u8; Foo::X]) {}
+    //~^ ERROR: associated constant `X` not found for `Foo<'_>` in the current scope
+}
+
+fn main() {}
diff --git a/tests/ui/const-generics/mgca/unresolved-iac-2.stderr b/tests/ui/const-generics/mgca/unresolved-iac-2.stderr
new file mode 100644
index 00000000000..a6c12877a4e
--- /dev/null
+++ b/tests/ui/const-generics/mgca/unresolved-iac-2.stderr
@@ -0,0 +1,15 @@
+error[E0220]: associated constant `X` not found for `Foo<'_>` in the current scope
+  --> $DIR/unresolved-iac-2.rs:10:25
+   |
+LL | struct Foo<'a> {
+   | -------------- associated constant `X` not found for this struct
+...
+LL |     fn foo(_: [u8; Foo::X]) {}
+   |                         ^ associated item not found in `Foo<'_>`
+   |
+   = note: the associated constant was found for
+           
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0220`.