From 0758c05c9792700dbc482eda8cd464c39d5ebed5 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Thu, 23 Feb 2023 20:12:01 +0100 Subject: [PATCH] recover from for-else and while-else --- compiler/rustc_parse/locales/en-US.ftl | 4 ++++ compiler/rustc_parse/src/errors.rs | 11 ++++++++++ compiler/rustc_parse/src/parser/expr.rs | 22 +++++++++++++++++++ tests/ui/for/for-else-err.rs | 8 +++++++ tests/ui/for/for-else-err.stderr | 17 ++++++++++++++ tests/ui/for/for-else-let-else-err.rs | 8 +++++++ tests/ui/for/for-else-let-else-err.stderr | 17 ++++++++++++++ .../let-else/let-else-brace-before-else.fixed | 4 ---- .../ui/let-else/let-else-brace-before-else.rs | 4 ---- .../let-else-brace-before-else.stderr | 17 +++----------- tests/ui/loops/loop-else-break-with-value.rs | 10 +++++++++ .../loops/loop-else-break-with-value.stderr | 18 +++++++++++++++ tests/ui/loops/loop-else-err.rs | 8 +++++++ tests/ui/loops/loop-else-err.stderr | 17 ++++++++++++++ tests/ui/loops/loop-else-let-else-err.rs | 8 +++++++ tests/ui/loops/loop-else-let-else-err.stderr | 17 ++++++++++++++ tests/ui/while/while-else-err.rs | 8 +++++++ tests/ui/while/while-else-err.stderr | 17 ++++++++++++++ tests/ui/while/while-else-let-else-err.rs | 8 +++++++ tests/ui/while/while-else-let-else-err.stderr | 17 ++++++++++++++ 20 files changed, 218 insertions(+), 22 deletions(-) create mode 100644 tests/ui/for/for-else-err.rs create mode 100644 tests/ui/for/for-else-err.stderr create mode 100644 tests/ui/for/for-else-let-else-err.rs create mode 100644 tests/ui/for/for-else-let-else-err.stderr create mode 100644 tests/ui/loops/loop-else-break-with-value.rs create mode 100644 tests/ui/loops/loop-else-break-with-value.stderr create mode 100644 tests/ui/loops/loop-else-err.rs create mode 100644 tests/ui/loops/loop-else-err.stderr create mode 100644 tests/ui/loops/loop-else-let-else-err.rs create mode 100644 tests/ui/loops/loop-else-let-else-err.stderr create mode 100644 tests/ui/while/while-else-err.rs create mode 100644 tests/ui/while/while-else-err.stderr create mode 100644 tests/ui/while/while-else-let-else-err.rs create mode 100644 tests/ui/while/while-else-let-else-err.stderr diff --git a/compiler/rustc_parse/locales/en-US.ftl b/compiler/rustc_parse/locales/en-US.ftl index 4ddeeed5b7e0a..e76e91fc1b135 100644 --- a/compiler/rustc_parse/locales/en-US.ftl +++ b/compiler/rustc_parse/locales/en-US.ftl @@ -151,6 +151,10 @@ parse_missing_in_in_for_loop = missing `in` in `for` loop parse_missing_expression_in_for_loop = missing expression to iterate on in `for` loop .suggestion = try adding an expression to the `for` loop +parse_loop_else = `{$loop_kind}...else` loops are not supported + .note = consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run + .loop_keyword = `else` is attached to this loop + parse_missing_comma_after_match_arm = expected `,` following `match` arm .suggestion = missing a comma here to end this `match` arm diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index c746a87096476..1662db36d10f9 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -451,6 +451,17 @@ pub(crate) struct MissingExpressionInForLoop { pub span: Span, } +#[derive(Diagnostic)] +#[diag(parse_loop_else)] +#[note] +pub(crate) struct LoopElseNotSupported { + #[primary_span] + pub span: Span, + pub loop_kind: &'static str, + #[label(parse_loop_keyword)] + pub loop_kw: Span, +} + #[derive(Diagnostic)] #[diag(parse_missing_comma_after_match_arm)] pub(crate) struct MissingCommaAfterMatchArm { diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 24d4c17f5d8ab..b2951e7a1847d 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2503,9 +2503,27 @@ impl<'a> Parser<'a> { let (attrs, loop_block) = self.parse_inner_attrs_and_block()?; let kind = ExprKind::ForLoop(pat, expr, loop_block, opt_label); + + self.recover_loop_else("for", lo)?; + Ok(self.mk_expr_with_attrs(lo.to(self.prev_token.span), kind, attrs)) } + /// Recovers from an `else` clause after a loop (`for...else`, `while...else`) + fn recover_loop_else(&mut self, loop_kind: &'static str, loop_kw: Span) -> PResult<'a, ()> { + if self.token.is_keyword(kw::Else) && self.may_recover() { + let else_span = self.token.span; + self.bump(); + let else_clause = self.parse_expr_else()?; + self.sess.emit_err(errors::LoopElseNotSupported { + span: else_span.to(else_clause.span), + loop_kind, + loop_kw, + }); + } + Ok(()) + } + fn error_missing_in_for_loop(&mut self) { let (span, sub): (_, fn(_) -> _) = if self.token.is_ident_named(sym::of) { // Possibly using JS syntax (#75311). @@ -2530,6 +2548,9 @@ impl<'a> Parser<'a> { err.span_label(cond.span, "this `while` condition successfully parsed"); err })?; + + self.recover_loop_else("while", lo)?; + Ok(self.mk_expr_with_attrs( lo.to(self.prev_token.span), ExprKind::While(cond, body, opt_label), @@ -2541,6 +2562,7 @@ impl<'a> Parser<'a> { fn parse_expr_loop(&mut self, opt_label: Option