From 6874bd27f527b6c5f40e8fd866d91813da2df35a Mon Sep 17 00:00:00 2001
From: Esteban Kuber <esteban@kuber.com.ar>
Date: Tue, 1 Mar 2022 19:40:48 +0000
Subject: [PATCH] Provide suggestion for missing `>` in a type parameter list

When encountering an inproperly terminated type parameter list, provide
a suggestion to close it after the last non-constraint type parameter
that was successfully parsed.

Fix #94058.
---
 compiler/rustc_parse/src/parser/path.rs       | 18 +++++++-
 .../parse/trait-path-expressions.stderr       |  5 +++
 .../parse/trait-path-segments.stderr          | 15 +++++++
 .../parse/trait-path-types.stderr             | 15 +++++++
 src/test/ui/issues/issue-34334.stderr         |  5 +++
 .../ui/parser/issues/issue-20616-2.stderr     |  5 +++
 .../ui/parser/issues/issue-20616-3.stderr     |  5 +++
 .../ui/parser/issues/issue-20616-4.stderr     |  5 +++
 .../ui/parser/issues/issue-20616-5.stderr     |  5 +++
 .../ui/parser/issues/issue-20616-6.stderr     |  5 +++
 .../ui/parser/issues/issue-20616-7.stderr     |  5 +++
 src/test/ui/parser/issues/issue-62660.stderr  |  5 +++
 src/test/ui/parser/issues/issue-84117.stderr  | 41 +++++++++++++++----
 src/test/ui/parser/lifetime-semicolon.stderr  |  5 +++
 ...closing-angle-bracket-eq-constraint.stderr | 15 +++++++
 ...g-closing-angle-bracket-struct-field-ty.rs | 11 +++++
 ...osing-angle-bracket-struct-field-ty.stderr | 15 +++++++
 .../removed-syntax-closure-lifetime.stderr    |  5 +++
 18 files changed, 175 insertions(+), 10 deletions(-)
 create mode 100644 src/test/ui/parser/missing-closing-angle-bracket-struct-field-ty.rs
 create mode 100644 src/test/ui/parser/missing-closing-angle-bracket-struct-field-ty.stderr

diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 07ce879de8f..596099bf2de 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -272,7 +272,23 @@ impl<'a> Parser<'a> {
                         lo,
                         ty_generics,
                     )?;
