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