diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index df865d77b9bb4..8d7470e252797 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2480,7 +2480,7 @@ impl<'a> Parser<'a> { )?; let guard = if this.eat_keyword(kw::If) { let if_span = this.prev_token.span; - let cond = this.parse_expr()?; + let cond = this.parse_match_guard_cond()?; let (has_let_expr, does_not_have_bin_op) = check_let_expr(&cond); if has_let_expr { if does_not_have_bin_op { @@ -2496,6 +2496,15 @@ impl<'a> Parser<'a> { }; let arrow_span = this.token.span; if let Err(mut err) = this.expect(&token::FatArrow) { + if guard.is_some() && this.token.kind == token::OpenDelim(token::Brace) { + err.span_suggestion_verbose( + this.token.span.shrink_to_lo(), + "try adding a fat arrow here", + "=> ".to_string(), + Applicability::MaybeIncorrect, + ); + err.emit(); + } // We might have a `=>` -> `=` or `->` typo (issue #89396). if TokenKind::FatArrow .similar_tokens() @@ -2617,6 +2626,26 @@ impl<'a> Parser<'a> { } } + fn parse_match_guard_cond(&mut self) -> PResult<'a, P> { + let snapshot = self.clone(); + let mut cond = self.parse_expr()?; + let (is_lhs_struct, is_rhs_struct) = match cond.kind { + ExprKind::Binary(_, ref lhs, ref rhs) => { + (matches!(lhs.kind, ExprKind::Struct(..)), matches!(rhs.kind, ExprKind::Struct(..))) + } + _ => (false, false), + }; + if !is_lhs_struct + && (!is_rhs_struct + || is_rhs_struct && self.token.kind != token::OpenDelim(token::Brace)) + && self.token.kind != token::FatArrow + { + *self = snapshot; + cond = self.parse_cond_expr()?; + } + Ok(cond) + } + fn is_do_catch_block(&self) -> bool { self.token.is_keyword(kw::Do) && self.is_keyword_ahead(1, &[kw::Catch]) diff --git a/src/test/ui/parser/issues/issue-15980.rs b/src/test/ui/parser/issues/issue-15980.rs index 87faa7d5ff1bf..ccd4881ccd3bd 100644 --- a/src/test/ui/parser/issues/issue-15980.rs +++ b/src/test/ui/parser/issues/issue-15980.rs @@ -5,13 +5,12 @@ fn main(){ match x { Err(ref e) if e.kind == io::EndOfFile { //~^ NOTE while parsing this struct + //~| ERROR expected one of `!`, `.`, `::`, `=>`, `?`, or an operator, found `{` + //~| NOTE expected one of `!`, `.`, `::`, `=>`, `?`, or an operator return //~^ ERROR expected identifier, found keyword `return` //~| NOTE expected identifier, found keyword } - //~^ NOTE expected one of `.`, `=>`, `?`, or an operator _ => {} - //~^ ERROR expected one of `.`, `=>`, `?`, or an operator, found reserved identifier `_` - //~| NOTE unexpected token } } diff --git a/src/test/ui/parser/issues/issue-15980.stderr b/src/test/ui/parser/issues/issue-15980.stderr index c59c811199ea8..67fb2d5edd613 100644 --- a/src/test/ui/parser/issues/issue-15980.stderr +++ b/src/test/ui/parser/issues/issue-15980.stderr @@ -1,9 +1,9 @@ error: expected identifier, found keyword `return` - --> $DIR/issue-15980.rs:8:13 + --> $DIR/issue-15980.rs:10:13 | LL | Err(ref e) if e.kind == io::EndOfFile { | ------------- while parsing this struct -LL | +... LL | return | ^^^^^^ expected identifier, found keyword | @@ -12,14 +12,16 @@ help: escape `return` to use it as an identifier LL | r#return | ++ -error: expected one of `.`, `=>`, `?`, or an operator, found reserved identifier `_` - --> $DIR/issue-15980.rs:13:9 +error: expected one of `!`, `.`, `::`, `=>`, `?`, or an operator, found `{` + --> $DIR/issue-15980.rs:6:47 | -LL | } - | - expected one of `.`, `=>`, `?`, or an operator -LL | -LL | _ => {} - | ^ unexpected token +LL | Err(ref e) if e.kind == io::EndOfFile { + | ^ expected one of `!`, `.`, `::`, `=>`, `?`, or an operator + | +help: try adding a fat arrow here + | +LL | Err(ref e) if e.kind == io::EndOfFile => { + | ++ error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/missing-fat-arrow-after-match-guard.rs b/src/test/ui/parser/missing-fat-arrow-after-match-guard.rs new file mode 100644 index 0000000000000..284680ebbea75 --- /dev/null +++ b/src/test/ui/parser/missing-fat-arrow-after-match-guard.rs @@ -0,0 +1,28 @@ +#[derive(PartialEq)] +struct Foo { + x: isize, +} + +fn foo() { + match () { + () if f == Foo { x: 42 } {} + //~^ ERROR expected one of `.`, `=>`, `?`, or an operator, found `{` + _ => {} + } +} + +fn main() { + let x = 1; + let y = 2; + let value = 3; + + match value { + Some(x) if x == y { + //~^ ERROR expected one of `!`, `.`, `::`, `=>`, `?`, or an operator, found `{` + x + }, + _ => { + y + } + } +} diff --git a/src/test/ui/parser/missing-fat-arrow-after-match-guard.stderr b/src/test/ui/parser/missing-fat-arrow-after-match-guard.stderr new file mode 100644 index 0000000000000..f2fd4ef844951 --- /dev/null +++ b/src/test/ui/parser/missing-fat-arrow-after-match-guard.stderr @@ -0,0 +1,24 @@ +error: expected one of `.`, `=>`, `?`, or an operator, found `{` + --> $DIR/missing-fat-arrow-after-match-guard.rs:8:34 + | +LL | () if f == Foo { x: 42 } {} + | ^ expected one of `.`, `=>`, `?`, or an operator + | +help: try adding a fat arrow here + | +LL | () if f == Foo { x: 42 } => {} + | ++ + +error: expected one of `!`, `.`, `::`, `=>`, `?`, or an operator, found `{` + --> $DIR/missing-fat-arrow-after-match-guard.rs:20:27 + | +LL | Some(x) if x == y { + | ^ expected one of `!`, `.`, `::`, `=>`, `?`, or an operator + | +help: try adding a fat arrow here + | +LL | Some(x) if x == y => { + | ++ + +error: aborting due to 2 previous errors +