Mismatched Types and Incorrect Arguments

Compiling my library I get 3 errors. All are mismatched types or incorrect arguments. The first is as follows:

fn fdsolve21_<T>(a: &ArrayView2<f64>, b: &ArrayView1<T>) -> Array1<T>
    |               - expected this type parameter
337 |     let (p, l, u, q) = pluq_decomp(&a.view(), PivotMethod::Rook);
    |                        ----------- ^^^^^^^^^ expected `&ArrayBase<ViewRepr<&T>, Dim<[usize; 2]>>`, found `&ArrayBase<ViewRepr<&f64>, Dim<[usize; 2]>>`
    |                        |
    |                        arguments to this function are incorrect
    = note: expected reference `&ArrayBase<ViewRepr<&T>, _>`
               found reference `&ArrayBase<ViewRepr<&f64>, _>

I do not understand why this is true. The function pluq_decomp allows a generic type T input, and f64 should therefore be valid input.

fn pluq_decomp<T>(a: &ArrayView2<T>, pivot: PivotMethod) -> (Array2<f64>, Array2<T>, Array2<T>, Array2<f64>)
    T: Signed + Num + PartialOrd + Clone + One + Zero + Sum + for<'a> Div<&'a T, Output=T>,
    for<'a> &'a T: Mul<&'a T, Output=T> + Sub<T, Output=T>,

I do not know if the fact that f64 and T as separate type inputs to the function pluq_decomp means that T cannot also be an f64, even though it satisfies trait bounds?

I think understanding this better will help me solve these errors.

When you have a generic type parameter, it's the caller who chooses the type, not the callee.

1 Like

No, there is no rule that type parameters must be different.

Based on the error, you must be doing something with the outputs of pluq_decomp that is causing pluq_decomp's T to be constrained equal to fdsolve21_'s T, thus causing pluq_decomp to expect its a to be &ArrayView2<T> and not &ArrayView2<f64>.

We need to see the full code of fdsolve21_, and preferably a full program that we can compile on the Playground and get the same errors — type inference problems cannot be fully understood without all the code that produced them.

1 Like

This is the most mininmal version I can produce that reproduces the error: Rust Playground

Okay, so consider the following logic. (In my text, T here always means the type parameter T of fdsolve21_, not the type parameter of any other function that also happens to be named T.)

  • fdsolve21_ returns an array that is computed from (among other things) l and u, and the returned array must have element type T.
  • Therefore, by the signatures of solve_lower_1d and solve_upper_1d, l and u must have element type T.
  • Therefore, pluq_decomp's return values that become l and u have element type T.
  • Therefore, the generic arguments to pluq_decomp must be pluq_decomp::<T>, not pluq_decomp::<f64>.
  • Therefore, you get a type error because you passed an array with element type f64, not T.

I expect that the place where the problem actually lies is either:

  • you passed the wrong variable (that had the wrong type) to one of those function calls, or
  • you want to be able to multiply f64 and T in some of the later steps, but their function signatures don't allow it.

What you can do to help diagnose the problem is add more type annotations; in particular, you can change the line

let (p, l, u, q) = pluq_decomp(&a.view(), PivotMethod::Rook);

to whichever one of these matches your intent,

let (p, l, u, q) = pluq_decomp::<f64>(&a.view(), PivotMethod::Rook);
let (p, l, u, q) = pluq_decomp::<T>(&a.view(), PivotMethod::Rook);

to force the type error to happen in a different place that is closer to where the problem is. This is a general characteristic of type inference across many variables, not even specific to Rust: errors can pop up far away from the mistake because the compiler doesn't know what you meant each of the intermediate steps to be. So, adding type annotations gives the compiler more info about what you meant and helps it give you a better error. Besides writing the function call generics explicitly, giving type annotations to each of the variables is also a good idea.

1 Like

Thanks this was very useful tip for debugging purposes.
I think I found it. Whilst I have been careful to try to account for the case with working with 'T and T' or 'f64 and T' with separate functions for the cases, I have missed the case for solve_upper_1d and solve_lower_1d. This function only permitted 'T and T' which I think is what led the compiler to expect a T when an f64 was given. I will branch that and see what happens.