Repository: rust
Issue: Type mismatch errors in a inferrence context could provide more information about how a type is inferred
Labels: A-diagnostics,T-compiler,A-inference,D-papercut,D-terse

Consider this code*:

```rust
fn use_string(s: String) {
    todo!()
}

fn use_str(s: &str) {
    todo!()
}

fn build_something<T>() -> T {
    todo!()
}

fn example_failure(branch: bool) {
    let value = build_something();  // 1

    match branch {
        false => {
            use_string(value);  // 2
        }
        true => {
            use_str(&value);  // 3
            use_string(value);
        }
    }
}
```

This code is correct and compiles successfully. At (1), we create an object of some generic type `T`. This type is inferred to be `String` because of (2). The `use_str` call at (3) then succeeds because `String: Deref<Target=str>`.

Now, consider this variation:

```rust
fn example_failure(branch: bool) {
    let value = build_something();

    match branch {
        true => {
            use_str(&value);
            use_string(value);
        }
        false => {
            use_string(value);
        }
    }
}
```

This is identical except that the branch arms are swapped. Intuitively, this should be fine; Rust's `match` doesn't have any fallthrough or other control flow complexity, so branch order shouldn't matter (except in the case of wildcard matching, but that doesn't change the fact that exactly one branch will only and always be executed).

However, we instead get this error:

```
error[E0277]: the size for values of type `str` cannot be known at compilation time
  --> src/lib.rs:13:9
   |
13 |     let value = build_something();
   |         ^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `str`
   = note: all local variables must have a statically known size
   = help: unsized locals are gated as an unstable feature

error[E0277]: the size for values of type `str` cannot be known at compilation time
  --> src/lib.rs:13:17
   |
8  | fn build_something<T>() -> T {
   |                    - required by this bound in `build_something`
...
13 |     let value = build_something();
   |                 ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `str`
help: consider relaxing the implicit `Sized` restriction
   |
8  | fn build_something<T: ?Sized>() -> T {
   |                     ^^^^^^^^

error[E0308]: mismatched types
  --> src/lib.rs:18:24
   |
18 |             use_string(value);
   |                        ^^^^^
   |                        |
   |                        expected struct `String`, found `str`
   |                        help: try using a conversion method: `value.to_string()`

error[E0308]: mismatched types
  --> src/lib.rs:21:24
   |
21 |             use_string(value);
   |                        ^^^^^
   |                        |
   |                        expected struct `String`, found `str`
   |                        help: try using a conversion method: `value.to_string()`

error: aborting due to 4 previous errors

Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.
error: could not compile `rust-crate`
```

This ended up being very confusing, because I couldn't see for a long time why `T` was being inferred as `str`. Intuitively, it didn't seem like switching the branch order should affect it, so I was looking in other places (like trying to find a misplaced `impl AsRef<str>`, for example) and it was a while before I scrutinized the branches and realized that `use_str` being first in lexical AST order is what was causing it.

This ticket isn't about that behavior; instead, I'd like to focus on the diagnostic. It would have been very helpful here to learn *why* `T` was inferred to be `str`. I'd formalize the rule like this: in the case where the type is generic *at the variable binding initialization site*, then type errors related to that value should gain an additional `Info` line describing where exactly the type inference occurred. For instance:

```rust
fn foo1(iter: impl Iterator<Item=i32>) -> Vec<i64> {
    // No additional diagnistics needed here, since the type is concrete
    // at initialization site
    let vec: Vec<i32> = iter.collect();
    vec
}

fn get_vec() -> Vec<i32> { todo!() }

fn foo2(iter: impl Iterator<Item=i32>) -> Vec<i64> {
    // No additional diagnistics needed here either, since the
    // type is immediately fully inferred by the init expression
    let vec = get_vec()
    vec
}

fn foo3(iter: impl Iterator<Item=i32>) -> Vec<i64> {
    // Now we're in trouble. We're going to get an error about Vec<i64>
    // being incompatible here; it would be helpful to include a diagnostic
    // highlighting the return type of `foo3` saying "T was inferred to be
    // Vec<i64> here"
    let vec = iter.collect();
    vec
}
```

This error appears in both current stable (1.55) and current nightly (1.57, 2021-09-19 5ecc8ad8462574354a55).

\* This is slight simplification of a real world case where I ran into this issue, here: https://github.com/Lucretiel/kaydle/blob/4f0344a4ccfb0d0768c5c14c8e57bafe0395208d/kaydle/src/serde/de.rs#L958-L969