Here is a kind of lengthy example because I was not able to reduce it further. Rust Playground
use std::marker::PhantomData;
use std::ops::{Add, Sub, Mul, Di
ScalarVal(1) + a resolves basically to <ScalarVal(1) as Add>.add(a), which looks for an Add implementation on ScalarVal.
For whatever reason, this one is checked first:
impl<PixelP> Add<Image<PixelP>> for ScalarVal<<PixelP as Pixel>::ScalarType>
where PixelP: Pixel,
ScalarVal<<PixelP as Pixel>::ScalarType>: Add<PixelP, Output = PixelP>
PixelP is uninstantiated at this point, so PixelP: Pixel can't be checked. Thus we get to
ScalarVal<<PixelP as Pixel>::ScalarType>: Add<PixelP, Output = PixelP>
Let's simplify this. Since PixelP is unknown right now, <PixelP as Pixel>::ScalarType is unknown. The actual information known by the compiler looks more like
impl<T> Add<Image<T>> for ScalarVal<_>
where ScalarVal<_>: Add<T, Output = T>
So ScalarVal<_> looks for an Add<T, Output = T>. This means we should look for an appropriate T. Obviously this means looking in ScalarVal's Add impls. Looking at the same one, we get
impl<T2> Add<Image<T2>> for ScalarVal<_>
where ScalarVal<_>: Add<T2, Output = T2>
which means that if this one matches, T == Image<T2>.
Obviously then T2 == Image<T3>, T3 == Image<T4>, etc. This results in an overflow and general sadness. Rust never finds a disproof, so can't ever guarantee it's going down the wrong path.