Improve diagnostic for missing half of binary operator in if
condition
This commit is contained in:
parent
6db0a0e9a4
commit
ba7374e517
@ -1988,25 +1988,34 @@ impl<'a> Parser<'a> {
|
|||||||
let lo = self.prev_token.span;
|
let lo = self.prev_token.span;
|
||||||
let cond = self.parse_cond_expr()?;
|
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 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
|
// 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
|
// return. This won't catch blocks with an explicit `return`, but that would be caught by
|
||||||
// the dead code lint.
|
// the dead code lint.
|
||||||
let thn = if self.eat_keyword(kw::Else) || !cond.returns() {
|
let thn = if self.token.is_keyword(kw::Else) || !cond.returns() {
|
||||||
self.error_missing_if_cond(lo, cond.span)
|
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 {
|
} else {
|
||||||
let attrs = self.parse_outer_attributes()?.take_for_recovery(); // For recovery.
|
let attrs = self.parse_outer_attributes()?.take_for_recovery(); // For recovery.
|
||||||
let not_block = self.token != token::OpenDelim(token::Brace);
|
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 {
|
if not_block {
|
||||||
err.span_label(lo, "this `if` expression has a condition, but no block");
|
self.error_missing_if_then_block(lo, Some(err), missing_then_block_binop_span())
|
||||||
if let ExprKind::Binary(_, _, ref right) = cond.kind {
|
} else {
|
||||||
if let ExprKind::Block(_, _) = right.kind {
|
err
|
||||||
err.help("maybe you forgot the right operand of the condition?");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
err
|
|
||||||
})?;
|
})?;
|
||||||
self.error_on_if_block_attrs(lo, false, block.span, &attrs);
|
self.error_on_if_block_attrs(lo, false, block.span, &attrs);
|
||||||
block
|
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))
|
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> {
|
fn error_missing_if_cond(&self, lo: Span, span: Span) -> P<ast::Block> {
|
||||||
let sp = self.sess.source_map().next_point(lo);
|
let sp = self.sess.source_map().next_point(lo);
|
||||||
self.struct_span_err(sp, "missing condition for `if` expression")
|
self.struct_span_err(sp, "missing condition for `if` expression")
|
||||||
|
@ -7,7 +7,11 @@ LL | if 5 == {
|
|||||||
LL | }
|
LL | }
|
||||||
| ^ expected `{`
|
| ^ 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
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
10
src/test/ui/parser/issue-91421.rs
Normal file
10
src/test/ui/parser/issue-91421.rs
Normal 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 };
|
||||||
|
}
|
21
src/test/ui/parser/issue-91421.stderr
Normal file
21
src/test/ui/parser/issue-91421.stderr
Normal 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`.
|
Loading…
x
Reference in New Issue
Block a user