-
-
Notifications
You must be signed in to change notification settings - Fork 14.5k
Description
(Originally reported in this comment in #31844)
In the following, we have a Child trait to represent a "parent-child" relationship between two types. Alice is a child of () and Bob is a child of Alice. Then, we have a trait Foo that we want to implement for Alice, and for all types that are children of a Foo (so Alice and Bob should both implement Foo):
#![feature(specialization)]
trait Child {
type Parent;
}
struct Alice;
impl Child for Alice {
type Parent = ();
}
struct Bob;
impl Child for Bob {
type Parent = Alice;
}
trait Foo { fn foo(&self); }
impl Foo for Alice {
fn foo(&self) { println!("Alice foo!"); }
}
// Implement for all children with parents that implement `Foo`
impl<T> Foo for T
where T: Child, T::Parent: Foo
{
default fn foo(&self) { println!("Descendant foo!"); }
}
fn main() {
Alice.foo();
Bob.foo();
}(playpen)
Expected output
The program should print "Alice foo!" and "Descendant foo!"
Actual output
The program fails to compile:
error[E0119]: conflicting implementations of trait `Foo` for type `Alice`:
--> <anon>:28:1
|
23 | impl Foo for Alice {
| - first implementation here
...
28 | impl<T> Foo for T
| ^ conflicting implementation for `Alice`
error: aborting due to previous error
Version info
$ rustc --version
rustc 1.13.0-nightly (55bf6a4f8 2016-09-18)
Other notes
There are two workarounds I've found to fix the error above.
The first is to just remove the T::Parent: Foo clause (which works in this case, but not so much for my actual usecase).
The second workaround is to introduce another trait, FooChild, which is implemented for all types where Self::Parent: Foo. We can then use FooChild in the where clause instead:
trait FooChild { }
impl<T> FooChild for T
where T: Child, T::Parent: Foo
{
}
// Implement for all children with parents that implement `Foo`
impl<T> Foo for T
// where T: Child, T::Parent: Foo
where T: FooChild
{
default fn foo(&self) { println!("Descendant foo!"); }
}
// ...(playpen)
Interestingly, the second workaround doesn't work when Child is moved into a separate crate (example repo)