Repository: rust
Issue: Misleading error message originating from the fact that closure types are not inferred being polymorphic over lifetimes. (And related errors in need of improvement.)
Labels: A-diagnostics,A-closures,T-lang,T-compiler,A-inference,D-papercut,D-terse

The following code produces an error message that doesn’t at all explain the actual problem.
```rust
fn foo() -> &'static str {
    let identity = |x| x;
    let result = identity("result!");
    let local_string: String = "local".into();
    let _ = identity(&local_string);
    
    result
}

```

([Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b38bbf2da51154080363926cbb21143d))

Errors:

```
   Compiling playground v0.0.1 (/playground)
error[E0515]: cannot return value referencing local variable `local_string`
 --> src/lib.rs:7:5
  |
5 |     let _ = identity(&local_string);
  |                      ------------- `local_string` is borrowed here
6 |     
7 |     result
  |     ^^^^^^ returns a value referencing data owned by the current function

error: aborting due to previous error

For more information about this error, try `rustc --explain E0515`.
error: could not compile `playground`.

To learn more, run the command again with --verbose.

```
In particular looking at this statement – “returns a value referencing data owned by the current function” – that’s just _not what is going on here_.

What really is going on here (as far as I can tell) is that `identity` is inferred as some closure implementing `Fn(A) -> A` for `A` to be determined, then the first call `identity("result!")` tells the type inference that `A` is `&'a str` for some `'a` to be determined, and finally `identity(&local_string)` already knows to apply unsized coercion and typechecks nailing `'a` down to the lifetime of `local_string`. This means `result` is an `&'a str` with that same lifetime.

A bit less confusing of an error message but still suboptimal IMO is what you get when trying to use a closure truly polymorphically:
```rust
fn foo() {
    let identity = |x| x;
    identity(1u8);
    identity(1u16);
}

```

([Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=4277c8cc1d67fab42fdb8330756b4055))

Errors:

```
   Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
 --> src/lib.rs:4:14
  |
4 |     identity(1u16);
  |              ^^^^ expected `u8`, found `u16`
  |
help: change the type of the numeric literal from `u16` to `u8`
  |
4 |     identity(1u8);
  |              ^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground`.

To learn more, run the command again with --verbose.

```
I think this could be improved by a message explaining where the expected type `u8` comes from.

<br></br><br></br>

Back to the original example.. in my opinion it would be nice if the example would not error at all. After all the following _does_ work:
```rust
fn str_closure<F: Fn(&str) -> &str>(f: F) -> F { f }

fn foo() -> &'static str {
    let identity = str_closure(|x| x);
    let result = identity("result!");
    let local_string: String = "local".into();
    let _ = identity(&local_string);
    
    result
}
```
However, this again doesn’t work:
```rust
fn str_closure<F: Fn(&str) -> &str>(f: F) -> F { f }

fn foo() -> &'static str {
    let closure = |x| x;
    let identity = str_closure(closure);
    let result = identity("result!");
    let local_string: String = "local".into();
    let _ = identity(&local_string);
    
    result
}
```

<br></br><br></br>

Finally, on the topic of _trying to get more polymorphism out of closures than they support_, I ran into this error message (which I could move into a separate issue if you guys think that it’s completely unrelated):
```rust
fn f<A>() -> A { unimplemented!() }
fn foo() {
    let _ = f;
}
```

([Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e7a932c7d50e8e7638a57b2373cf9b35))

Errors:

```
   Compiling playground v0.0.1 (/playground)
error[E0282]: type annotations needed for `fn() -> A {f::<A>}`
 --> src/lib.rs:3:13
  |
3 |     let _ = f;
  |         -   ^ cannot infer type for type parameter `A` declared on the function `f`
  |         |
  |         consider giving this pattern the explicit type `fn() -> A {f::<A>}`, where the type parameter `A` is specified

error: aborting due to previous error

For more information about this error, try `rustc --explain E0282`.
error: could not compile `playground`.

To learn more, run the command again with --verbose.

```
Which is just weird, because: What is this `fn() -> A {f::<A>}` syntax supposed to mean?

@rustbot modify labels to T-compiler, T-lang, A-diagnostics, D-incorrect, D-terse, D-papercut, C-bug, C-enhancement, A-closures, A-inference.