@@ -242,6 +242,12 @@ pub struct Parser<'a> {
242
242
desugar_doc_comments : bool ,
243
243
/// Whether we should configure out of line modules as we parse.
244
244
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 ,
245
251
}
246
252
247
253
@@ -563,6 +569,7 @@ impl<'a> Parser<'a> {
563
569
} ,
564
570
desugar_doc_comments,
565
571
cfg_mods : true ,
572
+ unmatched_angle_bracket_count : 0 ,
566
573
} ;
567
574
568
575
let tok = parser. next_tok ( ) ;
@@ -1027,7 +1034,7 @@ impl<'a> Parser<'a> {
1027
1034
/// starting token.
1028
1035
fn eat_lt ( & mut self ) -> bool {
1029
1036
self . expected_tokens . push ( TokenType :: Token ( token:: Lt ) ) ;
1030
- match self . token {
1037
+ let ate = match self . token {
1031
1038
token:: Lt => {
1032
1039
self . bump ( ) ;
1033
1040
true
@@ -1038,7 +1045,15 @@ impl<'a> Parser<'a> {
1038
1045
true
1039
1046
}
1040
1047
_ => 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) ;
1041
1054
}
1055
+
1056
+ ate
1042
1057
}
1043
1058
1044
1059
fn expect_lt ( & mut self ) -> PResult < ' a , ( ) > {
@@ -1054,24 +1069,35 @@ impl<'a> Parser<'a> {
1054
1069
/// signal an error.
1055
1070
fn expect_gt ( & mut self ) -> PResult < ' a , ( ) > {
1056
1071
self . expected_tokens . push ( TokenType :: Token ( token:: Gt ) ) ;
1057
- match self . token {
1072
+ let ate = match self . token {
1058
1073
token:: Gt => {
1059
1074
self . bump ( ) ;
1060
- Ok ( ( ) )
1075
+ Some ( ( ) )
1061
1076
}
1062
1077
token:: BinOp ( token:: Shr ) => {
1063
1078
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) )
1065
1080
}
1066
1081
token:: BinOpEq ( token:: Shr ) => {
1067
1082
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) )
1069
1084
}
1070
1085
token:: Ge => {
1071
1086
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) )
1073
1088
}
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 ( ) ,
1075
1101
}
1076
1102
}
1077
1103
@@ -2079,7 +2105,11 @@ impl<'a> Parser<'a> {
2079
2105
path_span = self . span . to ( self . span ) ;
2080
2106
}
2081
2107
2108
+ // See doc comment for `unmatched_angle_bracket_count`.
2082
2109
self . expect ( & token:: Gt ) ?;
2110
+ self . unmatched_angle_bracket_count -= 1 ;
2111
+ debug ! ( "parse_qpath: (decrement) count={:?}" , self . unmatched_angle_bracket_count) ;
2112
+
2083
2113
self . expect ( & token:: ModSep ) ?;
2084
2114
2085
2115
let qself = QSelf { ty, path_span, position : path. segments . len ( ) } ;
@@ -2182,9 +2212,15 @@ impl<'a> Parser<'a> {
2182
2212
}
2183
2213
let lo = self . span ;
2184
2214
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
+
2185
2220
let args = if self . eat_lt ( ) {
2186
2221
// `<'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) ?;
2188
2224
self . expect_gt ( ) ?;
2189
2225
let span = lo. to ( self . prev_span ) ;
2190
2226
AngleBracketedArgs { args, bindings, span } . into ( )
@@ -5319,6 +5355,163 @@ impl<'a> Parser<'a> {
5319
5355
}
5320
5356
}
5321
5357
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
+
5322
5515
/// Parses (possibly empty) list of lifetime and type arguments and associated type bindings,
5323
5516
/// possibly including trailing comma.
5324
5517
fn parse_generic_args ( & mut self ) -> PResult < ' a , ( Vec < GenericArg > , Vec < TypeBinding > ) > {
0 commit comments