]> git.lizzy.rs Git - rust.git/commitdiff
Correctly parse `{} && false` in tail expression
authorEsteban Küber <esteban@kuber.com.ar>
Wed, 22 Jul 2020 19:01:56 +0000 (12:01 -0700)
committerEsteban Küber <esteban@kuber.com.ar>
Wed, 22 Jul 2020 19:01:56 +0000 (12:01 -0700)
Fix #74233.

src/librustc_ast/util/parser.rs
src/librustc_parse/parser/expr.rs
src/librustc_typeck/check/demand.rs
src/librustc_typeck/check/mod.rs
src/test/ui/parser/expr-as-stmt-2.rs [new file with mode: 0644]
src/test/ui/parser/expr-as-stmt-2.stderr [new file with mode: 0644]
src/test/ui/parser/expr-as-stmt.fixed
src/test/ui/parser/expr-as-stmt.rs
src/test/ui/parser/expr-as-stmt.stderr

index e5bcc571d417637a7c5c64cbe65f3c98b4e57575..2ee94965756a5e0d72fc8bbe084b628f1c49f799 100644 (file)
@@ -222,7 +222,6 @@ pub fn can_continue_expr_unambiguously(&self) -> bool {
             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.
index 3926122606e6d851e80e30ae96241e935985b288..223986635a03a60e790895a7f2a6394d410e740f 100644 (file)
@@ -295,11 +295,18 @@ fn should_continue_as_assoc_expr(&mut self, lhs: &Expr) -> bool {
             // 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);
index be83ab259c2ecc0bcc96bd9484b099a70a593434..46303a99278dd9780c7d61c3904762b8f5ec862f 100644 (file)
@@ -34,6 +34,7 @@ pub fn emit_coerce_suggestions(
         }
         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);
     }
 
index 04e02704296defd79c3b2a8cbfc98eaee84c2eaf..57de1780c65ea374ebd7db733e1cb67559fdc2dc 100644 (file)
@@ -5403,6 +5403,14 @@ fn suggest_missing_await(
         }
     }
 
+    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<'_>,
diff --git a/src/test/ui/parser/expr-as-stmt-2.rs b/src/test/ui/parser/expr-as-stmt-2.rs
new file mode 100644 (file)
index 0000000..3a18bdc
--- /dev/null
@@ -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() {}
diff --git a/src/test/ui/parser/expr-as-stmt-2.stderr b/src/test/ui/parser/expr-as-stmt-2.stderr
new file mode 100644 (file)
index 0000000..ee07c36
--- /dev/null
@@ -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`.
index 1ce6f9c25034f811a881b80033d0156aba8cc0fa..02816ef2791b0dcaa5b83ec0a694795e5083e730 100644 (file)
@@ -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,
index b526c17488eaf72ee218a67bbda59cf5e50d9303..93baa8278f890b7bd431c0d86bf63c1d001d5721 100644 (file)
@@ -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,
index 4d93e130901e7be4cea4b9e36b32850ee2c330cb..324aed0ad7cf6df71e5ecb701edbe007e6fad0a6 100644 (file)
@@ -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
@@ -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`.