Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1481,11 +1481,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
match assoc_tag {
// Don't attempt to look up inherent associated types when the feature is not
// enabled. Theoretically it'd be fine to do so since we feature-gate their
// definition site. However, due to current limitations of the implementation
// (caused by us performing selection during HIR ty lowering instead of in the
// trait solver), IATs can lead to cycle errors (#108491) which mask the
// feature-gate error, needlessly confusing users who use IATs by accident
// (#113265).
// definition site. However, the current implementation of inherent associated
// items is somewhat brittle, so let's not run it by default.
ty::AssocTag::Type => return Ok(None),
ty::AssocTag::Const => {
// We also gate the mgca codepath for type-level uses of inherent consts
Expand Down Expand Up @@ -1514,9 +1511,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
})
.collect();

Copy link
Member Author

@fmease fmease Nov 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Obviously this is but a hotfix for a minute part of #142006. I was briefly toying with the idea of properly addressing #142006 now but for that I would need to rewrite type-relative path resolution in HIR ty lowering to properly assemble inherent & trait candidates (instead of eagerly trying to resolve them in sequence) but I realized I would only be stepping on your toes / doing throwaway work (#145825).

// At the moment, we actually bail out with a hard error if the selection of an inherent
// associated item fails (see below). This means we never consider trait associated items
// as potential fallback candidates (#142006). To temporarily mask that issue, let's not
// select at all if there are no early inherent candidates.
if candidates.is_empty() {
return Ok(None);
}

let (applicable_candidates, fulfillment_errors) =
self.select_inherent_assoc_candidates(span, self_ty, candidates.clone());

// FIXME(#142006): Don't eagerly error here, there might be applicable trait candidates.
let InherentAssocCandidate { impl_, assoc_item, scope: def_scope } =
match &applicable_candidates[..] {
&[] => Err(self.report_unresolved_inherent_assoc_item(
Expand All @@ -1537,6 +1543,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
)),
}?;

// FIXME(#142006): Don't eagerly validate here, there might be trait candidates that are
// accessible (visible and stable) contrary to the inherent candidate.
self.check_assoc_item(assoc_item, name, def_scope, block, span);

// FIXME(fmease): Currently creating throwaway `parent_args` to please
Expand Down
25 changes: 25 additions & 0 deletions tests/ui/associated-inherent-types/fall-back-to-trait-candidate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Ensure that IAT selection doesn't hard error on associated type paths that could refer to
// an inherent associated type if we can't find an applicable inherent candidate since there
// might still be valid trait associated type candidates.
//
// FIXME(#142006): This only covers the bare minimum, we also need to disqualify inherent
// candidates if they're inaccessible or if the impl headers don't match / apply.
//
// issue: <https://github.com/rust-lang/rust/issues/142006#issuecomment-2938846613>
//@ check-pass

#![feature(inherent_associated_types)]
#![expect(incomplete_features)]

struct Type;
trait Trait { type AssocTy; fn scope(); }

impl Trait for Type {
type AssocTy = ();

fn scope() {
let (): Self::AssocTy;
}
}

fn main() { <Type as Trait>::scope(); }
Copy link
Member Author

@fmease fmease Nov 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wrote this test and it's rooted in a deep misconception, namely that there can't ever be a case where we would pick a trait candidate over an inherent one. Back then I didn't know about #142006.

In essence, I don't like this test, hence its removal. Once we fix #142006, we'll have plenty of tests regarding "candidate preference/elimination".

This file was deleted.

This file was deleted.

This file was deleted.

28 changes: 28 additions & 0 deletions tests/ui/associated-inherent-types/prefer-inherent-over-trait.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#![feature(inherent_associated_types)]
#![expect(incomplete_features)]

// Ensure that prefer inherent associated types over trait associated types
// (assuming the impl headers match and they're accessible).
//@ check-pass

struct Adt;

impl Adt {
type Ty = ();
}

trait Trait {
type Ty;
fn scope();
}

impl Trait for Adt {
type Ty = i32;
fn scope() {
// We prefer the inherent assoc ty `Adt::Ty` (`()`) over the
// trait assoc ty `<Adt as Trait>::Ty` (`i32`).
let (): Self::Ty;
}
}

fn main() {}
Loading