@@ -243,6 +243,12 @@ pub struct Parser<'a> {
243
243
desugar_doc_comments : bool ,
244
244
/// Whether we should configure out of line modules as we parse.
245
245
pub cfg_mods : bool ,
246
+ /// This field is used to keep track of how many left angle brackets we have seen. This is
247
+ /// required in order to detect extra leading left angle brackets (`<` characters) and error
248
+ /// appropriately.
249
+ ///
250
+ /// See the comments in the `parse_path_segment` function for more details.
251
+ crate unmatched_angle_bracket_count : u32 ,
246
252
}
247
253
248
254
@@ -564,6 +570,7 @@ impl<'a> Parser<'a> {
564
570
} ,
565
571
desugar_doc_comments,
566
572
cfg_mods : true ,
573
+ unmatched_angle_bracket_count : 0 ,
567
574
} ;
568
575
569
576
let tok = parser. next_tok ( ) ;
@@ -1028,7 +1035,7 @@ impl<'a> Parser<'a> {
1028
1035
/// starting token.
1029
1036
fn eat_lt ( & mut self ) -> bool {
1030
1037
self . expected_tokens . push ( TokenType :: Token ( token:: Lt ) ) ;
1031
- match self . token {
1038
+ let ate = match self . token {
1032
1039
token:: Lt => {
1033
1040
self . bump ( ) ;
1034
1041
true
@@ -1039,7 +1046,15 @@ impl<'a> Parser<'a> {
1039
1046
true
1040
1047
}
1041
1048
_ => false ,
1049
+ } ;
1050
+
1051
+ if ate {
1052
+ // See doc comment for `unmatched_angle_bracket_count`.
1053
+ self . unmatched_angle_bracket_count += 1 ;
1054
+ debug ! ( "eat_lt: (increment) count={:?}" , self . unmatched_angle_bracket_count) ;
1042
1055
}
1056
+
1057
+ ate
1043
1058
}
1044
1059
1045
1060
fn expect_lt ( & mut self ) -> PResult < ' a , ( ) > {
@@ -1055,24 +1070,35 @@ impl<'a> Parser<'a> {
1055
1070
/// signal an error.
1056
1071
fn expect_gt ( & mut self ) -> PResult < ' a , ( ) > {
1057
1072
self . expected_tokens . push ( TokenType :: Token ( token:: Gt ) ) ;
1058
- match self . token {
1073
+ let ate = match self . token {
1059
1074
token:: Gt => {
1060
1075
self . bump ( ) ;
1061
- Ok ( ( ) )
1076
+ Some ( ( ) )
1062
1077
}
1063
1078
token:: BinOp ( token:: Shr ) => {
1064
1079
let span = self . span . with_lo ( self . span . lo ( ) + BytePos ( 1 ) ) ;
1065
- Ok ( self . bump_with ( token:: Gt , span) )
1080
+ Some ( self . bump_with ( token:: Gt , span) )
1066
1081
}
1067
1082
token:: BinOpEq ( token:: Shr ) => {
1068
1083
let span = self . span . with_lo ( self . span . lo ( ) + BytePos ( 1 ) ) ;
1069
- Ok ( self . bump_with ( token:: Ge , span) )
1084
+ Some ( self . bump_with ( token:: Ge , span) )
1070
1085
}
1071
1086
token:: Ge => {
1072
1087
let span = self . span . with_lo ( self . span . lo ( ) + BytePos ( 1 ) ) ;
1073
- Ok ( self . bump_with ( token:: Eq , span) )
1088
+ Some ( self . bump_with ( token:: Eq , span) )
1074
1089
}
1075
- _ => self . unexpected ( )
1090
+ _ => None ,
1091
+ } ;
1092
+
1093
+ match ate {
1094
+ Some ( x) => {
1095
+ // See doc comment for `unmatched_angle_bracket_count`.
1096
+ self . unmatched_angle_bracket_count -= 1 ;
1097
+ debug ! ( "expect_gt: (decrement) count={:?}" , self . unmatched_angle_bracket_count) ;
1098
+
1099
+ Ok ( x)
1100
+ } ,
1101
+ None => self . unexpected ( ) ,
1076
1102
}
1077
1103
}
1078
1104
@@ -2115,7 +2141,11 @@ impl<'a> Parser<'a> {
2115
2141
path_span = self . span . to ( self . span ) ;
2116
2142
}
2117
2143
2144
+ // See doc comment for `unmatched_angle_bracket_count`.
2118
2145
self . expect ( & token:: Gt ) ?;
2146
+ self . unmatched_angle_bracket_count -= 1 ;
2147
+ debug ! ( "parse_qpath: (decrement) count={:?}" , self . unmatched_angle_bracket_count) ;
2148
+
2119
2149
self . expect ( & token:: ModSep ) ?;
2120
2150
2121
2151
let qself = QSelf { ty, path_span, position : path. segments . len ( ) } ;
@@ -2238,9 +2268,15 @@ impl<'a> Parser<'a> {
2238
2268
}
2239
2269
let lo = self . span ;
2240
2270
2271
+ // We use `style == PathStyle::Expr` to check if this is in a recursion or not. If
2272
+ // it isn't, then we reset the unmatched angle bracket count as we're about to start
2273
+ // parsing a new path.
2274
+ if style == PathStyle :: Expr { self . unmatched_angle_bracket_count = 0 ; }
2275
+
2241
2276
let args = if self . eat_lt ( ) {
2242
2277
// `<'a, T, A = U>`
2243
- let ( args, bindings) = self . parse_generic_args ( ) ?;
2278
+ let ( args, bindings) =
2279
+ self . parse_generic_args_with_leaning_angle_bracket_recovery ( style, lo) ?;
2244
2280
self . expect_gt ( ) ?;
2245
2281
let span = lo. to ( self . prev_span ) ;
2246
2282
AngleBracketedArgs { args, bindings, span } . into ( )
@@ -5538,6 +5574,152 @@ impl<'a> Parser<'a> {
5538
5574
}
5539
5575
}
5540
5576
5577
+ /// Parse generic args (within a path segment) with recovery for extra leading angle brackets.
5578
+ /// For the purposes of understanding the parsing logic of generic arguments, this function
5579
+ /// can be thought of being the same as just calling `self.parse_generic_args()` if the source
5580
+ /// had the correct amount of leading angle brackets.
5581
+ ///
5582
+ /// ```ignore (diagnostics)
5583
+ /// bar::<<<<T as Foo>::Output>();
5584
+ /// ^^ help: remove extra angle brackets
5585
+ /// ```
5586
+ fn parse_generic_args_with_leaning_angle_bracket_recovery (
5587
+ & mut self ,
5588
+ style : PathStyle ,
5589
+ lo : Span ,
5590
+ ) -> PResult < ' a , ( Vec < GenericArg > , Vec < TypeBinding > ) > {
5591
+ // We need to detect whether there are extra leading left angle brackets and produce an
5592
+ // appropriate error and suggestion. This cannot be implemented by looking ahead at
5593
+ // upcoming tokens for a matching `>` character - if there are unmatched `<` tokens
5594
+ // then there won't be matching `>` tokens to find.
5595
+ //
5596
+ // To explain how this detection works, consider the following example:
5597
+ //
5598
+ // ```ignore (diagnostics)
5599
+ // bar::<<<<T as Foo>::Output>();
5600
+ // ^^ help: remove extra angle brackets
5601
+ // ```
5602
+ //
5603
+ // Parsing of the left angle brackets starts in this function. We start by parsing the
5604
+ // `<` token (incrementing the counter of unmatched angle brackets on `Parser` via
5605
+ // `eat_lt`):
5606
+ //
5607
+ // *Upcoming tokens:* `<<<<T as Foo>::Output>;`
5608
+ // *Unmatched count:* 1
5609
+ // *`parse_path_segment` calls deep:* 0
5610
+ //
5611
+ // This has the effect of recursing as this function is called if a `<` character
5612
+ // is found within the expected generic arguments:
5613
+ //
5614
+ // *Upcoming tokens:* `<<<T as Foo>::Output>;`
5615
+ // *Unmatched count:* 2
5616
+ // *`parse_path_segment` calls deep:* 1
5617
+ //
5618
+ // Eventually we will have recursed until having consumed all of the `<` tokens and
5619
+ // this will be reflected in the count:
5620
+ //
5621
+ // *Upcoming tokens:* `T as Foo>::Output>;`
5622
+ // *Unmatched count:* 4
5623
+ // `parse_path_segment` calls deep:* 3
5624
+ //
5625
+ // The parser will continue until reaching the first `>` - this will decrement the
5626
+ // unmatched angle bracket count and return to the parent invocation of this function
5627
+ // having succeeded in parsing:
5628
+ //
5629
+ // *Upcoming tokens:* `::Output>;`
5630
+ // *Unmatched count:* 3
5631
+ // *`parse_path_segment` calls deep:* 2
5632
+ //
5633
+ // This will continue until the next `>` character which will also return successfully
5634
+ // to the parent invocation of this function and decrement the count:
5635
+ //
5636
+ // *Upcoming tokens:* `;`
5637
+ // *Unmatched count:* 2
5638
+ // *`parse_path_segment` calls deep:* 1
5639
+ //
5640
+ // At this point, this function will expect to find another matching `>` character but
5641
+ // won't be able to and will return an error. This will continue all the way up the
5642
+ // call stack until the first invocation:
5643
+ //
5644
+ // *Upcoming tokens:* `;`
5645
+ // *Unmatched count:* 2
5646
+ // *`parse_path_segment` calls deep:* 0
5647
+ //
5648
+ // In doing this, we have managed to work out how many unmatched leading left angle
5649
+ // brackets there are, but we cannot recover as the unmatched angle brackets have
5650
+ // already been consumed. To remedy this, we keep a snapshot of the parser state
5651
+ // before we do the above. We can then inspect whether we ended up with a parsing error
5652
+ // and unmatched left angle brackets and if so, restore the parser state before we
5653
+ // consumed any `<` characters to emit an error and consume the erroneous tokens to
5654
+ // recover by attempting to parse again.
5655
+ //
5656
+ // In practice, the recursion of this function is indirect and there will be other
5657
+ // locations that consume some `<` characters - as long as we update the count when
5658
+ // this happens, it isn't an issue.
5659
+
5660
+ let is_first_invocation = style == PathStyle :: Expr ;
5661
+ // Take a snapshot before attempting to parse - we can restore this later.
5662
+ let snapshot = if is_first_invocation {
5663
+ Some ( self . clone ( ) )
5664
+ } else {
5665
+ None
5666
+ } ;
5667
+
5668
+ debug ! ( "parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)" ) ;
5669
+ match self . parse_generic_args ( ) {
5670
+ Ok ( value) => Ok ( value) ,
5671
+ Err ( ref mut e) if is_first_invocation && self . unmatched_angle_bracket_count > 0 => {
5672
+ // Cancel error from being unable to find `>`. We know the error
5673
+ // must have been this due to a non-zero unmatched angle bracket
5674
+ // count.
5675
+ e. cancel ( ) ;
5676
+
5677
+ // Swap `self` with our backup of the parser state before attempting to parse
5678
+ // generic arguments.
5679
+ let snapshot = mem:: replace ( self , snapshot. unwrap ( ) ) ;
5680
+
5681
+ debug ! (
5682
+ "parse_generic_args_with_leading_angle_bracket_recovery: (snapshot failure) \
5683
+ snapshot.count={:?}",
5684
+ snapshot. unmatched_angle_bracket_count,
5685
+ ) ;
5686
+
5687
+ // Eat the unmatched angle brackets.
5688
+ for _ in 0 ..snapshot. unmatched_angle_bracket_count {
5689
+ self . eat_lt ( ) ;
5690
+ }
5691
+
5692
+ // Make a span over ${unmatched angle bracket count} characters.
5693
+ let span = lo. with_hi (
5694
+ lo. lo ( ) + BytePos ( snapshot. unmatched_angle_bracket_count )
5695
+ ) ;
5696
+ let plural = snapshot. unmatched_angle_bracket_count > 1 ;
5697
+ self . diagnostic ( )
5698
+ . struct_span_err (
5699
+ span,
5700
+ & format ! (
5701
+ "unmatched angle bracket{}" ,
5702
+ if plural { "s" } else { "" }
5703
+ ) ,
5704
+ )
5705
+ . span_suggestion_with_applicability (
5706
+ span,
5707
+ & format ! (
5708
+ "remove extra angle bracket{}" ,
5709
+ if plural { "s" } else { "" }
5710
+ ) ,
5711
+ String :: new ( ) ,
5712
+ Applicability :: MachineApplicable ,
5713
+ )
5714
+ . emit ( ) ;
5715
+
5716
+ // Try again without unmatched angle bracket characters.
5717
+ self . parse_generic_args ( )
5718
+ } ,
5719
+ Err ( e) => Err ( e) ,
5720
+ }
5721
+ }
5722
+
5541
5723
/// Parses (possibly empty) list of lifetime and type arguments and associated type bindings,
5542
5724
/// possibly including trailing comma.
5543
5725
fn parse_generic_args ( & mut self ) -> PResult < ' a , ( Vec < GenericArg > , Vec < TypeBinding > ) > {
0 commit comments