Skip to content

trait selection arbitrarily resolves projection ambiguities #77112

@benjaminp

Description

@benjaminp
trait Print<T> {
    fn print(self);
}

impl Print<char> for () {
    fn print(self) {
        println!("char");
    }
}

impl Print<usize> for () {
    fn print(self) {
        println!("usize")
    }
}

fn make1() -> impl Print<char> + Print<usize> {}

fn make2() -> impl Print<usize> + Print<char> {}

fn main() { 
    make1().print();
    make2().print();
}

The above program (https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=2e211dacba7209200273bf1bc6a2b77f) prints

usize
char

Not only does rustc pick without guidance between Print<char>::print and Print<usize>::print, but it depends on the ordering of the predicates in the impl traits!

This problem happens because trait selection wants to prove that make1() implements Print. To do that, it arbitrarily selects Print<usize> even though the Print<char> bound would also suffice at the time of inference. It makes the opposite eager selection for make2().

The same problem underlies #66057, where eager selection of projection bounds prevents further inference from removing the ambiguity.

Analogous problems exist for associated traits with multiple predicates as they go through the same trait selection code path.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-associated-itemsArea: Associated items (types, constants & functions)A-impl-traitArea: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch.A-type-systemArea: Type systemC-bugCategory: This is a bug.P-mediumMedium priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-langRelevant to the language team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions