Repository: rust
Issue: "type annotations needed" in closure hints at suboptimal fix
Labels: A-diagnostics,T-compiler

<!--
Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
along with any information you feel relevant to replicating the bug.

If you cannot produce a minimal reproduction case (something that would work in
isolation), please provide the steps or even link to a repository that causes
the problematic output to occur.
-->

Given the following code: [play.rust-lang.org](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=400b1729dce810a5a01bca62c8d08601)

```rust
fn main() {
    let v: Vec<String> = vec![  // annotating Vec<String> here to make sure the error is unrelated
        "foo".to_string(),
        "bar".to_string(),
    ];
    let choose = |i| {
        if i < v.len() {
            &v[i]
        } else {
            ""
        }
    };
    println!("{:?}", choose(1usize));  // also 1usize for the same reason as above
}
```

The current output is:

```
   Compiling playground v0.0.1 (/playground)
error[E0271]: type mismatch resolving `<usize as SliceIndex<[String]>>::Output == str`
 --> src/main.rs:8:14
  |
8 |             &v[i]
  |              ^^^^ expected struct `String`, found `str`

For more information about this error, try `rustc --explain E0271`.
error: could not compile `playground` due to previous error

```
(no difference seen between nightly/beta/stable)

Ideally the output should look like:

```
   Compiling playground v0.0.1 (/playground)
error[E0282]: type annotations needed
 --> src/main.rs:6:19
  |
6 |     let choose = |i| {
  |                   ^ consider giving this closure parameter a type
  |
  = note: type must be known at this point

For more information about this error, try `rustc --explain E0282`.
error: could not compile `playground` due to previous error
```
which is the error message obtained from setting `choose = |i| i.to_string()`.

I believe the current error message is less helpful than it could be because
- "`<usize as SliceIndex<[String]>>::Output == str`" seems to suggest that `i: usize` was correctly guessed;
- "expected struct `String`, found `str`" points to an `str` vs `&str` vs `String` vs `&String` issue, which is one consequence but not the root cause.

These seem to point to the following fix:
```rs
let choose = |i| {
    if i < v.len() {
        &v[i] as &str   // added " as &str"
    } else {
        ""
    }
};
```
which does compile, but is less good a solution than
```rs
let choose = |i: usize| {   // added ": usize"
    if i < v.len() {
        &v[i]
    } else {
        ""
    }
};
```

The error message is also subject to big changes because of variations:
```rs
let choose = |i| {
    if i < v.len() {
        v[i].to_string()
    } else {
        "".to_string()
    }
};
```
produces
```
   Compiling playground v0.0.1 (/playground)
error[E0282]: type annotations needed
 --> src/main.rs:8:14
  |
8 |             v[i].to_string()
  |             ^^^^ cannot infer type
  |
  = note: type must be known at this point

For more information about this error, try `rustc --explain E0282`.
error: could not compile `playground` due to previous error
```
which again can be solved by either `(&v[i] as &str).to_string()` (bad) or `|i: usize|` (good).

Are there any known issues with (at least by default) changing such "type annotations needed" errors in closures with
unannotated arguments to point to the arguments instead of the expression at fault ?