From aedc1b6ad4845242d06a3f7cfb9b57db227b3511 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Dec 2023 17:37:32 -0800 Subject: [PATCH] Remove MacCall special case from recovery after missing 'if' after 'else' The change to the test is a little goofy because the compiler was guessing "correctly" before that `falsy! {}` is the condition as opposed to the else body. But I believe this change is fundamentally correct. Braced macro invocations in statement position are most often item-like (`thread_local! {...}`) as opposed to parenthesized macro invocations which are condition-like (`cfg!(...)`). --- compiler/rustc_parse/src/parser/expr.rs | 34 ++++++++++++++++++++----- tests/ui/parser/else-no-if.stderr | 10 +++----- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index bb0873a814d..52e3e33691a 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2733,13 +2733,35 @@ fn parse_expr_else(&mut self) -> PResult<'a, P> { let first_tok_span = self.token.span; match self.parse_expr() { Ok(cond) - // If it's not a free-standing expression, and is followed by a block, - // then it's very likely the condition to an `else if`. + // Try to guess the difference between a "condition-like" vs + // "statement-like" expression. + // + // We are seeing the following code, in which $cond is neither + // ExprKind::Block nor ExprKind::If (the 2 cases wherein this + // would be valid syntax). + // + // if ... { + // } else $cond + // + // If $cond is "condition-like" such as ExprKind::Binary, we + // want to suggest inserting `if`. + // + // if ... { + // } else if a == b { + // ^^ + // } + // + // If $cond is "statement-like" such as ExprKind::While then we + // want to suggest wrapping in braces. + // + // if ... { + // } else { + // ^ + // while true {} + // } + // ^ if self.check(&TokenKind::OpenDelim(Delimiter::Brace)) - && match cond.kind { - ExprKind::MacCall(_) => true, - _ => classify::expr_requires_semi_to_be_stmt(&cond), - } => + && classify::expr_requires_semi_to_be_stmt(&cond) => { self.dcx().emit_err(errors::ExpectedElseBlock { first_tok_span, diff --git a/tests/ui/parser/else-no-if.stderr b/tests/ui/parser/else-no-if.stderr index 9954505e7c8..2e3e8f6b50e 100644 --- a/tests/ui/parser/else-no-if.stderr +++ b/tests/ui/parser/else-no-if.stderr @@ -74,14 +74,12 @@ error: expected `{`, found `falsy` --> $DIR/else-no-if.rs:47:12 | LL | } else falsy! {} { - | ---- ^^^^^ - | | - | expected an `if` or a block after this `else` + | ^^^^^ expected `{` | -help: add an `if` if this is the condition of a chained `else if` statement +help: try placing this code inside a block | -LL | } else if falsy! {} { - | ++ +LL | } else { falsy! {} } { + | + + error: expected `{`, found `falsy` --> $DIR/else-no-if.rs:54:12