@@ -2188,7 +2188,27 @@ impl<'a> Parser<'a> {
21882188 enable_warning : bool )
21892189 -> PResult < ' a , ( ) > {
21902190 loop {
2191- segments. push ( self . parse_path_segment ( style, enable_warning) ?) ;
2191+ let segment = self . parse_path_segment ( style, enable_warning) ?;
2192+ if style == PathStyle :: Expr {
2193+ // In order to check for trailing angle brackets, we must have finished
2194+ // recursing (`parse_path_segment` can indirectly call this function),
2195+ // that is, the next token must be the highlighted part of the below example:
2196+ //
2197+ // `Foo::<Bar as Baz<T>>::Qux`
2198+ // ^ here
2199+ //
2200+ // As opposed to the below highlight (if we had only finished the first
2201+ // recursion):
2202+ //
2203+ // `Foo::<Bar as Baz<T>>::Qux`
2204+ // ^ here
2205+ //
2206+ // `PathStyle::Expr` is only provided at the root invocation and never in
2207+ // `parse_path_segment` to recurse and therefore can be checked to maintain
2208+ // this invariant.
2209+ self . check_trailing_angle_brackets ( & segment, token:: ModSep ) ;
2210+ }
2211+ segments. push ( segment) ;
21922212
21932213 if self . is_import_coupler ( ) || !self . eat ( & token:: ModSep ) {
21942214 return Ok ( ( ) ) ;
@@ -2821,6 +2841,8 @@ impl<'a> Parser<'a> {
28212841 // Assuming we have just parsed `.`, continue parsing into an expression.
28222842 fn parse_dot_suffix ( & mut self , self_arg : P < Expr > , lo : Span ) -> PResult < ' a , P < Expr > > {
28232843 let segment = self . parse_path_segment ( PathStyle :: Expr , true ) ?;
2844+ self . check_trailing_angle_brackets ( & segment, token:: OpenDelim ( token:: Paren ) ) ;
2845+
28242846 Ok ( match self . token {
28252847 token:: OpenDelim ( token:: Paren ) => {
28262848 // Method call `expr.f()`
@@ -2848,6 +2870,116 @@ impl<'a> Parser<'a> {
28482870 } )
28492871 }
28502872
2873+ /// This function checks if there are trailing angle brackets and produces
2874+ /// a diagnostic to suggest removing them.
2875+ ///
2876+ /// ```ignore (diagnostic)
2877+ /// let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>();
2878+ /// ^^ help: remove extra angle brackets
2879+ /// ```
2880+ fn check_trailing_angle_brackets ( & mut self , segment : & PathSegment , end : token:: Token ) {
2881+ // This function is intended to be invoked after parsing a path segment where there are two
2882+ // cases:
2883+ //
2884+ // 1. A specific token is expected after the path segment.
2885+ // eg. `x.foo(`, `x.foo::<u32>(` (parenthesis - method call),
2886+ // `Foo::`, or `Foo::<Bar>::` (mod sep - continued path).
2887+ // 2. No specific token is expected after the path segment.
2888+ // eg. `x.foo` (field access)
2889+ //
2890+ // This function is called after parsing `.foo` and before parsing the token `end` (if
2891+ // present). This includes any angle bracket arguments, such as `.foo::<u32>` or
2892+ // `Foo::<Bar>`.
2893+
2894+ // We only care about trailing angle brackets if we previously parsed angle bracket
2895+ // arguments. This helps stop us incorrectly suggesting that extra angle brackets be
2896+ // removed in this case:
2897+ //
2898+ // `x.foo >> (3)` (where `x.foo` is a `u32` for example)
2899+ //
2900+ // This case is particularly tricky as we won't notice it just looking at the tokens -
2901+ // it will appear the same (in terms of upcoming tokens) as below (since the `::<u32>` will
2902+ // have already been parsed):
2903+ //
2904+ // `x.foo::<u32>>>(3)`
2905+ let parsed_angle_bracket_args = segment. args
2906+ . as_ref ( )
2907+ . map ( |args| args. is_angle_bracketed ( ) )
2908+ . unwrap_or ( false ) ;
2909+
2910+ debug ! (
2911+ "check_trailing_angle_brackets: parsed_angle_bracket_args={:?}" ,
2912+ parsed_angle_bracket_args,
2913+ ) ;
2914+ if !parsed_angle_bracket_args {
2915+ return ;
2916+ }
2917+
2918+ // Keep the span at the start so we can highlight the sequence of `>` characters to be
2919+ // removed.
2920+ let lo = self . span ;
2921+
2922+ // We need to look-ahead to see if we have `>` characters without moving the cursor forward
2923+ // (since we might have the field access case and the characters we're eating are
2924+ // actual operators and not trailing characters - ie `x.foo >> 3`).
2925+ let mut position = 0 ;
2926+
2927+ // We can encounter `>` or `>>` tokens in any order, so we need to keep track of how
2928+ // many of each (so we can correctly pluralize our error messages) and continue to
2929+ // advance.
2930+ let mut number_of_shr = 0 ;
2931+ let mut number_of_gt = 0 ;
2932+ while self . look_ahead ( position, |t| {
2933+ trace ! ( "check_trailing_angle_brackets: t={:?}" , t) ;
2934+ if * t == token:: BinOp ( token:: BinOpToken :: Shr ) {
2935+ number_of_shr += 1 ;
2936+ true
2937+ } else if * t == token:: Gt {
2938+ number_of_gt += 1 ;
2939+ true
2940+ } else {
2941+ false
2942+ }
2943+ } ) {
2944+ position += 1 ;
2945+ }
2946+
2947+ // If we didn't find any trailing `>` characters, then we have nothing to error about.
2948+ debug ! (
2949+ "check_trailing_angle_brackets: number_of_gt={:?} number_of_shr={:?}" ,
2950+ number_of_gt, number_of_shr,
2951+ ) ;
2952+ if number_of_gt < 1 && number_of_shr < 1 {
2953+ return ;
2954+ }
2955+
2956+ // Finally, double check that we have our end token as otherwise this is the
2957+ // second case.
2958+ if self . look_ahead ( position, |t| {
2959+ trace ! ( "check_trailing_angle_brackets: t={:?}" , t) ;
2960+ * t == end
2961+ } ) {
2962+ // Eat from where we started until the end token so that parsing can continue
2963+ // as if we didn't have those extra angle brackets.
2964+ self . eat_to_tokens ( & [ & end] ) ;
2965+ let span = lo. until ( self . span ) ;
2966+
2967+ let plural = number_of_gt > 1 || number_of_shr >= 1 ;
2968+ self . diagnostic ( )
2969+ . struct_span_err (
2970+ span,
2971+ & format ! ( "unmatched angle bracket{}" , if plural { "s" } else { "" } ) ,
2972+ )
2973+ . span_suggestion_with_applicability (
2974+ span,
2975+ & format ! ( "remove extra angle bracket{}" , if plural { "s" } else { "" } ) ,
2976+ String :: new ( ) ,
2977+ Applicability :: MachineApplicable ,
2978+ )
2979+ . emit ( ) ;
2980+ }
2981+ }
2982+
28512983 fn parse_dot_or_call_expr_with_ ( & mut self , e0 : P < Expr > , lo : Span ) -> PResult < ' a , P < Expr > > {
28522984 let mut e = e0;
28532985 let mut hi;
0 commit comments