Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Specialization doesn't work when an impl has an associated type bound #36587

Closed
kylewlacy opened this issue Sep 19, 2016 · 2 comments
Closed
Labels
A-specialization Area: Trait impl specialization

Comments

@kylewlacy
Copy link

(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)

@apasel422 apasel422 added the A-specialization Area: Trait impl specialization label Sep 28, 2016
@apasel422
Copy link
Contributor

The original example exhibits conflicting implementations even without specialization (because () doesn't implement Foo, the generic impl doesn't apply to Alice), which makes me think this is related to or a duplicate of #23341.

@Mark-Simulacrum
Copy link
Member

I'm going to close in favor of #23341.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-specialization Area: Trait impl specialization
Projects
None yet
Development

No branches or pull requests

3 participants