I tried to compile the following code:
trait Foo {
type Value;
fn value() -> Self::Value
where
Self: Bar;
}
trait Bar: Foo {}
struct Person {}
impl<T> Foo for T {
type Value = String;
fn value() -> Self::Value
where
Self: Bar,
{
String::from("hello")
}
}
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:
-
If I implement
Foo
only forPerson
(i.e. change the lineimpl<T> Foo for T
toimpl Foo for Person
), it compiles. -
If I remove the restriction in
value()
thatSelf
must implementBar
(i.e. remove thewhere Self: Bar
invalue()
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.
Background
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.