Repository: rust
Issue: Unsatisfied trait bound on fn item should suggest `as fn()` if it is satisfied for fn pointer
Labels: A-diagnostics,T-compiler

Given the following code: [[playground]](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=47c96512e5b66aac5fab70201ece0d87)

```rust
trait Trait {}
impl Trait for fn() {}
fn take(_: impl Trait) {}

fn f() {}
fn main() {
    take(f);
}
```

The current output is:

```
error[[E0277]](https://doc.rust-lang.org/stable/error-index.html#E0277): the trait bound `fn() {f}: Trait` is not satisfied
 --> src/main.rs:7:10
  |
7 |     take(f);
  |     ---- ^ the trait `Trait` is not implemented for `fn() {f}`
  |     |
  |     required by a bound introduced by this call
  |
  = help: the trait `Trait` is implemented for `fn()`
note: required by a bound in `take`
 --> src/main.rs:3:17
  |
3 | fn take(_: impl Trait) {}
  |                 ^^^^^ required by this bound in `take`
```

Ideally the output should look like:

```
error[[E0277]](https://doc.rust-lang.org/stable/error-index.html#E0277): the trait bound `fn() {f}: Trait` is not satisfied
 --> src/main.rs:7:10
  |
7 |     take(f);
  |     ---- ^ the trait `Trait` is not implemented for fn item `fn() {f}`
  |     |
  |     required by a bound introduced by this call
  |
  = help: the trait `Trait` is implemented for fn pointer `fn()`
note: required by a bound in `take`
 --> src/main.rs:3:17
  |
3 | fn take(_: impl Trait) {}
  |                 ^^^^^ required by this bound in `take`
  |
help: Convert the fn item to a fn pointer with `as`
  |
7 |     take(f as fn());
  |           ++++++++
```

<details><summary>A more involved diagnostic example:</summary>

[[playground]](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=56c1021f84a0619534292ef1f3c19b65)

```rust
trait Trait {}
impl<A: PartialEq> Trait for A {}
fn take(_: impl Trait) {}

fn f() {}
fn main() {
    take(f);
}
```

The current output is:

```
error[[E0277]](https://doc.rust-lang.org/nightly/error-index.html#E0277): can't compare `fn() {f}` with `fn() {f}`
 --> src/main.rs:7:10
  |
7 |     take(f);
  |     ---- ^ no implementation for `fn() {f} == fn() {f}`
  |     |
  |     required by a bound introduced by this call
  |
  = help: the trait `PartialEq` is not implemented for `fn() {f}`
  = help: the following other types implement trait `PartialEq<Rhs>`:
            extern "C" fn() -> Ret
            extern "C" fn(A, B) -> Ret
            extern "C" fn(A, B, ...) -> Ret
            extern "C" fn(A, B, C) -> Ret
            extern "C" fn(A, B, C, ...) -> Ret
            extern "C" fn(A, B, C, D) -> Ret
            extern "C" fn(A, B, C, D, ...) -> Ret
            extern "C" fn(A, B, C, D, E) -> Ret
          and 68 others
note: required because of the requirements on the impl of `Trait` for `fn() {f}`
 --> src/main.rs:2:20
  |
2 | impl<A: PartialEq> Trait for A {}
  |                    ^^^^^     ^
note: required by a bound in `take`
 --> src/main.rs:3:17
  |
3 | fn take(_: impl Trait) {}
  |                 ^^^^^ required by this bound in `take`
```

Ideally the output should look like:

```
error[[E0277]](https://doc.rust-lang.org/nightly/error-index.html#E0277): can't compare `fn() {f}` with `fn() {f}`
 --> src/main.rs:7:10
  |
7 |     take(f);
  |     ---- ^ no implementation for `fn() {f} == fn() {f}`
  |     |
  |     required by a bound introduced by this call
  |
  = help: the trait `PartialEq` is not implemented for fn item `fn() {f}`
  = help: the trait `PartialEq` is implemented for fn pointer `fn()`
note: required because of the requirements on the impl of `Trait` for `fn() {f}`
 --> src/main.rs:2:20
  |
2 | impl<A: PartialEq> Trait for A {}
  |                    ^^^^^     ^
note: required by a bound in `take`
 --> src/main.rs:3:17
  |
3 | fn take(_: impl Trait) {}
  |                 ^^^^^ required by this bound in `take`
  |
help: Convert the fn item to a fn pointer with `as`
  |
7 |     take(f as fn());
  |           ++++++++
```

(bonus side effect: hiding the giant list of explicit variadic fn pointer impls)

</details>