From 44ff4df49dfbff2d21999ec9360ed8df655a6d9b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 6 Dec 2019 23:23:30 +0100 Subject: [PATCH] more recovery in if-parsing --- src/librustc_parse/parser/expr.rs | 41 +++++++++++-------- src/librustc_parse/parser/stmt.rs | 8 +++- ...-identifier-not-instead-of-negation.stderr | 2 +- src/test/ui/if/if-without-block.rs | 2 +- src/test/ui/if/if-without-block.stderr | 2 +- src/test/ui/issues/issue-13483.rs | 2 + src/test/ui/issues/issue-13483.stderr | 23 ++++++++++- src/test/ui/issues/issue-39848.stderr | 2 +- src/test/ui/issues/issue-51602.stderr | 2 +- src/test/ui/issues/issue-61858.stderr | 2 +- src/test/ui/issues/issue-62554.stderr | 2 +- .../label_break_value_illegal_uses.stderr | 2 +- src/test/ui/missing/missing-block-hint.stderr | 4 +- .../ui/parser/attr-stmt-expr-attr-bad.stderr | 8 ++-- .../parser/doc-comment-in-if-statement.stderr | 2 +- 15 files changed, 68 insertions(+), 36 deletions(-) diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 17198040d25b..e67d3f6991af 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -1412,21 +1412,18 @@ impl<'a> Parser<'a> { // 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. - if self.eat_keyword(kw::Else) || !cond.returns() { - let sp = self.sess.source_map().next_point(lo); - let mut err = - self.diagnostic().struct_span_err(sp, "missing condition for `if` expression"); - err.span_label(sp, "expected if condition here"); - return Err(err); - } - let not_block = self.token != token::OpenDelim(token::Brace); - let thn = self.parse_block().map_err(|mut err| { - if not_block { - err.span_label(lo, "this `if` statement has a condition, but no block"); - } - err - })?; - let mut els: Option> = None; + let thn = if self.eat_keyword(kw::Else) || !cond.returns() { + self.error_missing_if_cond(lo, cond.span) + } else { + let not_block = self.token != token::OpenDelim(token::Brace); + self.parse_block().map_err(|mut err| { + if not_block { + err.span_label(lo, "this `if` expression has a condition, but no block"); + } + err + })? + }; + let mut els = None; let mut hi = thn.span; if self.eat_keyword(kw::Else) { let elexpr = self.parse_else_expr()?; @@ -1436,6 +1433,16 @@ impl<'a> Parser<'a> { Ok(self.mk_expr(lo.to(hi), ExprKind::If(cond, thn, els), attrs)) } + fn error_missing_if_cond(&self, lo: Span, span: Span) -> P { + let sp = self.sess.source_map().next_point(lo); + self.struct_span_err(sp, "missing condition for `if` expression") + .span_label(sp, "expected if condition here") + .emit(); + let expr = self.mk_expr_err(span); + let stmt = self.mk_stmt(span, ast::StmtKind::Expr(expr)); + self.mk_block(vec![stmt], BlockCheckMode::Default, span) + } + /// Parses the condition of a `if` or `while` expression. fn parse_cond_expr(&mut self) -> PResult<'a, P> { let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; @@ -1465,10 +1472,10 @@ impl<'a> Parser<'a> { /// Parses an `else { ... }` expression (`else` token already eaten). fn parse_else_expr(&mut self) -> PResult<'a, P> { if self.eat_keyword(kw::If) { - return self.parse_if_expr(AttrVec::new()); + self.parse_if_expr(AttrVec::new()) } else { let blk = self.parse_block()?; - return Ok(self.mk_expr(blk.span, ExprKind::Block(blk, None), AttrVec::new())); + Ok(self.mk_expr(blk.span, ExprKind::Block(blk, None), AttrVec::new())) } } diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs index ed5649310e3f..44a197503bd7 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/src/librustc_parse/parser/stmt.rs @@ -411,7 +411,7 @@ impl<'a> Parser<'a> { continue; }; } - Ok(P(ast::Block { stmts, id: DUMMY_NODE_ID, rules: s, span: lo.to(self.prev_span) })) + Ok(self.mk_block(stmts, s, lo.to(self.prev_span))) } /// Parses a statement, including the trailing semicolon. @@ -471,7 +471,11 @@ impl<'a> Parser<'a> { .emit(); } - fn mk_stmt(&self, span: Span, kind: StmtKind) -> Stmt { + pub(super) fn mk_block(&self, stmts: Vec, rules: BlockCheckMode, span: Span) -> P { + P(Block { stmts, id: DUMMY_NODE_ID, rules, span }) + } + + pub(super) fn mk_stmt(&self, span: Span, kind: StmtKind) -> Stmt { Stmt { id: DUMMY_NODE_ID, kind, span } } } diff --git a/src/test/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr b/src/test/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr index f5edbe2a3af5..8025886a9eb4 100644 --- a/src/test/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr +++ b/src/test/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr @@ -26,7 +26,7 @@ error: expected `{`, found `;` --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:20:31 | LL | if not // lack of braces is [sic] - | -- this `if` statement has a condition, but no block + | -- this `if` expression has a condition, but no block LL | println!("Then when?"); | ^ | | diff --git a/src/test/ui/if/if-without-block.rs b/src/test/ui/if/if-without-block.rs index 3dde0ed7c718..8a4c59f32613 100644 --- a/src/test/ui/if/if-without-block.rs +++ b/src/test/ui/if/if-without-block.rs @@ -1,7 +1,7 @@ fn main() { let n = 1; if 5 == { - //~^ NOTE this `if` statement has a condition, but no block + //~^ NOTE this `if` expression has a condition, but no block println!("five"); } } diff --git a/src/test/ui/if/if-without-block.stderr b/src/test/ui/if/if-without-block.stderr index 1e45045adece..34df8e3d7794 100644 --- a/src/test/ui/if/if-without-block.stderr +++ b/src/test/ui/if/if-without-block.stderr @@ -2,7 +2,7 @@ error: expected `{`, found `}` --> $DIR/if-without-block.rs:7:1 | LL | if 5 == { - | -- this `if` statement has a condition, but no block + | -- this `if` expression has a condition, but no block ... LL | } | ^ expected `{` diff --git a/src/test/ui/issues/issue-13483.rs b/src/test/ui/issues/issue-13483.rs index cb53523b3b04..a2fd9264b153 100644 --- a/src/test/ui/issues/issue-13483.rs +++ b/src/test/ui/issues/issue-13483.rs @@ -1,6 +1,7 @@ fn main() { if true { } else if { //~ ERROR missing condition + //~^ ERROR mismatched types } else { } } @@ -8,6 +9,7 @@ fn main() { fn foo() { if true { } else if { //~ ERROR missing condition + //~^ ERROR mismatched types } bar(); } diff --git a/src/test/ui/issues/issue-13483.stderr b/src/test/ui/issues/issue-13483.stderr index df9f1dd0115d..5fd05b18ce06 100644 --- a/src/test/ui/issues/issue-13483.stderr +++ b/src/test/ui/issues/issue-13483.stderr @@ -5,10 +5,29 @@ LL | } else if { | ^ expected if condition here error: missing condition for `if` expression - --> $DIR/issue-13483.rs:10:14 + --> $DIR/issue-13483.rs:11:14 | LL | } else if { | ^ expected if condition here -error: aborting due to 2 previous errors +error[E0308]: mismatched types + --> $DIR/issue-13483.rs:3:15 + | +LL | } else if { + | _______________^ +LL | | +LL | | } else { + | |_____^ expected `bool`, found `()` +error[E0308]: mismatched types + --> $DIR/issue-13483.rs:11:15 + | +LL | } else if { + | _______________^ +LL | | +LL | | } + | |_____^ expected `bool`, found `()` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-39848.stderr b/src/test/ui/issues/issue-39848.stderr index 47aa8e17a304..11b145d6e0dc 100644 --- a/src/test/ui/issues/issue-39848.stderr +++ b/src/test/ui/issues/issue-39848.stderr @@ -4,7 +4,7 @@ error: expected `{`, found `foo` LL | if $tgt.has_$field() {} | -- -- help: try placing this code inside a block: `{ () }` | | - | this `if` statement has a condition, but no block + | this `if` expression has a condition, but no block ... LL | get_opt!(bar, foo); | ^^^ expected `{` diff --git a/src/test/ui/issues/issue-51602.stderr b/src/test/ui/issues/issue-51602.stderr index 1ad69c0191b5..d800890bca38 100644 --- a/src/test/ui/issues/issue-51602.stderr +++ b/src/test/ui/issues/issue-51602.stderr @@ -4,7 +4,7 @@ error: expected `{`, found keyword `in` LL | if i in 1..10 { | -- ^^ expected `{` | | - | this `if` statement has a condition, but no block + | this `if` expression has a condition, but no block error: aborting due to previous error diff --git a/src/test/ui/issues/issue-61858.stderr b/src/test/ui/issues/issue-61858.stderr index ea2ec3d013f5..8b95d9c6ae48 100644 --- a/src/test/ui/issues/issue-61858.stderr +++ b/src/test/ui/issues/issue-61858.stderr @@ -4,7 +4,7 @@ error: expected `{`, found `)` LL | (if foobar) | -- ^ expected `{` | | - | this `if` statement has a condition, but no block + | this `if` expression has a condition, but no block error: aborting due to previous error diff --git a/src/test/ui/issues/issue-62554.stderr b/src/test/ui/issues/issue-62554.stderr index 87aaa0366132..d59546e23839 100644 --- a/src/test/ui/issues/issue-62554.stderr +++ b/src/test/ui/issues/issue-62554.stderr @@ -17,7 +17,7 @@ error: expected `{`, found `macro_rules` LL | fn foo(u: u8) { if u8 macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s loo mod u8 { | -- ^^^^^^^^^^^ expected `{` | | - | this `if` statement has a condition, but no block + | this `if` expression has a condition, but no block | help: try placing this code inside a block | diff --git a/src/test/ui/label/label_break_value_illegal_uses.stderr b/src/test/ui/label/label_break_value_illegal_uses.stderr index 0036f0f1db0f..46b53c65b481 100644 --- a/src/test/ui/label/label_break_value_illegal_uses.stderr +++ b/src/test/ui/label/label_break_value_illegal_uses.stderr @@ -12,7 +12,7 @@ LL | if true 'b: {} | | | | | expected `{` | | help: try placing this code inside a block: `{ 'b: {} }` - | this `if` statement has a condition, but no block + | this `if` expression has a condition, but no block error: expected `{`, found `'b` --> $DIR/label_break_value_illegal_uses.rs:14:21 diff --git a/src/test/ui/missing/missing-block-hint.stderr b/src/test/ui/missing/missing-block-hint.stderr index ee86a3241e82..0f635817bf46 100644 --- a/src/test/ui/missing/missing-block-hint.stderr +++ b/src/test/ui/missing/missing-block-hint.stderr @@ -4,13 +4,13 @@ error: expected `{`, found `=>` LL | if (foo) => {} | -- ^^ expected `{` | | - | this `if` statement has a condition, but no block + | this `if` expression has a condition, but no block error: expected `{`, found `bar` --> $DIR/missing-block-hint.rs:7:13 | LL | if (foo) - | -- this `if` statement has a condition, but no block + | -- this `if` expression has a condition, but no block LL | bar; | ^^^- | | diff --git a/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr b/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr index 9a0d3176714f..30aa820141cf 100644 --- a/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr +++ b/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr @@ -149,7 +149,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; } | -- ^ --- help: try placing this code inside a block: `{ {}; }` | | | | | expected `{` - | this `if` statement has a condition, but no block + | this `if` expression has a condition, but no block error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:43:38 @@ -202,7 +202,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; } | -- ^ --- help: try placing this code inside a block: `{ {}; }` | | | | | expected `{` - | this `if` statement has a condition, but no block + | this `if` expression has a condition, but no block error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:56:51 @@ -225,7 +225,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; } | -- ^ --- help: try placing this code inside a block: `{ {}; }` | | | | | expected `{` - | this `if` statement has a condition, but no block + | this `if` expression has a condition, but no block error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:62:46 @@ -278,7 +278,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {} | -- ^ --- help: try placing this code inside a block: `{ {}; }` | | | | | expected `{` - | this `if` statement has a condition, but no block + | this `if` expression has a condition, but no block error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:75:67 diff --git a/src/test/ui/parser/doc-comment-in-if-statement.stderr b/src/test/ui/parser/doc-comment-in-if-statement.stderr index 6bcb77385d7d..a720dd68bd03 100644 --- a/src/test/ui/parser/doc-comment-in-if-statement.stderr +++ b/src/test/ui/parser/doc-comment-in-if-statement.stderr @@ -4,7 +4,7 @@ error: expected `{`, found doc comment `/*!*/` LL | if true /*!*/ {} | -- ^^^^^ expected `{` | | - | this `if` statement has a condition, but no block + | this `if` expression has a condition, but no block error: aborting due to previous error