Unexpected conflicting implementation for TryFrom

Viewed 66

I want to implement the trait TryFrom in a case like this:

struct T1;
struct T2(T1);

impl<U> TryFrom<U> for T2 where U: Into<T1> {
    type Error = ();
    fn try_from(val:U) -> Result<T2, Self::Error> {
        unimplemented!();
    }
}

which gives me this error:

error[E0119]: conflicting implementations of trait `std::convert::TryFrom<_>` for type `T2`
 --> src/lib.rs:4:1
  |
4 | impl<U> TryFrom<U> for T2 where U: Into<T1> {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: conflicting implementation in crate `core`:
          - impl<T, U> TryFrom<U> for T
            where U: Into<T>;

Here U implement Into<T1> not Into<T2> thus I don't really understand the error. I tried to confirm there is no blanket implementation by implementing this and it compiles without conflict:

struct T1;
struct T2(T1);

impl Into<T2> for T1 {
    fn into(self) -> T2 {
        unimplemented!();
    }
}

Is there any way around it? I don't want a default implementation here.

1 Answers

Trait implementations are not allowed to conflict. A type is perfectly allowed to implement both Into<T1> and Into<T2>. Your implementation would cause an ambiguity in this case whether to use the T: TryFrom<U> implementation by the built-in blanket implementation or from your blanket implementation. And thus there is a conflict and the compiler rejects your implementation.

Essentially you cannot implement TryFrom generically because of the blanket implementation; you can't avoid a potential conflict.

Your confirmation doesn't mean anything since there is no such blanket implementation for Into that would conflict between T1 and T2. If you tried to implement it generically, like impl Into<T2> for U where U: Into<T1>, that'd be a problem as well. The genericism is the core problem.

Related