-                    self.expect_gt()?;
+                    self.expect_gt().map_err(|mut err| {
+                        // Attempt to find places where a missing `>` might belong.
+                        if let Some(arg) = args
+                            .iter()
+                            .rev()
+                            .skip_while(|arg| matches!(arg, AngleBracketedArg::Constraint(_)))
+                            .next()
+                        {
+                            err.span_suggestion_verbose(
+                                arg.span().shrink_to_hi(),
+                                "you might have meant to end the type parameters here",
+                                ">".to_string(),
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
+                        err
+                    })?;
                     let span = lo.to(self.prev_token.span);
                     AngleBracketedArgs { args, span }.into()
                 } else {
diff --git a/src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr b/src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr
index b1fea6d33a7..272afc10b17 100644
--- a/src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr
+++ b/src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr
@@ -13,6 +13,11 @@ LL |   fn f2<'a>(arg : Box<dyn X< { 1 } = 32 >>) {}
    |                                  - ^ expected one of `,`, `:`, or `>`
    |                                  |
    |                                  maybe try to close unmatched angle bracket
+   |
+help: you might have meant to end the type parameters here
+   |
+LL |   fn f2<'a>(arg : Box<dyn X< { 1 }> = 32 >>) {}
+   |                                   +
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/generic-associated-types/parse/trait-path-segments.stderr b/src/test/ui/generic-associated-types/parse/trait-path-segments.stderr
index bfb109fbfa4..7394393c05e 100644
--- a/src/test/ui/generic-associated-types/parse/trait-path-segments.stderr
+++ b/src/test/ui/generic-associated-types/parse/trait-path-segments.stderr
@@ -5,6 +5,11 @@ LL |     fn f1<'a>(arg : Box<dyn X<X::Y = u32>>) {}
    |                                  - ^ expected one of 8 possible tokens
    |                                  |
    |                                  maybe try to close unmatched angle bracket
+   |
+help: you might have meant to end the type parameters here
+   |
+LL |     fn f1<'a>(arg : Box<dyn X<X::Y> = u32>>) {}
+   |                                   +
 
 error: expected one of `,`, `::`, `:`, or `>`, found `=`
   --> $DIR/trait-path-segments.rs:19:35
@@ -13,6 +18,11 @@ LL |     impl<T : X<<Self as X>::Y<'a> = &'a u32>> Z for T {}
    |                                 - ^ expected one of `,`, `::`, `:`, or `>`
    |                                 |
    |                                 maybe try to close unmatched angle bracket
+   |
+help: you might have meant to end the type parameters here
+   |
+LL |     impl<T : X<<Self as X>::Y<'a>> = &'a u32>> Z for T {}
+   |                                  +
 
 error: expected one of `!`, `+`, `,`, `::`, `:`, or `>`, found `=`
   --> $DIR/trait-path-segments.rs:30:25
@@ -21,6 +31,11 @@ LL |     impl<T : X<X::Y<'a> = &'a u32>> Z for T {}
    |                       - ^ expected one of `!`, `+`, `,`, `::`, `:`, or `>`
    |                       |
    |                       maybe try to close unmatched angle bracket
+   |
+help: you might have meant to end the type parameters here
+   |
+LL |     impl<T : X<X::Y<'a>> = &'a u32>> Z for T {}
+   |                        +
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/generic-associated-types/parse/trait-path-types.stderr b/src/test/ui/generic-associated-types/parse/trait-path-types.stderr
index c0fa41b9e0e..fe9ed579e34 100644
--- a/src/test/ui/generic-associated-types/parse/trait-path-types.stderr
+++ b/src/test/ui/generic-associated-types/parse/trait-path-types.stderr
@@ -5,6 +5,11 @@ LL |   fn f<'a>(arg : Box<dyn X< [u8; 1] = u32>>) {}
    |                                   - ^ expected one of `,`, `:`, or `>`
    |                                   |
    |                                   maybe try to close unmatched angle bracket
+   |
+help: you might have meant to end the type parameters here
+   |
+LL |   fn f<'a>(arg : Box<dyn X< [u8; 1]> = u32>>) {}
+   |                                    +
 
 error: expected one of `,`, `:`, or `>`, found `=`
   --> $DIR/trait-path-types.rs:13:37
@@ -13,6 +18,11 @@ LL |   fn f1<'a>(arg : Box<dyn X<(Y<'a>) = &'a ()>>) {}
    |                                   - ^ expected one of `,`, `:`, or `>`
    |                                   |
    |                                   maybe try to close unmatched angle bracket
+   |
+help: you might have meant to end the type parameters here
+   |
+LL |   fn f1<'a>(arg : Box<dyn X<(Y<'a>)> = &'a ()>>) {}
+   |                                    +
 
 error: expected one of `,`, `:`, or `>`, found `=`
   --> $DIR/trait-path-types.rs:18:33
@@ -21,6 +31,11 @@ LL |   fn f1<'a>(arg : Box<dyn X< 'a = u32 >>) {}
    |                              -- ^ expected one of `,`, `:`, or `>`
    |                              |
    |                              maybe try to close unmatched angle bracket
+   |
+help: you might have meant to end the type parameters here
+   |
+LL |   fn f1<'a>(arg : Box<dyn X< 'a> = u32 >>) {}
+   |                                +
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/issues/issue-34334.stderr b/src/test/ui/issues/issue-34334.stderr
index 49d6709a860..cd697445faf 100644
--- a/src/test/ui/issues/issue-34334.stderr
+++ b/src/test/ui/issues/issue-34334.stderr
@@ -6,6 +6,11 @@ LL |     let sr: Vec<(u32, _, _) = vec![];
    |         |                 |
    |         |                 maybe try to close unmatched angle bracket
    |         while parsing the type for `sr`
+   |
+help: you might have meant to end the type parameters here
+   |
+LL |     let sr: Vec<(u32, _, _)> = vec![];
+   |                            +
 
 error[E0277]: a value of type `Vec<(u32, _, _)>` cannot be built from an iterator over elements of type `()`
   --> $DIR/issue-34334.rs:5:87
