Surprising compiler error with trait bounds

Hi, for context, I'm currently working some interpolation code for images and ended up with a trait and a function defined similar to what follows (playground link):

trait CanInterpolate<V>
where
    V: Add<Output = V>,
    f32: Mul<V, Output = V>,
{
    fn to_vector(self) -> V;
    fn from_vector(v: V) -> Self;
}

fn interpolate<V, T>(a: f32, b: f32, c: T, d: T, e: T) -> T
where
    V: Add<Output = V>,
    f32: Mul<V, Output = V>,
    T: CanInterpolate<V>,
{
    let c_vec = c.to_vector();
    let d_vec = d.to_vector();
    let e_vec = e.to_vector();
    // T::from_vector((a+b) * c_vec + (a-b) * d_vec + (a*b) * e_vec) // not working
    T::from_vector((a+b) * c_vec + (a-b) * d_vec + Mul::<f32>::mul(a, b) * e_vec)
}

One line in the code is commented, because writing (a*b) confuses the compiler and forces it to believe that (a*b) must be of type V whereas it's totally fine as a regular f32. I thought the priority of operation with the parenthesis would make that clear. Do you know what is wrong with that line to make the compiler fail. Is there an issue with type inference maybe?

1 Like

Not an answer, but a fun fact: adding + Mul trait bound to the f32 in interpolate solves the issue (playground). Looks like the compiler "forgets" about all other implementations of trait for type (here, about Mul implementations for f32), when there is one of them in where clause.

2 Likes

Furthermore, this example does not compile too:

use core::ops::Mul;

fn test<V>() where f32: Mul<V, Output = V> {
    let _: f32 = 1f32 * 1f32;
}

The error is essentially the same (playground). Looks like definite bug. I'll try to research further.

3 Likes

Thanks for distilling it even more!

A short test showed that the same code (with core replaced by std, so that it could be potentially compiled on 2015 edition) yielded essentially the same error on Rust 1.0.0. Filed the issue on the Rust repo.

4 Likes

I'm gonna follow that one :slight_smile: