Skip to content

Commit 2db8d80

Browse files
authored
Merge pull request #12783 from Microsoft/es6-new-target
Add support for 'new.target' meta-property
2 parents e128b94 + 4098058 commit 2db8d80

22 files changed

+1148
-39
lines changed

src/compiler/binder.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3133,6 +3133,7 @@ namespace ts {
31333133
case SyntaxKind.TaggedTemplateExpression:
31343134
case SyntaxKind.ShorthandPropertyAssignment:
31353135
case SyntaxKind.StaticKeyword:
3136+
case SyntaxKind.MetaProperty:
31363137
// These nodes are ES6 syntax.
31373138
transformFlags |= TransformFlags.AssertES2015;
31383139
break;

src/compiler/checker.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ namespace ts {
241241
const visitedFlowNodes: FlowNode[] = [];
242242
const visitedFlowTypes: FlowType[] = [];
243243
const potentialThisCollisions: Node[] = [];
244+
const potentialNewTargetCollisions: Node[] = [];
244245
const awaitedTypeStack: number[] = [];
245246

246247
const diagnostics = createDiagnosticCollection();
@@ -10331,6 +10332,7 @@ namespace ts {
1033110332

1033210333
checkCollisionWithCapturedSuperVariable(node, node);
1033310334
checkCollisionWithCapturedThisVariable(node, node);
10335+
checkCollisionWithCapturedNewTargetVariable(node, node);
1033410336
checkNestedBlockScopedBinding(node, symbol);
1033510337

1033610338
const type = getTypeOfSymbol(localOrExportSymbol);
@@ -13857,6 +13859,24 @@ namespace ts {
1385713859
return getNonNullableType(checkExpression(node.expression));
1385813860
}
1385913861

13862+
function checkMetaProperty(node: MetaProperty) {
13863+
checkGrammarMetaProperty(node);
13864+
Debug.assert(node.keywordToken === SyntaxKind.NewKeyword && node.name.text === "target", "Unrecognized meta-property.");
13865+
const container = getNewTargetContainer(node);
13866+
if (!container) {
13867+
error(node, Diagnostics.Meta_property_0_is_only_allowed_in_the_body_of_a_function_declaration_function_expression_or_constructor, "new.target");
13868+
return unknownType;
13869+
}
13870+
else if (container.kind === SyntaxKind.Constructor) {
13871+
const symbol = getSymbolOfNode(container.parent);
13872+
return getTypeOfSymbol(symbol);
13873+
}
13874+
else {
13875+
const symbol = getSymbolOfNode(container);
13876+
return getTypeOfSymbol(symbol);
13877+
}
13878+
}
13879+
1386013880
function getTypeOfParameter(symbol: Symbol) {
1386113881
const type = getTypeOfSymbol(symbol);
1386213882
if (strictNullChecks) {
@@ -14265,6 +14285,7 @@ namespace ts {
1426514285
if (produceDiagnostics && node.kind !== SyntaxKind.MethodDeclaration) {
1426614286
checkCollisionWithCapturedSuperVariable(node, (<FunctionExpression>node).name);
1426714287
checkCollisionWithCapturedThisVariable(node, (<FunctionExpression>node).name);
14288+
checkCollisionWithCapturedNewTargetVariable(node, (<FunctionExpression>node).name);
1426814289
}
1426914290

1427014291
return type;
@@ -15299,6 +15320,8 @@ namespace ts {
1529915320
return checkAssertion(<AssertionExpression>node);
1530015321
case SyntaxKind.NonNullExpression:
1530115322
return checkNonNullAssertion(<NonNullExpression>node);
15323+
case SyntaxKind.MetaProperty:
15324+
return checkMetaProperty(<MetaProperty>node);
1530215325
case SyntaxKind.DeleteExpression:
1530315326
return checkDeleteExpression(<DeleteExpression>node);
1530415327
case SyntaxKind.VoidExpression:
@@ -16706,6 +16729,7 @@ namespace ts {
1670616729

1670716730
checkCollisionWithCapturedSuperVariable(node, node.name);
1670816731
checkCollisionWithCapturedThisVariable(node, node.name);
16732+
checkCollisionWithCapturedNewTargetVariable(node, node.name);
1670916733
checkCollisionWithRequireExportsInGeneratedCode(node, node.name);
1671016734
checkCollisionWithGlobalPromiseInGeneratedCode(node, node.name);
1671116735
}
@@ -17000,6 +17024,12 @@ namespace ts {
1700017024
}
1700117025
}
1700217026

17027+
function checkCollisionWithCapturedNewTargetVariable(node: Node, name: Identifier): void {
17028+
if (needCollisionCheckForIdentifier(node, name, "_newTarget")) {
17029+
potentialNewTargetCollisions.push(node);
17030+
}
17031+
}
17032+
1700317033
// this function will run after checking the source file so 'CaptureThis' is correct for all nodes
1700417034
function checkIfThisIsCapturedInEnclosingScope(node: Node): void {
1700517035
let current = node;
@@ -17018,6 +17048,23 @@ namespace ts {
1701817048
}
1701917049
}
1702017050

17051+
function checkIfNewTargetIsCapturedInEnclosingScope(node: Node): void {
17052+
let current = node;
17053+
while (current) {
17054+
if (getNodeCheckFlags(current) & NodeCheckFlags.CaptureNewTarget) {
17055+
const isDeclaration = node.kind !== SyntaxKind.Identifier;
17056+
if (isDeclaration) {
17057+
error((<Declaration>node).name, Diagnostics.Duplicate_identifier_newTarget_Compiler_uses_variable_declaration_newTarget_to_capture_new_target_meta_property_reference);
17058+
}
17059+
else {
17060+
error(node, Diagnostics.Expression_resolves_to_variable_declaration_newTarget_that_compiler_uses_to_capture_new_target_meta_property_reference);
17061+
}
17062+
return;
17063+
}
17064+
current = current.parent;
17065+
}
17066+
}
17067+
1702117068
function checkCollisionWithCapturedSuperVariable(node: Node, name: Identifier) {
1702217069
if (!needCollisionCheckForIdentifier(node, name, "_super")) {
1702317070
return;
@@ -17314,6 +17361,7 @@ namespace ts {
1731417361
}
1731517362
checkCollisionWithCapturedSuperVariable(node, <Identifier>node.name);
1731617363
checkCollisionWithCapturedThisVariable(node, <Identifier>node.name);
17364+
checkCollisionWithCapturedNewTargetVariable(node, <Identifier>node.name);
1731717365
checkCollisionWithRequireExportsInGeneratedCode(node, <Identifier>node.name);
1731817366
checkCollisionWithGlobalPromiseInGeneratedCode(node, <Identifier>node.name);
1731917367
}
@@ -18150,6 +18198,7 @@ namespace ts {
1815018198
if (node.name) {
1815118199
checkTypeNameIsReserved(node.name, Diagnostics.Class_name_cannot_be_0);
1815218200
checkCollisionWithCapturedThisVariable(node, node.name);
18201+
checkCollisionWithCapturedNewTargetVariable(node, node.name);
1815318202
checkCollisionWithRequireExportsInGeneratedCode(node, node.name);
1815418203
checkCollisionWithGlobalPromiseInGeneratedCode(node, node.name);
1815518204
}
@@ -18685,6 +18734,7 @@ namespace ts {
1868518734

1868618735
checkTypeNameIsReserved(node.name, Diagnostics.Enum_name_cannot_be_0);
1868718736
checkCollisionWithCapturedThisVariable(node, node.name);
18737+
checkCollisionWithCapturedNewTargetVariable(node, node.name);
1868818738
checkCollisionWithRequireExportsInGeneratedCode(node, node.name);
1868918739
checkCollisionWithGlobalPromiseInGeneratedCode(node, node.name);
1869018740
checkExportsOnMergedDeclarations(node);
@@ -19396,6 +19446,7 @@ namespace ts {
1939619446
checkGrammarSourceFile(node);
1939719447

1939819448
potentialThisCollisions.length = 0;
19449+
potentialNewTargetCollisions.length = 0;
1939919450

1940019451
deferredNodes = [];
1940119452
deferredUnusedIdentifierNodes = produceDiagnostics && noUnusedIdentifiers ? [] : undefined;
@@ -19424,6 +19475,11 @@ namespace ts {
1942419475
potentialThisCollisions.length = 0;
1942519476
}
1942619477

19478+
if (potentialNewTargetCollisions.length) {
19479+
forEach(potentialNewTargetCollisions, checkIfNewTargetIsCapturedInEnclosingScope)
19480+
potentialNewTargetCollisions.length = 0;
19481+
}
19482+
1942719483
links.flags |= NodeCheckFlags.TypeChecked;
1942819484
}
1942919485
}
@@ -21754,6 +21810,14 @@ namespace ts {
2175421810
}
2175521811
}
2175621812

21813+
function checkGrammarMetaProperty(node: MetaProperty) {
21814+
if (node.keywordToken === SyntaxKind.NewKeyword) {
21815+
if (node.name.text !== "target") {
21816+
return grammarErrorOnNode(node.name, Diagnostics._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_0, node.name.text, tokenToString(node.keywordToken), "target");
21817+
}
21818+
}
21819+
}
21820+
2175721821
function hasParseDiagnostics(sourceFile: SourceFile): boolean {
2175821822
return sourceFile.parseDiagnostics.length > 0;
2175921823
}

src/compiler/diagnosticMessages.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1775,6 +1775,14 @@
17751775
"category": "Error",
17761776
"code": 2542
17771777
},
1778+
"Duplicate identifier '_newTarget'. Compiler uses variable declaration '_newTarget' to capture 'new.target' meta-property reference.": {
1779+
"category": "Error",
1780+
"code": 2543
1781+
},
1782+
"Expression resolves to variable declaration '_newTarget' that compiler uses to capture 'new.target' meta-property reference.": {
1783+
"category": "Error",
1784+
"code": 2544
1785+
},
17781786
"JSX element attributes type '{0}' may not be a union type.": {
17791787
"category": "Error",
17801788
"code": 2600
@@ -3197,6 +3205,14 @@
31973205
"category": "Error",
31983206
"code": 17011
31993207
},
3208+
"'{0}' is not a valid meta-property for keyword '{1}'. Did you mean '{0}'?": {
3209+
"category": "Error",
3210+
"code": 17012
3211+
},
3212+
"Meta-property '{0}' is only allowed in the body of a function declaration, function expression, or constructor.": {
3213+
"category": "Error",
3214+
"code": 17013
3215+
},
32003216

32013217
"Circularity detected while resolving configuration: {0}": {
32023218
"category": "Error",

src/compiler/emitter.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,8 @@ namespace ts {
660660
return emitAsExpression(<AsExpression>node);
661661
case SyntaxKind.NonNullExpression:
662662
return emitNonNullExpression(<NonNullExpression>node);
663+
case SyntaxKind.MetaProperty:
664+
return emitMetaProperty(<MetaProperty>node);
663665

664666
// JSX
665667
case SyntaxKind.JsxElement:
@@ -1247,6 +1249,12 @@ namespace ts {
12471249
write("!");
12481250
}
12491251

1252+
function emitMetaProperty(node: MetaProperty) {
1253+
writeToken(node.keywordToken, node.pos);
1254+
write(".");
1255+
emit(node.name);
1256+
}
1257+
12501258
//
12511259
// Misc
12521260
//
@@ -2584,6 +2592,13 @@ namespace ts {
25842592
return makeUniqueName("class");
25852593
}
25862594

2595+
function generateNameForMethodOrAccessor(node: MethodDeclaration | AccessorDeclaration) {
2596+
if (isIdentifier(node.name)) {
2597+
return generateNameForNodeCached(node.name);
2598+
}
2599+
return makeTempVariableName(TempFlags.Auto);
2600+
}
2601+
25872602
/**
25882603
* Generates a unique name from a node.
25892604
*
@@ -2605,6 +2620,10 @@ namespace ts {
26052620
return generateNameForExportDefault();
26062621
case SyntaxKind.ClassExpression:
26072622
return generateNameForClassExpression();
2623+
case SyntaxKind.MethodDeclaration:
2624+
case SyntaxKind.GetAccessor:
2625+
case SyntaxKind.SetAccessor:
2626+
return generateNameForMethodOrAccessor(<MethodDeclaration | AccessorDeclaration>node);
26082627
default:
26092628
return makeTempVariableName(TempFlags.Auto);
26102629
}
@@ -2655,6 +2674,11 @@ namespace ts {
26552674
return node;
26562675
}
26572676

2677+
function generateNameForNodeCached(node: Node) {
2678+
const nodeId = getNodeId(node);
2679+
return nodeIdToGeneratedName[nodeId] || (nodeIdToGeneratedName[nodeId] = unescapeIdentifier(generateNameForNode(node)));
2680+
}
2681+
26582682
/**
26592683
* Gets the generated identifier text from a generated identifier.
26602684
*
@@ -2665,8 +2689,7 @@ namespace ts {
26652689
// Generated names generate unique names based on their original node
26662690
// and are cached based on that node's id
26672691
const node = getNodeForGeneratedName(name);
2668-
const nodeId = getNodeId(node);
2669-
return nodeIdToGeneratedName[nodeId] || (nodeIdToGeneratedName[nodeId] = unescapeIdentifier(generateNameForNode(node)));
2692+
return generateNameForNodeCached(node);
26702693
}
26712694
else {
26722695
// Auto, Loop, and Unique names are cached based on their unique

src/compiler/parser.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,8 @@ namespace ts {
198198
visitNode(cbNode, (<AsExpression>node).type);
199199
case SyntaxKind.NonNullExpression:
200200
return visitNode(cbNode, (<NonNullExpression>node).expression);
201+
case SyntaxKind.MetaProperty:
202+
return visitNode(cbNode, (<MetaProperty>node).name);
201203
case SyntaxKind.ConditionalExpression:
202204
return visitNode(cbNode, (<ConditionalExpression>node).condition) ||
203205
visitNode(cbNode, (<ConditionalExpression>node).questionToken) ||
@@ -4331,15 +4333,22 @@ namespace ts {
43314333
return isIdentifier() ? parseIdentifier() : undefined;
43324334
}
43334335

4334-
function parseNewExpression(): NewExpression {
4335-
const node = <NewExpression>createNode(SyntaxKind.NewExpression);
4336+
function parseNewExpression(): NewExpression | MetaProperty {
4337+
const fullStart = scanner.getStartPos();
43364338
parseExpected(SyntaxKind.NewKeyword);
4339+
if (parseOptional(SyntaxKind.DotToken)) {
4340+
const node = <MetaProperty>createNode(SyntaxKind.MetaProperty, fullStart);
4341+
node.keywordToken = SyntaxKind.NewKeyword;
4342+
node.name = parseIdentifierName();
4343+
return finishNode(node);
4344+
}
4345+
4346+
const node = <NewExpression>createNode(SyntaxKind.NewExpression, fullStart);
43374347
node.expression = parseMemberExpressionOrHigher();
43384348
node.typeArguments = tryParse(parseTypeArgumentsInExpression);
43394349
if (node.typeArguments || token() === SyntaxKind.OpenParenToken) {
43404350
node.arguments = parseArgumentList();
43414351
}
4342-
43434352
return finishNode(node);
43444353
}
43454354

0 commit comments

Comments
 (0)