@@ -342,33 +342,68 @@ impl<'a> PeepholeOptimizations {
342
342
result. push ( Statement :: ForStatement ( for_stmt) ) ;
343
343
}
344
344
Statement :: ForInStatement ( mut for_in_stmt) => {
345
- // "a; for (var b in c) d" => "for (var b in a, c) d"
346
- if let Some ( Statement :: ExpressionStatement ( prev_expr_stmt) ) = result. last_mut ( ) {
347
- // Annex B.3.5 allows initializers in non-strict mode
348
- // <https://tc39.es/ecma262/multipage/additional-ecmascript-features-for-web-browsers.html#sec-initializers-in-forin-statement-heads>
349
- // If there's a side-effectful initializer, we should not move the previous statement inside.
350
- let has_side_effectful_initializer = {
351
- if let ForStatementLeft :: VariableDeclaration ( var_decl) = & for_in_stmt. left {
352
- if var_decl. declarations . len ( ) == 1 {
353
- // only var can have a initializer
354
- var_decl. kind . is_var ( )
355
- && var_decl. declarations [ 0 ] . init . as_ref ( ) . is_some_and ( |init| {
356
- ctx. expression_may_have_side_effects ( init)
357
- } )
345
+ match result. last_mut ( ) {
346
+ // "a; for (var b in c) d" => "for (var b in a, c) d"
347
+ Some ( Statement :: ExpressionStatement ( prev_expr_stmt) ) => {
348
+ // Annex B.3.5 allows initializers in non-strict mode
349
+ // <https://tc39.es/ecma262/multipage/additional-ecmascript-features-for-web-browsers.html#sec-initializers-in-forin-statement-heads>
350
+ // If there's a side-effectful initializer, we should not move the previous statement inside.
351
+ let has_side_effectful_initializer = {
352
+ if let ForStatementLeft :: VariableDeclaration ( var_decl) =
353
+ & for_in_stmt. left
354
+ {
355
+ if var_decl. declarations . len ( ) == 1 {
356
+ // only var can have a initializer
357
+ var_decl. kind . is_var ( )
358
+ && var_decl. declarations [ 0 ] . init . as_ref ( ) . is_some_and (
359
+ |init| ctx. expression_may_have_side_effects ( init) ,
360
+ )
361
+ } else {
362
+ // the spec does not allow multiple declarations though
363
+ true
364
+ }
358
365
} else {
359
- // the spec does not allow multiple declarations though
360
- true
366
+ false
361
367
}
362
- } else {
363
- false
368
+ } ;
369
+ if !has_side_effectful_initializer {
370
+ let a = & mut prev_expr_stmt. expression ;
371
+ for_in_stmt. right = Self :: join_sequence ( a, & mut for_in_stmt. right , ctx) ;
372
+ result. pop ( ) ;
373
+ self . mark_current_function_as_changed ( ) ;
364
374
}
365
- } ;
366
- if !has_side_effectful_initializer {
367
- let a = & mut prev_expr_stmt. expression ;
368
- for_in_stmt. right = Self :: join_sequence ( a, & mut for_in_stmt. right , ctx) ;
369
- result. pop ( ) ;
370
- self . mark_current_function_as_changed ( ) ;
371
375
}
376
+ // "var a; for (a in b) c" => "for (var a in b) c"
377
+ Some ( Statement :: VariableDeclaration ( prev_var_decl) ) => {
378
+ if let ForStatementLeft :: AssignmentTargetIdentifier ( id) = & for_in_stmt. left
379
+ {
380
+ let prev_var_decl_no_init_item = {
381
+ if prev_var_decl. kind . is_var ( )
382
+ && prev_var_decl. declarations . len ( ) == 1
383
+ && prev_var_decl. declarations [ 0 ] . init . is_none ( )
384
+ {
385
+ Some ( & prev_var_decl. declarations [ 0 ] )
386
+ } else {
387
+ None
388
+ }
389
+ } ;
390
+ if let Some ( prev_var_decl_item) = prev_var_decl_no_init_item {
391
+ if let BindingPatternKind :: BindingIdentifier ( decl_id) =
392
+ & prev_var_decl_item. id . kind
393
+ {
394
+ if id. name == decl_id. name {
395
+ for_in_stmt. left =
396
+ ForStatementLeft :: VariableDeclaration ( ctx. ast . alloc (
397
+ ctx. ast . move_variable_declaration ( prev_var_decl) ,
398
+ ) ) ;
399
+ result. pop ( ) ;
400
+ self . mark_current_function_as_changed ( ) ;
401
+ }
402
+ }
403
+ }
404
+ }
405
+ }
406
+ _ => { }
372
407
}
373
408
result. push ( Statement :: ForInStatement ( for_in_stmt) ) ;
374
409
}
0 commit comments