Understanding conflicting blanket implementation when a new candidate is defined

⚓ Rust    📅 2025-10-03    👤 surdeus    👁️ 6      

surdeus

Hello! Sorry if this is a common question; it's a bit hard to search...
I am struggling to find a properly substantiated explanation (not just a guess) as to why the following happens:

Consider this:

struct Wrapper<T>(T);
trait E {}

impl<A, B> From<A> for Wrapper<B>
where
    A: Into<B> + E,
{
    fn from(value: A) -> Self {
        Self(value.into())
    }
}

struct X {}
impl E for Wrapper<X> {}

struct Y {}
impl E for Wrapper<Y> {}

fn main() {}

This does not compile:

error[E0119]: conflicting implementations of trait `From<Wrapper<_>>` for type `Wrapper<_>`
 --> src/main.rs:4:1
  |
4 | / impl<A, B> From<A> for Wrapper<B>
5 | | where
6 | |     A: Into<B> + E,
  | |___________________^
  |
  = note: conflicting implementation in crate `core`:
          - impl<T> From<T> for T;

I assume it's considering the possibility where, in the context of the blanket implementation, for some type U, A = Wrapper<U> and B = U; thus the implementation looks like impl<U> From<Wrapper<U>> for Wrapper<U>, which conflicts with the core implementation of impl<T> From<T> for T (T = Wrapper<U>).

But then, the actual question: why does it compile if one removes the line impl E for Wrapper<Y> {}, so there is only one implementation of E for a concrete type (X), or both of them?

  1. // impl E for Wrapper<X> {}
    // impl E for Wrapper<Y> {}
    
    Compiles;
  2. impl E for Wrapper<X> {}
    // impl E for Wrapper<Y> {}
    
    // or vice-versa
    
    Compiles;
  3. impl E for Wrapper<X> {}
    impl E for Wrapper<Y> {}
    // or more
    
    Does not compile.

How are cases 2 and 3, in particular, different? Does having two distinct types implementing that same trait somehow enable an overlap that does not occur with only one and I'm not seeing? Is the compiler analyzing generally different things in one case vs the other?

1 post - 1 participant

Read full topic

🏷️ Rust_feed