From afcf9b262d450edd1a7d54754e62f62d50052d8d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Thu, 5 Sep 2019 13:15:42 -0700
Subject: [PATCH 1/2] Bail out when encountering likely missing turbofish in
 parser

When encountering a likely intended turbofish without `::`, bubble
up the diagnostic instead of emitting it to allow the parser to recover
more gracefully and avoid uneccessary type errors that are likely to be
wrong.
---
 src/libsyntax/parse/diagnostics.rs            |  5 +-
 src/libsyntax/parse/parser/expr.rs            |  2 +-
 src/test/ui/did_you_mean/issue-40396.rs       | 11 ---
 src/test/ui/did_you_mean/issue-40396.stderr   | 80 +------------------
 .../require-parens-for-chained-comparison.rs  |  3 +-
 ...quire-parens-for-chained-comparison.stderr | 15 +---
 .../ui/parser/trait-object-lifetime-parens.rs |  1 -
 .../trait-object-lifetime-parens.stderr       | 11 +--
 8 files changed, 12 insertions(+), 116 deletions(-)

diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs
index d4e661d1a38b7..d050d4f4ce705 100644
--- a/src/libsyntax/parse/diagnostics.rs
+++ b/src/libsyntax/parse/diagnostics.rs
@@ -544,7 +544,7 @@ impl<'a> Parser<'a> {
     /// Produce an error if comparison operators are chained (RFC #558).
     /// We only need to check lhs, not rhs, because all comparison ops
     /// have same precedence and are left-associative
-    crate fn check_no_chained_comparison(&self, lhs: &Expr, outer_op: &AssocOp) {
+    crate fn check_no_chained_comparison(&self, lhs: &Expr, outer_op: &AssocOp) -> PResult<'a, ()> {
         debug_assert!(outer_op.is_comparison(),
                       "check_no_chained_comparison: {:?} is not comparison",
                       outer_op);
@@ -563,11 +563,14 @@ impl<'a> Parser<'a> {
                     err.help(
                         "use `::<...>` instead of `<...>` if you meant to specify type arguments");
                     err.help("or use `(...)` if you meant to specify fn arguments");
+                    // These cases cause too many knock-down errors, bail out (#61329).
+                    return Err(err);
                 }
                 err.emit();
             }
             _ => {}
         }
