@@ -32,6 +32,15 @@ namespace ts {
32
32
33
33
let enclosingFunctionParameterNames : UnderscoreEscapedMap < true > ;
34
34
35
+ /**
36
+ * Keeps track of property names accessed on super (`super.x`) within async functions.
37
+ */
38
+ let capturedSuperProperties : UnderscoreEscapedMap < true > ;
39
+ /** Whether the async function contains an element access on super (`super[x]`). */
40
+ let hasSuperElementAccess : boolean ;
41
+ /** A set of node IDs for generated super accessors (variable statements). */
42
+ const substitutedSuperAccessors : boolean [ ] = [ ] ;
43
+
35
44
// Save the previous transformation hooks.
36
45
const previousOnEmitNode = context . onEmitNode ;
37
46
const previousOnSubstituteNode = context . onSubstituteNode ;
@@ -53,10 +62,6 @@ namespace ts {
53
62
}
54
63
55
64
function visitor ( node : Node ) : VisitResult < Node > {
56
- if ( ( node . transformFlags & TransformFlags . ContainsES2017 ) === 0 ) {
57
- return node ;
58
- }
59
-
60
65
switch ( node . kind ) {
61
66
case SyntaxKind . AsyncKeyword :
62
67
// ES2017 async modifier should be elided for targets < ES2017
@@ -77,6 +82,18 @@ namespace ts {
77
82
case SyntaxKind . ArrowFunction :
78
83
return visitArrowFunction ( < ArrowFunction > node ) ;
79
84
85
+ case SyntaxKind . PropertyAccessExpression :
86
+ if ( capturedSuperProperties && isPropertyAccessExpression ( node ) && node . expression . kind === SyntaxKind . SuperKeyword ) {
87
+ capturedSuperProperties . set ( node . name . escapedText , true ) ;
88
+ }
89
+ return visitEachChild ( node , visitor , context ) ;
90
+
91
+ case SyntaxKind . ElementAccessExpression :
92
+ if ( capturedSuperProperties && ( < ElementAccessExpression > node ) . expression . kind === SyntaxKind . SuperKeyword ) {
93
+ hasSuperElementAccess = true ;
94
+ }
95
+ return visitEachChild ( node , visitor , context ) ;
96
+
80
97
default :
81
98
return visitEachChild ( node , visitor , context ) ;
82
99
}
@@ -398,6 +415,11 @@ namespace ts {
398
415
recordDeclarationName ( parameter , enclosingFunctionParameterNames ) ;
399
416
}
400
417
418
+ const savedCapturedSuperProperties = capturedSuperProperties ;
419
+ const savedHasSuperElementAccess = hasSuperElementAccess ;
420
+ capturedSuperProperties = createUnderscoreEscapedMap < true > ( ) ;
421
+ hasSuperElementAccess = false ;
422
+
401
423
let result : ConciseBody ;
402
424
if ( ! isArrowFunction ) {
403
425
const statements : Statement [ ] = [ ] ;
@@ -415,18 +437,29 @@ namespace ts {
415
437
416
438
addStatementsAfterPrologue ( statements , endLexicalEnvironment ( ) ) ;
417
439
440
+ // Minor optimization, emit `_super` helper to capture `super` access in an arrow.
441
+ // This step isn't needed if we eventually transform this to ES5.
442
+ const emitSuperHelpers = languageVersion >= ScriptTarget . ES2015 && resolver . getNodeCheckFlags ( node ) & ( NodeCheckFlags . AsyncMethodWithSuperBinding | NodeCheckFlags . AsyncMethodWithSuper ) ;
443
+
444
+ if ( emitSuperHelpers ) {
445
+ enableSubstitutionForAsyncMethodsWithSuper ( ) ;
446
+ // For each super property access (`super.x`), emit a `_super_x` accessor arrow function.
447
+ capturedSuperProperties . forEach ( ( _ , key ) => {
448
+ const variableStatement = createSuperAccessVariableStatement ( resolver , node , key ) ;
449
+ substitutedSuperAccessors [ getNodeId ( variableStatement ) ] = true ;
450
+ addStatementsAfterPrologue ( statements , [ variableStatement ] ) ;
451
+ } ) ;
452
+ }
453
+
418
454
const block = createBlock ( statements , /*multiLine*/ true ) ;
419
455
setTextRange ( block , node . body ) ;
420
456
421
- // Minor optimization, emit `_super` helper to capture `super` access in an arrow.
422
- // This step isn't needed if we eventually transform this to ES5.
423
- if ( languageVersion >= ScriptTarget . ES2015 ) {
457
+ if ( emitSuperHelpers && hasSuperElementAccess ) {
458
+ // Emit helpers for super element access expressions (`super[x]`).
424
459
if ( resolver . getNodeCheckFlags ( node ) & NodeCheckFlags . AsyncMethodWithSuperBinding ) {
425
- enableSubstitutionForAsyncMethodsWithSuper ( ) ;
426
460
addEmitHelper ( block , advancedAsyncSuperHelper ) ;
427
461
}
428
462
else if ( resolver . getNodeCheckFlags ( node ) & NodeCheckFlags . AsyncMethodWithSuper ) {
429
- enableSubstitutionForAsyncMethodsWithSuper ( ) ;
430
463
addEmitHelper ( block , asyncSuperHelper ) ;
431
464
}
432
465
}
@@ -452,6 +485,8 @@ namespace ts {
452
485
}
453
486
454
487
enclosingFunctionParameterNames = savedEnclosingFunctionParameterNames ;
488
+ capturedSuperProperties = savedCapturedSuperProperties ;
489
+ hasSuperElementAccess = savedHasSuperElementAccess ;
455
490
return result ;
456
491
}
457
492
@@ -493,6 +528,8 @@ namespace ts {
493
528
context . enableEmitNotification ( SyntaxKind . GetAccessor ) ;
494
529
context . enableEmitNotification ( SyntaxKind . SetAccessor ) ;
495
530
context . enableEmitNotification ( SyntaxKind . Constructor ) ;
531
+ // We need to be notified when entering the generated accessor arrow functions.
532
+ context . enableEmitNotification ( SyntaxKind . VariableStatement ) ;
496
533
}
497
534
}
498
535
@@ -516,6 +553,14 @@ namespace ts {
516
553
return ;
517
554
}
518
555
}
556
+ // Disable substitution in the generated super accessor itself.
557
+ else if ( enabledSubstitutions && substitutedSuperAccessors [ getNodeId ( node ) ] ) {
558
+ const savedEnclosingSuperContainerFlags = enclosingSuperContainerFlags ;
559
+ enclosingSuperContainerFlags = 0 as NodeCheckFlags ;
560
+ previousOnEmitNode ( hint , node , emitCallback ) ;
561
+ enclosingSuperContainerFlags = savedEnclosingSuperContainerFlags ;
562
+ return ;
563
+ }
519
564
previousOnEmitNode ( hint , node , emitCallback ) ;
520
565
}
521
566
@@ -548,17 +593,33 @@ namespace ts {
548
593
549
594
function substitutePropertyAccessExpression ( node : PropertyAccessExpression ) {
550
595
if ( node . expression . kind === SyntaxKind . SuperKeyword ) {
551
- return createSuperAccessInAsyncMethod (
552
- createLiteral ( idText ( node . name ) ) ,
553
- node
554
- ) ;
596
+ if ( enclosingSuperContainerFlags & NodeCheckFlags . AsyncMethodWithSuperBinding ) {
597
+ return setTextRange (
598
+ createPropertyAccess (
599
+ createCall (
600
+ createFileLevelUniqueName ( "_super_" + idText ( node . name ) ) ,
601
+ /* typeArguments */ undefined ,
602
+ /* argumentsArray */ undefined ) ,
603
+ "value" ) ,
604
+ node
605
+ ) ;
606
+ }
607
+ else {
608
+ return setTextRange (
609
+ createCall (
610
+ createFileLevelUniqueName ( "_super_" + idText ( node . name ) ) ,
611
+ /* typeArguments */ undefined ,
612
+ /* argumentsArray */ undefined ) ,
613
+ node
614
+ ) ;
615
+ }
555
616
}
556
617
return node ;
557
618
}
558
619
559
620
function substituteElementAccessExpression ( node : ElementAccessExpression ) {
560
621
if ( node . expression . kind === SyntaxKind . SuperKeyword ) {
561
- return createSuperAccessInAsyncMethod (
622
+ return createSuperElementAccessInAsyncMethod (
562
623
node . argumentExpression ,
563
624
node
564
625
) ;
@@ -593,7 +654,7 @@ namespace ts {
593
654
|| kind === SyntaxKind . SetAccessor ;
594
655
}
595
656
596
- function createSuperAccessInAsyncMethod ( argumentExpression : Expression , location : TextRange ) : LeftHandSideExpression {
657
+ function createSuperElementAccessInAsyncMethod ( argumentExpression : Expression , location : TextRange ) : LeftHandSideExpression {
597
658
if ( enclosingSuperContainerFlags & NodeCheckFlags . AsyncMethodWithSuperBinding ) {
598
659
return setTextRange (
599
660
createPropertyAccess (
@@ -620,6 +681,67 @@ namespace ts {
620
681
}
621
682
}
622
683
684
+ /** Creates a variable statement with an accessor function for the given super property name. */
685
+ export function createSuperAccessVariableStatement ( resolver : EmitResolver , node : FunctionLikeDeclaration , name : __String ) {
686
+ let accessor : Expression ;
687
+ if ( resolver . getNodeCheckFlags ( node ) & NodeCheckFlags . AsyncMethodWithSuperBinding ) {
688
+ // For async methods assigning into a super property, emit an object literal containing a "value" getter and setter.
689
+ accessor = createObjectLiteral ( [
690
+ createGetAccessor (
691
+ /* decorators */ undefined ,
692
+ /* modifiers */ undefined ,
693
+ "value" ,
694
+ /* parameters */ [ ] ,
695
+ /* type */ undefined ,
696
+ createBlock ( [
697
+ createReturn ( createPropertyAccess (
698
+ createSuper ( ) ,
699
+ unescapeLeadingUnderscores ( name ) ) ) ] ) ) ,
700
+ createSetAccessor (
701
+ /* decorators */ undefined ,
702
+ /* modifiers */ undefined ,
703
+ "value" ,
704
+ /* parameters */ [
705
+ createParameter (
706
+ /* decorators */ undefined ,
707
+ /* modifiers */ undefined ,
708
+ /* dotDotDotToken */ undefined ,
709
+ "v" ) ] ,
710
+ createBlock ( [
711
+ createExpressionStatement (
712
+ createAssignment (
713
+ createPropertyAccess (
714
+ createSuper ( ) ,
715
+ unescapeLeadingUnderscores ( name ) ) ,
716
+ createIdentifier ( "v" ) ) ) ] ) ) ,
717
+ ] ) ;
718
+ }
719
+ else if ( resolver . getNodeCheckFlags ( node ) & NodeCheckFlags . AsyncMethodWithSuper ) {
720
+ accessor = createArrowFunction (
721
+ /* modifiers */ undefined ,
722
+ /* typeParameters */ undefined ,
723
+ [ ] ,
724
+ /* type */ undefined ,
725
+ /* equalsGreaterThanToken */ undefined ,
726
+ createPropertyAccess (
727
+ createSuper ( ) ,
728
+ unescapeLeadingUnderscores ( name ) ) ) ;
729
+ }
730
+ else {
731
+ return Debug . fail ( `unexpected node check flags ${ resolver . getNodeCheckFlags ( node ) } ` ) ;
732
+ }
733
+ return createVariableStatement (
734
+ /* modifiers */ undefined ,
735
+ createVariableDeclarationList (
736
+ [
737
+ createVariableDeclaration (
738
+ createFileLevelUniqueName ( "_super_" + name ) ,
739
+ /* type */ undefined ,
740
+ accessor )
741
+ ] ,
742
+ NodeFlags . Const ) ) ;
743
+ }
744
+
623
745
const awaiterHelper : EmitHelper = {
624
746
name : "typescript:awaiter" ,
625
747
scoped : false ,
0 commit comments