more recovery in if-parsing

This commit is contained in:
Mazdak Farrokhzad 2019-12-06 23:23:30 +01:00
parent 7262dcc4a7
commit 44ff4df49d
15 changed files with 68 additions and 36 deletions

View File

@ -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<P<Expr>> = 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<ast::Block> {
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<Expr>> {
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<Expr>> {
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()))
}
}

View File

@ -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<Stmt>, rules: BlockCheckMode, span: Span) -> P<Block> {
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 }
}
}

View File

@ -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?");
| ^
| |

View File

@ -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");
}
}

View File

@ -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 `{`

View File

@ -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();
}

View File

@ -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`.

View File

@ -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 `{`

View File

@ -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

View File

@ -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

View File

@ -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
|

View File

@ -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

View File

@ -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;
| ^^^-
| |

View File

@ -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

View File

@ -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