+        Ok(())
     }
 
     crate fn maybe_report_ambiguous_plus(
diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs
index 5b9f0f1df6718..aeef216141299 100644
--- a/src/libsyntax/parse/parser/expr.rs
+++ b/src/libsyntax/parse/parser/expr.rs
@@ -231,7 +231,7 @@ impl<'a> Parser<'a> {
 
             self.bump();
             if op.is_comparison() {
-                self.check_no_chained_comparison(&lhs, &op);
+                self.check_no_chained_comparison(&lhs, &op)?;
             }
             // Special cases:
             if op == AssocOp::As {
diff --git a/src/test/ui/did_you_mean/issue-40396.rs b/src/test/ui/did_you_mean/issue-40396.rs
index 63eec50c2d29f..6902779f33d23 100644
--- a/src/test/ui/did_you_mean/issue-40396.rs
+++ b/src/test/ui/did_you_mean/issue-40396.rs
@@ -1,27 +1,16 @@
 fn foo() {
     (0..13).collect<Vec<i32>>();
     //~^ ERROR chained comparison
-    //~| ERROR expected value, found struct `Vec`
-    //~| ERROR expected value, found builtin type `i32`
-    //~| ERROR attempted to take value of method `collect`
 }
 
 fn bar() {
     Vec<i32>::new();
     //~^ ERROR chained comparison
-    //~| ERROR expected value, found struct `Vec`
-    //~| ERROR expected value, found builtin type `i32`
-    //~| ERROR cannot find function `new` in the crate root
 }
 
 fn qux() {
     (0..13).collect<Vec<i32>();
     //~^ ERROR chained comparison
-    //~| ERROR chained comparison
-    //~| ERROR expected value, found struct `Vec`
-    //~| ERROR expected value, found builtin type `i32`
-    //~| ERROR attempted to take value of method `collect`
-    //~| ERROR mismatched types
 }
 
 fn main() {}
diff --git a/src/test/ui/did_you_mean/issue-40396.stderr b/src/test/ui/did_you_mean/issue-40396.stderr
index fe517ee34949d..7a08fda27e355 100644
--- a/src/test/ui/did_you_mean/issue-40396.stderr
+++ b/src/test/ui/did_you_mean/issue-40396.stderr
@@ -8,7 +8,7 @@ LL |     (0..13).collect<Vec<i32>>();
    = help: or use `(...)` if you meant to specify fn arguments
 
 error: chained comparison operators require parentheses
-  --> $DIR/issue-40396.rs:10:8
+  --> $DIR/issue-40396.rs:7:8
    |
 LL |     Vec<i32>::new();
    |        ^^^^^^^
@@ -17,7 +17,7 @@ LL |     Vec<i32>::new();
    = help: or use `(...)` if you meant to specify fn arguments
 
 error: chained comparison operators require parentheses
-  --> $DIR/issue-40396.rs:18:20
+  --> $DIR/issue-40396.rs:12:20
    |
 LL |     (0..13).collect<Vec<i32>();
    |                    ^^^^^^^^
@@ -25,79 +25,5 @@ LL |     (0..13).collect<Vec<i32>();
    = help: use `::<...>` instead of `<...>` if you meant to specify type arguments
    = help: or use `(...)` if you meant to specify fn arguments
 
-error: chained comparison operators require parentheses
-  --> $DIR/issue-40396.rs:18:24
-   |
-LL |     (0..13).collect<Vec<i32>();
-   |                        ^^^^^^
-   |
-   = help: use `::<...>` instead of `<...>` if you meant to specify type arguments
-   = help: or use `(...)` if you meant to specify fn arguments
-
-error[E0423]: expected value, found struct `Vec`
-  --> $DIR/issue-40396.rs:2:21
-   |
-LL |     (0..13).collect<Vec<i32>>();
-   |                     ^^^ did you mean `Vec { /* fields */ }`?
-
-error[E0423]: expected value, found builtin type `i32`
-  --> $DIR/issue-40396.rs:2:25
-   |
-LL |     (0..13).collect<Vec<i32>>();
-   |                         ^^^ not a value
-
-error[E0423]: expected value, found struct `Vec`
-  --> $DIR/issue-40396.rs:10:5
-   |
-LL |     Vec<i32>::new();
-   |     ^^^ did you mean `Vec { /* fields */ }`?
-
-error[E0423]: expected value, found builtin type `i32`
-  --> $DIR/issue-40396.rs:10:9
-   |
-LL |     Vec<i32>::new();
-   |         ^^^ not a value
-
-error[E0425]: cannot find function `new` in the crate root
-  --> $DIR/issue-40396.rs:10:15
-   |
-LL |     Vec<i32>::new();
-   |               ^^^ not found in the crate root
-
-error[E0423]: expected value, found struct `Vec`
-  --> $DIR/issue-40396.rs:18:21
-   |
-LL |     (0..13).collect<Vec<i32>();
-   |                     ^^^ did you mean `Vec { /* fields */ }`?
-
-error[E0423]: expected value, found builtin type `i32`
-  --> $DIR/issue-40396.rs:18:25
-   |
-LL |     (0..13).collect<Vec<i32>();
-   |                         ^^^ not a value
-
-error[E0615]: attempted to take value of method `collect` on type `std::ops::Range<{integer}>`
-  --> $DIR/issue-40396.rs:2:13
-   |
-LL |     (0..13).collect<Vec<i32>>();
-   |             ^^^^^^^ help: use parentheses to call the method: `collect()`
-
-error[E0615]: attempted to take value of method `collect` on type `std::ops::Range<{integer}>`
-  --> $DIR/issue-40396.rs:18:13
-   |
-LL |     (0..13).collect<Vec<i32>();
-   |             ^^^^^^^ help: use parentheses to call the method: `collect()`
-
-error[E0308]: mismatched types
-  --> $DIR/issue-40396.rs:18:29
-   |
-LL |     (0..13).collect<Vec<i32>();
-   |                             ^^ expected bool, found ()
-   |
-   = note: expected type `bool`
-              found type `()`
-
-error: aborting due to 14 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0308, E0423, E0425, E0615.
-For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/require-parens-for-chained-comparison.rs b/src/test/ui/parser/require-parens-for-chained-comparison.rs
index 525be5d20e27f..3dcc0c8f3d496 100644
--- a/src/test/ui/parser/require-parens-for-chained-comparison.rs
+++ b/src/test/ui/parser/require-parens-for-chained-comparison.rs
@@ -11,8 +11,7 @@ fn main() {
     //~| ERROR: mismatched types
 
     f<X>();
-    //~^ ERROR: chained comparison operators require parentheses
-    //~| ERROR: binary operation `<` cannot be applied to type `fn() {f::<_>}`
+    //~^ ERROR chained comparison operators require parentheses
     //~| HELP: use `::<...>` instead of `<...>`
     //~| HELP: or use `(...)`
 }
diff --git a/src/test/ui/parser/require-parens-for-chained-comparison.stderr b/src/test/ui/parser/require-parens-for-chained-comparison.stderr
index 76e548de045aa..e927f4c32484e 100644
--- a/src/test/ui/parser/require-parens-for-chained-comparison.stderr
+++ b/src/test/ui/parser/require-parens-for-chained-comparison.stderr
@@ -37,17 +37,6 @@ LL |     false == 0 < 2;
    = note: expected type `bool`
               found type `{integer}`
 
-error[E0369]: binary operation `<` cannot be applied to type `fn() {f::<_>}`
-  --> $DIR/require-parens-for-chained-comparison.rs:13:6
-   |
-LL |     f<X>();
-   |     -^- X
-   |     |
-   |     fn() {f::<_>}
-   |
-   = note: an implementation of `std::cmp::PartialOrd` might be missing for `fn() {f::<_>}`
-
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0308, E0369.
-For more information about an error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/trait-object-lifetime-parens.rs b/src/test/ui/parser/trait-object-lifetime-parens.rs
index 5bbda4296ca7e..c8b0eb684f33d 100644
--- a/src/test/ui/parser/trait-object-lifetime-parens.rs
+++ b/src/test/ui/parser/trait-object-lifetime-parens.rs
@@ -9,7 +9,6 @@ fn check<'a>() {
     let _: Box<('a) + Trait>;
     //~^ ERROR expected type, found `'a`
     //~| ERROR expected `:`, found `)`
-    //~| ERROR chained comparison operators require parentheses
 }
 
 fn main() {}
diff --git a/src/test/ui/parser/trait-object-lifetime-parens.stderr b/src/test/ui/parser/trait-object-lifetime-parens.stderr
index 7ffc26e9edead..319a308c0137c 100644
--- a/src/test/ui/parser/trait-object-lifetime-parens.stderr
+++ b/src/test/ui/parser/trait-object-lifetime-parens.stderr
@@ -16,15 +16,6 @@ error: expected `:`, found `)`
 LL |     let _: Box<('a) + Trait>;
    |                   ^ expected `:`
 
-error: chained comparison operators require parentheses
-  --> $DIR/trait-object-lifetime-parens.rs:9:15
-   |
-LL |     let _: Box<('a) + Trait>;
-   |               ^^^^^^^^^^^^^^^
-   |
-   = help: use `::<...>` instead of `<...>` if you meant to specify type arguments
-   = help: or use `(...)` if you meant to specify fn arguments
-
 error: expected type, found `'a`
   --> $DIR/trait-object-lifetime-parens.rs:9:17
    |
@@ -33,5 +24,5 @@ LL |     let _: Box<('a) + Trait>;
    |         |
    |         while parsing the type for `_`
 
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
 

From dc613c6d055c1b45f7e11e6ee03e4a3095d5b8a9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Thu, 5 Sep 2019 15:29:31 -0700
Subject: [PATCH 2/2] Fix test

---
 src/test/ui-fulldeps/pprust-expr-roundtrip.rs | 47 ++++++++++---------
 1 file changed, 25 insertions(+), 22 deletions(-)

diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs
index 09f58521e5d5c..89c17cf4b3aa3 100644
--- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs
+++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs
@@ -32,13 +32,15 @@ use syntax::print::pprust;
 use syntax::ptr::P;
 
 
-fn parse_expr(ps: &ParseSess, src: &str) -> P<Expr> {
+fn parse_expr(ps: &ParseSess, src: &str) -> Option<P<Expr>> {
     let src_as_string = src.to_string();
 
-    let mut p = parse::new_parser_from_source_str(ps,
-                                                  FileName::Custom(src_as_string.clone()),
-                                                  src_as_string);
-    p.parse_expr().unwrap()
+    let mut p = parse::new_parser_from_source_str(
+        ps,
+        FileName::Custom(src_as_string.clone()),
+        src_as_string,
+    );
+    p.parse_expr().map_err(|mut e| e.cancel()).ok()
 }
 
 
@@ -209,22 +211,23 @@ fn run() {
         let printed = pprust::expr_to_string(&e);
         println!("printed: {}", printed);
 
-        let mut parsed = parse_expr(&ps, &printed);
-
-        // We want to know if `parsed` is structurally identical to `e`, ignoring trivial
-        // differences like placement of `Paren`s or the exact ranges of node spans.
-        // Unfortunately, there is no easy way to make this comparison. Instead, we add `Paren`s
-        // everywhere we can, then pretty-print. This should give an unambiguous representation of
-        // each `Expr`, and it bypasses nearly all of the parenthesization logic, so we aren't
-        // relying on the correctness of the very thing we're testing.
-        RemoveParens.visit_expr(&mut e);
-        AddParens.visit_expr(&mut e);
-        let text1 = pprust::expr_to_string(&e);
-        RemoveParens.visit_expr(&mut parsed);
-        AddParens.visit_expr(&mut parsed);
-        let text2 = pprust::expr_to_string(&parsed);
-        assert!(text1 == text2,
-                "exprs are not equal:\n  e =      {:?}\n  parsed = {:?}",
-                text1, text2);
+        // Ignore expressions with chained comparisons that fail to parse
+        if let Some(mut parsed) = parse_expr(&ps, &printed) {
+            // We want to know if `parsed` is structurally identical to `e`, ignoring trivial
+            // differences like placement of `Paren`s or the exact ranges of node spans.
+            // Unfortunately, there is no easy way to make this comparison. Instead, we add `Paren`s
+            // everywhere we can, then pretty-print. This should give an unambiguous representation
+            // of each `Expr`, and it bypasses nearly all of the parenthesization logic, so we
+            // aren't relying on the correctness of the very thing we're testing.
+            RemoveParens.visit_expr(&mut e);
+            AddParens.visit_expr(&mut e);
+            let text1 = pprust::expr_to_string(&e);
+            RemoveParens.visit_expr(&mut parsed);
+            AddParens.visit_expr(&mut parsed);
+            let text2 = pprust::expr_to_string(&parsed);
+            assert!(text1 == text2,
+                    "exprs are not equal:\n  e =      {:?}\n  parsed = {:?}",
+                    text1, text2);
+        }
     });
 }