From 5693a34db2f0e929995fe7aa03d307bafa9360aa Mon Sep 17 00:00:00 2001 From: sjwang05 <63834813+sjwang05@users.noreply.github.com> Date: Thu, 9 Nov 2023 00:31:42 -0800 Subject: [PATCH] Suggest fix for ; within let-chains --- compiler/rustc_parse/src/parser/expr.rs | 24 ++++++++++-- tests/ui/parser/semi-in-let-chain.rs | 27 +++++++++++++ tests/ui/parser/semi-in-let-chain.stderr | 50 ++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 4 deletions(-) create mode 100644 tests/ui/parser/semi-in-let-chain.rs create mode 100644 tests/ui/parser/semi-in-let-chain.stderr diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 19690a6964be9..235b28b6e26e2 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2441,10 +2441,26 @@ impl<'a> Parser<'a> { self.error_on_extra_if(&cond)?; // Parse block, which will always fail, but we can add a nice note to the error self.parse_block().map_err(|mut err| { - err.span_note( - cond_span, - "the `if` expression is missing a block after this condition", - ); + if self.prev_token == token::Semi + && self.token == token::AndAnd + && let maybe_let = self.look_ahead(1, |t| t.clone()) + && maybe_let.is_keyword(kw::Let) + { + err.span_suggestion( + self.prev_token.span, + "consider removing this semicolon to parse the `let` as part of the same chain", + "", + Applicability::MachineApplicable, + ).span_note( + self.token.span.to(maybe_let.span), + "you likely meant to continue parsing the let-chain starting here", + ); + } else { + err.span_note( + cond_span, + "the `if` expression is missing a block after this condition", + ); + } err })? } diff --git a/tests/ui/parser/semi-in-let-chain.rs b/tests/ui/parser/semi-in-let-chain.rs new file mode 100644 index 0000000000000..9c21af0372d25 --- /dev/null +++ b/tests/ui/parser/semi-in-let-chain.rs @@ -0,0 +1,27 @@ +// Issue #117720 + +#![feature(let_chains)] + +fn main() { + if let () = () + && let () = (); //~ERROR + && let () = () + { + } +} + +fn foo() { + if let () = () + && () == (); //~ERROR + && 1 < 0 + { + } +} + +fn bar() { + if let () = () + && () == (); //~ERROR + && let () = () + { + } +} diff --git a/tests/ui/parser/semi-in-let-chain.stderr b/tests/ui/parser/semi-in-let-chain.stderr new file mode 100644 index 0000000000000..c1a8f92965eb8 --- /dev/null +++ b/tests/ui/parser/semi-in-let-chain.stderr @@ -0,0 +1,50 @@ +error: expected `{`, found `;` + --> $DIR/semi-in-let-chain.rs:7:23 + | +LL | && let () = (); + | ^ expected `{` + | +note: you likely meant to continue parsing the let-chain starting here + --> $DIR/semi-in-let-chain.rs:8:9 + | +LL | && let () = () + | ^^^^^^ +help: consider removing this semicolon to parse the `let` as part of the same chain + | +LL - && let () = (); +LL + && let () = () + | + +error: expected `{`, found `;` + --> $DIR/semi-in-let-chain.rs:15:20 + | +LL | && () == (); + | ^ expected `{` + | +note: the `if` expression is missing a block after this condition + --> $DIR/semi-in-let-chain.rs:14:8 + | +LL | if let () = () + | ________^ +LL | | && () == (); + | |___________________^ + +error: expected `{`, found `;` + --> $DIR/semi-in-let-chain.rs:23:20 + | +LL | && () == (); + | ^ expected `{` + | +note: you likely meant to continue parsing the let-chain starting here + --> $DIR/semi-in-let-chain.rs:24:9 + | +LL | && let () = () + | ^^^^^^ +help: consider removing this semicolon to parse the `let` as part of the same chain + | +LL - && () == (); +LL + && () == () + | + +error: aborting due to 3 previous errors +