Skip to content

Commit

Permalink
Rollup merge of #74650 - estebank:ambiguous-expr-binop, r=eddyb
Browse files Browse the repository at this point in the history
Correctly parse `{} && false` in tail expression

Fix #74233, fix #54186.
  • Loading branch information
tmandry committed Aug 14, 2020
2 parents 81dc88f + 9b5a974 commit 5b5eec7
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 25 deletions.
1 change: 0 additions & 1 deletion src/librustc_ast/util/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,6 @@ impl AssocOp {
Greater | // `{ 42 } > 3`
GreaterEqual | // `{ 42 } >= 3`
AssignOp(_) | // `{ 42 } +=`
LAnd | // `{ 42 } &&foo`
As | // `{ 42 } as usize`
// Equal | // `{ 42 } == { 42 }` Accepting these here would regress incorrect
// NotEqual | // `{ 42 } != { 42 } struct literals parser recovery.
Expand Down
11 changes: 9 additions & 2 deletions src/librustc_parse/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,11 +318,18 @@ impl<'a> Parser<'a> {
// want to keep their span info to improve diagnostics in these cases in a later stage.
(true, Some(AssocOp::Multiply)) | // `{ 42 } *foo = bar;` or `{ 42 } * 3`
(true, Some(AssocOp::Subtract)) | // `{ 42 } -5`
(true, Some(AssocOp::LAnd)) | // `{ 42 } &&x` (#61475)
(true, Some(AssocOp::Add)) // `{ 42 } + 42
// If the next token is a keyword, then the tokens above *are* unambiguously incorrect:
// `if x { a } else { b } && if y { c } else { d }`
if !self.look_ahead(1, |t| t.is_reserved_ident()) => {
if !self.look_ahead(1, |t| t.is_used_keyword()) => {
// These cases are ambiguous and can't be identified in the parser alone.
let sp = self.sess.source_map().start_point(self.token.span);
self.sess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span);
false
}
(true, Some(AssocOp::LAnd)) => {
// `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`. Separated from the
// above due to #74233.
// These cases are ambiguous and can't be identified in the parser alone.
let sp = self.sess.source_map().start_point(self.token.span);
self.sess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span);
Expand Down
1 change: 1 addition & 0 deletions src/librustc_typeck/check/demand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
self.suggest_missing_await(err, expr, expected, expr_ty);
self.suggest_missing_parentheses(err, expr);
self.note_need_for_fn_pointer(err, expected, expr_ty);
}

Expand Down
8 changes: 8 additions & 0 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5401,6 +5401,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}

fn suggest_missing_parentheses(&self, err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>) {
let sp = self.tcx.sess.source_map().start_point(expr.span);
if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) {
// `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
self.tcx.sess.parse_sess.expr_parentheses_needed(err, *sp, None);
}
}

fn note_need_for_fn_pointer(
&self,
err: &mut DiagnosticBuilder<'_>,
Expand Down
10 changes: 10 additions & 0 deletions src/test/ui/parser/expr-as-stmt-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// This is not autofixable because we give extra suggestions to end the first expression with `;`.
fn foo(a: Option<u32>, b: Option<u32>) -> bool {
if let Some(x) = a { true } else { false }
//~^ ERROR mismatched types
//~| ERROR mismatched types
&& //~ ERROR mismatched types
if let Some(y) = a { true } else { false }
}

fn main() {}
33 changes: 33 additions & 0 deletions src/test/ui/parser/expr-as-stmt-2.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
error[E0308]: mismatched types
--> $DIR/expr-as-stmt-2.rs:3:26
|
LL | if let Some(x) = a { true } else { false }
| ---------------------^^^^------------------ help: consider using a semicolon here
| | |
| | expected `()`, found `bool`
| expected this to be `()`

error[E0308]: mismatched types
--> $DIR/expr-as-stmt-2.rs:3:40
|
LL | if let Some(x) = a { true } else { false }
| -----------------------------------^^^^^--- help: consider using a semicolon here
| | |
| | expected `()`, found `bool`
| expected this to be `()`

error[E0308]: mismatched types
--> $DIR/expr-as-stmt-2.rs:6:5
|
LL | fn foo(a: Option<u32>, b: Option<u32>) -> bool {
| ---- expected `bool` because of return type
LL | if let Some(x) = a { true } else { false }
| ------------------------------------------ help: parentheses are required to parse this as an expression: `(if let Some(x) = a { true } else { false })`
...
LL | / &&
LL | | if let Some(y) = a { true } else { false }
| |______________________________________________^ expected `bool`, found `&&bool`

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0308`.
6 changes: 0 additions & 6 deletions src/test/ui/parser/expr-as-stmt.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,6 @@ fn baz() -> i32 {
//~^ ERROR mismatched types
}

fn qux(a: Option<u32>, b: Option<u32>) -> bool {
(if let Some(x) = a { true } else { false })
&& //~ ERROR expected expression
if let Some(y) = a { true } else { false }
}

fn moo(x: u32) -> bool {
(match x {
_ => 1,
Expand Down
6 changes: 0 additions & 6 deletions src/test/ui/parser/expr-as-stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,6 @@ fn baz() -> i32 {
//~^ ERROR mismatched types
}

fn qux(a: Option<u32>, b: Option<u32>) -> bool {
if let Some(x) = a { true } else { false }
&& //~ ERROR expected expression
if let Some(y) = a { true } else { false }
}

fn moo(x: u32) -> bool {
match x {
_ => 1,
Expand Down
12 changes: 2 additions & 10 deletions src/test/ui/parser/expr-as-stmt.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,8 @@ LL | { 42 } + foo;
| |
| help: parentheses are required to parse this as an expression: `({ 42 })`

error: expected expression, found `&&`
--> $DIR/expr-as-stmt.rs:30:5
|
LL | if let Some(x) = a { true } else { false }
| ------------------------------------------ help: parentheses are required to parse this as an expression: `(if let Some(x) = a { true } else { false })`
LL | &&
| ^^ expected expression

error: expected expression, found `>`
--> $DIR/expr-as-stmt.rs:37:7
--> $DIR/expr-as-stmt.rs:31:7
|
LL | } > 0
| ^ expected expression
Expand Down Expand Up @@ -75,7 +67,7 @@ LL | { 3 } * 3
| |
| help: parentheses are required to parse this as an expression: `({ 3 })`

error: aborting due to 10 previous errors
error: aborting due to 9 previous errors

Some errors have detailed explanations: E0308, E0614.
For more information about an error, try `rustc --explain E0308`.

0 comments on commit 5b5eec7

Please sign in to comment.