Repository: rust
Issue: Misleading error message for closure lifetime mismatch
Labels: A-diagnostics,A-closures,T-compiler,C-bug

Here's a fairly minimal reproduction of the code I was working with: ([Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=86a9401a58692c0066ef248a8ceafe62))

```rust
type Input<'a> = &'a [u8];

fn bar<I, O, F>(f: F) -> impl Fn(I) -> O
    where F: Fn(I) -> O,
{
    f
}

// This version does not work:
fn foo<O, F>(f: F) -> impl Fn(Input) -> O
    where F: Fn(Input) -> O
{
    bar(f)
}

// This version works:
fn foo2<'a, O, F>(f: F) -> impl Fn(Input<'a>) -> O
    where F: Fn(Input<'a>) -> O
{
    bar(f)
}
```

The idea is that we want to define a function `foo` that takes a function and returns a new function by calling `bar`. The function `bar` also takes a function and returns a new function. In this minimal example, `bar` just returns `f`, but you can imagine that in a real application it would do something more interesting. This code resembles what you might see in a parser combinator library.

The error message you get with this code is as follows:

```rust
error[E0277]: expected a `std::ops::Fn<(&[u8],)>` closure, found `impl std::ops::Fn<(&[u8],)>`
  --> src/lib.rs:10:23
   |
10 | fn foo<O, F>(f: F) -> impl Fn(Input) -> O
   |                       ^^^^^^^^^^^^^^^^^^^ expected an `Fn<(&[u8],)>` closure, found `impl std::ops::Fn<(&[u8],)>`
...
13 |     bar(f)
   |     ------ this returned value is of type `impl std::ops::Fn<(&[u8],)>`
   |
   = help: the trait `for<'r> std::ops::Fn<(&'r [u8],)>` is not implemented for `impl std::ops::Fn<(&[u8],)>`
   = note: the return type of a function must have a statically known size

error[E0271]: type mismatch resolving `for<'r> <impl std::ops::Fn<(&[u8],)> as std::ops::FnOnce<(&'r [u8],)>>::Output == O`
  --> src/lib.rs:10:23
   |
10 | fn foo<O, F>(f: F) -> impl Fn(Input) -> O
   |                       ^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter, found concrete lifetime
   |
   = note: the return type of a function must have a statically known size

error: aborting due to 2 previous errors
```

There are a couple of misleading things about this message:

1. The expected and found text looks like it should be compatible, the error isn't clear from this part of the message:
   ```
   expected an `Fn<(&[u8],)>` closure, found `impl std::ops::Fn<(&[u8],)>`
   ```
2. The following can lead you to add `for<'a>` to your trait bound, which will only take you further in the wrong direction (it happened to me today!)
    ```
    the trait `for<'r> std::ops::Fn<(&'r [u8],)>` is not implemented for `impl std::ops::Fn<(&[u8],)>`
    ```
    If you try adding `for<'a>` to the trait bound, you get some further error messages which are even less helpful :(

The problem is actually something not even shown in the error message: the lifetime of the reference in the argument type needs to be the same as the lifetime of the reference in the return type. If you do that (as in `foo2` above), the code compiles with no issues. Is there a reliable way for us to detect cases like this so we can improve the error message?

Thanks for all your work. :)

# Meta

`rustc --version --verbose`:
```
$ rustc --version --verbose
rustc 1.42.0 (b8cedc004 2020-03-09)
binary: rustc
commit-hash: b8cedc00407a4c56a3bda1ed605c6fc166655447
commit-date: 2020-03-09
host: x86_64-unknown-linux-gnu
release: 1.42.0
LLVM version: 9.0
```