@@ -242,6 +242,12 @@ pub struct Parser<'a> {
242242 desugar_doc_comments : bool ,
243243 /// Whether we should configure out of line modules as we parse.
244244 pub cfg_mods : bool ,
245+ /// This field is used to keep track of how many left angle brackets we have seen. This is
246+ /// required in order to detect extra leading left angle brackets (`<` characters) and error
247+ /// appropriately.
248+ ///
249+ /// See the comments in the `parse_path_segment` function for more details.
250+ crate unmatched_angle_bracket_count : u32 ,
245251}
246252
247253
@@ -563,6 +569,7 @@ impl<'a> Parser<'a> {
563569 } ,
564570 desugar_doc_comments,
565571 cfg_mods : true ,
572+ unmatched_angle_bracket_count : 0 ,
566573 } ;
567574
568575 let tok = parser. next_tok ( ) ;
@@ -1027,7 +1034,7 @@ impl<'a> Parser<'a> {
10271034 /// starting token.
10281035 fn eat_lt ( & mut self ) -> bool {
10291036 self . expected_tokens . push ( TokenType :: Token ( token:: Lt ) ) ;
1030- match self . token {
1037+ let ate = match self . token {
10311038 token:: Lt => {
10321039 self . bump ( ) ;
10331040 true
@@ -1038,7 +1045,15 @@ impl<'a> Parser<'a> {
10381045 true
10391046 }
10401047 _ => false ,
1048+ } ;
1049+
1050+ if ate {
1051+ // See doc comment for `unmatched_angle_bracket_count`.
1052+ self . unmatched_angle_bracket_count += 1 ;
1053+ debug ! ( "eat_lt: (increment) count={:?}" , self . unmatched_angle_bracket_count) ;
10411054 }
1055+
1056+ ate
10421057 }
10431058
10441059 fn expect_lt ( & mut self ) -> PResult < ' a , ( ) > {
@@ -1054,24 +1069,35 @@ impl<'a> Parser<'a> {
10541069 /// signal an error.
10551070 fn expect_gt ( & mut self ) -> PResult < ' a , ( ) > {
10561071 self . expected_tokens . push ( TokenType :: Token ( token:: Gt ) ) ;
1057- match self . token {
1072+ let ate = match self . token {
10581073 token:: Gt => {
10591074 self . bump ( ) ;
1060- Ok ( ( ) )
1075+ Some ( ( ) )
10611076 }
10621077 token:: BinOp ( token:: Shr ) => {
10631078 let span = self . span . with_lo ( self . span . lo ( ) + BytePos ( 1 ) ) ;
1064- Ok ( self . bump_with ( token:: Gt , span) )
1079+ Some ( self . bump_with ( token:: Gt , span) )
10651080 }
10661081 token:: BinOpEq ( token:: Shr ) => {
10671082 let span = self . span . with_lo ( self . span . lo ( ) + BytePos ( 1 ) ) ;
1068- Ok ( self . bump_with ( token:: Ge , span) )
1083+ Some ( self . bump_with ( token:: Ge , span) )
10691084 }
10701085 token:: Ge => {
10711086 let span = self . span . with_lo ( self . span . lo ( ) + BytePos ( 1 ) ) ;
1072- Ok ( self . bump_with ( token:: Eq , span) )
1087+ Some ( self . bump_with ( token:: Eq , span) )
10731088 }
1074- _ => self . unexpected ( )
1089+ _ => None ,
1090+ } ;
1091+
1092+ match ate {
1093+ Some ( x) => {
1094+ // See doc comment for `unmatched_angle_bracket_count`.
1095+ self . unmatched_angle_bracket_count -= 1 ;
1096+ debug ! ( "expect_gt: (decrement) count={:?}" , self . unmatched_angle_bracket_count) ;
1097+
1098+ Ok ( x)
1099+ } ,
1100+ None => self . unexpected ( ) ,
10751101 }
10761102 }
10771103
@@ -2079,7 +2105,11 @@ impl<'a> Parser<'a> {
20792105 path_span = self . span . to ( self . span ) ;
20802106 }
20812107
2108+ // See doc comment for `unmatched_angle_bracket_count`.
20822109 self . expect ( & token:: Gt ) ?;
2110+ self . unmatched_angle_bracket_count -= 1 ;
2111+ debug ! ( "parse_qpath: (decrement) count={:?}" , self . unmatched_angle_bracket_count) ;
2112+
20832113 self . expect ( & token:: ModSep ) ?;
20842114
20852115 let qself = QSelf { ty, path_span, position : path. segments . len ( ) } ;
@@ -2182,9 +2212,15 @@ impl<'a> Parser<'a> {
21822212 }
21832213 let lo = self . span ;
21842214
2215+ // We use `style == PathStyle::Expr` to check if this is in a recursion or not. If
2216+ // it isn't, then we reset the unmatched angle bracket count as we're about to start
2217+ // parsing a new path.
2218+ if style == PathStyle :: Expr { self . unmatched_angle_bracket_count = 0 ; }
2219+
21852220 let args = if self . eat_lt ( ) {
21862221 // `<'a, T, A = U>`
2187- let ( args, bindings) = self . parse_generic_args ( ) ?;
2222+ let ( args, bindings) =
2223+ self . parse_generic_args_with_leaning_angle_bracket_recovery ( style, lo) ?;
21882224 self . expect_gt ( ) ?;
21892225 let span = lo. to ( self . prev_span ) ;
21902226 AngleBracketedArgs { args, bindings, span } . into ( )
@@ -5319,6 +5355,163 @@ impl<'a> Parser<'a> {
53195355 }
53205356 }
53215357
5358+ /// Parse generic args (within a path segment) with recovery for extra leading angle brackets.
5359+ /// For the purposes of understanding the parsing logic of generic arguments, this function
5360+ /// can be thought of being the same as just calling `self.parse_generic_args()` if the source
5361+ /// had the correct amount of leading angle brackets.
5362+ ///
5363+ /// ```ignore (diagnostics)
5364+ /// bar::<<<<T as Foo>::Output>();
5365+ /// ^^ help: remove extra angle brackets
5366+ /// ```
5367+ fn parse_generic_args_with_leaning_angle_bracket_recovery (
5368+ & mut self ,
5369+ style : PathStyle ,
5370+ lo : Span ,
5371+ ) -> PResult < ' a , ( Vec < GenericArg > , Vec < TypeBinding > ) > {
5372+ // We need to detect whether there are extra leading left angle brackets and produce an
5373+ // appropriate error and suggestion. This cannot be implemented by looking ahead at
5374+ // upcoming tokens for a matching `>` character - if there are unmatched `<` tokens
5375+ // then there won't be matching `>` tokens to find.
5376+ //
5377+ // To explain how this detection works, consider the following example:
5378+ //
5379+ // ```ignore (diagnostics)
5380+ // bar::<<<<T as Foo>::Output>();
5381+ // ^^ help: remove extra angle brackets
5382+ // ```
5383+ //
5384+ // Parsing of the left angle brackets starts in this function. We start by parsing the
5385+ // `<` token (incrementing the counter of unmatched angle brackets on `Parser` via
5386+ // `eat_lt`):
5387+ //
5388+ // *Upcoming tokens:* `<<<<T as Foo>::Output>;`
5389+ // *Unmatched count:* 1
5390+ // *`parse_path_segment` calls deep:* 0
5391+ //
5392+ // This has the effect of recursing as this function is called if a `<` character
5393+ // is found within the expected generic arguments:
5394+ //
5395+ // *Upcoming tokens:* `<<<T as Foo>::Output>;`
5396+ // *Unmatched count:* 2
5397+ // *`parse_path_segment` calls deep:* 1
5398+ //
5399+ // Eventually we will have recursed until having consumed all of the `<` tokens and
5400+ // this will be reflected in the count:
5401+ //
5402+ // *Upcoming tokens:* `T as Foo>::Output>;`
5403+ // *Unmatched count:* 4
5404+ // `parse_path_segment` calls deep:* 3
5405+ //
5406+ // The parser will continue until reaching the first `>` - this will decrement the
5407+ // unmatched angle bracket count and return to the parent invocation of this function
5408+ // having succeeded in parsing:
5409+ //
5410+ // *Upcoming tokens:* `::Output>;`
5411+ // *Unmatched count:* 3
5412+ // *`parse_path_segment` calls deep:* 2
5413+ //
5414+ // This will continue until the next `>` character which will also return successfully
5415+ // to the parent invocation of this function and decrement the count:
5416+ //
5417+ // *Upcoming tokens:* `;`
5418+ // *Unmatched count:* 2
5419+ // *`parse_path_segment` calls deep:* 1
5420+ //
5421+ // At this point, this function will expect to find another matching `>` character but
5422+ // won't be able to and will return an error. This will continue all the way up the
5423+ // call stack until the first invocation:
5424+ //
5425+ // *Upcoming tokens:* `;`
5426+ // *Unmatched count:* 2
5427+ // *`parse_path_segment` calls deep:* 0
5428+ //
5429+ // In doing this, we have managed to work out how many unmatched leading left angle
5430+ // brackets there are, but we cannot recover as the unmatched angle brackets have
5431+ // already been consumed. To remedy this, whenever `parse_generic_args` is invoked, we
5432+ // make a snapshot of the current parser state and invoke it on that and inspect
5433+ // the result:
5434+ //
5435+ // - If success (ie. when it found a matching `>` character) then the snapshot state
5436+ // is kept (this is required to propagate the count upwards).
5437+ //
5438+ // - If error and in was in a recursive call, then the snapshot state is kept (this is
5439+ // required to propagate the count upwards).
5440+ //
5441+ // - If error and this was the first invocation (before any recursion had taken place)
5442+ // then we choose not to keep the snapshot state - that way we haven't actually
5443+ // consumed any of the `<` characters, but can still inspect the count from the
5444+ // snapshot to know how many `<` characters to remove. Using this information, we can
5445+ // emit an error and consume the extra `<` characters before attempting to parse
5446+ // the generic arguments again (this time hopefullt successfully as the unmatched `<`
5447+ // characters are gone).
5448+ //
5449+ // In practice, the recursion of this function is indirect and there will be other
5450+ // locations that consume some `<` characters - as long as we update the count when
5451+ // this happens, it isn't an issue.
5452+ let mut snapshot = self . clone ( ) ;
5453+ debug ! ( "parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)" ) ;
5454+ match snapshot. parse_generic_args ( ) {
5455+ Ok ( value) => {
5456+ debug ! (
5457+ "parse_generic_args_with_leading_angle_bracket_recovery: (snapshot success) \
5458+ snapshot.count={:?}",
5459+ snapshot. unmatched_angle_bracket_count,
5460+ ) ;
5461+ mem:: replace ( self , snapshot) ;
5462+ Ok ( value)
5463+ } ,
5464+ Err ( mut e) => {
5465+ debug ! (
5466+ "parse_generic_args_with_leading_angle_bracket_recovery: (snapshot failure) \
5467+ snapshot.count={:?}",
5468+ snapshot. unmatched_angle_bracket_count,
5469+ ) ;
5470+ if style == PathStyle :: Expr && snapshot. unmatched_angle_bracket_count > 0 {
5471+ // Cancel error from being unable to find `>`. We know the error
5472+ // must have been this due to a non-zero unmatched angle bracket
5473+ // count.
5474+ e. cancel ( ) ;
5475+
5476+ // Eat the unmatched angle brackets.
5477+ for _ in 0 ..snapshot. unmatched_angle_bracket_count {
5478+ self . eat_lt ( ) ;
5479+ }
5480+
5481+ // Make a span over ${unmatched angle bracket count} characters.
5482+ let span = lo. with_hi (
5483+ lo. lo ( ) + BytePos ( snapshot. unmatched_angle_bracket_count )
5484+ ) ;
5485+ let plural = snapshot. unmatched_angle_bracket_count > 1 ;
5486+ self . diagnostic ( )
5487+ . struct_span_err (
5488+ span,
5489+ & format ! (
5490+ "unmatched angle bracket{}" ,
5491+ if plural { "s" } else { "" }
5492+ ) ,
5493+ )
5494+ . span_suggestion_with_applicability (
5495+ span,
5496+ & format ! (
5497+ "remove extra angle bracket{}" ,
5498+ if plural { "s" } else { "" }
5499+ ) ,
5500+ String :: new ( ) ,
5501+ Applicability :: MachineApplicable ,
5502+ )
5503+ . emit ( ) ;
5504+
5505+ // Try again without unmatched angle bracket characters.
5506+ self . parse_generic_args ( )
5507+ } else {
5508+ mem:: replace ( self , snapshot) ;
5509+ Err ( e)
5510+ }
5511+ } ,
5512+ }
5513+ }
5514+
53225515 /// Parses (possibly empty) list of lifetime and type arguments and associated type bindings,
53235516 /// possibly including trailing comma.
53245517 fn parse_generic_args ( & mut self ) -> PResult < ' a , ( Vec < GenericArg > , Vec < TypeBinding > ) > {
0 commit comments