about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Tolnay <dtolnay@gmail.com>2023-12-29 17:37:32 -0800
committerDavid Tolnay <dtolnay@gmail.com>2024-05-11 15:49:51 -0700
commitaedc1b6ad4845242d06a3f7cfb9b57db227b3511 (patch)
tree870db4f5636d88f78590959bb71249bf50eb9ca6
parent0f6a51d4958dff5a29c121801bcdd619d71db541 (diff)
downloadrust-aedc1b6ad4845242d06a3f7cfb9b57db227b3511.tar.gz
rust-aedc1b6ad4845242d06a3f7cfb9b57db227b3511.zip
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!(...)`).
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs34
-rw-r--r--tests/ui/parser/else-no-if.stderr10
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 @@ impl<'a> Parser<'a> {
             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