Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3133,6 +3133,7 @@ namespace ts {
case SyntaxKind.TaggedTemplateExpression:
case SyntaxKind.ShorthandPropertyAssignment:
case SyntaxKind.StaticKeyword:
case SyntaxKind.MetaProperty:
// These nodes are ES6 syntax.
transformFlags |= TransformFlags.AssertES2015;
break;
Expand Down
64 changes: 64 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ namespace ts {
const visitedFlowNodes: FlowNode[] = [];
const visitedFlowTypes: FlowType[] = [];
const potentialThisCollisions: Node[] = [];
const potentialNewTargetCollisions: Node[] = [];
const awaitedTypeStack: number[] = [];

const diagnostics = createDiagnosticCollection();
Expand Down Expand Up @@ -10196,6 +10197,7 @@ namespace ts {

checkCollisionWithCapturedSuperVariable(node, node);
checkCollisionWithCapturedThisVariable(node, node);
checkCollisionWithCapturedNewTargetVariable(node, node);
checkNestedBlockScopedBinding(node, symbol);

const type = getTypeOfSymbol(localOrExportSymbol);
Expand Down Expand Up @@ -13720,6 +13722,24 @@ namespace ts {
return getNonNullableType(checkExpression(node.expression));
}

function checkMetaProperty(node: MetaProperty) {
checkGrammarMetaProperty(node);
Debug.assert(node.keywordToken === SyntaxKind.NewKeyword && node.name.text === "target", "Unrecognized meta-property.");
const container = getNewTargetContainer(node);
if (!container) {
error(node, Diagnostics.Meta_property_0_is_only_allowed_in_the_body_of_a_function_declaration_function_expression_or_constructor, "new.target");
return unknownType;
}
else if (container.kind === SyntaxKind.Constructor) {
const symbol = getSymbolOfNode(container.parent);
return getTypeOfSymbol(symbol);
}
else {
const symbol = getSymbolOfNode(container);
return getTypeOfSymbol(symbol);
}
}

function getTypeOfParameter(symbol: Symbol) {
const type = getTypeOfSymbol(symbol);
if (strictNullChecks) {
Expand Down Expand Up @@ -14128,6 +14148,7 @@ namespace ts {
if (produceDiagnostics && node.kind !== SyntaxKind.MethodDeclaration) {
checkCollisionWithCapturedSuperVariable(node, (<FunctionExpression>node).name);
checkCollisionWithCapturedThisVariable(node, (<FunctionExpression>node).name);
checkCollisionWithCapturedNewTargetVariable(node, (<FunctionExpression>node).name);
}

return type;
Expand Down Expand Up @@ -15152,6 +15173,8 @@ namespace ts {
return checkAssertion(<AssertionExpression>node);
case SyntaxKind.NonNullExpression:
return checkNonNullAssertion(<NonNullExpression>node);
case SyntaxKind.MetaProperty:
return checkMetaProperty(<MetaProperty>node);
case SyntaxKind.DeleteExpression:
return checkDeleteExpression(<DeleteExpression>node);
case SyntaxKind.VoidExpression:
Expand Down Expand Up @@ -16552,6 +16575,7 @@ namespace ts {

checkCollisionWithCapturedSuperVariable(node, node.name);
checkCollisionWithCapturedThisVariable(node, node.name);
checkCollisionWithCapturedNewTargetVariable(node, node.name);
checkCollisionWithRequireExportsInGeneratedCode(node, node.name);
checkCollisionWithGlobalPromiseInGeneratedCode(node, node.name);
}
Expand Down Expand Up @@ -16835,6 +16859,12 @@ namespace ts {
}
}

function checkCollisionWithCapturedNewTargetVariable(node: Node, name: Identifier): void {
if (needCollisionCheckForIdentifier(node, name, "_newTarget")) {
potentialNewTargetCollisions.push(node);
}
}

// this function will run after checking the source file so 'CaptureThis' is correct for all nodes
function checkIfThisIsCapturedInEnclosingScope(node: Node): void {
let current = node;
Expand All @@ -16853,6 +16883,23 @@ namespace ts {
}
}

function checkIfNewTargetIsCapturedInEnclosingScope(node: Node): void {
let current = node;
while (current) {
if (getNodeCheckFlags(current) & NodeCheckFlags.CaptureNewTarget) {
const isDeclaration = node.kind !== SyntaxKind.Identifier;
if (isDeclaration) {
error((<Declaration>node).name, Diagnostics.Duplicate_identifier_newTarget_Compiler_uses_variable_declaration_newTarget_to_capture_new_target_meta_property_reference);
}
else {
error(node, Diagnostics.Expression_resolves_to_variable_declaration_newTarget_that_compiler_uses_to_capture_new_target_meta_property_reference);
}
return;
}
current = current.parent;
}
}

function checkCollisionWithCapturedSuperVariable(node: Node, name: Identifier) {
if (!needCollisionCheckForIdentifier(node, name, "_super")) {
return;
Expand Down Expand Up @@ -17148,6 +17195,7 @@ namespace ts {
}
checkCollisionWithCapturedSuperVariable(node, <Identifier>node.name);
checkCollisionWithCapturedThisVariable(node, <Identifier>node.name);
checkCollisionWithCapturedNewTargetVariable(node, <Identifier>node.name);
checkCollisionWithRequireExportsInGeneratedCode(node, <Identifier>node.name);
checkCollisionWithGlobalPromiseInGeneratedCode(node, <Identifier>node.name);
}
Expand Down Expand Up @@ -17984,6 +18032,7 @@ namespace ts {
if (node.name) {
checkTypeNameIsReserved(node.name, Diagnostics.Class_name_cannot_be_0);
checkCollisionWithCapturedThisVariable(node, node.name);
checkCollisionWithCapturedNewTargetVariable(node, node.name);
checkCollisionWithRequireExportsInGeneratedCode(node, node.name);
checkCollisionWithGlobalPromiseInGeneratedCode(node, node.name);
}
Expand Down Expand Up @@ -18518,6 +18567,7 @@ namespace ts {

checkTypeNameIsReserved(node.name, Diagnostics.Enum_name_cannot_be_0);
checkCollisionWithCapturedThisVariable(node, node.name);
checkCollisionWithCapturedNewTargetVariable(node, node.name);
checkCollisionWithRequireExportsInGeneratedCode(node, node.name);
checkCollisionWithGlobalPromiseInGeneratedCode(node, node.name);
checkExportsOnMergedDeclarations(node);
Expand Down Expand Up @@ -19223,6 +19273,7 @@ namespace ts {
checkGrammarSourceFile(node);

potentialThisCollisions.length = 0;
potentialNewTargetCollisions.length = 0;

deferredNodes = [];
deferredUnusedIdentifierNodes = produceDiagnostics && noUnusedIdentifiers ? [] : undefined;
Expand Down Expand Up @@ -19251,6 +19302,11 @@ namespace ts {
potentialThisCollisions.length = 0;
}

if (potentialNewTargetCollisions.length) {
forEach(potentialNewTargetCollisions, checkIfNewTargetIsCapturedInEnclosingScope)
potentialNewTargetCollisions.length = 0;
}

links.flags |= NodeCheckFlags.TypeChecked;
}
}
Expand Down Expand Up @@ -21581,6 +21637,14 @@ namespace ts {
}
}

function checkGrammarMetaProperty(node: MetaProperty) {
if (node.keywordToken === SyntaxKind.NewKeyword) {
if (node.name.text !== "target") {
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");
}
}
}

function hasParseDiagnostics(sourceFile: SourceFile): boolean {
return sourceFile.parseDiagnostics.length > 0;
}
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,8 @@ namespace ts {
* is created if `value` was appended.
* @param value The value to append to the array. If `value` is `undefined`, nothing is
* appended.
* @param copyOnWrite Indicates whether to return a fresh array rather than modify the
* existing array.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this can be removed.

*/
export function append<T>(to: T[] | undefined, value: T | undefined): T[] | undefined {
if (value === undefined) return to;
Expand Down
16 changes: 16 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -1771,6 +1771,14 @@
"category": "Error",
"code": 2542
},
"Duplicate identifier '_newTarget'. Compiler uses variable declaration '_newTarget' to capture 'new.target' meta-property reference.": {
"category": "Error",
"code": 2543
},
"Expression resolves to variable declaration '_newTarget' that compiler uses to capture 'new.target' meta-property reference.": {
"category": "Error",
"code": 2544
},
"JSX element attributes type '{0}' may not be a union type.": {
"category": "Error",
"code": 2600
Expand Down Expand Up @@ -3169,6 +3177,14 @@
"category": "Error",
"code": 17011
},
"'{0}' is not a valid meta-property for keyword '{1}'. Did you mean '{0}'?": {
"category": "Error",
"code": 17012
},
"Meta-property '{0}' is only allowed in the body of a function declaration, function expression, or constructor.": {
"category": "Error",
"code": 17013
},

"Circularity detected while resolving configuration: {0}": {
"category": "Error",
Expand Down
27 changes: 25 additions & 2 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,8 @@ namespace ts {
return emitAsExpression(<AsExpression>node);
case SyntaxKind.NonNullExpression:
return emitNonNullExpression(<NonNullExpression>node);
case SyntaxKind.MetaProperty:
return emitMetaProperty(<MetaProperty>node);

// JSX
case SyntaxKind.JsxElement:
Expand Down Expand Up @@ -1249,6 +1251,12 @@ namespace ts {
write("!");
}

function emitMetaProperty(node: MetaProperty) {
writeToken(node.keywordToken, node.pos);
write(".");
emit(node.name);
}

//
// Misc
//
Expand Down Expand Up @@ -2571,6 +2579,13 @@ namespace ts {
return makeUniqueName("class");
}

function generateNameForMethodOrAccessor(node: MethodDeclaration | AccessorDeclaration) {
if (isIdentifier(node.name)) {
return generateNameForNodeCached(node.name);
}
return makeTempVariableName(TempFlags.Auto);
}

/**
* Generates a unique name from a node.
*
Expand All @@ -2592,6 +2607,10 @@ namespace ts {
return generateNameForExportDefault();
case SyntaxKind.ClassExpression:
return generateNameForClassExpression();
case SyntaxKind.MethodDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
return generateNameForMethodOrAccessor(<MethodDeclaration | AccessorDeclaration>node);
default:
return makeTempVariableName(TempFlags.Auto);
}
Expand Down Expand Up @@ -2642,6 +2661,11 @@ namespace ts {
return node;
}

function generateNameForNodeCached(node: Node) {
const nodeId = getNodeId(node);
return nodeIdToGeneratedName[nodeId] || (nodeIdToGeneratedName[nodeId] = unescapeIdentifier(generateNameForNode(node)));
}

/**
* Gets the generated identifier text from a generated identifier.
*
Expand All @@ -2652,8 +2676,7 @@ namespace ts {
// Generated names generate unique names based on their original node
// and are cached based on that node's id
const node = getNodeForGeneratedName(name);
const nodeId = getNodeId(node);
return nodeIdToGeneratedName[nodeId] || (nodeIdToGeneratedName[nodeId] = unescapeIdentifier(generateNameForNode(node)));
return generateNameForNodeCached(node);
}
else {
// Auto, Loop, and Unique names are cached based on their unique
Expand Down
15 changes: 12 additions & 3 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,8 @@ namespace ts {
visitNode(cbNode, (<AsExpression>node).type);
case SyntaxKind.NonNullExpression:
return visitNode(cbNode, (<NonNullExpression>node).expression);
case SyntaxKind.MetaProperty:
return visitNode(cbNode, (<MetaProperty>node).name);
case SyntaxKind.ConditionalExpression:
return visitNode(cbNode, (<ConditionalExpression>node).condition) ||
visitNode(cbNode, (<ConditionalExpression>node).questionToken) ||
Expand Down Expand Up @@ -4329,15 +4331,22 @@ namespace ts {
return isIdentifier() ? parseIdentifier() : undefined;
}

function parseNewExpression(): NewExpression {
const node = <NewExpression>createNode(SyntaxKind.NewExpression);
function parseNewExpression(): NewExpression | MetaProperty {
const fullStart = scanner.getStartPos();
parseExpected(SyntaxKind.NewKeyword);
if (parseOptional(SyntaxKind.DotToken)) {
const node = <MetaProperty>createNode(SyntaxKind.MetaProperty, fullStart);
node.keywordToken = SyntaxKind.NewKeyword;
node.name = parseIdentifierName();
return finishNode(node);
}

const node = <NewExpression>createNode(SyntaxKind.NewExpression, fullStart);
node.expression = parseMemberExpressionOrHigher();
node.typeArguments = tryParse(parseTypeArgumentsInExpression);
if (node.typeArguments || token() === SyntaxKind.OpenParenToken) {
node.arguments = parseArgumentList();
}

return finishNode(node);
}

Expand Down
Loading