Skip to content

Commit 56401a1

Browse files
Update async await transpilation to avoid captures of super when using ES2015+ output.
MS Edge 17 does not properly capture references to `super` in an arrow function. Closes #3101
1 parent 826b0fc commit 56401a1

File tree

5 files changed

+121
-6
lines changed

5 files changed

+121
-6
lines changed

src/com/google/javascript/jscomp/RewriteAsyncFunctions.java

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,10 +243,33 @@ private void convertAsyncFunction(NodeTraversal t, LexicalContext functionContex
243243
newBody.addChildToBack(IR.constNode(IR.name(ASYNC_ARGUMENTS), IR.name("arguments")));
244244
NodeUtil.addFeatureToScript(t.getCurrentFile(), Feature.CONST_DECLARATIONS);
245245
}
246+
boolean needsSuperTranspilation = compiler.getOptions().needsTranspilationFrom(FeatureSet.ES6);
246247
for (String replacedMethodName : functionContext.replacedSuperProperties) {
248+
// MS Edge 17 cannot properly capture references to "super" in an arrow function.
249+
// If we are not transpiling classes, switch to using Object.getPrototypeOf(this.constructor)
250+
// as a replacement for super.
251+
// If we are transpiling classes, the super reference will be handled elsewhere.
252+
Node superReference;
253+
if (needsSuperTranspilation) {
254+
superReference = IR.superNode();
255+
} else {
256+
// instance super: Object.getPrototypeOf(this.constructor).prototype
257+
// static super: Object.getPrototypeOf(this.constructor)
258+
superReference =
259+
IR.call(
260+
IR.getprop(IR.name("Object"), IR.string("getPrototypeOf")),
261+
IR.getprop(IR.thisNode(), IR.string("constructor")));
262+
if (!originalFunction.getParent().isStaticMember()) {
263+
superReference = IR.getprop(superReference, IR.string("prototype"));
264+
}
265+
}
266+
247267
// const super$get$x = () => super.x;
248-
Node arrowFunction = IR.arrowFunction(
249-
IR.name(""), IR.paramList(), IR.getprop(IR.superNode(), IR.string(replacedMethodName)));
268+
Node arrowFunction =
269+
IR.arrowFunction(
270+
IR.name(""),
271+
IR.paramList(),
272+
IR.getprop(superReference, IR.string(replacedMethodName)));
250273
compiler.reportChangeToChangeScope(arrowFunction);
251274
NodeUtil.addFeatureToScript(t.getCurrentFile(), Feature.ARROW_FUNCTIONS);
252275

src/com/google/javascript/jscomp/RewriteAsyncIteration.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -557,17 +557,38 @@ private void prependTempVarDeclarations(LexicalContext ctx, NodeTraversal t) {
557557
IR.constNode(IR.name(argumentsVarName), IR.name("arguments"))
558558
.useSourceInfoFromForTree(block));
559559
}
560+
boolean needsSuperTranspilation = compiler.getOptions().needsTranspilationFrom(FeatureSet.ES6);
560561
for (String replacedMethodName : thisSuperArgsCtx.usedSuperProperties) {
561562
// { // prefixBlock
562563
// const $jscomp$asyncIter$this = this;
563564
// const $jscomp$asyncIter$arguments = arguments;
564565
// const $jscomp$asyncIter$super$get$x = () => super.x;
565566
// }
567+
//
568+
// MS Edge 17 cannot properly capture references to "super" in an arrow function.
569+
// If we are not transpiling classes, switch to using Object.getPrototypeOf(this.constructor)
570+
// as a replacement for super.
571+
// If we are transpiling classes, the super reference will be handled elsewhere.
572+
Node superReference;
573+
if (needsSuperTranspilation) {
574+
superReference = IR.superNode();
575+
} else {
576+
// instance super: Object.getPrototypeOf(this.constructor).prototype
577+
// static super: Object.getPrototypeOf(this.constructor)
578+
superReference =
579+
IR.call(
580+
IR.getprop(IR.name("Object"), IR.string("getPrototypeOf")),
581+
IR.getprop(IR.thisNode(), IR.string("constructor")));
582+
if (!ctx.function.getParent().isStaticMember()) {
583+
superReference = IR.getprop(superReference, IR.string("prototype"));
584+
}
585+
}
586+
566587
Node arrowFunction =
567588
IR.arrowFunction(
568589
IR.name(""),
569590
IR.paramList(),
570-
IR.getprop(IR.superNode(), IR.string(replacedMethodName)));
591+
IR.getprop(superReference, IR.string(replacedMethodName)));
571592
compiler.reportChangeToChangeScope(arrowFunction);
572593
NodeUtil.addFeatureToScript(t.getCurrentFile(), Feature.ARROW_FUNCTIONS);
573594
String superReplacementName = superPropGetterPrefix + replacedMethodName;

