diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2021-12-02 22:16:13 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-12-02 22:16:13 +0100 |
| commit | dbb9e224af79a6c26c7b887662c5d2c21cf51b88 (patch) | |
| tree | 7adc33772286848c56a6a5d8018fd239d1daabbc /compiler/rustc_parse/src | |
| parent | 39641319ad135007b498e9f936a2894276c65d3b (diff) | |
| parent | ba7374e517415696c383a6c7b79214d2168dff21 (diff) | |
| download | rust-dbb9e224af79a6c26c7b887662c5d2c21cf51b88.tar.gz rust-dbb9e224af79a6c26c7b887662c5d2c21cf51b88.zip | |
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`
Diffstat (limited to 'compiler/rustc_parse/src')
| -rw-r--r-- | compiler/rustc_parse/src/parser/expr.rs | 51 |
1 files changed, 41 insertions, 10 deletions
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index f7ee874c831..1dbd7bad0f0 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -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") |
