Search code examples
rusttype-inference

What is the difference between [fn] vs [(fn, u8)] in terms of type-inference?


Why does this compile:

fn main() {
   let xs = [||1, ||2, ||3];
}

but this does not?

fn main() {
   let xs = [(||1, 1), (||2, 2), (||3, 3)];
}
error[E0308]: mismatched types
 --> src/main.rs:2:29
  |
2 |     let xs = [((|| 1), 1), ((|| 2), 2), ((|| 3), 3)];
  |                 --          ^^^^^^ expected closure, found a different closure
  |                 |
  |                 the expected closure
  |
  = note: expected closure `{closure@src/main.rs:2:17: 2:19}`
             found closure `{closure@src/main.rs:2:30: 2:32}`
  = note: no two closures, even if identical, have the same type
  = help: consider boxing your closure and/or using it as a trait object

error[E0308]: mismatched types
 --> src/main.rs:2:42
  |
2 |     let xs = [((|| 1), 1), ((|| 2), 2), ((|| 3), 3)];
  |                 -- the expected closure  ^^^^^^ expected closure, found a different closure
  |
  = note: expected closure `{closure@src/main.rs:2:17: 2:19}`
             found closure `{closure@src/main.rs:2:43: 2:45}`
  = note: no two closures, even if identical, have the same type
  = help: consider boxing your closure and/or using it as a trait object

To be clear, the question is not why does it not compile. It is what is the difference between these two that makes the first compile but the second does not?.


Solution

  • The first case is special cased in the compiler: when some types are required to unify (such as when all of them are elements of the same array), and all of them are non-capturing closures, the compiler automatically coerces them to function pointers. This does not work if they are tuple that contain non-capturing closures, however.

    The relevant code in rustc is here, if you're interested.