@@ -3154,13 +3154,55 @@ impl<'a> Parser<'a> {
3154
3154
// Parse: `for <src_pat> in <src_expr> <src_loop_block>`
3155
3155
3156
3156
let pat = self . parse_pat ( ) ?;
3157
- self . expect_keyword ( keywords:: In ) ?;
3158
- let expr = self . parse_expr_res ( Restrictions :: NO_STRUCT_LITERAL , None ) ?;
3159
- let ( iattrs, loop_block) = self . parse_inner_attrs_and_block ( ) ?;
3160
- attrs. extend ( iattrs) ;
3157
+ // Save the state of the parser before parsing 'in'.
3158
+ let parser_snapshot_before_in = self . clone ( ) ;
3159
+ match self . expect_keyword ( keywords:: In ) {
3160
+ Ok ( ( ) ) => {
3161
+ let expr = self . parse_expr_res ( Restrictions :: NO_STRUCT_LITERAL , None ) ?;
3162
+ let ( iattrs, loop_block) = self . parse_inner_attrs_and_block ( ) ?;
3163
+ attrs. extend ( iattrs) ;
3161
3164
3162
- let hi = self . prev_span ;
3163
- Ok ( self . mk_expr ( span_lo. to ( hi) , ExprKind :: ForLoop ( pat, expr, loop_block, opt_ident) , attrs) )
3165
+ let hi = self . prev_span ;
3166
+ Ok ( self . mk_expr (
3167
+ span_lo. to ( hi) ,
3168
+ ExprKind :: ForLoop ( pat, expr, loop_block, opt_ident) ,
3169
+ attrs) )
3170
+ }
3171
+ Err ( mut in_err) => {
3172
+ let parser_snapshot_after_in = self . clone ( ) ;
3173
+ // Rewind to before attempting to parse the 'in'.
3174
+ mem:: replace ( self , parser_snapshot_before_in) ;
3175
+
3176
+ match self . parse_expr_res ( Restrictions :: NO_STRUCT_LITERAL , None ) {
3177
+ Ok ( expr) => {
3178
+ // Successfully parsed the expr, print a nice error message.
3179
+ in_err. cancel ( ) ;
3180
+ let in_span = parser_snapshot_after_in. span ;
3181
+ let mut err = self . sess . span_diagnostic
3182
+ . struct_span_err ( in_span, "missing `in` in `for` loop" ) ;
3183
+ err. span_label ( in_span, "expected `in` here" ) ;
3184
+ let sugg = pprust:: to_string ( |s| {
3185
+ s. s . word ( "for " ) ?;
3186
+ s. print_pat ( & pat) ?;
3187
+ s. s . word ( " in " ) ?;
3188
+ s. print_expr ( & expr)
3189
+ } ) ;
3190
+ err. span_suggestion (
3191
+ in_span,
3192
+ "try adding `in`" ,
3193
+ sugg) ;
3194
+ Err ( err)
3195
+ }
3196
+ Err ( mut expr_err) => {
3197
+ // Couldn't parse as an expr, return original error and parser state.
3198
+ expr_err. cancel ( ) ;
3199
+ mem:: replace ( self , parser_snapshot_after_in) ;
3200
+ Err ( in_err)
3201
+ }
3202
+ }
3203
+ }
3204
+
3205
+ }
3164
3206
}
3165
3207
3166
3208
/// Parse a 'while' or 'while let' expression ('while' token already eaten)
0 commit comments