Skip to content

If inherent associated type selection fails, we should still consider trait associated type candidates as a fallback #142006

Open
@fmease

Description

@fmease

For context, applicable inherent associated item candidates shadow trait associated item ones (where applicable means the self type of the candidate impl unifies and its predicates hold). IAT selection does respect that which is good as it follows the behavior of associated functions and constants (in bodies).

However, contrary to inherent associated functions and constants (in bodies), we currently bail out early with a hard error if we fail to select an applicable IAT! Moreover assuming PR #140247 gets merged in its current form, this will extend to candidates in general. Meaning, we'll error early if there are no candidates whatsoever! (See my separate comment for an example).

Ideally, we'd only fail overall if we also failed to find a suitable trait associated type candidate (by means of resolve_type_relative_path). Rephrased, inapplicable IAT candidates should not shadow trait assoc ty candidates.

Examples

Inherent Associated Types

These should compile but currently don't for the reason mentioned above.

#![feature(inherent_associated_types)]

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

impl Type // *inapplicable* impl candidate (predicate `<String as Copy>` is unsatisfied)
where
    for<'_delay> String: Copy,
{
   type AssocTy = i32; // the IAT
}

impl Trait for Type {
    type AssocTy = ();

    fn scope() {
        let (): Self::AssocTy; //~ ERROR the associated type `AssocTy` exists for `Type`, but its trait bounds were not satisfied
//              ^^^^^^^^^^^^^ Ideally, this would resolve to the *trait* associated type
//                            `<Self as Trait>::AssocTy` (via resolve_type_relative_path/SelfTyAlias)
//                            given the fact that the IAT candidate is *inapplicable*!
    }
}

fn main() { <Type as Trait>::scope(); }
#![feature(inherent_associated_types)]

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

impl Type<u128> { // *inapplicable* impl candidate (`u128` doesn't unify with `()`)
   type AssocTy = i32; // the IAT
}

impl Trait for Type<()> {
    type AssocTy = ();

    fn scope() {
        let (): Self::AssocTy; //~ ERROR associated type `AssocTy` not found for `Type<()>` in the current scope
//              ^^^^^^^^^^^^^ Ideally, this would resolve to the *trait* associated type
//                            `<Self as Trait>::AssocTy` (via resolve_type_relative_path/SelfTyAlias)
//                            given the fact that the IAT candidate is *inapplicable*!
    }
}

fn main() { <Type<()> as Trait>::scope(); }

Inherent Associated Functions & Constants

When resolving associated functions and constants (in bodies), inapplicable inherent candidates do not shadow trait candidates, so the following cases pass compilation as expected and exit with 0 when executed.

Example | IAC&IAF inapplicable (unsatisfied predicate)
//@ run-pass

struct Type;
trait Trait {
    const C: i32; fn f() -> i32;
    fn scope();
}

impl Type // *inapplicable* impl candidate
where
    for<'_delay> String: Copy,
{
   const C: i32 = 0; fn f() -> i32 { 0 }
}

impl Trait for Type {
    const C: i32 = 1; fn f() -> i32 { 1 }
    fn scope() {
        assert_eq!((Self::C, Self::f()), (1, 1)); // OK!
    }
}

fn main() { <Type as Trait>::scope(); }
Example | IAC&IAF inapplicable (ununifiable self ty)
//@ run-pass

struct Type<T>(T);
trait Trait { const C: i32; fn f() -> i32; fn scope(); }

impl Type<u128> { // *inapplicable* impl candidate
    const C: i32 = 0; fn f() -> i32 { 0 }
}

impl Trait for Type<()> {
    const C: i32 = 1; fn f() -> i32 { 1 }

    fn scope() {
         assert_eq!((Self::C, Self::f()), (1, 1)); // OK!
    }
}

fn main() { <Type<()> as Trait>::scope(); }

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.F-inherent_associated_types`#![feature(inherent_associated_types)]`T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-typesRelevant to the types team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    Status

    To Do

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions