Skip to content

Commit 2f62fd3

Browse files
authored
Rollup merge of #133051 - estebank:cond-misparse, r=jieyouxu
Increase accuracy of `if` condition misparse suggestion Fix #132656. Look at the expression that was parsed when trying to recover from a bad `if` condition to determine what was likely intended by the user beyond "maybe this was meant to be an `else` body". ``` error: expected `{`, found `map` --> $DIR/missing-dot-on-if-condition-expression-fixable.rs:4:30 | LL | for _ in [1, 2, 3].iter()map(|x| x) {} | ^^^ expected `{` | help: you might have meant to write a method call | LL | for _ in [1, 2, 3].iter().map(|x| x) {} | + ``` If a macro statement has been parsed after `else`, suggest a missing `if`: ``` error: expected `{`, found `falsy` --> $DIR/else-no-if.rs:47:12 | LL | } else falsy! {} { | ---- ^^^^^ | | | expected an `if` or a block after this `else` | help: add an `if` if this is the condition of a chained `else if` statement | LL | } else if falsy! {} { | ++ ```
2 parents 2d9690d + 6913194 commit 2f62fd3

17 files changed

+435
-36
lines changed

compiler/rustc_parse/src/parser/expr.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -2683,6 +2683,13 @@ impl<'a> Parser<'a> {
26832683
// ^^
26842684
// }
26852685
//
2686+
// We account for macro calls that were meant as conditions as well.
2687+
//
2688+
// if ... {
2689+
// } else if macro! { foo bar } {
2690+
// ^^
2691+
// }
2692+
//
26862693
// If $cond is "statement-like" such as ExprKind::While then we
26872694
// want to suggest wrapping in braces.
26882695
//
@@ -2693,7 +2700,9 @@ impl<'a> Parser<'a> {
26932700
// }
26942701
// ^
26952702
if self.check(&TokenKind::OpenDelim(Delimiter::Brace))
2696-
&& classify::expr_requires_semi_to_be_stmt(&cond) =>
2703+
&& (classify::expr_requires_semi_to_be_stmt(&cond)
2704+
|| matches!(cond.kind, ExprKind::MacCall(..)))
2705+
=>
26972706
{
26982707
self.dcx().emit_err(errors::ExpectedElseBlock {
26992708
first_tok_span,

compiler/rustc_parse/src/parser/stmt.rs

+102-7
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,7 @@ impl<'a> Parser<'a> {
475475
}
476476

477477
fn error_block_no_opening_brace_msg(&mut self, msg: Cow<'static, str>) -> Diag<'a> {
478+
let prev = self.prev_token.span;
478479
let sp = self.token.span;
479480
let mut e = self.dcx().struct_span_err(sp, msg);
480481
let do_not_suggest_help = self.token.is_keyword(kw::In) || self.token == token::Colon;
@@ -514,8 +515,97 @@ impl<'a> Parser<'a> {
514515
} else {
515516
stmt.span
516517
};
518+
self.suggest_fixes_misparsed_for_loop_head(
519+
&mut e,
520+
prev.between(sp),
521+
stmt_span,
522+
&stmt.kind,
523+
);
524+
}
525+
Err(e) => {
526+
self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore);
527+
e.cancel();
528+
}
529+
_ => {}
530+
}
531+
e.span_label(sp, "expected `{`");
532+
e
533+
}
534+
535+
fn suggest_fixes_misparsed_for_loop_head(
536+
&self,
537+
e: &mut Diag<'_>,
538+
between: Span,
539+
stmt_span: Span,
540+
stmt_kind: &StmtKind,
541+
) {
542+
match (&self.token.kind, &stmt_kind) {
543+
(token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
544+
if let ExprKind::Call(..) = expr.kind =>
545+
{
546+
// for _ in x y() {}
547+
e.span_suggestion_verbose(
548+
between,
549+
"you might have meant to write a method call",
550+
".".to_string(),
551+
Applicability::MaybeIncorrect,
552+
);
553+
}
554+
(token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
555+
if let ExprKind::Field(..) = expr.kind =>
556+
{
557+
// for _ in x y.z {}
558+
e.span_suggestion_verbose(
559+
between,
560+
"you might have meant to write a field access",
561+
".".to_string(),
562+
Applicability::MaybeIncorrect,
563+
);
564+
}
565+
(token::CloseDelim(Delimiter::Brace), StmtKind::Expr(expr))
566+
if let ExprKind::Struct(expr) = &expr.kind
567+
&& let None = expr.qself
568+
&& expr.path.segments.len() == 1 =>
569+
{
570+
// This is specific to "mistyped `if` condition followed by empty body"
571+
//
572+
// for _ in x y {}
573+
e.span_suggestion_verbose(
574+
between,
575+
"you might have meant to write a field access",
576+
".".to_string(),
577+
Applicability::MaybeIncorrect,
578+
);
579+
}
580+
(token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
581+
if let ExprKind::Lit(lit) = expr.kind
582+
&& let None = lit.suffix
583+
&& let token::LitKind::Integer | token::LitKind::Float = lit.kind =>
584+
{
585+
// for _ in x 0 {}
586+
// for _ in x 0.0 {}
587+
e.span_suggestion_verbose(
588+
between,
589+
format!("you might have meant to write a field access"),
590+
".".to_string(),
591+
Applicability::MaybeIncorrect,
592+
);
593+
}
594+
(token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
595+
if let ExprKind::Loop(..)
596+
| ExprKind::If(..)
597+
| ExprKind::While(..)
598+
| ExprKind::Match(..)
599+
| ExprKind::ForLoop { .. }
600+
| ExprKind::TryBlock(..)
601+
| ExprKind::Ret(..)
602+
| ExprKind::Closure(..)
603+
| ExprKind::Struct(..)
604+
| ExprKind::Try(..) = expr.kind =>
605+
{
606+
// These are more likely to have been meant as a block body.
517607
e.multipart_suggestion(
518-
"try placing this code inside a block",
608+
"you might have meant to write this as part of a block",
519609
vec![
520610
(stmt_span.shrink_to_lo(), "{ ".to_string()),
521611
(stmt_span.shrink_to_hi(), " }".to_string()),
@@ -524,14 +614,19 @@ impl<'a> Parser<'a> {
524614
Applicability::MaybeIncorrect,
525615
);
526616
}
527-
Err(e) => {
528-
self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore);
529-
e.cancel();
617+
(token::OpenDelim(Delimiter::Brace), _) => {}
618+
(_, _) => {
619+
e.multipart_suggestion(
620+
"you might have meant to write this as part of a block",
621+
vec![
622+
(stmt_span.shrink_to_lo(), "{ ".to_string()),
623+
(stmt_span.shrink_to_hi(), " }".to_string()),
624+
],
625+
// Speculative; has been misleading in the past (#46836).
626+
Applicability::MaybeIncorrect,
627+
);
530628
}
531-
_ => {}
532629
}
533-
e.span_label(sp, "expected `{`");
534-
e
535630
}
536631

537632
fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> {

tests/ui/issues/issue-39848.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ LL | if $tgt.has_$field() {}
1616
LL | get_opt!(bar, foo);
1717
| ------------------ in this macro invocation
1818
= note: this error originates in the macro `get_opt` (in Nightly builds, run with -Z macro-backtrace for more info)
19-
help: try placing this code inside a block
19+
help: you might have meant to write a method call
2020
|
21-
LL | if $tgt.has_{ $field() } {}
22-
| + +
21+
LL | if $tgt.has_.$field() {}
22+
| +
2323

2424
error: aborting due to 1 previous error
2525

tests/ui/let-else/let-else-if.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error: conditional `else if` is not supported for `let...else`
44
LL | let Some(_) = Some(()) else if true {
55
| ^^ expected `{`
66
|
7-
help: try placing this code inside a block
7+
help: you might have meant to write this as part of a block
88
|
99
LL ~ let Some(_) = Some(()) else { if true {
1010
LL |

tests/ui/lint/issue-104392.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ LL | { unsafe 92 }
66
| |
77
| while parsing this `unsafe` expression
88
|
9-
help: try placing this code inside a block
9+
help: you might have meant to write this as part of a block
1010
|
1111
LL | { unsafe { 92 } }
1212
| + +

tests/ui/missing/missing-block-hint.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ note: the `if` expression is missing a block after this condition
2525
|
2626
LL | if (foo)
2727
| ^^^^^
28-
help: try placing this code inside a block
28+
help: you might have meant to write this as part of a block
2929
|
3030
LL | { bar; }
3131
| + +

tests/ui/parser/bad-if-statements.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ note: the `if` expression is missing a block after this condition
2929
|
3030
LL | if true x
3131
| ^^^^
32-
help: try placing this code inside a block
32+
help: you might have meant to write this as part of a block
3333
|
3434
LL | if true { x }
3535
| + +
@@ -65,7 +65,7 @@ note: the `if` expression is missing a block after this condition
6565
|
6666
LL | if true x else {}
6767
| ^^^^
68-
help: try placing this code inside a block
68+
help: you might have meant to write this as part of a block
6969
|
7070
LL | if true { x } else {}
7171
| + +

tests/ui/parser/block-no-opening-brace.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ LL | loop
66
LL | let x = 0;
77
| ^^^ expected `{`
88
|
9-
help: try placing this code inside a block
9+
help: you might have meant to write this as part of a block
1010
|
1111
LL | { let x = 0; }
1212
| + +
@@ -21,7 +21,7 @@ LL | while true
2121
LL | let x = 0;
2222
| ^^^ expected `{`
2323
|
24-
help: try placing this code inside a block
24+
help: you might have meant to write this as part of a block
2525
|
2626
LL | { let x = 0; }
2727
| + +
@@ -32,7 +32,7 @@ error: expected `{`, found keyword `let`
3232
LL | let x = 0;
3333
| ^^^ expected `{`
3434
|
35-
help: try placing this code inside a block
35+
help: you might have meant to write this as part of a block
3636
|
3737
LL | { let x = 0; }
3838
| + +

tests/ui/parser/closure-return-syntax.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error: expected `{`, found `22`
44
LL | let x = || -> i32 22;
55
| ^^ expected `{`
66
|
7-
help: try placing this code inside a block
7+
help: you might have meant to write this as part of a block
88
|
99
LL | let x = || -> i32 { 22 };
1010
| + +

tests/ui/parser/else-no-if.stderr

+10-8
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ error: expected `{`, found `falsy`
3030
LL | } else falsy();
3131
| ^^^^^ expected `{`
3232
|
33-
help: try placing this code inside a block
33+
help: you might have meant to write this as part of a block
3434
|
3535
LL | } else { falsy() };
3636
| + +
@@ -41,7 +41,7 @@ error: expected `{`, found keyword `loop`
4141
LL | } else loop{}
4242
| ^^^^ expected `{`
4343
|
44-
help: try placing this code inside a block
44+
help: you might have meant to write this as part of a block
4545
|
4646
LL | } else { loop{} }
4747
| + +
@@ -65,7 +65,7 @@ error: expected `{`, found `falsy`
6565
LL | } else falsy!();
6666
| ^^^^^ expected `{`
6767
|
68-
help: try placing this code inside a block
68+
help: you might have meant to write this as part of a block
6969
|
7070
LL | } else { falsy!() };
7171
| + +
@@ -74,20 +74,22 @@ error: expected `{`, found `falsy`
7474
--> $DIR/else-no-if.rs:47:12
7575
|
7676
LL | } else falsy! {} {
77-
| ^^^^^ expected `{`
77+
| ---- ^^^^^
78+
| |
79+
| expected an `if` or a block after this `else`
7880
|
79-
help: try placing this code inside a block
81+
help: add an `if` if this is the condition of a chained `else if` statement
8082
|
81-
LL | } else { falsy! {} } {
82-
| + +
83+
LL | } else if falsy! {} {
84+
| ++
8385

8486
error: expected `{`, found `falsy`
8587
--> $DIR/else-no-if.rs:54:12
8688
|
8789
LL | } else falsy! {};
8890
| ^^^^^ expected `{`
8991
|
90-
help: try placing this code inside a block
92+
help: you might have meant to write this as part of a block
9193
|
9294
LL | } else { falsy! {} };
9395
| + +

tests/ui/parser/label-after-block-like.stderr

+7-7
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ note: the `if` expression is missing a block after this condition
2323
|
2424
LL | if let () = () 'a {}
2525
| ^^^^^^^^^^^
26-
help: try placing this code inside a block
26+
help: you might have meant to write this as part of a block
2727
|
2828
LL | if let () = () { 'a {} }
2929
| + +
@@ -53,7 +53,7 @@ note: the `if` expression is missing a block after this condition
5353
|
5454
LL | if true 'a {}
5555
| ^^^^
56-
help: try placing this code inside a block
56+
help: you might have meant to write this as part of a block
5757
|
5858
LL | if true { 'a {} }
5959
| + +
@@ -80,7 +80,7 @@ LL | loop 'a {}
8080
| |
8181
| while parsing this `loop` expression
8282
|
83-
help: try placing this code inside a block
83+
help: you might have meant to write this as part of a block
8484
|
8585
LL | loop { 'a {} }
8686
| + +
@@ -108,7 +108,7 @@ LL | while true 'a {}
108108
| | this `while` condition successfully parsed
109109
| while parsing the body of this `while` expression
110110
|
111-
help: try placing this code inside a block
111+
help: you might have meant to write this as part of a block
112112
|
113113
LL | while true { 'a {} }
114114
| + +
@@ -136,7 +136,7 @@ LL | while let () = () 'a {}
136136
| | this `while` condition successfully parsed
137137
| while parsing the body of this `while` expression
138138
|
139-
help: try placing this code inside a block
139+
help: you might have meant to write this as part of a block
140140
|
141141
LL | while let () = () { 'a {} }
142142
| + +
@@ -161,7 +161,7 @@ error: expected `{`, found `'a`
161161
LL | for _ in 0..0 'a {}
162162
| ^^ expected `{`
163163
|
164-
help: try placing this code inside a block
164+
help: you might have meant to write this as part of a block
165165
|
166166
LL | for _ in 0..0 { 'a {} }
167167
| + +
@@ -188,7 +188,7 @@ LL | unsafe 'a {}
188188
| |
189189
| while parsing this `unsafe` expression
190190
|
191-
help: try placing this code inside a block
191+
help: you might have meant to write this as part of a block
192192
|
193193
LL | unsafe { 'a {} }
194194
| + +

0 commit comments

Comments
 (0)