test/com/google/javascript/jscomp/IntegrationTest.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3988,7 +3988,8 @@ public void testAsyncFunctionSuper() {
39883988
"}",
39893989
"class Baz extends Foo {",
39903990
" bar() {",
3991-
" const $jscomp$async$this = this, $jscomp$async$super$get$bar = () => super.bar;",
3991+
" const $jscomp$async$this = this, $jscomp$async$super$get$bar =",
3992+
" () => Object.getPrototypeOf(this.constructor).prototype.bar;",
39923993
" return $jscomp.asyncExecutePromiseGeneratorFunction(function*() {",
39933994
" yield Promise.resolve();",
39943995
" $jscomp$async$super$get$bar().call($jscomp$async$this);",
@@ -4041,7 +4042,8 @@ public void testAsyncIterationSuper() {
40414042
"class Baz extends Foo {",
40424043
" bar() {",
40434044
" const $jscomp$asyncIter$this = this,",
4044-
" $jscomp$asyncIter$super$get$bar = () => super.bar;",
4045+
" $jscomp$asyncIter$super$get$bar =",
4046+
" () => Object.getPrototypeOf(this.constructor).prototype.bar;",
40454047
" return new $jscomp.AsyncGeneratorWrapper(function*() {",
40464048
" $jscomp$asyncIter$super$get$bar().call($jscomp$asyncIter$this).next();",
40474049
" }());",

test/com/google/javascript/jscomp/RewriteAsyncFunctionsTest.java

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,74 @@ public void testInnerSuperReference() {
142142
"}"));
143143
}
144144

145+
@Test
146+
public void testInnerSuperCallEs2015Out() {
147+
setLanguageOut(LanguageMode.ECMASCRIPT_2015);
148+
test(
149+
lines(
150+
"class A {",
151+
" m() {",
152+
" return this;",
153+
" }",
154+
"}",
155+
"class X extends A {",
156+
" async m() {",
157+
" return super.m();",
158+
" }",
159+
"}"),
160+
lines(
161+
"class A {",
162+
" m() {",
163+
" return this;",
164+
" }",
165+
"}",
166+
"class X extends A {",
167+
" m() {",
168+
" const $jscomp$async$this = this;",
169+
" const $jscomp$async$super$get$m =",
170+
" () => Object.getPrototypeOf(this.constructor).prototype.m;",
171+
" return $jscomp.asyncExecutePromiseGeneratorFunction(",
172+
" function* () {",
173+
" return $jscomp$async$super$get$m().call($jscomp$async$this);",
174+
" });",
175+
" }",
176+
"}"));
177+
}
178+
179+
@Test
180+
public void testInnerSuperCallStaticEs2015Out() {
181+
setLanguageOut(LanguageMode.ECMASCRIPT_2015);
182+
test(
183+
lines(
184+
"class A {",
185+
" static m() {",
186+
" return this;",
187+
" }",
188+
"}",
189+
"class X extends A {",
190+
" static async m() {",
191+
" return super.m();",
192+
" }",
193+
"}"),
194+
lines(
195+
"class A {",
196+
" static m() {",
197+
" return this;",
198+
" }",
199+
"}",
200+
"class X extends A {",
201+
" static m() {",
202+
" const $jscomp$async$this = this;",
203+
" const $jscomp$async$super$get$m =",
204+
" () => Object.getPrototypeOf(this.constructor).m;",
205+
" return $jscomp.asyncExecutePromiseGeneratorFunction(",
206+
" function* () {",
207+
" return $jscomp$async$super$get$m().call($jscomp$async$this);",
208+
" });",
209+
" }",
210+
"}"));
211+
}
212+
145213
@Test
146214
public void testNestedArrowFunctionUsingThis() {
147215
test(

test/com/google/javascript/jscomp/RewriteAsyncIterationTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,8 @@ public void testInnerSuperReferenceInAsyncGenerator() {
225225
"}",
226226
"class X extends A {",
227227
" m() {",
228-
" const $jscomp$asyncIter$super$get$m = () => super.m;",
228+
" const $jscomp$asyncIter$super$get$m =",
229+
" () => Object.getPrototypeOf(this.constructor).prototype.m;",
229230
" return new $jscomp.AsyncGeneratorWrapper(",
230231
" function* () {",
231232
" const tmp = $jscomp$asyncIter$super$get$m();",

0 commit comments

Comments
 (0)