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`
This commit is contained in:
Matthias Krüger 2021-12-02 22:16:13 +01:00 committed by GitHub
commit dbb9e224af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 77 additions and 11 deletions

View File

@ -1988,25 +1988,34 @@ impl<'a> Parser<'a> {
let lo = self.prev_token.span;
let cond = self.parse_cond_expr()?;
let missing_then_block_binop_span = || {
match cond.kind {
ExprKind::Binary(Spanned { span: binop_span, .. }, _, ref right)
if let ExprKind::Block(..) = right.kind => Some(binop_span),
_ => None
}
};
// Verify that the parsed `if` condition makes sense as a condition. If it is a block, then
// verify that the last statement is either an implicit return (no `;`) or an explicit
// return. This won't catch blocks with an explicit `return`, but that would be caught by
// the dead code lint.
let thn = if self.eat_keyword(kw::Else) || !cond.returns() {
self.error_missing_if_cond(lo, cond.span)
let thn = if self.token.is_keyword(kw::Else) || !cond.returns() {
if let Some(binop_span) = missing_then_block_binop_span() {
self.error_missing_if_then_block(lo, None, Some(binop_span)).emit();
self.mk_block_err(cond.span)
} else {
self.error_missing_if_cond(lo, cond.span)
}
} else {
let attrs = self.parse_outer_attributes()?.take_for_recovery(); // For recovery.
let not_block = self.token != token::OpenDelim(token::Brace);
let block = self.parse_block().map_err(|mut err| {
let block = self.parse_block().map_err(|err| {
if not_block {
err.span_label(lo, "this `if` expression has a condition, but no block");
if let ExprKind::Binary(_, _, ref right) = cond.kind {
if let ExprKind::Block(_, _) = right.kind {
err.help("maybe you forgot the right operand of the condition?");
}
}
self.error_missing_if_then_block(lo, Some(err), missing_then_block_binop_span())
} else {
err
}
err
})?;
self.error_on_if_block_attrs(lo, false, block.span, &attrs);
block
@ -2015,6 +2024,28 @@ impl<'a> Parser<'a> {
Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::If(cond, thn, els), attrs))
}
fn error_missing_if_then_block(
&self,
if_span: Span,
err: Option<DiagnosticBuilder<'a>>,
binop_span: Option<Span>,
) -> DiagnosticBuilder<'a> {
let msg = "this `if` expression has a condition, but no block";
let mut err = if let Some(mut err) = err {
err.span_label(if_span, msg);
err
} else {
self.struct_span_err(if_span, msg)
};
if let Some(binop_span) = binop_span {
err.span_help(binop_span, "maybe you forgot the right operand of the condition?");
}
err
}
fn error_missing_if_cond(&self, lo: Span, span: Span) -> P<ast::Block> {
let sp = self.sess.source_map().next_point(lo);
self.struct_span_err(sp, "missing condition for `if` expression")

View File

@ -7,7 +7,11 @@ LL | if 5 == {
LL | }
| ^ expected `{`
|
= help: maybe you forgot the right operand of the condition?
help: maybe you forgot the right operand of the condition?
--> $DIR/if-without-block.rs:3:10
|
LL | if 5 == {
| ^^
error: aborting due to previous error

View File

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

View File

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