24
24
import com .google .common .collect .HashBasedTable ;
25
25
import com .google .common .collect .HashMultimap ;
26
26
import com .google .common .collect .LinkedHashMultimap ;
27
- import com .google .common .collect .Multimap ;
27
+ import com .google .common .collect .SetMultimap ;
28
28
import com .google .common .collect .Table ;
29
29
import com .google .javascript .jscomp .NodeTraversal .AbstractPostOrderCallback ;
30
30
import com .google .javascript .jscomp .colors .StandardColors ;
34
34
import com .google .javascript .rhino .JSDocInfo ;
35
35
import com .google .javascript .rhino .Node ;
36
36
import com .google .javascript .rhino .Token ;
37
- import java .util .Collection ;
38
37
import java .util .HashSet ;
39
38
import java .util .LinkedHashMap ;
40
39
import java .util .LinkedHashSet ;
@@ -243,9 +242,11 @@ private class LoopClosureTransformer extends AbstractPostOrderCallback {
243
242
private static final String LOOP_OBJECT_PROPERTY_NAME = "$jscomp$loop$prop$" ;
244
243
private final Map <Node , LoopObject > loopObjectMap = new LinkedHashMap <>();
245
244
246
- private final Multimap <Node , LoopObject > functionLoopObjectsMap = LinkedHashMultimap .create ();
247
- private final Multimap <Node , String > functionHandledMap = HashMultimap .create ();
248
- private final Multimap <Var , Node > referenceMap = LinkedHashMultimap .create ();
245
+ private final SetMultimap <Node , LoopObject > nodesRequiringloopObjectsClosureMap =
246
+ LinkedHashMultimap .create ();
247
+ private final SetMultimap <Node , String > nodesHandledForLoopObjectClosure =
248
+ HashMultimap .create ();
249
+ private final SetMultimap <Var , Node > referenceMap = LinkedHashMultimap .create ();
249
250
// Maps from a var to a unique property name for that var
250
251
// e.g. 'i' -> '$jscomp$loop$prop$i$0'
251
252
private final Map <Var , String > propertyNameMap = new LinkedHashMap <>();
@@ -303,11 +304,26 @@ public void visit(NodeTraversal t, Node n, Node parent) {
303
304
}
304
305
305
306
if (outerMostFunctionScope != null ) {
306
- Node function = outerMostFunctionScope .getRootNode ();
307
- if (functionHandledMap .containsEntry (function , name )) {
307
+ Node enclosingFunction = outerMostFunctionScope .getRootNode ();
308
+
309
+ // There are two categories of functions we might find here:
310
+ // 1. a getter or setter in an object literal. We will wrap the entire object literal in
311
+ // a closure to capture the value of the let/const.
312
+ // 2. a function declaration or expression. We will wrap the function in a closure.
313
+ // (At this point, class methods/getters/setters and object literal member functions are
314
+ // transpiled away.)
315
+ final Node nodeToWrapInClosure ;
316
+ if (enclosingFunction .getParent ().isGetterDef ()
317
+ || enclosingFunction .getParent ().isSetterDef ()) {
318
+ nodeToWrapInClosure = enclosingFunction .getGrandparent ();
319
+ checkState (nodeToWrapInClosure .isObjectLit ());
320
+ } else {
321
+ nodeToWrapInClosure = enclosingFunction ;
322
+ }
323
+ if (nodesHandledForLoopObjectClosure .containsEntry (nodeToWrapInClosure , name )) {
308
324
return ;
309
325
}
310
- functionHandledMap .put (function , name );
326
+ nodesHandledForLoopObjectClosure .put (nodeToWrapInClosure , name );
311
327
312
328
LoopObject object =
313
329
loopObjectMap .computeIfAbsent (
@@ -318,8 +334,7 @@ public void visit(NodeTraversal t, Node n, Node parent) {
318
334
String newPropertyName = createUniquePropertyName (var );
319
335
object .vars .add (var );
320
336
propertyNameMap .put (var , newPropertyName );
321
-
322
- functionLoopObjectsMap .put (function , object );
337
+ nodesRequiringloopObjectsClosureMap .put (nodeToWrapInClosure , object );
323
338
}
324
339
}
325
340
@@ -485,9 +500,9 @@ private void transformLoopClosure() {
485
500
}
486
501
487
502
// Create wrapper functions and call them.
488
- for (Node function : functionLoopObjectsMap .keySet ()) {
503
+ for (Node functionOrObjectLit : nodesRequiringloopObjectsClosureMap .keySet ()) {
489
504
Node returnNode = IR .returnNode ();
490
- Collection <LoopObject > objects = functionLoopObjectsMap .get (function );
505
+ Set <LoopObject > objects = nodesRequiringloopObjectsClosureMap .get (functionOrObjectLit );
491
506
Node [] objectNames = new Node [objects .size ()];
492
507
Node [] objectNamesForCall = new Node [objects .size ()];
493
508
int i = 0 ;
@@ -505,18 +520,18 @@ private void transformLoopClosure() {
505
520
IR .block (returnNode ),
506
521
type (StandardColors .TOP_OBJECT ));
507
522
compiler .reportChangeToChangeScope (iife );
508
- Node call = astFactory .createCall (iife , type (function ), objectNamesForCall );
523
+ Node call = astFactory .createCall (iife , type (functionOrObjectLit ), objectNamesForCall );
509
524
call .putBooleanProp (Node .FREE_CALL , true );
510
525
Node replacement ;
511
- if (NodeUtil .isFunctionDeclaration (function )) {
526
+ if (NodeUtil .isFunctionDeclaration (functionOrObjectLit )) {
512
527
replacement =
513
- IR .var (IR .name (function .getFirstChild ().getString ()), call )
514
- .srcrefTreeIfMissing (function );
528
+ IR .var (IR .name (functionOrObjectLit .getFirstChild ().getString ()), call )
529
+ .srcrefTreeIfMissing (functionOrObjectLit );
515
530
} else {
516
- replacement = call .srcrefTreeIfMissing (function );
531
+ replacement = call .srcrefTreeIfMissing (functionOrObjectLit );
517
532
}
518
- function .replaceWith (replacement );
519
- returnNode .addChildToFront (function );
533
+ functionOrObjectLit .replaceWith (replacement );
534
+ returnNode .addChildToFront (functionOrObjectLit );
520
535
compiler .reportChangeToEnclosingScope (replacement );
521
536
}
522
537
}
0 commit comments