Repository: rust
Issue: Error message for trying to bind range of units to unit suggests invalid code
Labels: A-diagnostics,T-compiler,C-bug,D-invalid-suggestion

Given the [following code](https://play.rust-lang.org/?code=fn%20g%28%29%20%7B%0A%20%20%20%20let%20%28%29%20%3D%20%28%29..%3B%0A%20%20%20%20let%20%28%29%20%3D%20..%28%29%3B%0A%20%20%20%20let%20%28%29%20%3D%20..%3D%28%29%3B%0A%20%20%20%20let%20%28%29%20%3D%20%28%29..%28%29%3B%0A%20%20%20%20let%20%28%29%20%3D%20%28%29..%3D%28%29%3B%0A%7D):

```rust
fn g() {
    let () = ()..;
    let () = ..();
    let () = ..=();
    let () = ()..();
    let () = ()..=();
}
```

The current output is:

<details>

```
error[E0308]: mismatched types
 --> src/lib.rs:2:9
  |
2 |     let () = ()..;
  |         ^^   ---- this expression has type `RangeFrom<()>`
  |         |
  |         expected struct `RangeFrom`, found `()`
  |
  = note: expected struct `RangeFrom<()>`
          found unit type `()`
help: you might have meant to use field `start` whose type is `()`
  |
2 |     let () = ()...start;
  |              ~~~~~~~~~~

error[E0308]: mismatched types
 --> src/lib.rs:3:9
  |
3 |     let () = ..();
  |         ^^   ---- this expression has type `RangeTo<()>`
  |         |
  |         expected struct `RangeTo`, found `()`
  |
  = note: expected struct `RangeTo<()>`
          found unit type `()`
help: you might have meant to use field `end` whose type is `()`
  |
3 |     let () = ..().end;
  |              ~~~~~~~~

error[E0308]: mismatched types
 --> src/lib.rs:4:9
  |
4 |     let () = ..=();
  |         ^^   ----- this expression has type `RangeToInclusive<()>`
  |         |
  |         expected struct `RangeToInclusive`, found `()`
  |
  = note: expected struct `RangeToInclusive<()>`
          found unit type `()`
help: you might have meant to use field `end` whose type is `()`
  |
4 |     let () = ..=().end;
  |              ~~~~~~~~~

error[E0308]: mismatched types
 --> src/lib.rs:5:9
  |
5 |     let () = ()..();
  |         ^^   ------ this expression has type `std::ops::Range<()>`
  |         |
  |         expected struct `std::ops::Range`, found `()`
  |
  = note: expected struct `std::ops::Range<()>`
          found unit type `()`
help: you might have meant to use field `start` whose type is `()`
  |
5 |     let () = ()..().start;
  |              ~~~~~~~~~~~~

error[E0308]: mismatched types
 --> src/lib.rs:6:9
  |
6 |     let () = ()..=();
  |         ^^   ------- this expression has type `RangeInclusive<()>`
  |         |
  |         expected struct `RangeInclusive`, found `()`
  |
  = note: expected struct `RangeInclusive<()>`
          found unit type `()`
help: you might have meant to use field `start` whose type is `()`
  |
6 |     let () = ()..=().start;
  |              ~~~~~~~~~~~~~

For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` due to 5 previous errors
```

</details>

Blindly applying all the suggestions would lead to:

```rust
fn g() {
    let () = ()...start;
    let () = ..().end;
    let () = ..=().end;
    let () = ()..().start;
    let () = ()..=().start;
}
```

...which is obviously syntactically invalid.

Ideally the output should account for required parenthesis and look like:

<details>

```
error[E0308]: mismatched types
 --> src/lib.rs:2:9
  |
2 |     let () = ()..;
  |         ^^   ---- this expression has type `RangeFrom<()>`
  |         |
  |         expected struct `RangeFrom`, found `()`
  |
  = note: expected struct `RangeFrom<()>`
          found unit type `()`
help: you might have meant to use field `start` whose type is `()`
  |
2 |     let () = (()..).start;
  |              ~~~~~~~~~~~~

error[E0308]: mismatched types
 --> src/lib.rs:3:9
  |
3 |     let () = ..();
  |         ^^   ---- this expression has type `RangeTo<()>`
  |         |
  |         expected struct `RangeTo`, found `()`
  |
  = note: expected struct `RangeTo<()>`
          found unit type `()`
help: you might have meant to use field `end` whose type is `()`
  |
3 |     let () = (..()).end;
  |              ~~~~~~~~~~

error[E0308]: mismatched types
 --> src/lib.rs:4:9
  |
4 |     let () = ..=();
  |         ^^   ----- this expression has type `RangeToInclusive<()>`
  |         |
  |         expected struct `RangeToInclusive`, found `()`
  |
  = note: expected struct `RangeToInclusive<()>`
          found unit type `()`
help: you might have meant to use field `end` whose type is `()`
  |
4 |     let () = (..=()).end;
  |              ~~~~~~~~~~~

error[E0308]: mismatched types
 --> src/lib.rs:5:9
  |
5 |     let () = ()..();
  |         ^^   ------ this expression has type `std::ops::Range<()>`
  |         |
  |         expected struct `std::ops::Range`, found `()`
  |
  = note: expected struct `std::ops::Range<()>`
          found unit type `()`
help: you might have meant to use field `start` whose type is `()`
  |
5 |     let () = (()..()).start;
  |              ~~~~~~~~~~~~~~

error[E0308]: mismatched types
 --> src/lib.rs:6:9
  |
6 |     let () = ()..=();
  |         ^^   ------- this expression has type `RangeInclusive<()>`
  |         |
  |         expected struct `RangeInclusive`, found `()`
  |
  = note: expected struct `RangeInclusive<()>`
          found unit type `()`
help: you might have meant to use field `start` whose type is `()`
  |
6 |     let () = (()..=()).start;
  |              ~~~~~~~~~~~~~~~

For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` due to 5 previous errors
```

</details>

This issue is reproducible on stable versions from 1.51.0 to 1.58.0, latest beta (`rustc 1.59.0-beta.1 (7c0b25092 2022-01-13)`) and latest nightly (`rustc 1.60.0-nightly (9ad5d82f8 2022-01-18)`) at the moment.

<details><summary>Some other things about this bug</summary>

* Running compiler on "fixed" program leads to error message which suggests adding _even more_ field accesses.
* It seems like it is required to bind value to unit pattern in order to trigger the bug. Other ways to require unit value that I tried (binding to a wildcard pattern with unit type type ascription, calling with a function with excepts a unit argument, returning range from a unit returning function) do not work.
* It seems like it breaks only with units and not with any other type.

</details>


<!-- TRIAGEBOT_START -->

<!-- TRIAGEBOT_ASSIGN_START -->

<!-- TRIAGEBOT_ASSIGN_DATA_START$${"user":"terrarier2111"}$$TRIAGEBOT_ASSIGN_DATA_END -->

<!-- TRIAGEBOT_ASSIGN_END -->
<!-- TRIAGEBOT_END -->