Skip to content

Commit 62aeead

Browse files
committed
Merge branch 'master' into fixUnionOfTupleIndexing
# Conflicts: # src/compiler/checker.ts
2 parents 48f2dd9 + 85a3475 commit 62aeead

File tree

57 files changed

+1829
-439
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+1829
-439
lines changed

CODE_OF_CONDUCT.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [[email protected]](mailto:[email protected]) with any additional questions or comments.

src/compiler/binder.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3445,7 +3445,9 @@ namespace ts {
34453445
// ES6 syntax, and requires a lexical `this` binding.
34463446
if (transformFlags & TransformFlags.Super) {
34473447
transformFlags ^= TransformFlags.Super;
3448-
transformFlags |= TransformFlags.ContainsSuper;
3448+
// super inside of an async function requires hoisting the super access (ES2017).
3449+
// same for super inside of an async generator, which is ESNext.
3450+
transformFlags |= TransformFlags.ContainsSuper | TransformFlags.ContainsES2017 | TransformFlags.ContainsESNext;
34493451
}
34503452

34513453
node.transformFlags = transformFlags | TransformFlags.HasComputedFlags;
@@ -3461,7 +3463,9 @@ namespace ts {
34613463
// ES6 syntax, and requires a lexical `this` binding.
34623464
if (expressionFlags & TransformFlags.Super) {
34633465
transformFlags &= ~TransformFlags.Super;
3464-
transformFlags |= TransformFlags.ContainsSuper;
3466+
// super inside of an async function requires hoisting the super access (ES2017).
3467+
// same for super inside of an async generator, which is ESNext.
3468+
transformFlags |= TransformFlags.ContainsSuper | TransformFlags.ContainsES2017 | TransformFlags.ContainsESNext;
34653469
}
34663470

34673471
node.transformFlags = transformFlags | TransformFlags.HasComputedFlags;

src/compiler/checker.ts

Lines changed: 129 additions & 89 deletions
Large diffs are not rendered by default.

src/compiler/parser.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6441,13 +6441,6 @@ namespace ts {
64416441
indent += asterisk.length;
64426442
}
64436443
break;
6444-
case SyntaxKind.Identifier:
6445-
// Anything else is doc comment text. We just save it. Because it
6446-
// wasn't a tag, we can no longer parse a tag on this line until we hit the next
6447-
// line break.
6448-
pushComment(scanner.getTokenText());
6449-
state = JSDocState.SavingComments;
6450-
break;
64516444
case SyntaxKind.WhitespaceTrivia:
64526445
// only collect whitespace if we're already saving comments or have just crossed the comment indent margin
64536446
const whitespace = scanner.getTokenText();
@@ -6462,7 +6455,9 @@ namespace ts {
64626455
case SyntaxKind.EndOfFileToken:
64636456
break loop;
64646457
default:
6465-
// anything other than whitespace or asterisk at the beginning of the line starts the comment text
6458+
// Anything else is doc comment text. We just save it. Because it
6459+
// wasn't a tag, we can no longer parse a tag on this line until we hit the next
6460+
// line break.
64666461
state = JSDocState.SavingComments;
64676462
pushComment(scanner.getTokenText());
64686463
break;

src/compiler/transformers/es2017.ts

Lines changed: 144 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,15 @@ namespace ts {
3232

3333
let enclosingFunctionParameterNames: UnderscoreEscapedMap<true>;
3434

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+
3544
// Save the previous transformation hooks.
3645
const previousOnEmitNode = context.onEmitNode;
3746
const previousOnSubstituteNode = context.onSubstituteNode;
@@ -56,7 +65,6 @@ namespace ts {
5665
if ((node.transformFlags & TransformFlags.ContainsES2017) === 0) {
5766
return node;
5867
}
59-
6068
switch (node.kind) {
6169
case SyntaxKind.AsyncKeyword:
6270
// ES2017 async modifier should be elided for targets < ES2017
@@ -77,6 +85,18 @@ namespace ts {
7785
case SyntaxKind.ArrowFunction:
7886
return visitArrowFunction(<ArrowFunction>node);
7987

88+
case SyntaxKind.PropertyAccessExpression:
89+
if (capturedSuperProperties && isPropertyAccessExpression(node) && node.expression.kind === SyntaxKind.SuperKeyword) {
90+
capturedSuperProperties.set(node.name.escapedText, true);
91+
}
92+
return visitEachChild(node, visitor, context);
93+
94+
case SyntaxKind.ElementAccessExpression:
95+
if (capturedSuperProperties && (<ElementAccessExpression>node).expression.kind === SyntaxKind.SuperKeyword) {
96+
hasSuperElementAccess = true;
97+
}
98+
return visitEachChild(node, visitor, context);
99+
80100
default:
81101
return visitEachChild(node, visitor, context);
82102
}
@@ -398,6 +418,11 @@ namespace ts {
398418
recordDeclarationName(parameter, enclosingFunctionParameterNames);
399419
}
400420

421+
const savedCapturedSuperProperties = capturedSuperProperties;
422+
const savedHasSuperElementAccess = hasSuperElementAccess;
423+
capturedSuperProperties = createUnderscoreEscapedMap<true>();
424+
hasSuperElementAccess = false;
425+
401426
let result: ConciseBody;
402427
if (!isArrowFunction) {
403428
const statements: Statement[] = [];
@@ -415,18 +440,26 @@ namespace ts {
415440

416441
addStatementsAfterPrologue(statements, endLexicalEnvironment());
417442

443+
// Minor optimization, emit `_super` helper to capture `super` access in an arrow.
444+
// This step isn't needed if we eventually transform this to ES5.
445+
const emitSuperHelpers = languageVersion >= ScriptTarget.ES2015 && resolver.getNodeCheckFlags(node) & (NodeCheckFlags.AsyncMethodWithSuperBinding | NodeCheckFlags.AsyncMethodWithSuper);
446+
447+
if (emitSuperHelpers) {
448+
enableSubstitutionForAsyncMethodsWithSuper();
449+
const variableStatement = createSuperAccessVariableStatement(resolver, node, capturedSuperProperties);
450+
substitutedSuperAccessors[getNodeId(variableStatement)] = true;
451+
addStatementsAfterPrologue(statements, [variableStatement]);
452+
}
453+
418454
const block = createBlock(statements, /*multiLine*/ true);
419455
setTextRange(block, node.body);
420456

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]`).
424459
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.AsyncMethodWithSuperBinding) {
425-
enableSubstitutionForAsyncMethodsWithSuper();
426460
addEmitHelper(block, advancedAsyncSuperHelper);
427461
}
428462
else if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.AsyncMethodWithSuper) {
429-
enableSubstitutionForAsyncMethodsWithSuper();
430463
addEmitHelper(block, asyncSuperHelper);
431464
}
432465
}
@@ -452,6 +485,8 @@ namespace ts {
452485
}
453486

454487
enclosingFunctionParameterNames = savedEnclosingFunctionParameterNames;
488+
capturedSuperProperties = savedCapturedSuperProperties;
489+
hasSuperElementAccess = savedHasSuperElementAccess;
455490
return result;
456491
}
457492

@@ -493,6 +528,8 @@ namespace ts {
493528
context.enableEmitNotification(SyntaxKind.GetAccessor);
494529
context.enableEmitNotification(SyntaxKind.SetAccessor);
495530
context.enableEmitNotification(SyntaxKind.Constructor);
531+
// We need to be notified when entering the generated accessor arrow functions.
532+
context.enableEmitNotification(SyntaxKind.VariableStatement);
496533
}
497534
}
498535

@@ -516,6 +553,14 @@ namespace ts {
516553
return;
517554
}
518555
}
556+
// Disable substitution in the generated super accessor itself.
557+
else if (enabledSubstitutions && substitutedSuperAccessors[getNodeId(node)]) {
558+
const savedEnclosingSuperContainerFlags = enclosingSuperContainerFlags;
559+
enclosingSuperContainerFlags = 0;
560+
previousOnEmitNode(hint, node, emitCallback);
561+
enclosingSuperContainerFlags = savedEnclosingSuperContainerFlags;
562+
return;
563+
}
519564
previousOnEmitNode(hint, node, emitCallback);
520565
}
521566

@@ -548,8 +593,10 @@ namespace ts {
548593

549594
function substitutePropertyAccessExpression(node: PropertyAccessExpression) {
550595
if (node.expression.kind === SyntaxKind.SuperKeyword) {
551-
return createSuperAccessInAsyncMethod(
552-
createLiteral(idText(node.name)),
596+
return setTextRange(
597+
createPropertyAccess(
598+
createFileLevelUniqueName("_super"),
599+
node.name),
553600
node
554601
);
555602
}
@@ -558,7 +605,7 @@ namespace ts {
558605

559606
function substituteElementAccessExpression(node: ElementAccessExpression) {
560607
if (node.expression.kind === SyntaxKind.SuperKeyword) {
561-
return createSuperAccessInAsyncMethod(
608+
return createSuperElementAccessInAsyncMethod(
562609
node.argumentExpression,
563610
node
564611
);
@@ -593,12 +640,12 @@ namespace ts {
593640
|| kind === SyntaxKind.SetAccessor;
594641
}
595642

596-
function createSuperAccessInAsyncMethod(argumentExpression: Expression, location: TextRange): LeftHandSideExpression {
643+
function createSuperElementAccessInAsyncMethod(argumentExpression: Expression, location: TextRange): LeftHandSideExpression {
597644
if (enclosingSuperContainerFlags & NodeCheckFlags.AsyncMethodWithSuperBinding) {
598645
return setTextRange(
599646
createPropertyAccess(
600647
createCall(
601-
createFileLevelUniqueName("_super"),
648+
createFileLevelUniqueName("_superIndex"),
602649
/*typeArguments*/ undefined,
603650
[argumentExpression]
604651
),
@@ -610,7 +657,7 @@ namespace ts {
610657
else {
611658
return setTextRange(
612659
createCall(
613-
createFileLevelUniqueName("_super"),
660+
createFileLevelUniqueName("_superIndex"),
614661
/*typeArguments*/ undefined,
615662
[argumentExpression]
616663
),
@@ -620,6 +667,89 @@ namespace ts {
620667
}
621668
}
622669

670+
/** Creates a variable named `_super` with accessor properties for the given property names. */
671+
export function createSuperAccessVariableStatement(resolver: EmitResolver, node: FunctionLikeDeclaration, names: UnderscoreEscapedMap<true>) {
672+
// Create a variable declaration with a getter/setter (if binding) definition for each name:
673+
// const _super = Object.create(null, { x: { get: () => super.x, set: (v) => super.x = v }, ... });
674+
const hasBinding = (resolver.getNodeCheckFlags(node) & NodeCheckFlags.AsyncMethodWithSuperBinding) !== 0;
675+
const accessors: PropertyAssignment[] = [];
676+
names.forEach((_, key) => {
677+
const name = unescapeLeadingUnderscores(key);
678+
const getterAndSetter: PropertyAssignment[] = [];
679+
getterAndSetter.push(createPropertyAssignment(
680+
"get",
681+
createArrowFunction(
682+
/* modifiers */ undefined,
683+
/* typeParameters */ undefined,
684+
/* parameters */ [],
685+
/* type */ undefined,
686+
/* equalsGreaterThanToken */ undefined,
687+
createPropertyAccess(
688+
createSuper(),
689+
name
690+
)
691+
)
692+
));
693+
if (hasBinding) {
694+
getterAndSetter.push(
695+
createPropertyAssignment(
696+
"set",
697+
createArrowFunction(
698+
/* modifiers */ undefined,
699+
/* typeParameters */ undefined,
700+
/* parameters */ [
701+
createParameter(
702+
/* decorators */ undefined,
703+
/* modifiers */ undefined,
704+
/* dotDotDotToken */ undefined,
705+
"v",
706+
/* questionToken */ undefined,
707+
/* type */ undefined,
708+
/* initializer */ undefined
709+
)
710+
],
711+
/* type */ undefined,
712+
/* equalsGreaterThanToken */ undefined,
713+
createAssignment(
714+
createPropertyAccess(
715+
createSuper(),
716+
name),
717+
createIdentifier("v")
718+
)
719+
)
720+
)
721+
);
722+
}
723+
accessors.push(
724+
createPropertyAssignment(
725+
name,
726+
createObjectLiteral(getterAndSetter),
727+
)
728+
);
729+
});
730+
return createVariableStatement(
731+
/* modifiers */ undefined,
732+
createVariableDeclarationList(
733+
[
734+
createVariableDeclaration(
735+
createFileLevelUniqueName("_super"),
736+
/* type */ undefined,
737+
createCall(
738+
createPropertyAccess(
739+
createIdentifier("Object"),
740+
"create"
741+
),
742+
/* typeArguments */ undefined,
743+
[
744+
createNull(),
745+
createObjectLiteral(accessors, /* multiline */ true)
746+
]
747+
)
748+
)
749+
],
750+
NodeFlags.Const));
751+
}
752+
623753
const awaiterHelper: EmitHelper = {
624754
name: "typescript:awaiter",
625755
scoped: false,
@@ -667,14 +797,14 @@ namespace ts {
667797
name: "typescript:async-super",
668798
scoped: true,
669799
text: helperString`
670-
const ${"_super"} = name => super[name];`
800+
const ${"_superIndex"} = name => super[name];`
671801
};
672802

673803
export const advancedAsyncSuperHelper: EmitHelper = {
674804
name: "typescript:advanced-async-super",
675805
scoped: true,
676806
text: helperString`
677-
const ${"_super"} = (function (geti, seti) {
807+
const ${"_superIndex"} = (function (geti, seti) {
678808
const cache = Object.create(null);
679809
return name => cache[name] || (cache[name] = { get value() { return geti(name); }, set value(v) { seti(name, v); } });
680810
})(name => super[name], (name, value) => super[name] = value);`

0 commit comments

Comments
 (0)