Wrong type in error message note when return type is tuple

I found an unusual error message when tried to compile the following code -

fn test_error_msg() -> (
    HashSet<&'static HttpReq>,
) {
    let mut qps:Vec<Vec<u32>> = Vec::with_capacity(10);
    let mut conn_count:Vec<Vec<u32>> = Vec::with_capacity(10);
    let mut req_to_secondaries: HashSet<&HttpReq> = HashSet::new();
    (qps, req_to_secondaries, conn_count)

One of the error messages is

error[E0308]: mismatched types
  --> src/main.rs:20:5
10 |   fn test_error_msg() -> (
   |  ________________________-
11 | |     Vec<u32>,
12 | |     Vec<u32>,
13 | |     HashSet<&'static HttpReq>,
14 | |     Vec<ConnectionCount>,
15 | |     Vec<ConnectionCount>,
16 | | ) {
   | |_- expected `(Vec<u32>, Vec<u32>, HashSet<&'static HttpReq>, Vec<ConnectionCount>, Vec<ConnectionCount>)` because of return type
20 |       (qps, req_to_secondaries, conn_count)
   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected a tuple with 5 elements, found one with 3 elements
   = note: expected tuple `(Vec<u32>, Vec<u32>, HashSet<&'static HttpReq>, Vec<ConnectionCount>, Vec<ConnectionCount>)`
              found tuple `(Vec<u32>, Vec<u32>, HashSet<&'static HttpReq>)`

In the note it says found tuple `(Vec<u32>, Vec<u32>, HashSet<&'static HttpReq>)` but what I'm actually returning is (Vec<Vec<u32>>, Vec<Vec<u32>>, HashSet<&'static HttpReq>)

Is it a bug or there's a reason behind it?

The return type is the 5-element tuple that the error message is talking about. There is no particular meaning behind what is "expected" and what is "found", since Rust's type system (and inference) work via unification. Unification is a logical process which concerns equality of types, and it doesn't really matter where a type comes from (is it from the declaration of the return type or is it inferred from a value). So the situation is symmetric, and there is no particular reason why one or the other of two mismatched types comes out as "expected" or "found".

1 Like

Seems like a diagnostics bug to me

let x: (i32,) = (0i64, 0i64);
error[E0308]: mismatched types
 --> src/main.rs:2:21
2 |     let x: (i32,) = (0i64, 0i64);
  |            ------   ^^^^^^^^^^^^ expected a tuple with 1 element, found one with 2 elements
  |            |
  |            expected due to this
  = note: expected tuple `(i32,)`
             found tuple `(i32, i64)`

When the tuples are of different lengths, the error message will use the types of the elements from the expected type in its found type even when they're different.


It's probably just continuing on assuming you wanted the ascribed/expected type to be able to report more errors.

(For example)
  • Type check (0i64, 0i64) against expected (i32,)
    • [recurse to find type]
      • Type check 0i64 against expected i32
        • Error, it's an i64... but continue on so we can give more errors, so:
        • [type is i32]
      • Type check 0i64 with no expectation
        • [type is i64]
      • [type is (i32, i64)
    • Error, it's a (i32, i64) not a (i32,)... but continue on
  • [type of x still considered to be (i32,)]

E.g. foo here doesn't throw an error about not being able to debug print.

Not sure how costly it would be to recursively carry around infalliably incorrect types.