Repository: rust
Issue: Description of E0495 failure difficult to parse
Labels: A-diagnostics,T-compiler,A-variance

Given the following code: https://godbolt.org/z/6ndY3zx7q

```rust
pub fn next<'buf, 'read, T>(
    r: &'read mut i32,
    f: impl FnOnce(&mut &'read &'buf i32) -> T,
) -> T { todo!() }

pub fn tagged<'buf, 'read, T>(
    r: &'read mut i32,
    f: impl FnOnce(&mut &'read &'buf i32) -> T,
) -> T {
    next(r, move |e| inner(e, f))
}

pub fn inner<'buf, 'read, T>(
    r: &'read mut &&'buf i32,
    f: impl FnOnce(&mut &'read &'buf i32) -> T,
) -> T { todo!() }
```

The current output is:

```rust
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'buf` due to conflicting requirements
  --> <source>:10:22
   |
10 |     next(r, move |e| inner(e, f))
   |                      ^^^^^
   |
note: first, the lifetime cannot outlive the lifetime `'buf` as defined on the function body at 6:15...
  --> <source>:6:15
   |
6  | pub fn tagged<'buf, 'read, T>(
   |               ^^^^
note: ...but the lifetime must also be valid for the lifetime `'read` as defined on the function body at 6:21...
  --> <source>:6:21
   |
6  | pub fn tagged<'buf, 'read, T>(
   |                     ^^^^^
note: ...so that the types are compatible
  --> <source>:10:22
   |
10 |     next(r, move |e| inner(e, f))
   |                      ^^^^^
   = note: expected `for<'r> FnOnce<(&'r mut &&i32,)>`
              found `for<'r> FnOnce<(&'r mut &'read &'buf i32,)>`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0495`.
Compiler returned: 1
```

I run into this (the "bad variance diagonistic") whenever I'm doing anything particularly difficult with lifetimes. Even though most people would say I'm a very advanced Rust user, this particular class of diagnostics is extremely time-consuming for me to unwind. This error always means one of two things:
- I'm missing an explicit lifetime somewhere. The diagnostic provides no hints as to where it is and I need to hunt through the crate to find it.
- The API I've designed is impossible to implement because it causes the borrow checker to prove a contradiction.

Both of these are pretty frustrating, and I have to use my personal heuristics to resolve them. I've honestly just gotten used to the pain and am only filing this because @estebank nudged me. I don't want to imagine how a newbie feels when they see this error.

I don't have... obvious suggestions for improving the diagnostic, since I don't actually know how the current borrow checker implementation aggregates information. After all, it would be very hard for it to guess which lifetime I missed, since it would need to explore many more paths.

However, there may be hope. The pretty-printed types are really unhelpful, which points to an underlying issue:
```rust
   = note: expected `for<'r> FnOnce<(&'r mut &&i32,)>`  // Lol what's &&i32?
              found `for<'r> FnOnce<(&'r mut &'read &'buf i32,)>`
```
There's a bunch of different lifetimes with similar names involved. Which `'buf` is it referring to? What are the anonymous lifetimes in `for<'r> FnOnce<(&'r mut &&i32,)>`? The compiler has clearly given these regions anonymous names, so it might be worth highlighting them with something like "Call this region `'1`" or similar, so that they can be printed in the error?

Perhaps it might also be useful to add a note that lists out the incompatible constraints as a where clause, once we've given the lifetime inference variables names. It would be easier to parse at a glance than trying to build it up from prose.

Finally, I wonder if it's helpful for the compiler to say "btw, I can't do this reduction I wanted to make because this lifetime isn't covariant".