Repository: rust
Issue: Clarification of compiler diagnostic 'no two closures, even if identical, have the same type'
Labels: A-diagnostics,T-compiler

Consider the following function which returns a closure `impl`

```rust
fn returns_closure(hmm: bool) -> impl Fn(i32) -> i32 {
    if hmm {
        |x| x + 1
    } else {
        |x| x * 2
    }
}

fn main() {
    println!("{}", returns_closure(true)(10));
    println!("{}", returns_closure(false)(10));
}
```
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=5d676e682519cae13533bd1d5c82ebd3

This builds and runs providing the following output:

```
11
20
```

This seems reasonable at first glance, however consider a changed version:
```rust
fn returns_closure(hmm: bool, y: u32) -> impl Fn(i32) -> i32 {
    if hmm {
        |x| x + y
    } else {
        |x| x * y
    }
}

fn main() {
    println!("{}", returns_closure(true, 3)(10));
    println!("{}", returns_closure(false, 4)(10));
}
```
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=43bdb248873d31bc470b0fc9fb8a2ab3

This fails to build with:

```
error[E0308]: `if` and `else` have incompatible types
 --> src/main.rs:5:9
  |
2 | /     if hmm {
3 | |         |x| x + y
  | |         --------- expected because of this
4 | |     } else {
5 | |         |x| x * y
  | |         ^^^^^^^^^ expected closure, found a different closure
6 | |     }
  | |_____- `if` and `else` have incompatible types
  |
  = note: expected type `[closure@src/main.rs:3:9: 3:18]`
          found closure `[closure@src/main.rs:5:9: 5:18]`
  = note: no two closures, even if identical, have the same type
  = help: consider boxing your closure and/or using it as a trait object

For more information about this error, try `rustc --explain E0308`.
```

The first example uses two closures and compiles and runs fine, demonstrating we do have two closures of the same type which the output from the second example states cannot happen.

I suspect what's happening is the first closures don't capture from the environment so are seen as function pointers both with type `fn(i32) -> i32`. So this is just an issue of clarifying the second error message e.g. 'no two closure which capture the environment, even if identical, have the same type'. 

Changing the first example as follows seems to confirm this:

```rust
fn returns_closure(hmm: bool) -> fn(i32) -> i32 {
    if hmm {
        |x| x + 1
    } else {
        |x| x * 2
    }
}

fn main() {
    println!("{}", returns_closure(true)(10));
    println!("{}", returns_closure(false)(10));
}
```
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c628f6a790b886b7975542a7fd89f734

(Builds and runs with identical results to the first example)

From reading the rust reference you could say 'closure' inherently means environment capture (i.e. `|x| x + 1` is not a closure), but that conflicts with language used in the rust book so could lead to confusion.

If it's intended that closures from the first example should have different types there's something more serious going on with the type inference/checking.

`rustc --version --verbose`:
```
rustc 1.56.0-nightly (ccffcafd5 2021-08-11)
binary: rustc
commit-hash: ccffcafd55e58f769d4b0efc0064bf65e76998e4
commit-date: 2021-08-11
host: x86_64-unknown-linux-gnu
release: 1.56.0-nightly
LLVM version: 12.0.1
```