@@ -59,12 +59,14 @@ private static final class ConstructorData {
59
59
// meaning compiler.getTranspilationNamespace() does not work.
60
60
private GlobalNamespace globalNamespace ;
61
61
private final StaticScope transpilationNamespace ;
62
+ private final UniqueIdSupplier uniqueIdSupplier ;
62
63
63
64
public Es6ConvertSuperConstructorCalls (AbstractCompiler compiler ) {
64
65
this .compiler = compiler ;
65
66
this .astFactory = compiler .createAstFactory ();
66
67
this .transpilationNamespace = compiler .getTranspilationNamespace ();
67
68
this .constructorDataStack = new ArrayDeque <>();
69
+ this .uniqueIdSupplier = compiler .getUniqueIdSupplier ();
68
70
}
69
71
70
72
@ Override
@@ -109,6 +111,14 @@ private void visitSuper(NodeTraversal t, ConstructorData constructorData) {
109
111
if (superCalls .isEmpty ()) {
110
112
return ; // nothing to do
111
113
}
114
+
115
+ // Give a unique name to the $jscomp$super$this variables created when rewriting this super to
116
+ // preserve normalization.
117
+ String uniqueSuperThisName =
118
+ SUPER_THIS
119
+ + "$"
120
+ + uniqueIdSupplier .getUniqueId (compiler .getInput (NodeUtil .getInputId (constructor )));
121
+
112
122
if (constructor .isFromExterns ()) {
113
123
// This class is defined in an externs file, so it's only a stub, not the actual
114
124
// implementation that should be instantiated.
@@ -142,14 +152,14 @@ private void visitSuper(NodeTraversal t, ConstructorData constructorData) {
142
152
// To correctly extend them with the ES5 classes we're generating here, we must use
143
153
// `$jscomp.construct`, which is our wrapper around `Reflect.construct`.
144
154
convertSuperCallsToJsCompConstructCalls (
145
- constructor , superCalls , superClassNameNode , thisType );
155
+ constructor , superCalls , superClassNameNode , thisType , uniqueSuperThisName );
146
156
} else if (isNativeErrorClass (t , superClassQName )) {
147
157
// TODO(bradfordcsmith): It might be better to use $jscomp.construct() for these instead
148
158
// of our custom-made, Error-specific workaround.
149
159
for (Node superCall : superCalls ) {
150
160
Node newSuperCall =
151
161
createNewSuperCall (superClassNameNode , superCall , thisType , type (superCall ));
152
- replaceNativeErrorSuperCall (superCall , newSuperCall );
162
+ replaceNativeErrorSuperCall (superCall , newSuperCall , t . getInput () );
153
163
}
154
164
} else if (isKnownToReturnOnlyUndefined (superClassQName )) {
155
165
// super() will not change the value of `this`.
@@ -207,13 +217,14 @@ private void visitSuper(NodeTraversal t, ConstructorData constructorData) {
207
217
final AstFactory .Type typeOfThis = getTypeOfThisForConstructor (constructor );
208
218
// `this` -> `$jscomp$super$this` throughout the constructor body,
209
219
// except for super() calls.
210
- updateThisToSuperThis (typeOfThis , constructorBody , superCalls );
220
+ updateThisToSuperThis (typeOfThis , constructorBody , superCalls , uniqueSuperThisName );
211
221
// Start constructor with `var $jscomp$super$this;`
212
222
constructorBody .addChildToFront (
213
- IR .var (astFactory .createName (SUPER_THIS , typeOfThis )).srcrefTree (constructorBody ));
223
+ IR .var (astFactory .createName (uniqueSuperThisName , typeOfThis ))
224
+ .srcrefTree (constructorBody ));
214
225
// End constructor with `return $jscomp$super$this;`
215
226
constructorBody .addChildToBack (
216
- IR .returnNode (astFactory .createName (SUPER_THIS , typeOfThis ))
227
+ IR .returnNode (astFactory .createName (uniqueSuperThisName , typeOfThis ))
217
228
.srcrefTree (constructorBody ));
218
229
// Replace each super() call with `($jscomp$super$this = <newSuperCall> || this)`
219
230
for (Node superCall : superCalls ) {
@@ -223,7 +234,7 @@ private void visitSuper(NodeTraversal t, ConstructorData constructorData) {
223
234
superCall .replaceWith (
224
235
astFactory
225
236
.createAssign (
226
- astFactory .createName (SUPER_THIS , typeOfThis ),
237
+ astFactory .createName (uniqueSuperThisName , typeOfThis ),
227
238
astFactory .createOr (newSuperCall , astFactory .createThis (typeOfThis )))
228
239
.srcrefTreeIfMissing (superCall ));
229
240
}
@@ -255,7 +266,11 @@ private void visitSuper(NodeTraversal t, ConstructorData constructorData) {
255
266
* </code></pre>
256
267
*/
257
268
private void convertSuperCallsToJsCompConstructCalls (
258
- Node constructor , List <Node > superCalls , Node superClassNameNode , AstFactory .Type thisType ) {
269
+ Node constructor ,
270
+ List <Node > superCalls ,
271
+ Node superClassNameNode ,
272
+ AstFactory .Type thisType ,
273
+ String uniqueSuperThisName ) {
259
274
Node constructorBody = checkNotNull (constructor .getChildAtIndex (2 ));
260
275
Node firstStatement = constructorBody .getFirstChild ();
261
276
// A constructor body with no call to `super()` is a syntax error for a class that has an
@@ -278,21 +293,23 @@ private void convertSuperCallsToJsCompConstructCalls(
278
293
final AstFactory .Type typeOfThis = getTypeOfThisForConstructor (constructor );
279
294
// `this` -> `$jscomp$super$this` throughout the constructor body,
280
295
// except for super() calls.
281
- updateThisToSuperThis (typeOfThis , constructorBody , superCalls );
296
+ updateThisToSuperThis (typeOfThis , constructorBody , superCalls , uniqueSuperThisName );
282
297
// Start constructor with `var $jscomp$super$this;`
283
298
constructorBody .addChildToFront (
284
- astFactory .createSingleVarNameDeclaration (SUPER_THIS ).srcrefTree (constructorBody ));
299
+ astFactory
300
+ .createSingleVarNameDeclaration (uniqueSuperThisName )
301
+ .srcrefTree (constructorBody ));
285
302
// End constructor with `return $jscomp$super$this;`
286
303
constructorBody .addChildToBack (
287
304
astFactory
288
- .createReturn (astFactory .createName (SUPER_THIS , typeOfThis ))
305
+ .createReturn (astFactory .createName (uniqueSuperThisName , typeOfThis ))
289
306
.srcrefTree (constructorBody ));
290
307
// Replace each super() call with `($jscomp$super$this = $jscomp.construct(...))`
291
308
for (Node superCall : superCalls ) {
292
309
superCall .replaceWith (
293
310
astFactory
294
311
.createAssign (
295
- astFactory .createName (SUPER_THIS , typeOfThis ).srcref (superCall ),
312
+ astFactory .createName (uniqueSuperThisName , typeOfThis ).srcref (superCall ),
296
313
createJSCompConstructorCall (superClassNameNode , superCall , thisType ))
297
314
.srcref (superCall ));
298
315
}
@@ -534,7 +551,8 @@ private static boolean isSpreadOfArguments(Node node) {
534
551
return node .isSpread () && node .getOnlyChild ().matchesName ("arguments" );
535
552
}
536
553
537
- private void replaceNativeErrorSuperCall (Node superCall , Node newSuperCall ) {
554
+ private void replaceNativeErrorSuperCall (
555
+ Node superCall , Node newSuperCall , CompilerInput compilerInput ) {
538
556
// The native error class constructors always return a new object instead of initializing
539
557
// `this`, so a workaround is needed.
540
558
Node superStatement = NodeUtil .getEnclosingStatement (superCall );
@@ -543,23 +561,27 @@ private void replaceNativeErrorSuperCall(Node superCall, Node newSuperCall) {
543
561
544
562
AstFactory .Type thisType = type (newSuperCall );
545
563
564
+ // Give a unique name to the $jscomp$tmp$error; variables created when rewriting this super to
565
+ // preserve normalization.
566
+ String tmpErrorName = TMP_ERROR + "$" + uniqueIdSupplier .getUniqueId (compilerInput );
567
+
546
568
// var $jscomp$tmp$error;
547
569
Node getError =
548
- IR .var (astFactory .createName (TMP_ERROR , thisType )).srcrefTreeIfMissing (superCall );
570
+ IR .var (astFactory .createName (tmpErrorName , thisType )).srcrefTreeIfMissing (superCall );
549
571
getError .insertBefore (superStatement );
550
572
551
573
// Create an expression to initialize `this` from temporary Error object at the point
552
574
// where super.apply() was called.
553
575
// $jscomp$tmp$error = Error.call(this, ...),
554
576
Node getTmpError =
555
- astFactory .createAssign (astFactory .createName (TMP_ERROR , thisType ), newSuperCall );
577
+ astFactory .createAssign (astFactory .createName (tmpErrorName , thisType ), newSuperCall );
556
578
// this.message = $jscomp$tmp$error.message,
557
579
Node copyMessage =
558
580
astFactory .createAssign (
559
581
astFactory .createGetProp (
560
582
astFactory .createThis (thisType ), "message" , type (StandardColors .STRING )),
561
583
astFactory .createGetProp (
562
- astFactory .createName (TMP_ERROR , thisType ),
584
+ astFactory .createName (tmpErrorName , thisType ),
563
585
"message" ,
564
586
type (StandardColors .STRING )));
565
587
@@ -569,12 +591,12 @@ private void replaceNativeErrorSuperCall(Node superCall, Node newSuperCall) {
569
591
Node setStack =
570
592
astFactory .createAnd (
571
593
astFactory .createIn (
572
- astFactory .createString ("stack" ), astFactory .createName (TMP_ERROR , thisType )),
594
+ astFactory .createString ("stack" ), astFactory .createName (tmpErrorName , thisType )),
573
595
astFactory .createAssign (
574
596
astFactory .createGetProp (
575
597
astFactory .createThis (thisType ), "stack" , type (StandardColors .STRING )),
576
598
astFactory .createGetProp (
577
- astFactory .createName (TMP_ERROR , thisType ),
599
+ astFactory .createName (tmpErrorName , thisType ),
578
600
"stack" ,
579
601
type (StandardColors .STRING ))));
580
602
Node superErrorExpr =
@@ -666,7 +688,10 @@ private boolean isDefinedInSources(NodeTraversal t, String varName) {
666
688
}
667
689
668
690
private void updateThisToSuperThis (
669
- final AstFactory .Type typeOfThis , Node constructorBody , final List <Node > superCalls ) {
691
+ final AstFactory .Type typeOfThis ,
692
+ Node constructorBody ,
693
+ final List <Node > superCalls ,
694
+ final String uniqueSuperThisName ) {
670
695
NodeTraversal .Callback replaceThisWithSuperThis =
671
696
new NodeTraversal .Callback () {
672
697
@ Override
@@ -684,11 +709,11 @@ public boolean shouldTraverse(NodeTraversal nodeTraversal, Node n, Node parent)
684
709
@ Override
685
710
public void visit (NodeTraversal t , Node n , Node parent ) {
686
711
if (n .isThis ()) {
687
- Node superThis = astFactory .createName (SUPER_THIS , type (n )).srcref (n );
712
+ Node superThis = astFactory .createName (uniqueSuperThisName , type (n )).srcref (n );
688
713
n .replaceWith (superThis );
689
714
} else if (n .isReturn () && !n .hasChildren ()) {
690
715
// An empty return needs to be changed to return $jscomp$super$this
691
- n .addChildToFront (astFactory .createName (SUPER_THIS , typeOfThis ).srcref (n ));
716
+ n .addChildToFront (astFactory .createName (uniqueSuperThisName , typeOfThis ).srcref (n ));
692
717
}
693
718
}
694
719
};
0 commit comments