Repository: rust
Issue: Ranges of match expressions incorrectly parsed
Labels: A-grammar,C-bug

<!--
Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
along with any information you feel relevant to replicating the bug.
-->

Playground link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=037f6cc1aa5c9a0fc250ee3abf69bb1d

```rust
use core::ops::{RangeInclusive, Range, RangeFrom, RangeTo, RangeToInclusive};

fn inclusive() -> RangeInclusive<u32> {
    match 1 { x => x }..=match 2 { x => x }
}
fn exclusive() -> Range<u32> {
    match 1 { x => x }..match 2 { x => x }
}
fn from() -> RangeFrom<u32> {
    match 1 { x => x }..
}
fn to() -> RangeTo<u32> {
    ..match 2 { x => x }
}
fn to_inclusive() -> RangeToInclusive<u32> {
    ..=match 2 { x => x }
}
```

Compiler output:

```
error[E0308]: mismatched types
 --> src/lib.rs:4:5
  |
4 |     match 1 { x => x }..=match 2 { x => x }
  |     ^^^^^^^^^^^^^^^^^^- help: consider using a semicolon here
  |     |
  |     expected `()`, found integer

error[E0308]: mismatched types
 --> src/lib.rs:4:23
  |
3 | fn inclusive() -> RangeInclusive<u32> {
  |                   ------------------- expected `RangeInclusive<u32>` because of return type
4 |     match 1 { x => x }..=match 2 { x => x }
  |                       ^^^^^^^^^^^^^^^^^^^^^ expected `RangeInclusive<u32>`, found `RangeToInclusive<{integer}>`
  |
  = note: expected struct `RangeInclusive<u32>`
             found struct `RangeToInclusive<{integer}>`

error[E0308]: mismatched types
 --> src/lib.rs:7:5
  |
7 |     match 1 { x => x }..match 2 { x => x }
  |     ^^^^^^^^^^^^^^^^^^- help: consider using a semicolon here
  |     |
  |     expected `()`, found integer

error[E0308]: mismatched types
 --> src/lib.rs:7:23
  |
6 | fn exclusive() -> Range<u32> {
  |                   ---------- expected `std::ops::Range<u32>` because of return type
7 |     match 1 { x => x }..match 2 { x => x }
  |                       ^^^^^^^^^^^^^^^^^^^^ expected `Range<u32>`, found `RangeTo<{integer}>`
  |
  = note: expected struct `std::ops::Range<u32>`
             found struct `RangeTo<{integer}>`

error[E0308]: mismatched types
  --> src/lib.rs:10:5
   |
10 |     match 1 { x => x }..
   |     ^^^^^^^^^^^^^^^^^^- help: consider using a semicolon here
   |     |
   |     expected `()`, found integer

error[E0308]: mismatched types
  --> src/lib.rs:10:23
   |
9  | fn from() -> RangeFrom<u32> {
   |              -------------- expected `RangeFrom<u32>` because of return type
10 |     match 1 { x => x }..
   |                       ^^ expected `RangeFrom<u32>`, found `RangeFull`
   |
   = note: expected struct `RangeFrom<u32>`
              found struct `RangeFull`

For more information about this error, try `rustc --explain E0308`.
```

I'd expect each of the above to compile into a simple range with start 1 and end 2, but instead, the compiler is interpreting the match statement before the range operator as a unit expression, then failing to typecheck. This means that while the `to()` and `to_inclusive()` functions compile correctly, the rest don't.

While this *is* parsed correctly with parentheses around the range expression, this triggers the `unused_parentheses` lint which auto-fixes to the above version. Here's a playground link for that: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=3962072dc9d1c3c3532cca8885ad69a6

```rust
use core::ops::{RangeInclusive, Range, RangeFrom, RangeTo, RangeToInclusive};

pub fn inclusive() -> RangeInclusive<u32> {
    (match 1 { x => x }..=match 2 { x => x })
}
pub fn exclusive() -> Range<u32> {
    (match 1 { x => x }..match 2 { x => x })
}
pub fn from() -> RangeFrom<u32> {
    (match 1 { x => x }..)
}
pub fn to() -> RangeTo<u32> {
    ..match 2 { x => x }
}
pub fn to_inclusive() -> RangeToInclusive<u32> {
    ..=match 2 { x => x }
}
```

Compiler output:

```
warning: unnecessary parentheses around block return value
 --> src/lib.rs:4:5
  |
4 |     (match 1 { x => x }..=match 2 { x => x })
  |     ^                                       ^
  |
  = note: `#[warn(unused_parens)]` on by default
help: remove these parentheses
  |
4 -     (match 1 { x => x }..=match 2 { x => x })
4 +     match 1 { x => x }..=match 2 { x => x }
  |

warning: unnecessary parentheses around block return value
 --> src/lib.rs:7:5
  |
7 |     (match 1 { x => x }..match 2 { x => x })
  |     ^                                      ^
  |
help: remove these parentheses
  |
7 -     (match 1 { x => x }..match 2 { x => x })
7 +     match 1 { x => x }..match 2 { x => x }
  |

warning: unnecessary parentheses around block return value
  --> src/lib.rs:10:5
   |
10 |     (match 1 { x => x }..)
   |     ^                    ^
   |
help: remove these parentheses
   |
10 -     (match 1 { x => x }..)
10 +     match 1 { x => x }..
   |
```

This bug exists on both stable (1.70.0) and nightly (2023-06-04).

I'm not sure whether the parentheses should be required or not, but regardless, this is at least a diagnostic issue, since recommending to remove parentheses around the expression causes it to fail.