@@ -2592,53 +2592,59 @@ impl<'a> Parser<'a> {
25922592 }
25932593
25942594 fn parse_for_head ( & mut self ) -> PResult < ' a , ( P < Pat > , P < Expr > ) > {
2595- let pat = if self . token . kind == token:: OpenDelim ( Delimiter :: Parenthesis ) {
2595+ let begin_paren = if self . token . kind == token:: OpenDelim ( Delimiter :: Parenthesis ) {
25962596 // Record whether we are about to parse `for (`.
25972597 // This is used below for recovery in case of `for ( $stuff ) $block`
25982598 // in which case we will suggest `for $stuff $block`.
25992599 let start_span = self . token . span ;
26002600 let left = self . prev_token . span . between ( self . look_ahead ( 1 , |t| t. span ) ) ;
2601- match self . parse_pat_allow_top_alt (
2602- None ,
2603- RecoverComma :: Yes ,
2604- RecoverColon :: Yes ,
2605- CommaRecoveryMode :: LikelyTuple ,
2606- ) {
2607- Ok ( pat) => pat,
2608- Err ( err) if self . eat_keyword ( kw:: In ) => {
2609- let expr = match self . parse_expr_res ( Restrictions :: NO_STRUCT_LITERAL , None ) {
2610- Ok ( expr) => expr,
2611- Err ( expr_err) => {
2612- expr_err. cancel ( ) ;
2613- return Err ( err) ;
2614- }
2615- } ;
2616- return if self . token . kind == token:: CloseDelim ( Delimiter :: Parenthesis ) {
2617- let span = vec ! [ start_span, self . token. span] ;
2618- let right = self . prev_token . span . between ( self . look_ahead ( 1 , |t| t. span ) ) ;
2619- self . bump ( ) ; // )
2620- err. cancel ( ) ;
2621- self . sess . emit_err ( errors:: ParenthesesInForHead {
2622- span,
2623- // With e.g. `for (x) in y)` this would replace `(x) in y)`
2624- // with `x) in y)` which is syntactically invalid.
2625- // However, this is prevented before we get here.
2626- sugg : errors:: ParenthesesInForHeadSugg { left, right } ,
2627- } ) ;
2628- Ok ( ( self . mk_pat ( start_span. to ( right) , ast:: PatKind :: Wild ) , expr) )
2629- } else {
2630- Err ( err)
2631- } ;
2632- }
2633- Err ( err) => return Err ( err) ,
2634- }
2601+ Some ( ( start_span, left) )
26352602 } else {
2603+ None
2604+ } ;
2605+ // Try to parse the pattern `for ($PAT) in $EXPR`.
2606+ let pat = match (
26362607 self . parse_pat_allow_top_alt (
26372608 None ,
26382609 RecoverComma :: Yes ,
26392610 RecoverColon :: Yes ,
26402611 CommaRecoveryMode :: LikelyTuple ,
2641- ) ?
2612+ ) ,
2613+ begin_paren,
2614+ ) {
2615+ ( Ok ( pat) , _) => pat, // Happy path.
2616+ ( Err ( err) , Some ( ( start_span, left) ) ) if self . eat_keyword ( kw:: In ) => {
2617+ // We know for sure we have seen `for ($SOMETHING in`. In the happy path this would
2618+ // happen right before the return of this method.
2619+ let expr = match self . parse_expr_res ( Restrictions :: NO_STRUCT_LITERAL , None ) {
2620+ Ok ( expr) => expr,
2621+ Err ( expr_err) => {
2622+ // We don't know what followed the `in`, so cancel and bubble up the
2623+ // original error.
2624+ expr_err. cancel ( ) ;
2625+ return Err ( err) ;
2626+ }
2627+ } ;
2628+ return if self . token . kind == token:: CloseDelim ( Delimiter :: Parenthesis ) {
2629+ // We know for sure we have seen `for ($SOMETHING in $EXPR)`, so we recover the
2630+ // parser state and emit a targetted suggestion.
2631+ let span = vec ! [ start_span, self . token. span] ;
2632+ let right = self . prev_token . span . between ( self . look_ahead ( 1 , |t| t. span ) ) ;
2633+ self . bump ( ) ; // )
2634+ err. cancel ( ) ;
2635+ self . sess . emit_err ( errors:: ParenthesesInForHead {
2636+ span,
2637+ // With e.g. `for (x) in y)` this would replace `(x) in y)`
2638+ // with `x) in y)` which is syntactically invalid.
2639+ // However, this is prevented before we get here.
2640+ sugg : errors:: ParenthesesInForHeadSugg { left, right } ,
2641+ } ) ;
2642+ Ok ( ( self . mk_pat ( start_span. to ( right) , ast:: PatKind :: Wild ) , expr) )
2643+ } else {
2644+ Err ( err) // Some other error, bubble up.
2645+ } ;
2646+ }
2647+ ( Err ( err) , _) => return Err ( err) , // Some other error, bubble up.
26422648 } ;
26432649 if !self . eat_keyword ( kw:: In ) {
26442650 self . error_missing_in_for_loop ( ) ;
0 commit comments