Skip to content

Ranges of match expressions incorrectly parsed #112329

Open
@clarfonthey

Description

@clarfonthey

Playground link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=037f6cc1aa5c9a0fc250ee3abf69bb1d

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

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-grammarArea: The grammar of RustC-bugCategory: This is a bug.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions