Why does this `Into` trait impl conflicts with the blanket impl?

This code gives the following error message:

   Compiling playground v0.0.1 (/playground)
error[E0119]: conflicting implementations of trait `std::convert::Into<_>` for type `Wrapper<_>`
 --> src/lib.rs:3:1
  |
3 | impl<T> Into<T> for Wrapper<T> {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: conflicting implementation in crate `core`:
          - impl<T, U> Into<U> for T
            where U: From<T>;

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

IIUC this blanket impl is only valid if U: From<T> - in this case, it would be T: From<Wrapper<T>>, but since this bound isn't implemented, why is there a conflict?

Thanks!

It's not enough for the compiler to consider what traits are currently implemented – it has to consider what traits are possible to implement. Otherwise, the mere addition of a trait would be a breaking change, which is undesirable. You are only allowed to create impls which are impossible to create otherwise – this is why there are seemingly funny rules around ordering of type parameters in generic impls.

5 Likes

For a more concrete example, you probably agree it's reasonable that you should be able to implement this:

impl<T> AsRef<T> for Wrapper<T> {
    fn as_ref(&self) -> &T {
        &self.0
    }
}

As after all, you "own" Wrapper. But elsewhere, I might have a type like so:

#[derive(Clone)]
struct Mine;
impl<U> From<U> for Mine where U: AsRef<Mine> {
    fn from(you: U) -> Self {
        you.as_ref().clone()
    }
}

Which is also perfectly reasonable as I own Mine. But note, this is an implementation of Mine: From<Wrapper<Mine>> due to the generics involved.

Playground.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.