Boiethios
Boiethios

Reputation: 42789

Why does the compiler say that the call is ambiguous in associated types while it isn't?

This code:

trait SayHello {
    fn say_hello() { println!("hello") }
}

trait Foo {
    type Hello: SayHello;
}

trait Bar: Foo {
    type Hello: SayHello;
}

struct Generic<T>(T);

impl<T> Generic<T> where T: Bar<Hello = <T as Foo>::Hello> {
    fn say_hello() {
        T::Hello::say_hello()
    }
}

returns this error:

error[E0221]: ambiguous associated type `Hello` in bounds of `T`
  --> src/lib.rs:17:9
   |
6  |     type Hello: SayHello;
   |     --------------------- ambiguous `Hello` from `Foo`
...
10 |     type Hello: SayHello;
   |     --------------------- ambiguous `Hello` from `Bar`
...
17 |         T::Hello::say_hello()
   |         ^^^^^^^^^^^^^^^^^^^ ambiguous associated type `Hello`
   |
help: use fully qualified syntax to disambiguate
   |
17 |         <T as Foo>::Hello()
   |         ^^^^^^^^^^^^^^^^^
help: use fully qualified syntax to disambiguate
   |
17 |         <T as Bar>::Hello()
   |         ^^^^^^^^^^^^^^^^^

But there shouldn't be any ambiguity. It's clearly stated that the Hello associated type is the same in Foo and bar.

Upvotes: 2

Views: 1921

Answers (1)

sebpuetz
sebpuetz

Reputation: 2618

If T implements Bar, it also has to implement Foo, as per your bound on the trait. Therefore, T::Hello in say_hello() can both refer to <T as Foo>::Hello or <T as Bar>::Hello, which fixes your example.

It'd be possible to introduce another parameter H: SayHello and set both Foo::Hello and Bar::Hello to H. Dispatch to say_hello() then works via H::say_hello(), rather than T::Hello::say_hello().

struct Generic<T>(T);

impl<T, H> Generic<T> where T: Bar<Hello=H> + Foo<Hello=H>, H: SayHello {
    fn say_hello() {
        H::say_hello()
    }
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=920368d7c2d4e5eea98465de8b193b9e

Upvotes: 4

Related Questions