Attempting to compile this as-is produces the following compile error:
error[E0119]: conflicting implementations of trait `TryFrom<_>` for type `A`
--> src/lib.rs:7:1
|
7 | impl<T> TryFrom<T> for A {
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- impl<T, U> TryFrom<U> for T
where U: Into<T>;
My current understanding is that it's not possible to implement TryFrom<T> using a generic type parameter T like this because this impl means that for any and every type T that could possibly exist, TryFrom<T> is implemented for A. Some of these types T might also implement Into<A>and for those that do, an implementation of TryFrom<T> for A is already provided by the blanket impl defined in std: impl<T, U> TryFrom<U> for T where U: Into<T>.
Is this explanation correct? And if so, why isn't it possible to exclude all types T which might implement Into<A> using a trait bound like this?
trait MyTrait;
struct A;
impl<T: MyTrait> TryFrom<T> for A {
type Error = Infallible;
fn try_from(_input: T) -> Result<Self, Self::Error> { Ok(A) }
}
It seems to me that since MyTrait is a private trait, only types defined the same crate can implement it, and therefore impl<T: MyTrait> TryFrom<T> for A only applies to a finite set of types T which can all be proven not to implement Into<A> and therefore not introduce a trait impl conflict via the blanket impl. If this is not possible why not?
A implements From<A> via From’s blanket implementation, and therefore the standard library implements TryFrom<A> for A, which overlaps with your implementation when T = A. Therefore, your implementation does overlap and even a perfect compiler must not allow it. (Update: this is incorrect, because there is no impl MyTrait for A.)
(If Rust had “not equals” bounds on type parameters, then you could require T != A, but this has the same kinds of issues as specialization.)
True, but A does not implement MyTrait, so shouldn't A be excluded from the possible types of T via the trait bound T: MyTrait? If the entire crate was just
trait MyTrait {}
struct A;
struct B;
impl MyTrait for B {}
impl<T: MyTrait> TryFrom<T> for A {
type Error = Infallible;
fn try_from(_input: T) -> Result<Self, Self::Error> { Ok(A) }
}
Wouldn't B be the only possible type in the universe that could match the generic type parameter T in the impl<T: MyTrait> TryFrom<T> for A? If B is the only possible T and B does not implement Into<A>, it seems that there should be no trait impl conflict with the blanket impl from std.
I still get the conflict with the blanket impl from std (impl<T, U> TryFrom<U> for T where U: Into<T>). Does anyone know why restricting the type of T in with the trait bound : MyTrait in impl<T: MyTrait> TryFrom<T> for A is not sufficient to satisfy the coherence checker? The way I see it, the only type that could ever match T is B which does not implement Into<A>, so I'm not seeing where the trait impl conflict is coming from.