diff --git a/src/test/ui/parser/issues/issue-20616-2.stderr b/src/test/ui/parser/issues/issue-20616-2.stderr
index 01e3d3dd7cc..13e6aa7d605 100644
--- a/src/test/ui/parser/issues/issue-20616-2.stderr
+++ b/src/test/ui/parser/issues/issue-20616-2.stderr
@@ -3,6 +3,11 @@ error: expected one of `,`, `:`, `=`, or `>`, found `(`
    |
 LL | type Type_2 = Type_1_<'static ()>;
    |                               ^ expected one of `,`, `:`, `=`, or `>`
+   |
+help: you might have meant to end the type parameters here
+   |
+LL | type Type_2 = Type_1_<'static> ()>;
+   |                              +
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/issues/issue-20616-3.stderr b/src/test/ui/parser/issues/issue-20616-3.stderr
index b535c7a3267..dbff116e505 100644
--- a/src/test/ui/parser/issues/issue-20616-3.stderr
+++ b/src/test/ui/parser/issues/issue-20616-3.stderr
@@ -3,6 +3,11 @@ error: expected one of `>`, a const expression, lifetime, or type, found `,`
    |
 LL | type Type_3<T> = Box<T,,>;
    |                        ^ expected one of `>`, a const expression, lifetime, or type
+   |
+help: you might have meant to end the type parameters here
+   |
+LL | type Type_3<T> = Box<T>,,>;
+   |                       +
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/issues/issue-20616-4.stderr b/src/test/ui/parser/issues/issue-20616-4.stderr
index 2b3b75f3119..48a06e00b24 100644
--- a/src/test/ui/parser/issues/issue-20616-4.stderr
+++ b/src/test/ui/parser/issues/issue-20616-4.stderr
@@ -3,6 +3,11 @@ error: expected one of `>`, a const expression, lifetime, or type, found `,`
    |
 LL | type Type_4<T> = Type_1_<'static,, T>;
    |                                  ^ expected one of `>`, a const expression, lifetime, or type
+   |
+help: you might have meant to end the type parameters here
+   |
+LL | type Type_4<T> = Type_1_<'static>,, T>;
+   |                                 +
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/issues/issue-20616-5.stderr b/src/test/ui/parser/issues/issue-20616-5.stderr
index 1ec1dbde695..84bee2ad184 100644
--- a/src/test/ui/parser/issues/issue-20616-5.stderr
+++ b/src/test/ui/parser/issues/issue-20616-5.stderr
@@ -3,6 +3,11 @@ error: expected one of `>`, a const expression, lifetime, or type, found `,`
    |
 LL | type Type_5<'a> = Type_1_<'a, (),,>;
    |                                  ^ expected one of `>`, a const expression, lifetime, or type
+   |
+help: you might have meant to end the type parameters here
+   |
+LL | type Type_5<'a> = Type_1_<'a, ()>,,>;
+   |                                 +
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/issues/issue-20616-6.stderr b/src/test/ui/parser/issues/issue-20616-6.stderr
index 7401abdd091..67de41b9747 100644
--- a/src/test/ui/parser/issues/issue-20616-6.stderr
+++ b/src/test/ui/parser/issues/issue-20616-6.stderr
@@ -3,6 +3,11 @@ error: expected one of `>`, a const expression, lifetime, or type, found `,`
    |
 LL | type Type_6 = Type_5_<'a,,>;
    |                          ^ expected one of `>`, a const expression, lifetime, or type
+   |
+help: you might have meant to end the type parameters here
+   |
+LL | type Type_6 = Type_5_<'a>,,>;
+   |                         +
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/issues/issue-20616-7.stderr b/src/test/ui/parser/issues/issue-20616-7.stderr
index e2c3efe8447..3b8e07fa0d0 100644
--- a/src/test/ui/parser/issues/issue-20616-7.stderr
+++ b/src/test/ui/parser/issues/issue-20616-7.stderr
@@ -3,6 +3,11 @@ error: expected one of `>`, a const expression, lifetime, or type, found `,`
    |
 LL | type Type_7 = Box<(),,>;
    |                      ^ expected one of `>`, a const expression, lifetime, or type
