Type Mismatch for Associated Type

I tried to compile the following code:

trait Foo {
    type Value;

    fn value() -> Self::Value
        Self: Bar;

trait Bar: Foo {}

struct Person {}

impl<T> Foo for T {
    type Value = String;

    fn value() -> Self::Value
        Self: Bar,

impl Bar for Person {}

fn main() {
    let x = Person::value();
    println!("{}", x);

but I get the following error:

error[E0308]: mismatched types
  --> temp2.rs:20:9
14 |     type Value = String;
   |     -------------------- expected this associated type
15 |
16 |     fn value() -> Self::Value
   |                   ----------- expected `<T as Foo>::Value` because of return type
20 |         String::from("hello")
   |         ^^^^^^^^^^^^^^^^^^^^^ expected associated type, found struct `std::string::String`
   = note: expected associated type `<T as Foo>::Value`
                       found struct `std::string::String`

For me, it's clearly that <T as Foo>::Value is std::string::String, since type Value = String;. Why the compiler cannot recognize it? Is this a compiler's bug? Or I'm doing something illogical here?

Here's some of my experiments:

  1. If I implement Foo only for Person (i.e. change the line impl<T> Foo for T to impl Foo for Person), it compiles.

  2. If I remove the restriction in value() that Self must implement Bar (i.e. remove the where Self: Bar in value() function), it compiles.

Originally, I thought the cause of this error is cycling dependency, i.e. when calling Person::value(), Person need to implement Bar (because of the where Self: Bar), which itself need to implement Foo (because of trait Bar: Foo). However, experiment 1 tells me that it's not the cause. Then I thought maybe there's something to do with generic, but experiment 2 tells me that impl<T> Foo for T works.


I tried to answer this question in stackoverflow, but I failed. I'm not sure whether this is a compiler's bug or not, so I'm asking it here. If it is, then I will open an issue on github.

The Self: Bar constraint is doing something weird here, because it works without it.

I believe this behavior is expected (if unfortunate). What happens here is that the <T as Foo>::Value projection is resolved using the Self: Bar (or T: Bar) where-clause instead of the written impl. It is intentional that where-clauses are preferred over free impls, but here the where-clause does not allow the <T as Foo>::Value projection to succeed (since the where-clause does not specify the type of Value).

Interesting point. It works if you remove the : Foo from trait Bar: Foo {}.

However, if I change only the line impl<T> Foo for T to impl Foo for Person (without removing where Self::Bar) as in my experiment 1, then it also compiles. Doesn't that mean the compiler is able to resolve <T as Foo>::Value to String?

Yes, that is somewhat surprising. I'm not sure where that discrepancy comes from.

So breaking the dependency cycle (remove either where Self: Bar or : Foo) makes it compile. Use concrete type directly instead of generics (change impl<T> Foo for T to impl Foo for Person) also makes it compile. It fails only if both dependency cycle and generic exist.