@@ -881,6 +881,40 @@ impl<'a> Parser<'a> {
881
881
}
882
882
}
883
883
884
+ /// Expect and consume a `+`. if `+=` is seen, replace it with a `=`
885
+ /// and continue. If a `+` is not seen, return false.
886
+ ///
887
+ /// This is using when token splitting += into +.
888
+ /// See issue 47856 for an example of when this may occur.
889
+ fn eat_plus ( & mut self ) -> bool {
890
+ self . expected_tokens . push ( TokenType :: Token ( token:: BinOp ( token:: Plus ) ) ) ;
891
+ match self . token {
892
+ token:: BinOp ( token:: Plus ) => {
893
+ self . bump ( ) ;
894
+ true
895
+ }
896
+ token:: BinOpEq ( token:: Plus ) => {
897
+ let span = self . span . with_lo ( self . span . lo ( ) + BytePos ( 1 ) ) ;
898
+ self . bump_with ( token:: Eq , span) ;
899
+ true
900
+ }
901
+ _ => false ,
902
+ }
903
+ }
904
+
905
+
906
+ /// Checks to see if the next token is either `+` or `+=`.
907
+ /// Otherwise returns false.
908
+ fn check_plus ( & mut self ) -> bool {
909
+ if self . token . is_like_plus ( ) {
910
+ true
911
+ }
912
+ else {
913
+ self . expected_tokens . push ( TokenType :: Token ( token:: BinOp ( token:: Plus ) ) ) ;
914
+ false
915
+ }
916
+ }
917
+
884
918
/// Expect and consume an `&`. If `&&` is seen, replace it with a single
885
919
/// `&` and continue. If an `&` is not seen, signal an error.
886
920
fn expect_and ( & mut self ) -> PResult < ' a , ( ) > {
@@ -1517,7 +1551,7 @@ impl<'a> Parser<'a> {
1517
1551
1518
1552
if ts. len ( ) == 1 && !last_comma {
1519
1553
let ty = ts. into_iter ( ) . nth ( 0 ) . unwrap ( ) . into_inner ( ) ;
1520
- let maybe_bounds = allow_plus && self . token == token :: BinOp ( token :: Plus ) ;
1554
+ let maybe_bounds = allow_plus && self . token . is_like_plus ( ) ;
1521
1555
match ty. node {
1522
1556
// `(TY_BOUND_NOPAREN) + BOUND + ...`.
1523
1557
TyKind :: Path ( None , ref path) if maybe_bounds => {
@@ -1586,7 +1620,7 @@ impl<'a> Parser<'a> {
1586
1620
self . parse_ty_bare_fn ( lifetime_defs) ?
1587
1621
} else {
1588
1622
let path = self . parse_path ( PathStyle :: Type ) ?;
1589
- let parse_plus = allow_plus && self . check ( & token :: BinOp ( token :: Plus ) ) ;
1623
+ let parse_plus = allow_plus && self . check_plus ( ) ;
1590
1624
self . parse_remaining_bounds ( lifetime_defs, path, lo, parse_plus) ?
1591
1625
}
1592
1626
} else if self . eat_keyword ( keywords:: Impl ) {
@@ -1603,7 +1637,7 @@ impl<'a> Parser<'a> {
1603
1637
impl_dyn_multi = bounds. len ( ) > 1 || self . prev_token_kind == PrevTokenKind :: Plus ;
1604
1638
TyKind :: TraitObject ( bounds, TraitObjectSyntax :: Dyn )
1605
1639
} else if self . check ( & token:: Question ) ||
1606
- self . check_lifetime ( ) && self . look_ahead ( 1 , |t| t == & token :: BinOp ( token :: Plus ) ) {
1640
+ self . check_lifetime ( ) && self . look_ahead ( 1 , |t| t. is_like_plus ( ) ) {
1607
1641
// Bound list (trait object type)
1608
1642
TyKind :: TraitObject ( self . parse_ty_param_bounds_common ( allow_plus) ?,
1609
1643
TraitObjectSyntax :: None )
@@ -1623,7 +1657,7 @@ impl<'a> Parser<'a> {
1623
1657
// Just a type path or bound list (trait object type) starting with a trait.
1624
1658
// `Type`
1625
1659
// `Trait1 + Trait2 + 'a`
1626
- if allow_plus && self . check ( & token :: BinOp ( token :: Plus ) ) {
1660
+ if allow_plus && self . check_plus ( ) {
1627
1661
self . parse_remaining_bounds ( Vec :: new ( ) , path, lo, true ) ?
1628
1662
} else {
1629
1663
TyKind :: Path ( None , path)
@@ -1650,7 +1684,7 @@ impl<'a> Parser<'a> {
1650
1684
let poly_trait_ref = PolyTraitRef :: new ( generic_params, path, lo. to ( self . prev_span ) ) ;
1651
1685
let mut bounds = vec ! [ TraitTyParamBound ( poly_trait_ref, TraitBoundModifier :: None ) ] ;
1652
1686
if parse_plus {
1653
- self . bump ( ) ; // `+`
1687
+ self . eat_plus ( ) ; // `+`, or `+=` gets split and `+` is discarded
1654
1688
bounds. append ( & mut self . parse_ty_param_bounds ( ) ?) ;
1655
1689
}
1656
1690
Ok ( TyKind :: TraitObject ( bounds, TraitObjectSyntax :: None ) )
@@ -1671,7 +1705,7 @@ impl<'a> Parser<'a> {
1671
1705
1672
1706
fn maybe_recover_from_bad_type_plus ( & mut self , allow_plus : bool , ty : & Ty ) -> PResult < ' a , ( ) > {
1673
1707
// Do not add `+` to expected tokens.
1674
- if !allow_plus || self . token != token :: BinOp ( token :: Plus ) {
1708
+ if !allow_plus || ! self . token . is_like_plus ( ) {
1675
1709
return Ok ( ( ) )
1676
1710
}
1677
1711
@@ -4872,7 +4906,7 @@ impl<'a> Parser<'a> {
4872
4906
break
4873
4907
}
4874
4908
4875
- if !allow_plus || !self . eat ( & token :: BinOp ( token :: Plus ) ) {
4909
+ if !allow_plus || !self . eat_plus ( ) {
4876
4910
break
4877
4911
}
4878
4912
}
@@ -4891,7 +4925,7 @@ impl<'a> Parser<'a> {
4891
4925
while self . check_lifetime ( ) {
4892
4926
lifetimes. push ( self . expect_lifetime ( ) ) ;
4893
4927
4894
- if !self . eat ( & token :: BinOp ( token :: Plus ) ) {
4928
+ if !self . eat_plus ( ) {
4895
4929
break
4896
4930
}
4897
4931
}
@@ -5037,7 +5071,7 @@ impl<'a> Parser<'a> {
5037
5071
let mut seen_type = false ;
5038
5072
let mut seen_binding = false ;
5039
5073
loop {
5040
- if self . check_lifetime ( ) && self . look_ahead ( 1 , |t| t != & token :: BinOp ( token :: Plus ) ) {
5074
+ if self . check_lifetime ( ) && self . look_ahead ( 1 , |t| !t . is_like_plus ( ) ) {
5041
5075
// Parse lifetime argument.
5042
5076
lifetimes. push ( self . expect_lifetime ( ) ) ;
5043
5077
if seen_type || seen_binding {
@@ -5106,7 +5140,7 @@ impl<'a> Parser<'a> {
5106
5140
5107
5141
loop {
5108
5142
let lo = self . span ;
5109
- if self . check_lifetime ( ) && self . look_ahead ( 1 , |t| t != & token :: BinOp ( token :: Plus ) ) {
5143
+ if self . check_lifetime ( ) && self . look_ahead ( 1 , |t| !t . is_like_plus ( ) ) {
5110
5144
let lifetime = self . expect_lifetime ( ) ;
5111
5145
// Bounds starting with a colon are mandatory, but possibly empty.
5112
5146
self . expect ( & token:: Colon ) ?;
0 commit comments