Partition trait implementation based on associated type of other trait

I want to implement a trait A for all implementers of another trait B, but I want to have different implementations based on the associated type of this other trait. This should be possible in theory since the associated type of a trait is unique for an implementer and therefore it should partition the implementers without overlap.

This is the code that does not compile:

struct S1;
struct S2;

trait A {
    type O;
}

trait B {}

impl<T> B for T where T: A<O = S1> {}
impl<T> B for T where T: A<O = S2> {}

I get this error when compiling:

error[E0119]: conflicting implementations of trait `B`
  --> src/lib.rs:11:1
   |
10 | impl<T> B for T where T: A<O = S1> {}
   | ---------------------------------- first implementation here
11 | impl<T> B for T where T: A<O = S2> {}
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation

For more information about this error, try `rustc --explain E0119`.
error: could not compile `playground` (lib) due to 1 previous error

Why is this not possible? Is there some fundamental problem or is it just a missing feature in the type checker? Is it somehow possible to achieve what I want (favorably on stable Rust)?

This is a long-standing missing feature: Can't write non-overlapping blanket impls that involve associated type bindings · Issue #20400 · rust-lang/rust · GitHub. It requires both implementation work and consideration of the design implications.

For now, the general principle is that you can only have at most one impl<T> Trait for T, regardless of what bounds T has.

1 Like

Here's a workaround.

1 Like

Ah thanks for the help! That is awesome.

Unfortunately my example was a bit simplified and my underlying problem is a bit different (but related) and I don't think your workaround will work there.

Basically I want to do the following:

struct S1;
struct S2;

struct G<T>(T);

trait A {
    type O;
}

impl<T> From<u32> for G<T> where T: A<O = S1> {}
impl<T> TryFrom<u32> for G<T> where T: A<O = S1> {}

(this is still a simplification but I don't want to make this more complicated)