+   |
+help: you might have meant to end the type parameters here
+   |
+LL | type Type_7 = Box<()>,,>;
+   |                     +
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/issues/issue-62660.stderr b/src/test/ui/parser/issues/issue-62660.stderr
index a50ada9056b..be0b9a524df 100644
--- a/src/test/ui/parser/issues/issue-62660.stderr
+++ b/src/test/ui/parser/issues/issue-62660.stderr
@@ -3,6 +3,11 @@ error: expected one of `!`, `(`, `+`, `,`, `::`, `:`, `<`, `=`, or `>`, found `)
    |
 LL |     pub fn foo(_: i32, self: Box<Self) {}
    |                                      ^ expected one of 9 possible tokens
+   |
+help: you might have meant to end the type parameters here
+   |
+LL |     pub fn foo(_: i32, self: Box<Self>) {}
+   |                                      +
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/issues/issue-84117.stderr b/src/test/ui/parser/issues/issue-84117.stderr
index 5b9cc53baa5..a2407affeef 100644
--- a/src/test/ui/parser/issues/issue-84117.stderr
+++ b/src/test/ui/parser/issues/issue-84117.stderr
@@ -2,10 +2,18 @@ error: expected one of `>`, a const expression, lifetime, or type, found `}`
   --> $DIR/issue-84117.rs:2:67
    |
 LL |     let outer_local:e_outer<&str, { let inner_local:e_inner<&str, }
-   |                                         ------------              ^ expected one of `>`, a const expression, lifetime, or type
-   |                                         |          |
-   |                                         |          help: use `=` if you meant to assign
+   |                                         -----------               ^ expected one of `>`, a const expression, lifetime, or type
+   |                                         |
    |                                         while parsing the type for `inner_local`
+   |
+help: you might have meant to end the type parameters here
+   |
+LL |     let outer_local:e_outer<&str, { let inner_local:e_inner<&str>, }
+   |                                                                 +
+help: use `=` if you meant to assign
+   |
+LL |     let outer_local:e_outer<&str, { let inner_local =e_inner<&str, }
+   |                                                     ~
 
 error: expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `,`
   --> $DIR/issue-84117.rs:2:65
@@ -17,21 +25,36 @@ error: expected one of `,`, `:`, `=`, or `>`, found `}`
   --> $DIR/issue-84117.rs:8:1
    |
 LL |     let outer_local:e_outer<&str, { let inner_local:e_inner<&str, }
-   |         ------------ help: use `=` if you meant to assign          - expected one of `,`, `:`, `=`, or `>`
-   |         |
-   |         while parsing the type for `outer_local`
+   |         ----------- while parsing the type for `outer_local`       - expected one of `,`, `:`, `=`, or `>`
 ...
 LL | }
    | ^ unexpected token
+   |
+help: you might have meant to end the type parameters here
+   |
+LL |     let outer_local:e_outer<&str, { let inner_local:e_inner<&str, }>
+   |                                                                    +
+help: use `=` if you meant to assign
+   |
+LL |     let outer_local =e_outer<&str, { let inner_local:e_inner<&str, }
+   |                     ~
 
 error: expected one of `>`, a const expression, lifetime, or type, found `}`
   --> $DIR/issue-84117.rs:2:67
    |
 LL |     let outer_local:e_outer<&str, { let inner_local:e_inner<&str, }
-   |                                         ------------              ^ expected one of `>`, a const expression, lifetime, or type
-   |                                         |          |
-   |                                         |          help: use `=` if you meant to assign
+   |                                         -----------               ^ expected one of `>`, a const expression, lifetime, or type
+   |                                         |
    |                                         while parsing the type for `inner_local`
+   |
+help: you might have meant to end the type parameters here
+   |
+LL |     let outer_local:e_outer<&str, { let inner_local:e_inner<&str>, }
+   |                                                                 +
+help: use `=` if you meant to assign
+   |
+LL |     let outer_local:e_outer<&str, { let inner_local =e_inner<&str, }
+   |                                                     ~
 
 error: expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `,`
   --> $DIR/issue-84117.rs:2:65
diff --git a/src/test/ui/parser/lifetime-semicolon.stderr b/src/test/ui/parser/lifetime-semicolon.stderr
index 3b67705aae9..948f9655e1e 100644
--- a/src/test/ui/parser/lifetime-semicolon.stderr
+++ b/src/test/ui/parser/lifetime-semicolon.stderr
@@ -3,6 +3,11 @@ error: expected one of `,`, `:`, `=`, or `>`, found `;`
    |
 LL | fn foo<'a, 'b>(x: &mut Foo<'a; 'b>) {}
    |                              ^ expected one of `,`, `:`, `=`, or `>`
+   |
+help: you might have meant to end the type parameters here
+   |
+LL | fn foo<'a, 'b>(x: &mut Foo<'a>; 'b>) {}
+   |                              +
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr b/src/test/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr
index 93403372bcb..427234e97cf 100644
--- a/src/test/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr
+++ b/src/test/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr
@@ -6,6 +6,11 @@ LL |   let v : Vec<(u32,_) = vec![];
    |       |             |
    |       |             maybe try to close unmatched angle bracket
    |       while parsing the type for `v`
+   |
+help: you might have meant to end the type parameters here
+   |
+LL |   let v : Vec<(u32,_)> = vec![];
+   |                      +
 
 error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `{`
   --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:13:32
@@ -14,6 +19,11 @@ LL |   let foo : Foo::<T1, T2 = Foo {_a : arg1, _b : arg2};
    |       ---                      ^ expected one of 7 possible tokens
    |       |
    |       while parsing the type for `foo`
+   |
+help: you might have meant to end the type parameters here
+   |
+LL |   let foo : Foo::<T1>, T2 = Foo {_a : arg1, _b : arg2};
+   |                     +
 
 error: expected one of `,`, `:`, or `>`, found `=`
   --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:18:18
@@ -23,6 +33,11 @@ LL |   let v : Vec<'a = vec![];
    |       |       |
    |       |       maybe try to close unmatched angle bracket
    |       while parsing the type for `v`
+   |
+help: you might have meant to end the type parameters here
+   |
+LL |   let v : Vec<'a> = vec![];
+   |                 +
 
 error[E0282]: type annotations needed for `Vec<T>`
   --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:7:25
diff --git a/src/test/ui/parser/missing-closing-angle-bracket-struct-field-ty.rs b/src/test/ui/parser/missing-closing-angle-bracket-struct-field-ty.rs
new file mode 100644
index 00000000000..d69a56c51d3
--- /dev/null
+++ b/src/test/ui/parser/missing-closing-angle-bracket-struct-field-ty.rs
@@ -0,0 +1,11 @@
+// run-rustifx
+#![allow(unused)]
+use std::sync::{Arc, Mutex};
+
+pub struct Foo {
+    a: Mutex<usize>,
+    b: Arc<Mutex<usize>, //~ HELP you might have meant to end the type parameters here
+    c: Arc<Mutex<usize>>,
+} //~ ERROR expected one of
+
+fn main() {}
diff --git a/src/test/ui/parser/missing-closing-angle-bracket-struct-field-ty.stderr b/src/test/ui/parser/missing-closing-angle-bracket-struct-field-ty.stderr
new file mode 100644
index 00000000000..46ca1f06be6
--- /dev/null
+++ b/src/test/ui/parser/missing-closing-angle-bracket-struct-field-ty.stderr
@@ -0,0 +1,15 @@
+error: expected one of `>`, a const expression, lifetime, or type, found `}`
+  --> $DIR/missing-closing-angle-bracket-struct-field-ty.rs:9:1
+   |
+LL |     c: Arc<Mutex<usize>>,
+   |                          - expected one of `>`, a const expression, lifetime, or type
+LL | }
+   | ^ unexpected token
+   |
+help: you might have meant to end the type parameters here
+   |
+LL |     b: Arc<Mutex<usize>>,
+   |                        +
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/removed-syntax-closure-lifetime.stderr b/src/test/ui/parser/removed-syntax-closure-lifetime.stderr
index 63b6e138ce5..e107c6b78b3 100644
--- a/src/test/ui/parser/removed-syntax-closure-lifetime.stderr
+++ b/src/test/ui/parser/removed-syntax-closure-lifetime.stderr
@@ -3,6 +3,11 @@ error: expected one of `!`, `(`, `+`, `,`, `::`, `:`, `<`, `=`, or `>`, found `/
    |
 LL | type closure = Box<lt/fn()>;
    |                      ^ expected one of 9 possible tokens
+   |
+help: you might have meant to end the type parameters here
+   |
+LL | type closure = Box<lt>/fn()>;
+   |                      +
 
 error: aborting due to previous error