The problem is that someone can implement Storage , so From impl you wrote matches with impl in the standard impl<T> From<T> for T library (i.e. everything can be converted to itself).
In particular,
struct Tricky; impl Storage for Tricky { type Error = MyError<Tricky>; }
(The setting here means that it does not actually compile - MyError<Tricky> is infinitely large - but this error is not related to discussions about impl s / coherence / overlap and really small changes to MyError can compile it without changing the fundamental problem, for example, add Box as StorageProblem(Box<S::Error>), )
If we replace Tricky instead of S with your impl, we get:
impl From<MyError<Tricky>> for MyError<Tricky> { ... }
This impl exactly matches self-conversion with T == MyError<Tricky> , and therefore, the compiler does not know which one to choose. Instead of random / random selection, the Rust compiler avoids such situations, so the source code must be rejected due to this risk.
This limitation of connectivity can definitely be annoying and is one of the reasons that specialization is a highly anticipated feature: it essentially allows the compiler to manually instruct how to handle the overlap ... at least one of the extensions to the current restricted form allows this.
source share