@@ -2610,53 +2610,59 @@ impl<'a> Parser<'a> {
26102610 }
26112611
26122612 fn parse_for_head ( & mut self ) -> PResult < ' a , ( P < Pat > , P < Expr > ) > {
2613- let pat = if self . token . kind == token:: OpenDelim ( Delimiter :: Parenthesis ) {
2613+ let begin_paren = if self . token . kind == token:: OpenDelim ( Delimiter :: Parenthesis ) {
26142614 // Record whether we are about to parse `for (`.
26152615 // This is used below for recovery in case of `for ( $stuff ) $block`
26162616 // in which case we will suggest `for $stuff $block`.
26172617 let start_span = self . token . span ;
26182618 let left = self . prev_token . span . between ( self . look_ahead ( 1 , |t| t. span ) ) ;
2619- match self . parse_pat_allow_top_alt (
2620- None ,
2621- RecoverComma :: Yes ,
2622- RecoverColon :: Yes ,
2623- CommaRecoveryMode :: LikelyTuple ,
2624- ) {
2625- Ok ( pat) => pat,
2626- Err ( err) if self . eat_keyword ( kw:: In ) => {
2627- let expr = match self . parse_expr_res ( Restrictions :: NO_STRUCT_LITERAL , None ) {
2628- Ok ( expr) => expr,
2629- Err ( expr_err) => {
2630- expr_err. cancel ( ) ;
2631- return Err ( err) ;
2632- }
2633- } ;
2634- return if self . token . kind == token:: CloseDelim ( Delimiter :: Parenthesis ) {
2635- let span = vec ! [ start_span, self . token. span] ;
2636- let right = self . prev_token . span . between ( self . look_ahead ( 1 , |t| t. span ) ) ;
2637- self . bump ( ) ; // )
2638- err. cancel ( ) ;
2639- self . sess . emit_err ( errors:: ParenthesesInForHead {
2640- span,
2641- // With e.g. `for (x) in y)` this would replace `(x) in y)`
2642- // with `x) in y)` which is syntactically invalid.
2643- // However, this is prevented before we get here.
2644- sugg : errors:: ParenthesesInForHeadSugg { left, right } ,
2645- } ) ;
2646- Ok ( ( self . mk_pat ( start_span. to ( right) , ast:: PatKind :: Wild ) , expr) )
2647- } else {
2648- Err ( err)
2649- } ;
2650- }
2651- Err ( err) => return Err ( err) ,
2652- }
2619+ Some ( ( start_span, left) )
26532620 } else {
2621+ None
2622+ } ;
2623+ // Try to parse the pattern `for ($PAT) in $EXPR`.
2624+ let pat = match (
26542625 self . parse_pat_allow_top_alt (
26552626 None ,
26562627 RecoverComma :: Yes ,
26572628 RecoverColon :: Yes ,
26582629 CommaRecoveryMode :: LikelyTuple ,
2659- ) ?
2630+ ) ,
2631+ begin_paren,
2632+ ) {
2633+ ( Ok ( pat) , _) => pat, // Happy path.
2634+ ( Err ( err) , Some ( ( start_span, left) ) ) if self . eat_keyword ( kw:: In ) => {
2635+ // We know for sure we have seen `for ($SOMETHING in`. In the happy path this would
2636+ // happen right before the return of this method.
2637+ let expr = match self . parse_expr_res ( Restrictions :: NO_STRUCT_LITERAL , None ) {
2638+ Ok ( expr) => expr,
2639+ Err ( expr_err) => {
2640+ // We don't know what followed the `in`, so cancel and bubble up the
2641+ // original error.
2642+ expr_err. cancel ( ) ;
2643+ return Err ( err) ;
2644+ }
2645+ } ;
2646+ return if self . token . kind == token:: CloseDelim ( Delimiter :: Parenthesis ) {
2647+ // We know for sure we have seen `for ($SOMETHING in $EXPR)`, so we recover the
2648+ // parser state and emit a targetted suggestion.
2649+ let span = vec ! [ start_span, self . token. span] ;
2650+ let right = self . prev_token . span . between ( self . look_ahead ( 1 , |t| t. span ) ) ;
2651+ self . bump ( ) ; // )
2652+ err. cancel ( ) ;
2653+ self . sess . emit_err ( errors:: ParenthesesInForHead {
2654+ span,
2655+ // With e.g. `for (x) in y)` this would replace `(x) in y)`
2656+ // with `x) in y)` which is syntactically invalid.
2657+ // However, this is prevented before we get here.
2658+ sugg : errors:: ParenthesesInForHeadSugg { left, right } ,
2659+ } ) ;
2660+ Ok ( ( self . mk_pat ( start_span. to ( right) , ast:: PatKind :: Wild ) , expr) )
2661+ } else {
2662+ Err ( err) // Some other error, bubble up.
2663+ } ;
2664+ }
2665+ ( Err ( err) , _) => return Err ( err) , // Some other error, bubble up.
26602666 } ;
26612667 if !self . eat_keyword ( kw:: In ) {
26622668 self . error_missing_in_for_loop ( ) ;
0 commit comments