Skip to content

Parenthesized match guards should have a specific parser error (and suggestion) #100825

Closed
@CAD97

Description

@CAD97

Given the following code: [playground]

pub fn test(val: i32) {
    match val {
        (0 if true) => {}
        _ => {}
    }
}

The current output is:

error: expected identifier, found keyword `if`
 --> src/lib.rs:3:12
  |
3 |         (0 if true) => {}
  |            ^^ expected identifier, found keyword

error: expected one of `)`, `,`, `...`, `..=`, `..`, or `|`, found keyword `if`
 --> src/lib.rs:3:12
  |
3 |         (0 if true) => {}
  |           -^^ expected one of `)`, `,`, `...`, `..=`, `..`, or `|`
  |           |
  |           help: missing `,`

error: expected one of `)`, `,`, `@`, or `|`, found keyword `true`
 --> src/lib.rs:3:15
  |
3 |         (0 if true) => {}
  |              -^^^^ expected one of `)`, `,`, `@`, or `|`
  |              |
  |              help: missing `,`

error[E0308]: mismatched types
 --> src/lib.rs:3:9
  |
2 |     match val {
  |           --- this expression has type `i32`
3 |         (0 if true) => {}
  |         ^^^^^^^^^^^ expected `i32`, found tuple
  |
  = note: expected type `i32`
            found tuple `(_, _, _)`

Ideally the output should look like:

error: match pattern guard not allowed here
 --> src/lib.rs:3:9
  |
3 |         (0 if true) => {}
  |            ^^^^^^^ not supported
  |
  = note: match pattern guards must appear at the top level
help: move the guard to the top level
  |
3 -         (_ if true) => {}
3 +         (_) if true => {}
  |

As-is, results in unused_parens warning. Alternative help that doesn't:

help: remove these parentheses
  |
3 -         (0 if true) => {}
3 +         0 if true => {}
  |

Bonus points:

  • Stash this error while parsing and tweak it later when types are available; e.g. if the scrutinee actually is (_, _, _), perhaps (_, r#if, true) (what this currently seemingly error-recovers as) actually was meant. With a non-tuple scrutinee, though, clearly the parenthesization was meant.

  • Support parsing parenthesized guards in nested patterns and give the nice parser error there. Note that for the guard lifting to be semantics preserving, it must not exit any alt (|) pattern combinations.

    examples
    Some(0 if true) => Some(_) if true;
    (0, 0 if true) => (0, 0) if true;
    (_ if true) | 0 => {} // cannot be written as a single pattern
    0 | _ if true => 0 | _ if true; // is a valid pattern: (0 | _) if true
    Struct { field: 0 if true } => Struct { field: 0 } if true;

@rustbot label +D-confusing +D-verbose

(Is this D-invalid-suggestion Diagnostics: A structured suggestion resulting in incorrect code. ? The help is not moving towards correct code.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsA-parserArea: The lexing & parsing of Rust source code to an ASTD-confusingDiagnostics: Confusing error or lint that should be reworked.D-invalid-suggestionDiagnostics: A structured suggestion resulting in incorrect code.D-verboseDiagnostics: Too much output caused by a single piece of incorrect code.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions