Repository: rust
Issue: Confusing diagnostics resulting from a function with the bound `T: FnOnce() -> T` that takes `T` and returns `T`
Labels: C-enhancement,A-diagnostics,A-trait-system,A-closures,T-compiler,D-confusing,D-verbose

I tried this code ([playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=4c66b2f455d1d8e600ba92650cb8a772)):

```rust
fn closure_ret_closure<T: FnOnce() -> T>(f: T) -> T {
    f()
}

fn main() {
    closure_ret_closure(|| 4);
}
```

I expected to see this happen:

Either a diagnostic proclaiming that the type parameter for `closure_ret_closure` is recursive or a diagnostic that clearly states that `|| 4` does not return `FnOnce() -> FnOnce() -> FnOnce() -> ...`.

Instead, this happened:

Two seemingly conflicting diagnostics are emitted:
```
error[E0277]: expected a `FnOnce<()>` closure, found `{integer}`
 --> src/main.rs:6:5
  |
1 | fn closure_ret_closure<T: FnOnce() -> T>(f: T) -> T {
  |                           ------------- required by this bound in `closure_ret_closure`
...
6 |     closure_ret_closure(|| 4);
  |     ^^^^^^^^^^^^^^^^^^^ expected an `FnOnce<()>` closure, found `{integer}`
  |
  = help: the trait `FnOnce<()>` is not implemented for `{integer}`
  = note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }`

error[E0308]: mismatched types
 --> src/main.rs:6:25
  |
6 |     closure_ret_closure(|| 4);
  |                         ^^^^ expected integer, found closure
  |
  = note: expected type `{integer}`
          found closure `[closure@src/main.rs:6:25: 6:29]`
```

The first diagnostic claims that `{integer}`, the type of the value returned by the closure, is not a `FnOnce() -> ...`. It is not immediately clear that this is in reference to the return type, so the user may believe the value in question is the parameter.

The second diagnostic claims that it expects the parameter to be of type `{integer}`. This is quite strange, because the previous diagnostic just told us that `T: FnOnce() -> FnOnce() -> ...`, and `{integer}` does not fit that requirement.

What may be happening is that since the result of calling `|| 4` is of type `{integer}`, the compiler believes `T` must be `{integer}`. Since `{integer}` does not implement `FnOnce() -> {integer}`, it doesn't fit the bounds on `T`, generating the first diagnostic. Then, the compiler sees that `|| 4` is not a valid argument to `closure_ret_closure`, since `f: T` and for this monomorphization, `T` = `{integer}`.

Even writing out the logic behind this error is quite confusing, so it would be helpful to improve these diagnostics in case a user accidentally stumbles upon them. I'm not entirely sure how to accomplish this, but making it clearer that the first diagnostic (E0277) is referring to the return type might help.

Unfortunately, I'm not sure if anything can be done regarding the rather strange `T: FnOnce() -> T` bound, since it's quite possible to implement a type that *can* satisfy `T: FnOnce() -> T` on nightly. This compiles and runs successfully ([playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=8b7e341a0adc90c36f310cf4d5c4daf0)):
```rust
#![feature(fn_traits)]
#![feature(unboxed_closures)]

struct Foo;

impl FnOnce<()> for Foo {
    type Output = Self;

    extern "rust-call" fn call_once(self, _: ()) -> Self::Output {
        self
    }
}

fn closure_ret_closure<T: FnOnce() -> T>(f: T) -> T {
    f()
}

fn main() {
    closure_ret_closure(Foo);
}
```

Since (as far as I know) `FnOnce` can only be implemented on nightly, we may be able to get away with making trait bounds like `T: FnOnce() -> T` a deny-by-default lint, or at least warn-by-default. I'm not certain if this would be entirely feasible/possible with the current trait system, however, since that would be equivalent to linting against this:

```rust
trait Foo {
    type Bar;
}

fn baz<T: Foo<Bar = T>>(_: T) { unimplemented!() }
```

### Meta
`rustc --version --verbose`:
```
rustc 1.48.0 (7eac88abb 2020-11-16)
binary: rustc
commit-hash: 7eac88abb2e57e752f3302f02be5f3ce3d7adfb4
commit-date: 2020-11-16
host: x86_64-unknown-linux-gnu
release: 1.48.0
LLVM version: 11.0
```

`rustc +nightly --version --verbose`:
```
rustc 1.51.0-nightly (257becbfe 2020-12-27)
binary: rustc
commit-hash: 257becbfe4987d1f7b12af5a8dd5ed96697cd2e8
commit-date: 2020-12-27
host: x86_64-unknown-linux-gnu
release: 1.51.0-nightly
```

@rustbot modify labels: +A-diagnostics +A-traits +C-enhancement +D-confusing +T-compiler