ScalarVal(1) + a allows basically <ScalarVal(1) as Add>.add(a) , which is looking for an Add implementation on ScalarVal .
For some reason, this 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 not confirmed at this point, therefore PixelP: Pixel cannot be verified. So we get
ScalarVal<<PixelP as Pixel>::ScalarType>: Add<PixelP, Output = PixelP>
Let it simplify. Since PixelP unknown right now, <PixelP as Pixel>::ScalarType unknown. The actual information known to the compiler is more like
impl<T> Add<Image<T>> for ScalarVal<_> where ScalarVal<_>: Add<T, Output = T>
So ScalarVal<_> looking for Add<T, Output = T> . This means that we must look for a suitable T Obviously, this means a search in ScalarVal Add impl s. Looking at the same, we get
impl<T2> Add<Image<T2>> for ScalarVal<_> where ScalarVal<_>: Add<T2, Output = T2>
which means that if it matches, T == Image<T2> .
Obviously, then T2 == Image<T3> , T3 == Image<T4> , etc. This leads to overflow and general sadness. Rust never detects intelligibility, so it can never guarantee that it is going the wrong way.