Skip to content

Commit dbb9e22

Browse files
authored
Rollup merge of #91435 - FabianWolff:issue-91421-if-then, r=lcnr
Improve diagnostic for missing half of binary operator in `if` condition Fixes #91421. I've also changed it so that it doesn't consume the `else` token in the error case, because it will try to consume it again afterwards, leading to this incorrect error message (where the `else` reported as missing is actually there): ``` error: expected one of `.`, `;`, `?`, `else`, or an operator, found `{` --> src/main.rs:4:12 | 4 | } else { 4 }; | ^ expected one of `.`, `;`, `?`, `else`, or an operator ``` r? `@lcnr`
2 parents 3964131 + ba7374e commit dbb9e22

File tree

4 files changed

+77
-11
lines changed

4 files changed

+77
-11
lines changed

compiler/rustc_parse/src/parser/expr.rs

+41-10
Original file line numberDiff line numberDiff line change
@@ -1988,25 +1988,34 @@ impl<'a> Parser<'a> {
19881988
let lo = self.prev_token.span;
19891989
let cond = self.parse_cond_expr()?;
19901990

1991+
let missing_then_block_binop_span = || {
1992+
match cond.kind {
1993+
ExprKind::Binary(Spanned { span: binop_span, .. }, _, ref right)
1994+
if let ExprKind::Block(..) = right.kind => Some(binop_span),
1995+
_ => None
1996+
}
1997+
};
1998+
19911999
// Verify that the parsed `if` condition makes sense as a condition. If it is a block, then
19922000
// verify that the last statement is either an implicit return (no `;`) or an explicit
19932001
// return. This won't catch blocks with an explicit `return`, but that would be caught by
19942002
// the dead code lint.
1995-
let thn = if self.eat_keyword(kw::Else) || !cond.returns() {
1996-
self.error_missing_if_cond(lo, cond.span)
2003+
let thn = if self.token.is_keyword(kw::Else) || !cond.returns() {
2004+
if let Some(binop_span) = missing_then_block_binop_span() {
2005+
self.error_missing_if_then_block(lo, None, Some(binop_span)).emit();
2006+
self.mk_block_err(cond.span)
2007+
} else {
2008+
self.error_missing_if_cond(lo, cond.span)
2009+
}
19972010
} else {
19982011
let attrs = self.parse_outer_attributes()?.take_for_recovery(); // For recovery.
19992012
let not_block = self.token != token::OpenDelim(token::Brace);
2000-
let block = self.parse_block().map_err(|mut err| {
2013+
let block = self.parse_block().map_err(|err| {
20012014
if not_block {
2002-
err.span_label(lo, "this `if` expression has a condition, but no block");
2003-
if let ExprKind::Binary(_, _, ref right) = cond.kind {
2004-
if let ExprKind::Block(_, _) = right.kind {
2005-
err.help("maybe you forgot the right operand of the condition?");
2006-
}
2007-
}
2015+
self.error_missing_if_then_block(lo, Some(err), missing_then_block_binop_span())
2016+
} else {
2017+
err
20082018
}
2009-
err
20102019
})?;
20112020
self.error_on_if_block_attrs(lo, false, block.span, &attrs);
20122021
block
@@ -2015,6 +2024,28 @@ impl<'a> Parser<'a> {
20152024
Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::If(cond, thn, els), attrs))
20162025
}
20172026

2027+
fn error_missing_if_then_block(
2028+
&self,
2029+
if_span: Span,
2030+
err: Option<DiagnosticBuilder<'a>>,
2031+
binop_span: Option<Span>,
2032+
) -> DiagnosticBuilder<'a> {
2033+
let msg = "this `if` expression has a condition, but no block";
2034+
2035+
let mut err = if let Some(mut err) = err {
2036+
err.span_label(if_span, msg);
2037+
err
2038+
} else {
2039+
self.struct_span_err(if_span, msg)
2040+
};
2041+
2042+
if let Some(binop_span) = binop_span {
2043+
err.span_help(binop_span, "maybe you forgot the right operand of the condition?");
2044+
}
2045+
2046+
err
2047+
}
2048+
20182049
fn error_missing_if_cond(&self, lo: Span, span: Span) -> P<ast::Block> {
20192050
let sp = self.sess.source_map().next_point(lo);
20202051
self.struct_span_err(sp, "missing condition for `if` expression")

src/test/ui/expr/if/if-without-block.stderr

+5-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ LL | if 5 == {
77
LL | }
88
| ^ expected `{`
99
|
10-
= help: maybe you forgot the right operand of the condition?
10+
help: maybe you forgot the right operand of the condition?
11+
--> $DIR/if-without-block.rs:3:10
12+
|
13+
LL | if 5 == {
14+
| ^^
1115

1216
error: aborting due to previous error
1317

src/test/ui/parser/issue-91421.rs

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Regression test for issue #91421.
2+
3+
fn main() {
4+
let value = if true && {
5+
//~^ ERROR: this `if` expression has a condition, but no block
6+
//~| HELP: maybe you forgot the right operand of the condition?
7+
3
8+
//~^ ERROR: mismatched types [E0308]
9+
} else { 4 };
10+
}

src/test/ui/parser/issue-91421.stderr

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error: this `if` expression has a condition, but no block
2+
--> $DIR/issue-91421.rs:4:17
3+
|
4+
LL | let value = if true && {
5+
| ^^
6+
|
7+
help: maybe you forgot the right operand of the condition?
8+
--> $DIR/issue-91421.rs:4:25
9+
|
10+
LL | let value = if true && {
11+
| ^^
12+
13+
error[E0308]: mismatched types
14+
--> $DIR/issue-91421.rs:7:9
15+
|
16+
LL | 3
17+
| ^ expected `bool`, found integer
18+
19+
error: aborting due to 2 previous errors
20+
21+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)