@@ -881,6 +881,40 @@ impl<'a> Parser<'a> {
881881 }
882882 }
883883
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+
884918 /// Expect and consume an `&`. If `&&` is seen, replace it with a single
885919 /// `&` and continue. If an `&` is not seen, signal an error.
886920 fn expect_and ( & mut self ) -> PResult < ' a , ( ) > {
@@ -1517,7 +1551,7 @@ impl<'a> Parser<'a> {
15171551
15181552 if ts. len ( ) == 1 && !last_comma {
15191553 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 ( ) ;
15211555 match ty. node {
15221556 // `(TY_BOUND_NOPAREN) + BOUND + ...`.
15231557 TyKind :: Path ( None , ref path) if maybe_bounds => {
@@ -1586,7 +1620,7 @@ impl<'a> Parser<'a> {
15861620 self . parse_ty_bare_fn ( lifetime_defs) ?
15871621 } else {
15881622 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 ( ) ;
15901624 self . parse_remaining_bounds ( lifetime_defs, path, lo, parse_plus) ?
15911625 }
15921626 } else if self . eat_keyword ( keywords:: Impl ) {
@@ -1603,7 +1637,7 @@ impl<'a> Parser<'a> {
16031637 impl_dyn_multi = bounds. len ( ) > 1 || self . prev_token_kind == PrevTokenKind :: Plus ;
16041638 TyKind :: TraitObject ( bounds, TraitObjectSyntax :: Dyn )
16051639 } 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 ( ) ) {
16071641 // Bound list (trait object type)
16081642 TyKind :: TraitObject ( self . parse_ty_param_bounds_common ( allow_plus) ?,
16091643 TraitObjectSyntax :: None )
@@ -1623,7 +1657,7 @@ impl<'a> Parser<'a> {
16231657 // Just a type path or bound list (trait object type) starting with a trait.
16241658 // `Type`
16251659 // `Trait1 + Trait2 + 'a`
1626- if allow_plus && self . check ( & token :: BinOp ( token :: Plus ) ) {
1660+ if allow_plus && self . check_plus ( ) {
16271661 self . parse_remaining_bounds ( Vec :: new ( ) , path, lo, true ) ?
16281662 } else {
16291663 TyKind :: Path ( None , path)
@@ -1650,7 +1684,7 @@ impl<'a> Parser<'a> {
16501684 let poly_trait_ref = PolyTraitRef :: new ( generic_params, path, lo. to ( self . prev_span ) ) ;
16511685 let mut bounds = vec ! [ TraitTyParamBound ( poly_trait_ref, TraitBoundModifier :: None ) ] ;
16521686 if parse_plus {
1653- self . bump ( ) ; // `+`
1687+ self . eat_plus ( ) ; // `+`, or `+=` gets split and `+` is discarded
16541688 bounds. append ( & mut self . parse_ty_param_bounds ( ) ?) ;
16551689 }
16561690 Ok ( TyKind :: TraitObject ( bounds, TraitObjectSyntax :: None ) )
@@ -1671,7 +1705,7 @@ impl<'a> Parser<'a> {
16711705
16721706 fn maybe_recover_from_bad_type_plus ( & mut self , allow_plus : bool , ty : & Ty ) -> PResult < ' a , ( ) > {
16731707 // 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 ( ) {
16751709 return Ok ( ( ) )
16761710 }
16771711
@@ -4872,7 +4906,7 @@ impl<'a> Parser<'a> {
48724906 break
48734907 }
48744908
4875- if !allow_plus || !self . eat ( & token :: BinOp ( token :: Plus ) ) {
4909+ if !allow_plus || !self . eat_plus ( ) {
48764910 break
48774911 }
48784912 }
@@ -4891,7 +4925,7 @@ impl<'a> Parser<'a> {
48914925 while self . check_lifetime ( ) {
48924926 lifetimes. push ( self . expect_lifetime ( ) ) ;
48934927
4894- if !self . eat ( & token :: BinOp ( token :: Plus ) ) {
4928+ if !self . eat_plus ( ) {
48954929 break
48964930 }
48974931 }
@@ -5037,7 +5071,7 @@ impl<'a> Parser<'a> {
50375071 let mut seen_type = false ;
50385072 let mut seen_binding = false ;
50395073 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 ( ) ) {
50415075 // Parse lifetime argument.
50425076 lifetimes. push ( self . expect_lifetime ( ) ) ;
50435077 if seen_type || seen_binding {
@@ -5106,7 +5140,7 @@ impl<'a> Parser<'a> {
51065140
51075141 loop {
51085142 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 ( ) ) {
51105144 let lifetime = self . expect_lifetime ( ) ;
51115145 // Bounds starting with a colon are mandatory, but possibly empty.
51125146 self . expect ( & token:: Colon ) ?;
0 commit comments