Skip to content

Commit 5b5eec7

Browse files
authored
Rollup merge of #74650 - estebank:ambiguous-expr-binop, r=eddyb
Correctly parse `{} && false` in tail expression Fix #74233, fix #54186.
2 parents 81dc88f + 9b5a974 commit 5b5eec7

File tree

9 files changed

+63
-25
lines changed

9 files changed

+63
-25
lines changed

src/librustc_ast/util/parser.rs

-1
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,6 @@ impl AssocOp {
222222
Greater | // `{ 42 } > 3`
223223
GreaterEqual | // `{ 42 } >= 3`
224224
AssignOp(_) | // `{ 42 } +=`
225-
LAnd | // `{ 42 } &&foo`
226225
As | // `{ 42 } as usize`
227226
// Equal | // `{ 42 } == { 42 }` Accepting these here would regress incorrect
228227
// NotEqual | // `{ 42 } != { 42 } struct literals parser recovery.

src/librustc_parse/parser/expr.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -318,11 +318,18 @@ impl<'a> Parser<'a> {
318318
// want to keep their span info to improve diagnostics in these cases in a later stage.
319319
(true, Some(AssocOp::Multiply)) | // `{ 42 } *foo = bar;` or `{ 42 } * 3`
320320
(true, Some(AssocOp::Subtract)) | // `{ 42 } -5`
321-
(true, Some(AssocOp::LAnd)) | // `{ 42 } &&x` (#61475)
322321
(true, Some(AssocOp::Add)) // `{ 42 } + 42
323322
// If the next token is a keyword, then the tokens above *are* unambiguously incorrect:
324323
// `if x { a } else { b } && if y { c } else { d }`
325-
if !self.look_ahead(1, |t| t.is_reserved_ident()) => {
324+
if !self.look_ahead(1, |t| t.is_used_keyword()) => {
325+
// These cases are ambiguous and can't be identified in the parser alone.
326+
let sp = self.sess.source_map().start_point(self.token.span);
327+
self.sess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span);
328+
false
329+
}
330+
(true, Some(AssocOp::LAnd)) => {
331+
// `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`. Separated from the
332+
// above due to #74233.
326333
// These cases are ambiguous and can't be identified in the parser alone.
327334
let sp = self.sess.source_map().start_point(self.token.span);
328335
self.sess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span);

src/librustc_typeck/check/demand.rs

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
3434
}
3535
self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
3636
self.suggest_missing_await(err, expr, expected, expr_ty);
37+
self.suggest_missing_parentheses(err, expr);
3738
self.note_need_for_fn_pointer(err, expected, expr_ty);
3839
}
3940

src/librustc_typeck/check/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -5401,6 +5401,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
54015401
}
54025402
}
54035403

5404+
fn suggest_missing_parentheses(&self, err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>) {
5405+
let sp = self.tcx.sess.source_map().start_point(expr.span);
5406+
if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) {
5407+
// `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
5408+
self.tcx.sess.parse_sess.expr_parentheses_needed(err, *sp, None);
5409+
}
5410+
}
5411+
54045412
fn note_need_for_fn_pointer(
54055413
&self,
54065414
err: &mut DiagnosticBuilder<'_>,

src/test/ui/parser/expr-as-stmt-2.rs

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// This is not autofixable because we give extra suggestions to end the first expression with `;`.
2+
fn foo(a: Option<u32>, b: Option<u32>) -> bool {
3+
if let Some(x) = a { true } else { false }
4+
//~^ ERROR mismatched types
5+
//~| ERROR mismatched types
6+
&& //~ ERROR mismatched types
7+
if let Some(y) = a { true } else { false }
8+
}
9+
10+
fn main() {}
+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/expr-as-stmt-2.rs:3:26
3+
|
4+
LL | if let Some(x) = a { true } else { false }
5+
| ---------------------^^^^------------------ help: consider using a semicolon here
6+
| | |
7+
| | expected `()`, found `bool`
8+
| expected this to be `()`
9+
10+
error[E0308]: mismatched types
11+
--> $DIR/expr-as-stmt-2.rs:3:40
12+
|
13+
LL | if let Some(x) = a { true } else { false }
14+
| -----------------------------------^^^^^--- help: consider using a semicolon here
15+
| | |
16+
| | expected `()`, found `bool`
17+
| expected this to be `()`
18+
19+
error[E0308]: mismatched types
20+
--> $DIR/expr-as-stmt-2.rs:6:5
21+
|
22+
LL | fn foo(a: Option<u32>, b: Option<u32>) -> bool {
23+
| ---- expected `bool` because of return type
24+
LL | if let Some(x) = a { true } else { false }
25+
| ------------------------------------------ help: parentheses are required to parse this as an expression: `(if let Some(x) = a { true } else { false })`
26+
...
27+
LL | / &&
28+
LL | | if let Some(y) = a { true } else { false }
29+
| |______________________________________________^ expected `bool`, found `&&bool`
30+
31+
error: aborting due to 3 previous errors
32+
33+
For more information about this error, try `rustc --explain E0308`.

src/test/ui/parser/expr-as-stmt.fixed

-6
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,6 @@ fn baz() -> i32 {
2525
//~^ ERROR mismatched types
2626
}
2727

28-
fn qux(a: Option<u32>, b: Option<u32>) -> bool {
29-
(if let Some(x) = a { true } else { false })
30-
&& //~ ERROR expected expression
31-
if let Some(y) = a { true } else { false }
32-
}
33-
3428
fn moo(x: u32) -> bool {
3529
(match x {
3630
_ => 1,

src/test/ui/parser/expr-as-stmt.rs

-6
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,6 @@ fn baz() -> i32 {
2525
//~^ ERROR mismatched types
2626
}
2727

28-
fn qux(a: Option<u32>, b: Option<u32>) -> bool {
29-
if let Some(x) = a { true } else { false }
30-
&& //~ ERROR expected expression
31-
if let Some(y) = a { true } else { false }
32-
}
33-
3428
fn moo(x: u32) -> bool {
3529
match x {
3630
_ => 1,

src/test/ui/parser/expr-as-stmt.stderr

+2-10
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,8 @@ LL | { 42 } + foo;
2222
| |
2323
| help: parentheses are required to parse this as an expression: `({ 42 })`
2424

25-
error: expected expression, found `&&`
26-
--> $DIR/expr-as-stmt.rs:30:5
27-
|
28-
LL | if let Some(x) = a { true } else { false }
29-
| ------------------------------------------ help: parentheses are required to parse this as an expression: `(if let Some(x) = a { true } else { false })`
30-
LL | &&
31-
| ^^ expected expression
32-
3325
error: expected expression, found `>`
34-
--> $DIR/expr-as-stmt.rs:37:7
26+
--> $DIR/expr-as-stmt.rs:31:7
3527
|
3628
LL | } > 0
3729
| ^ expected expression
@@ -75,7 +67,7 @@ LL | { 3 } * 3
7567
| |
7668
| help: parentheses are required to parse this as an expression: `({ 3 })`
7769

78-
error: aborting due to 10 previous errors
70+
error: aborting due to 9 previous errors
7971

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

0 commit comments

Comments
 (0)