diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 97db8fc14c6..2352ebb6167 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -3136,6 +3136,7 @@ namespace ts { case SyntaxKind.TaggedTemplateExpression: case SyntaxKind.ShorthandPropertyAssignment: case SyntaxKind.StaticKeyword: + case SyntaxKind.MetaProperty: // These nodes are ES6 syntax. transformFlags |= TransformFlags.AssertES2015; break; diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 48a0876d881..1842ee53b5d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -241,6 +241,7 @@ namespace ts { const visitedFlowNodes: FlowNode[] = []; const visitedFlowTypes: FlowType[] = []; const potentialThisCollisions: Node[] = []; + const potentialNewTargetCollisions: Node[] = []; const awaitedTypeStack: number[] = []; const diagnostics = createDiagnosticCollection(); @@ -10368,6 +10369,7 @@ namespace ts { checkCollisionWithCapturedSuperVariable(node, node); checkCollisionWithCapturedThisVariable(node, node); + checkCollisionWithCapturedNewTargetVariable(node, node); checkNestedBlockScopedBinding(node, symbol); const type = getTypeOfSymbol(localOrExportSymbol); @@ -10409,7 +10411,7 @@ namespace ts { // the entire control flow graph from the variable's declaration (i.e. when the flow container and // declaration container are the same). const assumeInitialized = isParameter || isOuterVariable || - type !== autoType && type !== autoArrayType && (!strictNullChecks || (type.flags & TypeFlags.Any) !== 0) || + type !== autoType && type !== autoArrayType && (!strictNullChecks || (type.flags & TypeFlags.Any) !== 0 || isInTypeQuery(node)) || isInAmbientContext(declaration); const flowType = getFlowTypeOfReference(node, type, assumeInitialized, flowContainer); // A variable is considered uninitialized when it is possible to analyze the entire control flow graph @@ -13893,6 +13895,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) { @@ -14301,6 +14321,7 @@ namespace ts { if (produceDiagnostics && node.kind !== SyntaxKind.MethodDeclaration) { checkCollisionWithCapturedSuperVariable(node, (node).name); checkCollisionWithCapturedThisVariable(node, (node).name); + checkCollisionWithCapturedNewTargetVariable(node, (node).name); } return type; @@ -15335,6 +15356,8 @@ namespace ts { return checkAssertion(node); case SyntaxKind.NonNullExpression: return checkNonNullAssertion(node); + case SyntaxKind.MetaProperty: + return checkMetaProperty(node); case SyntaxKind.DeleteExpression: return checkDeleteExpression(node); case SyntaxKind.VoidExpression: @@ -16742,6 +16765,7 @@ namespace ts { checkCollisionWithCapturedSuperVariable(node, node.name); checkCollisionWithCapturedThisVariable(node, node.name); + checkCollisionWithCapturedNewTargetVariable(node, node.name); checkCollisionWithRequireExportsInGeneratedCode(node, node.name); checkCollisionWithGlobalPromiseInGeneratedCode(node, node.name); } @@ -17034,6 +17058,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; @@ -17052,6 +17082,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((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; @@ -17348,6 +17395,7 @@ namespace ts { } checkCollisionWithCapturedSuperVariable(node, node.name); checkCollisionWithCapturedThisVariable(node, node.name); + checkCollisionWithCapturedNewTargetVariable(node, node.name); checkCollisionWithRequireExportsInGeneratedCode(node, node.name); checkCollisionWithGlobalPromiseInGeneratedCode(node, node.name); } @@ -18184,6 +18232,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); } @@ -18719,6 +18768,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); @@ -19424,6 +19474,7 @@ namespace ts { checkGrammarSourceFile(node); potentialThisCollisions.length = 0; + potentialNewTargetCollisions.length = 0; deferredNodes = []; deferredUnusedIdentifierNodes = produceDiagnostics && noUnusedIdentifiers ? [] : undefined; @@ -19452,6 +19503,11 @@ namespace ts { potentialThisCollisions.length = 0; } + if (potentialNewTargetCollisions.length) { + forEach(potentialNewTargetCollisions, checkIfNewTargetIsCapturedInEnclosingScope) + potentialNewTargetCollisions.length = 0; + } + links.flags |= NodeCheckFlags.TypeChecked; } } @@ -21780,6 +21836,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; } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index a049f560010..78263747874 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1775,6 +1775,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 @@ -3197,6 +3205,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", diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 13868acc287..2ff342138c8 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -660,6 +660,8 @@ namespace ts { return emitAsExpression(node); case SyntaxKind.NonNullExpression: return emitNonNullExpression(node); + case SyntaxKind.MetaProperty: + return emitMetaProperty(node); // JSX case SyntaxKind.JsxElement: @@ -1247,6 +1249,12 @@ namespace ts { write("!"); } + function emitMetaProperty(node: MetaProperty) { + writeToken(node.keywordToken, node.pos); + write("."); + emit(node.name); + } + // // Misc // @@ -2586,6 +2594,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. * @@ -2607,6 +2622,10 @@ namespace ts { return generateNameForExportDefault(); case SyntaxKind.ClassExpression: return generateNameForClassExpression(); + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + return generateNameForMethodOrAccessor(node); default: return makeTempVariableName(TempFlags.Auto); } @@ -2657,6 +2676,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. * @@ -2667,8 +2691,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 diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 76b45bf60c6..63302a3d42e 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -198,6 +198,8 @@ namespace ts { visitNode(cbNode, (node).type); case SyntaxKind.NonNullExpression: return visitNode(cbNode, (node).expression); + case SyntaxKind.MetaProperty: + return visitNode(cbNode, (node).name); case SyntaxKind.ConditionalExpression: return visitNode(cbNode, (node).condition) || visitNode(cbNode, (node).questionToken) || @@ -4335,15 +4337,22 @@ namespace ts { return isIdentifier() ? parseIdentifier() : undefined; } - function parseNewExpression(): NewExpression { - const node = createNode(SyntaxKind.NewExpression); + function parseNewExpression(): NewExpression | MetaProperty { + const fullStart = scanner.getStartPos(); parseExpected(SyntaxKind.NewKeyword); + if (parseOptional(SyntaxKind.DotToken)) { + const node = createNode(SyntaxKind.MetaProperty, fullStart); + node.keywordToken = SyntaxKind.NewKeyword; + node.name = parseIdentifierName(); + return finishNode(node); + } + + const node = createNode(SyntaxKind.NewExpression, fullStart); node.expression = parseMemberExpressionOrHigher(); node.typeArguments = tryParse(parseTypeArgumentsInExpression); if (node.typeArguments || token() === SyntaxKind.OpenParenToken) { node.arguments = parseArgumentList(); } - return finishNode(node); } diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index 1bfc6964b0f..4693d96d2c3 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -248,14 +248,16 @@ namespace ts { // // Subtree facts // + NewTarget = 1 << 14, // Contains a 'new.target' meta-property + NewTargetInComputedPropertyName = 1 << 15, // Contains a 'new.target' meta-property in a computed property name. - // NOTE: To be added in a later PR // // Subtree masks // SubtreeFactsMask = ~AncestorFactsMask, + PropagateNewTargetMask = NewTarget | NewTargetInComputedPropertyName, } export function transformES2015(context: TransformationContext) { @@ -480,6 +482,9 @@ namespace ts { case SyntaxKind.ThisKeyword: return visitThisKeyword(node); + case SyntaxKind.MetaProperty: + return visitMetaProperty(node); + case SyntaxKind.MethodDeclaration: return visitMethodDeclaration(node); @@ -564,7 +569,7 @@ namespace ts { function visitThisKeyword(node: Node): Node { if (convertedLoopState) { if (hierarchyFacts & HierarchyFacts.ArrowFunction) { - // if the enclosing function is an ArrowFunction is then we use the captured 'this' keyword. + // if the enclosing function is an ArrowFunction then we use the captured 'this' keyword. convertedLoopState.containsLexicalThis = true; return node; } @@ -867,7 +872,7 @@ namespace ts { } statements.push(constructorFunction); - exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None); + exitSubtree(ancestorFacts, HierarchyFacts.PropagateNewTargetMask, HierarchyFacts.None); convertedLoopState = savedConvertedLoopState; } @@ -948,6 +953,11 @@ namespace ts { } addRange(statements, endLexicalEnvironment()); + + if (constructor) { + prependCaptureNewTargetIfNeeded(statements, constructor, /*copyOnWrite*/ false); + } + const block = createBlock( createNodeArray( statements, @@ -1391,6 +1401,77 @@ namespace ts { statements.push(captureThisStatement); } + function prependCaptureNewTargetIfNeeded(statements: Statement[], node: FunctionLikeDeclaration, copyOnWrite: boolean): Statement[] { + if (hierarchyFacts & HierarchyFacts.NewTarget) { + let newTarget: Expression; + switch (node.kind) { + case SyntaxKind.ArrowFunction: + return statements; + + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + // Methods and accessors cannot be constructors, so 'new.target' will + // always return 'undefined'. + newTarget = createVoidZero(); + break; + + case SyntaxKind.Constructor: + // Class constructors can only be called with `new`, so `this.constructor` + // should be relatively safe to use. + newTarget = createPropertyAccess( + setEmitFlags(createThis(), EmitFlags.NoSubstitution), + "constructor" + ); + break; + + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + // Functions can be called or constructed, and may have a `this` due to + // being a member or when calling an imported function via `other_1.f()`. + newTarget = createConditional( + createLogicalAnd( + setEmitFlags(createThis(), EmitFlags.NoSubstitution), + createBinary( + setEmitFlags(createThis(), EmitFlags.NoSubstitution), + SyntaxKind.InstanceOfKeyword, + getLocalName(node) + ) + ), + createPropertyAccess( + setEmitFlags(createThis(), EmitFlags.NoSubstitution), + "constructor" + ), + createVoidZero() + ); + break; + + default: + Debug.failBadSyntaxKind(node); + break; + } + + const captureNewTargetStatement = createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList([ + createVariableDeclaration( + "_newTarget", + /*type*/ undefined, + newTarget + ) + ]) + ); + + if (copyOnWrite) { + return [captureNewTargetStatement, ...statements]; + } + + statements.unshift(captureNewTargetStatement); + } + + return statements; + } + /** * Adds statements to the class body function for a class to define the members of the * class. @@ -1466,7 +1547,7 @@ namespace ts { // old emitter. setEmitFlags(statement, EmitFlags.NoSourceMap); - exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None); + exitSubtree(ancestorFacts, HierarchyFacts.PropagateNewTargetMask, hierarchyFacts & HierarchyFacts.PropagateNewTargetMask ? HierarchyFacts.NewTarget : HierarchyFacts.None); return statement; } @@ -1545,7 +1626,7 @@ namespace ts { call.startsOnNewLine = true; } - exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None); + exitSubtree(ancestorFacts, HierarchyFacts.PropagateNewTargetMask, hierarchyFacts & HierarchyFacts.PropagateNewTargetMask ? HierarchyFacts.NewTarget : HierarchyFacts.None); return call; } @@ -1589,20 +1670,26 @@ namespace ts { : enterSubtree(HierarchyFacts.FunctionExcludes, HierarchyFacts.FunctionIncludes); const savedConvertedLoopState = convertedLoopState; convertedLoopState = undefined; - const updated = updateFunctionExpression( + + const parameters = visitParameterList(node.parameters, visitor, context); + const body = node.transformFlags & TransformFlags.ES2015 + ? transformFunctionBody(node) + : visitFunctionBodyDownLevel(node); + const name = hierarchyFacts & HierarchyFacts.NewTarget + ? getLocalName(node) + : node.name; + + exitSubtree(ancestorFacts, HierarchyFacts.PropagateNewTargetMask, HierarchyFacts.None); + convertedLoopState = savedConvertedLoopState; + return updateFunctionExpression( node, /*modifiers*/ undefined, - node.name, + name, /*typeParameters*/ undefined, - visitParameterList(node.parameters, visitor, context), + parameters, /*type*/ undefined, - node.transformFlags & TransformFlags.ES2015 - ? transformFunctionBody(node) - : visitFunctionBody(node.body, functionBodyVisitor, context) + body ); - exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None); - convertedLoopState = savedConvertedLoopState; - return updated; } /** @@ -1614,22 +1701,26 @@ namespace ts { const savedConvertedLoopState = convertedLoopState; convertedLoopState = undefined; const ancestorFacts = enterSubtree(HierarchyFacts.FunctionExcludes, HierarchyFacts.FunctionIncludes); - const updated = updateFunctionDeclaration( + const parameters = visitParameterList(node.parameters, visitor, context); + const body = node.transformFlags & TransformFlags.ES2015 + ? transformFunctionBody(node) + : visitFunctionBodyDownLevel(node); + const name = hierarchyFacts & HierarchyFacts.NewTarget + ? getLocalName(node) + : node.name; + + exitSubtree(ancestorFacts, HierarchyFacts.PropagateNewTargetMask, HierarchyFacts.None); + convertedLoopState = savedConvertedLoopState; + return updateFunctionDeclaration( node, /*decorators*/ undefined, visitNodes(node.modifiers, visitor, isModifier), - node.name, + name, /*typeParameters*/ undefined, - visitParameterList(node.parameters, visitor, context), + parameters, /*type*/ undefined, - node.transformFlags & TransformFlags.ES2015 - ? transformFunctionBody(node) - : visitFunctionBody(node.body, functionBodyVisitor, context) + body ); - - exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None); - convertedLoopState = savedConvertedLoopState; - return updated; } /** @@ -1645,22 +1736,27 @@ namespace ts { const ancestorFacts = container && isClassLike(container) && !hasModifier(node, ModifierFlags.Static) ? enterSubtree(HierarchyFacts.FunctionExcludes, HierarchyFacts.FunctionIncludes | HierarchyFacts.NonStaticClassElement) : enterSubtree(HierarchyFacts.FunctionExcludes, HierarchyFacts.FunctionIncludes); - const expression = setOriginalNode( + const parameters = visitParameterList(node.parameters, visitor, context); + const body = transformFunctionBody(node); + if (hierarchyFacts & HierarchyFacts.NewTarget && !name && (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression)) { + name = getGeneratedNameForNode(node); + } + + exitSubtree(ancestorFacts, HierarchyFacts.PropagateNewTargetMask, HierarchyFacts.None); + convertedLoopState = savedConvertedLoopState; + return setOriginalNode( createFunctionExpression( /*modifiers*/ undefined, node.asteriskToken, name, /*typeParameters*/ undefined, - visitParameterList(node.parameters, visitor, context), + parameters, /*type*/ undefined, - transformFunctionBody(node), + body, location ), /*original*/ node ); - exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None); - convertedLoopState = savedConvertedLoopState; - return expression; } /** @@ -1735,6 +1831,8 @@ namespace ts { const lexicalEnvironment = context.endLexicalEnvironment(); addRange(statements, lexicalEnvironment); + prependCaptureNewTargetIfNeeded(statements, node, /*copyOnWrite*/ false); + // If we added any final generated statements, this must be a multi-line block if (!multiLine && lexicalEnvironment && lexicalEnvironment.length) { multiLine = true; @@ -1753,6 +1851,17 @@ namespace ts { return block; } + function visitFunctionBodyDownLevel(node: FunctionDeclaration | FunctionExpression) { + const updated = visitFunctionBody(node.body, functionBodyVisitor, context); + return updateBlock( + updated, + createNodeArray( + prependCaptureNewTargetIfNeeded(updated.statements, node, /*copyOnWrite*/ true), + /*location*/ updated.statements + ) + ); + } + function visitBlock(node: Block, isFunctionBody: boolean): Block { if (isFunctionBody) { // A function body is not a block scope. @@ -2832,7 +2941,7 @@ namespace ts { if (startsOnNewLine) { expression.startsOnNewLine = true; } - exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None); + exitSubtree(ancestorFacts, HierarchyFacts.PropagateNewTargetMask, hierarchyFacts & HierarchyFacts.PropagateNewTargetMask ? HierarchyFacts.NewTarget : HierarchyFacts.None); return expression; } @@ -2897,7 +3006,7 @@ namespace ts { convertedLoopState = undefined; const ancestorFacts = enterSubtree(HierarchyFacts.FunctionExcludes, HierarchyFacts.FunctionIncludes); const updated = visitEachChild(node, visitor, context); - exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None); + exitSubtree(ancestorFacts, HierarchyFacts.PropagateNewTargetMask, HierarchyFacts.None); convertedLoopState = savedConvertedLoopState; return updated; } @@ -2918,7 +3027,7 @@ namespace ts { function visitComputedPropertyName(node: ComputedPropertyName) { const ancestorFacts = enterSubtree(HierarchyFacts.ComputedPropertyNameExcludes, HierarchyFacts.ComputedPropertyNameIncludes); const updated = visitEachChild(node, visitor, context); - exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None); + exitSubtree(ancestorFacts, HierarchyFacts.PropagateNewTargetMask, hierarchyFacts & HierarchyFacts.PropagateNewTargetMask ? HierarchyFacts.NewTargetInComputedPropertyName : HierarchyFacts.None); return updated; } @@ -3297,6 +3406,19 @@ namespace ts { : createIdentifier("_super"); } + function visitMetaProperty(node: MetaProperty) { + if (node.keywordToken === SyntaxKind.NewKeyword && node.name.text === "target") { + if (hierarchyFacts & HierarchyFacts.ComputedPropertyName) { + hierarchyFacts |= HierarchyFacts.NewTargetInComputedPropertyName; + } + else { + hierarchyFacts |= HierarchyFacts.NewTarget; + } + return createIdentifier("_newTarget"); + } + return node; + } + /** * Called by the printer just before a node is printed. * diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 2489434c82d..5ac44840dd1 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -272,6 +272,7 @@ ExpressionWithTypeArguments, AsExpression, NonNullExpression, + MetaProperty, // Misc TemplateSpan, @@ -1462,6 +1463,14 @@ expression: Expression; } + // NOTE: MetaProperty is really a MemberExpression, but we consider it a PrimaryExpression + // for the same reasons we treat NewExpression as a PrimaryExpression. + export interface MetaProperty extends PrimaryExpression { + kind: SyntaxKind.MetaProperty; + keywordToken: SyntaxKind; + name: Identifier; + } + /// A JSX expression of the form ... export interface JsxElement extends PrimaryExpression { kind: SyntaxKind.JsxElement; @@ -2722,6 +2731,7 @@ TypeChecked = 0x00000001, // Node has been type checked LexicalThis = 0x00000002, // Lexical 'this' reference CaptureThis = 0x00000004, // Lexical 'this' used in body + CaptureNewTarget = 0x00000008, // Lexical 'new.target' used in body SuperInstance = 0x00000100, // Instance 'super' reference SuperStatic = 0x00000200, // Static 'super' reference ContextChecked = 0x00000400, // Contextual types have been assigned diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index f74c450d61a..c9d01d62778 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1026,6 +1026,20 @@ namespace ts { } } + export function getNewTargetContainer(node: Node) { + const container = getThisContainer(node, /*includeArrowFunctions*/ false); + if (container) { + switch (container.kind) { + case SyntaxKind.Constructor: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + return container; + } + } + + return undefined; + } + /** * Given an super call/property node, returns the closest node where * - a super call/property access is legal in the node and not legal in the parent node the node. @@ -1233,6 +1247,7 @@ namespace ts { case SyntaxKind.JsxSelfClosingElement: case SyntaxKind.YieldExpression: case SyntaxKind.AwaitExpression: + case SyntaxKind.MetaProperty: return true; case SyntaxKind.QualifiedName: while (node.parent.kind === SyntaxKind.QualifiedName) { @@ -3882,7 +3897,8 @@ namespace ts { || kind === SyntaxKind.ThisKeyword || kind === SyntaxKind.TrueKeyword || kind === SyntaxKind.SuperKeyword - || kind === SyntaxKind.NonNullExpression; + || kind === SyntaxKind.NonNullExpression + || kind === SyntaxKind.MetaProperty; } export function isLeftHandSideExpression(node: Node): node is LeftHandSideExpression { diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 8cd0a9664a0..456fffb2ddc 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -113,7 +113,10 @@ namespace ts.codefix { } registerCodeFix({ - errorCodes: [Diagnostics.Cannot_find_name_0.code], + errorCodes: [ + Diagnostics.Cannot_find_name_0.code, + Diagnostics._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead.code + ], getCodeActions: (context: CodeFixContext) => { const sourceFile = context.sourceFile; const checker = context.program.getTypeChecker(); @@ -128,6 +131,12 @@ namespace ts.codefix { const cachedImportDeclarations: (ImportDeclaration | ImportEqualsDeclaration)[][] = []; let cachedNewImportInsertPosition: number; + const currentTokenMeaning = getMeaningFromLocation(token); + if (context.errorCode === Diagnostics._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead.code) { + const symbol = checker.getAliasedSymbol(checker.getSymbolAtLocation(token)); + return getCodeActionForImport(symbol, /*isDefault*/ false, /*isNamespaceImport*/ true); + } + const allPotentialModules = checker.getAmbientModules(); for (const otherSourceFile of allSourceFiles) { if (otherSourceFile !== sourceFile && isExternalOrCommonJsModule(otherSourceFile)) { @@ -135,7 +144,6 @@ namespace ts.codefix { } } - const currentTokenMeaning = getMeaningFromLocation(token); for (const moduleSymbol of allPotentialModules) { context.cancellationToken.throwIfCancellationRequested(); @@ -205,7 +213,7 @@ namespace ts.codefix { return declarations ? some(symbol.declarations, decl => !!(getMeaningFromDeclaration(decl) & meaning)) : false; } - function getCodeActionForImport(moduleSymbol: Symbol, isDefault?: boolean): ImportCodeAction[] { + function getCodeActionForImport(moduleSymbol: Symbol, isDefault?: boolean, isNamespaceImport?: boolean): ImportCodeAction[] { const existingDeclarations = getImportDeclarations(moduleSymbol); if (existingDeclarations.length > 0) { // With an existing import statement, there are more than one actions the user can do. @@ -215,8 +223,6 @@ namespace ts.codefix { return [getCodeActionForNewImport()]; } - - function getCodeActionsForExistingImport(declarations: (ImportDeclaration | ImportEqualsDeclaration)[]): ImportCodeAction[] { const actions: ImportCodeAction[] = []; @@ -264,7 +270,7 @@ namespace ts.codefix { actions.push(getCodeActionForNamespaceImport(namespaceImportDeclaration)); } - if (namedImportDeclaration && namedImportDeclaration.importClause && + if (!isNamespaceImport && namedImportDeclaration && namedImportDeclaration.importClause && (namedImportDeclaration.importClause.name || namedImportDeclaration.importClause.namedBindings)) { /** * If the existing import declaration already has a named import list, just @@ -388,7 +394,9 @@ namespace ts.codefix { const moduleSpecifierWithoutQuotes = stripQuotes(moduleSpecifier || getModuleSpecifierForNewImport()); const importStatementText = isDefault ? `import ${name} from "${moduleSpecifierWithoutQuotes}"` - : `import { ${name} } from "${moduleSpecifierWithoutQuotes}"`; + : isNamespaceImport + ? `import * as ${name} from "${moduleSpecifierWithoutQuotes}"` + : `import { ${name} } from "${moduleSpecifierWithoutQuotes}"`; // if this file doesn't have any import statements, insert an import statement and then insert a new line // between the only import statement and user code. Otherwise just insert the statement because chances diff --git a/tests/baselines/reference/invalidNewTarget.es5.errors.txt b/tests/baselines/reference/invalidNewTarget.es5.errors.txt new file mode 100644 index 00000000000..080267c36eb --- /dev/null +++ b/tests/baselines/reference/invalidNewTarget.es5.errors.txt @@ -0,0 +1,78 @@ +tests/cases/conformance/es6/newTarget/invalidNewTarget.es5.ts(1,11): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es5.ts(2,17): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es5.ts(5,6): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es5.ts(6,18): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es5.ts(7,22): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es5.ts(8,20): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es5.ts(9,15): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es5.ts(11,13): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es5.ts(12,25): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es5.ts(13,29): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es5.ts(14,27): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es5.ts(15,22): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es5.ts(19,6): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es5.ts(20,18): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es5.ts(21,22): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es5.ts(22,20): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es5.ts(23,8): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + + +==== tests/cases/conformance/es6/newTarget/invalidNewTarget.es5.ts (17 errors) ==== + const a = new.target; + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + const b = () => new.target; + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + + class C { + [new.target]() { } + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + c() { return new.target; } + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + get d() { return new.target; } + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + set e(_) { _ = new.target; } + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + f = () => new.target; + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + + static [new.target]() { } + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + static g() { return new.target; } + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + static get h() { return new.target; } + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + static set i(_) { _ = new.target; } + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + static j = () => new.target; + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + } + + const O = { + [new.target]: undefined, + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + k() { return new.target; }, + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + get l() { return new.target; }, + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + set m(_) { _ = new.target; }, + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + n: new.target, + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + }; \ No newline at end of file diff --git a/tests/baselines/reference/invalidNewTarget.es5.js b/tests/baselines/reference/invalidNewTarget.es5.js new file mode 100644 index 00000000000..866dac270af --- /dev/null +++ b/tests/baselines/reference/invalidNewTarget.es5.js @@ -0,0 +1,77 @@ +//// [invalidNewTarget.es5.ts] +const a = new.target; +const b = () => new.target; + +class C { + [new.target]() { } + c() { return new.target; } + get d() { return new.target; } + set e(_) { _ = new.target; } + f = () => new.target; + + static [new.target]() { } + static g() { return new.target; } + static get h() { return new.target; } + static set i(_) { _ = new.target; } + static j = () => new.target; +} + +const O = { + [new.target]: undefined, + k() { return new.target; }, + get l() { return new.target; }, + set m(_) { _ = new.target; }, + n: new.target, +}; + +//// [invalidNewTarget.es5.js] +var a = _newTarget; +var b = function () { return _newTarget; }; +var C = (function () { + function C() { + var _newTarget = this.constructor; + this.f = function () { return _newTarget; }; + } + C.prototype[_newTarget] = function () { }; + C.prototype.c = function () { var _newTarget = void 0; return _newTarget; }; + Object.defineProperty(C.prototype, "d", { + get: function () { var _newTarget = void 0; return _newTarget; }, + enumerable: true, + configurable: true + }); + Object.defineProperty(C.prototype, "e", { + set: function (_) { var _newTarget = void 0; _ = _newTarget; }, + enumerable: true, + configurable: true + }); + C[_newTarget] = function () { }; + C.g = function () { var _newTarget = void 0; return _newTarget; }; + Object.defineProperty(C, "h", { + get: function () { var _newTarget = void 0; return _newTarget; }, + enumerable: true, + configurable: true + }); + Object.defineProperty(C, "i", { + set: function (_) { var _newTarget = void 0; _ = _newTarget; }, + enumerable: true, + configurable: true + }); + return C; +}()); +C.j = function () { return _newTarget; }; +var O = (_a = {}, + _a[_newTarget] = undefined, + _a.k = function () { var _newTarget = void 0; return _newTarget; }, + Object.defineProperty(_a, "l", { + get: function () { var _newTarget = void 0; return _newTarget; }, + enumerable: true, + configurable: true + }), + Object.defineProperty(_a, "m", { + set: function (_) { var _newTarget = void 0; _ = _newTarget; }, + enumerable: true, + configurable: true + }), + _a.n = _newTarget, + _a); +var _a; diff --git a/tests/baselines/reference/invalidNewTarget.es6.errors.txt b/tests/baselines/reference/invalidNewTarget.es6.errors.txt new file mode 100644 index 00000000000..ee5404ed781 --- /dev/null +++ b/tests/baselines/reference/invalidNewTarget.es6.errors.txt @@ -0,0 +1,78 @@ +tests/cases/conformance/es6/newTarget/invalidNewTarget.es6.ts(1,11): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es6.ts(2,17): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es6.ts(5,6): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es6.ts(6,18): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es6.ts(7,22): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es6.ts(8,20): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es6.ts(9,15): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es6.ts(11,13): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es6.ts(12,25): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es6.ts(13,29): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es6.ts(14,27): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es6.ts(15,22): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es6.ts(19,6): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es6.ts(20,18): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es6.ts(21,22): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es6.ts(22,20): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. +tests/cases/conformance/es6/newTarget/invalidNewTarget.es6.ts(23,8): error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + + +==== tests/cases/conformance/es6/newTarget/invalidNewTarget.es6.ts (17 errors) ==== + const a = new.target; + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + const b = () => new.target; + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + + class C { + [new.target]() { } + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + c() { return new.target; } + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + get d() { return new.target; } + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + set e(_) { _ = new.target; } + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + f = () => new.target; + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + + static [new.target]() { } + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + static g() { return new.target; } + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + static get h() { return new.target; } + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + static set i(_) { _ = new.target; } + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + static j = () => new.target; + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + } + + const O = { + [new.target]: undefined, + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + k() { return new.target; }, + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + get l() { return new.target; }, + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + set m(_) { _ = new.target; }, + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + n: new.target, + ~~~~~~~~~~ +!!! error TS17013: Meta-property 'new.target' is only allowed in the body of a function declaration, function expression, or constructor. + }; \ No newline at end of file diff --git a/tests/baselines/reference/invalidNewTarget.es6.js b/tests/baselines/reference/invalidNewTarget.es6.js new file mode 100644 index 00000000000..ed1b2cc1592 --- /dev/null +++ b/tests/baselines/reference/invalidNewTarget.es6.js @@ -0,0 +1,50 @@ +//// [invalidNewTarget.es6.ts] +const a = new.target; +const b = () => new.target; + +class C { + [new.target]() { } + c() { return new.target; } + get d() { return new.target; } + set e(_) { _ = new.target; } + f = () => new.target; + + static [new.target]() { } + static g() { return new.target; } + static get h() { return new.target; } + static set i(_) { _ = new.target; } + static j = () => new.target; +} + +const O = { + [new.target]: undefined, + k() { return new.target; }, + get l() { return new.target; }, + set m(_) { _ = new.target; }, + n: new.target, +}; + +//// [invalidNewTarget.es6.js] +const a = new.target; +const b = () => new.target; +class C { + constructor() { + this.f = () => new.target; + } + [new.target]() { } + c() { return new.target; } + get d() { return new.target; } + set e(_) { _ = new.target; } + static [new.target]() { } + static g() { return new.target; } + static get h() { return new.target; } + static set i(_) { _ = new.target; } +} +C.j = () => new.target; +const O = { + [new.target]: undefined, + k() { return new.target; }, + get l() { return new.target; }, + set m(_) { _ = new.target; }, + n: new.target, +}; diff --git a/tests/baselines/reference/newTarget.es5.js b/tests/baselines/reference/newTarget.es5.js new file mode 100644 index 00000000000..0de967d5477 --- /dev/null +++ b/tests/baselines/reference/newTarget.es5.js @@ -0,0 +1,74 @@ +//// [newTarget.es5.ts] +class A { + constructor() { + const a = new.target; + const b = () => new.target; + } + static c = function () { return new.target; } + d = function () { return new.target; } +} + +class B extends A { + constructor() { + super(); + const e = new.target; + const f = () => new.target; + } +} + +function f1() { + const g = new.target; + const h = () => new.target; +} + +const f2 = function () { + const i = new.target; + const j = () => new.target; +} + +const O = { + k: function () { return new.target; } +}; + + + +//// [newTarget.es5.js] +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +var A = (function () { + function A() { + var _newTarget = this.constructor; + this.d = function _a() { var _newTarget = this && this instanceof _a ? this.constructor : void 0; return _newTarget; }; + var a = _newTarget; + var b = function () { return _newTarget; }; + } + return A; +}()); +A.c = function _a() { var _newTarget = this && this instanceof _a ? this.constructor : void 0; return _newTarget; }; +var B = (function (_super) { + __extends(B, _super); + function B() { + var _newTarget = this.constructor; + var _this = _super.call(this) || this; + var e = _newTarget; + var f = function () { return _newTarget; }; + return _this; + } + return B; +}(A)); +function f1() { + var _newTarget = this && this instanceof f1 ? this.constructor : void 0; + var g = _newTarget; + var h = function () { return _newTarget; }; +} +var f2 = function _b() { + var _newTarget = this && this instanceof _b ? this.constructor : void 0; + var i = _newTarget; + var j = function () { return _newTarget; }; +}; +var O = { + k: function _c() { var _newTarget = this && this instanceof _c ? this.constructor : void 0; return _newTarget; } +}; diff --git a/tests/baselines/reference/newTarget.es5.symbols b/tests/baselines/reference/newTarget.es5.symbols new file mode 100644 index 00000000000..34cdb3f34c3 --- /dev/null +++ b/tests/baselines/reference/newTarget.es5.symbols @@ -0,0 +1,63 @@ +=== tests/cases/conformance/es6/newTarget/newTarget.es5.ts === +class A { +>A : Symbol(A, Decl(newTarget.es5.ts, 0, 0)) + + constructor() { + const a = new.target; +>a : Symbol(a, Decl(newTarget.es5.ts, 2, 13)) + + const b = () => new.target; +>b : Symbol(b, Decl(newTarget.es5.ts, 3, 13)) + } + static c = function () { return new.target; } +>c : Symbol(A.c, Decl(newTarget.es5.ts, 4, 5)) + + d = function () { return new.target; } +>d : Symbol(A.d, Decl(newTarget.es5.ts, 5, 49)) +} + +class B extends A { +>B : Symbol(B, Decl(newTarget.es5.ts, 7, 1)) +>A : Symbol(A, Decl(newTarget.es5.ts, 0, 0)) + + constructor() { + super(); +>super : Symbol(A, Decl(newTarget.es5.ts, 0, 0)) + + const e = new.target; +>e : Symbol(e, Decl(newTarget.es5.ts, 12, 13)) + + const f = () => new.target; +>f : Symbol(f, Decl(newTarget.es5.ts, 13, 13)) + } +} + +function f1() { +>f1 : Symbol(f1, Decl(newTarget.es5.ts, 15, 1)) + + const g = new.target; +>g : Symbol(g, Decl(newTarget.es5.ts, 18, 9)) + + const h = () => new.target; +>h : Symbol(h, Decl(newTarget.es5.ts, 19, 9)) +} + +const f2 = function () { +>f2 : Symbol(f2, Decl(newTarget.es5.ts, 22, 5)) + + const i = new.target; +>i : Symbol(i, Decl(newTarget.es5.ts, 23, 9)) + + const j = () => new.target; +>j : Symbol(j, Decl(newTarget.es5.ts, 24, 9)) +} + +const O = { +>O : Symbol(O, Decl(newTarget.es5.ts, 27, 5)) + + k: function () { return new.target; } +>k : Symbol(k, Decl(newTarget.es5.ts, 27, 11)) + +}; + + diff --git a/tests/baselines/reference/newTarget.es5.types b/tests/baselines/reference/newTarget.es5.types new file mode 100644 index 00000000000..ddbe78537b2 --- /dev/null +++ b/tests/baselines/reference/newTarget.es5.types @@ -0,0 +1,95 @@ +=== tests/cases/conformance/es6/newTarget/newTarget.es5.ts === +class A { +>A : A + + constructor() { + const a = new.target; +>a : typeof A +>new.target : typeof A +>target : any + + const b = () => new.target; +>b : () => typeof A +>() => new.target : () => typeof A +>new.target : typeof A +>target : any + } + static c = function () { return new.target; } +>c : () => any +>function () { return new.target; } : () => any +>new.target : () => any +>target : any + + d = function () { return new.target; } +>d : () => any +>function () { return new.target; } : () => any +>new.target : () => any +>target : any +} + +class B extends A { +>B : B +>A : A + + constructor() { + super(); +>super() : void +>super : typeof A + + const e = new.target; +>e : typeof B +>new.target : typeof B +>target : any + + const f = () => new.target; +>f : () => typeof B +>() => new.target : () => typeof B +>new.target : typeof B +>target : any + } +} + +function f1() { +>f1 : () => void + + const g = new.target; +>g : () => void +>new.target : () => void +>target : any + + const h = () => new.target; +>h : () => () => void +>() => new.target : () => () => void +>new.target : () => void +>target : any +} + +const f2 = function () { +>f2 : () => void +>function () { const i = new.target; const j = () => new.target;} : () => void + + const i = new.target; +>i : () => void +>new.target : () => void +>target : any + + const j = () => new.target; +>j : () => () => void +>() => new.target : () => () => void +>new.target : () => void +>target : any +} + +const O = { +>O : { k: () => any; } +>{ k: function () { return new.target; }} : { k: () => any; } + + k: function () { return new.target; } +>k : () => any +>function () { return new.target; } : () => any +>new.target : () => any +>target : any + +}; + + diff --git a/tests/baselines/reference/newTarget.es6.js b/tests/baselines/reference/newTarget.es6.js new file mode 100644 index 00000000000..2bd95ff9f98 --- /dev/null +++ b/tests/baselines/reference/newTarget.es6.js @@ -0,0 +1,61 @@ +//// [newTarget.es6.ts] +class A { + constructor() { + const a = new.target; + const b = () => new.target; + } + static c = function () { return new.target; } + d = function () { return new.target; } +} + +class B extends A { + constructor() { + super(); + const e = new.target; + const f = () => new.target; + } +} + +function f1() { + const g = new.target; + const h = () => new.target; +} + +const f2 = function () { + const i = new.target; + const j = () => new.target; +} + +const O = { + k: function () { return new.target; } +}; + + + +//// [newTarget.es6.js] +class A { + constructor() { + this.d = function () { return new.target; }; + const a = new.target; + const b = () => new.target; + } +} +A.c = function () { return new.target; }; +class B extends A { + constructor() { + super(); + const e = new.target; + const f = () => new.target; + } +} +function f1() { + const g = new.target; + const h = () => new.target; +} +const f2 = function () { + const i = new.target; + const j = () => new.target; +}; +const O = { + k: function () { return new.target; } +}; diff --git a/tests/baselines/reference/newTarget.es6.symbols b/tests/baselines/reference/newTarget.es6.symbols new file mode 100644 index 00000000000..b20ea3dba93 --- /dev/null +++ b/tests/baselines/reference/newTarget.es6.symbols @@ -0,0 +1,63 @@ +=== tests/cases/conformance/es6/newTarget/newTarget.es6.ts === +class A { +>A : Symbol(A, Decl(newTarget.es6.ts, 0, 0)) + + constructor() { + const a = new.target; +>a : Symbol(a, Decl(newTarget.es6.ts, 2, 13)) + + const b = () => new.target; +>b : Symbol(b, Decl(newTarget.es6.ts, 3, 13)) + } + static c = function () { return new.target; } +>c : Symbol(A.c, Decl(newTarget.es6.ts, 4, 5)) + + d = function () { return new.target; } +>d : Symbol(A.d, Decl(newTarget.es6.ts, 5, 49)) +} + +class B extends A { +>B : Symbol(B, Decl(newTarget.es6.ts, 7, 1)) +>A : Symbol(A, Decl(newTarget.es6.ts, 0, 0)) + + constructor() { + super(); +>super : Symbol(A, Decl(newTarget.es6.ts, 0, 0)) + + const e = new.target; +>e : Symbol(e, Decl(newTarget.es6.ts, 12, 13)) + + const f = () => new.target; +>f : Symbol(f, Decl(newTarget.es6.ts, 13, 13)) + } +} + +function f1() { +>f1 : Symbol(f1, Decl(newTarget.es6.ts, 15, 1)) + + const g = new.target; +>g : Symbol(g, Decl(newTarget.es6.ts, 18, 9)) + + const h = () => new.target; +>h : Symbol(h, Decl(newTarget.es6.ts, 19, 9)) +} + +const f2 = function () { +>f2 : Symbol(f2, Decl(newTarget.es6.ts, 22, 5)) + + const i = new.target; +>i : Symbol(i, Decl(newTarget.es6.ts, 23, 9)) + + const j = () => new.target; +>j : Symbol(j, Decl(newTarget.es6.ts, 24, 9)) +} + +const O = { +>O : Symbol(O, Decl(newTarget.es6.ts, 27, 5)) + + k: function () { return new.target; } +>k : Symbol(k, Decl(newTarget.es6.ts, 27, 11)) + +}; + + diff --git a/tests/baselines/reference/newTarget.es6.types b/tests/baselines/reference/newTarget.es6.types new file mode 100644 index 00000000000..08ef8429b3c --- /dev/null +++ b/tests/baselines/reference/newTarget.es6.types @@ -0,0 +1,95 @@ +=== tests/cases/conformance/es6/newTarget/newTarget.es6.ts === +class A { +>A : A + + constructor() { + const a = new.target; +>a : typeof A +>new.target : typeof A +>target : any + + const b = () => new.target; +>b : () => typeof A +>() => new.target : () => typeof A +>new.target : typeof A +>target : any + } + static c = function () { return new.target; } +>c : () => any +>function () { return new.target; } : () => any +>new.target : () => any +>target : any + + d = function () { return new.target; } +>d : () => any +>function () { return new.target; } : () => any +>new.target : () => any +>target : any +} + +class B extends A { +>B : B +>A : A + + constructor() { + super(); +>super() : void +>super : typeof A + + const e = new.target; +>e : typeof B +>new.target : typeof B +>target : any + + const f = () => new.target; +>f : () => typeof B +>() => new.target : () => typeof B +>new.target : typeof B +>target : any + } +} + +function f1() { +>f1 : () => void + + const g = new.target; +>g : () => void +>new.target : () => void +>target : any + + const h = () => new.target; +>h : () => () => void +>() => new.target : () => () => void +>new.target : () => void +>target : any +} + +const f2 = function () { +>f2 : () => void +>function () { const i = new.target; const j = () => new.target;} : () => void + + const i = new.target; +>i : () => void +>new.target : () => void +>target : any + + const j = () => new.target; +>j : () => () => void +>() => new.target : () => () => void +>new.target : () => void +>target : any +} + +const O = { +>O : { k: () => any; } +>{ k: function () { return new.target; }} : { k: () => any; } + + k: function () { return new.target; } +>k : () => any +>function () { return new.target; } : () => any +>new.target : () => any +>target : any + +}; + + diff --git a/tests/baselines/reference/typeofStrictNull.js b/tests/baselines/reference/typeofStrictNull.js new file mode 100644 index 00000000000..520a72b9f0f --- /dev/null +++ b/tests/baselines/reference/typeofStrictNull.js @@ -0,0 +1,8 @@ +//// [typeofStrictNull.ts] + +let a: number; +let b: typeof a; + +//// [typeofStrictNull.js] +var a; +var b; diff --git a/tests/baselines/reference/typeofStrictNull.symbols b/tests/baselines/reference/typeofStrictNull.symbols new file mode 100644 index 00000000000..7b2dfb41797 --- /dev/null +++ b/tests/baselines/reference/typeofStrictNull.symbols @@ -0,0 +1,9 @@ +=== tests/cases/compiler/typeofStrictNull.ts === + +let a: number; +>a : Symbol(a, Decl(typeofStrictNull.ts, 1, 3)) + +let b: typeof a; +>b : Symbol(b, Decl(typeofStrictNull.ts, 2, 3)) +>a : Symbol(a, Decl(typeofStrictNull.ts, 1, 3)) + diff --git a/tests/baselines/reference/typeofStrictNull.types b/tests/baselines/reference/typeofStrictNull.types new file mode 100644 index 00000000000..59344727987 --- /dev/null +++ b/tests/baselines/reference/typeofStrictNull.types @@ -0,0 +1,9 @@ +=== tests/cases/compiler/typeofStrictNull.ts === + +let a: number; +>a : number + +let b: typeof a; +>b : number +>a : number + diff --git a/tests/cases/compiler/typeofStrictNull.ts b/tests/cases/compiler/typeofStrictNull.ts new file mode 100644 index 00000000000..ede2b857305 --- /dev/null +++ b/tests/cases/compiler/typeofStrictNull.ts @@ -0,0 +1,4 @@ +// @strictNullChecks: true + +let a: number; +let b: typeof a; \ No newline at end of file diff --git a/tests/cases/conformance/es6/newTarget/invalidNewTarget.es5.ts b/tests/cases/conformance/es6/newTarget/invalidNewTarget.es5.ts new file mode 100644 index 00000000000..cda2d4d2ce7 --- /dev/null +++ b/tests/cases/conformance/es6/newTarget/invalidNewTarget.es5.ts @@ -0,0 +1,25 @@ +// @target: es5 +const a = new.target; +const b = () => new.target; + +class C { + [new.target]() { } + c() { return new.target; } + get d() { return new.target; } + set e(_) { _ = new.target; } + f = () => new.target; + + static [new.target]() { } + static g() { return new.target; } + static get h() { return new.target; } + static set i(_) { _ = new.target; } + static j = () => new.target; +} + +const O = { + [new.target]: undefined, + k() { return new.target; }, + get l() { return new.target; }, + set m(_) { _ = new.target; }, + n: new.target, +}; \ No newline at end of file diff --git a/tests/cases/conformance/es6/newTarget/invalidNewTarget.es6.ts b/tests/cases/conformance/es6/newTarget/invalidNewTarget.es6.ts new file mode 100644 index 00000000000..5043c160e10 --- /dev/null +++ b/tests/cases/conformance/es6/newTarget/invalidNewTarget.es6.ts @@ -0,0 +1,25 @@ +// @target: es6 +const a = new.target; +const b = () => new.target; + +class C { + [new.target]() { } + c() { return new.target; } + get d() { return new.target; } + set e(_) { _ = new.target; } + f = () => new.target; + + static [new.target]() { } + static g() { return new.target; } + static get h() { return new.target; } + static set i(_) { _ = new.target; } + static j = () => new.target; +} + +const O = { + [new.target]: undefined, + k() { return new.target; }, + get l() { return new.target; }, + set m(_) { _ = new.target; }, + n: new.target, +}; \ No newline at end of file diff --git a/tests/cases/conformance/es6/newTarget/newTarget.es5.ts b/tests/cases/conformance/es6/newTarget/newTarget.es5.ts new file mode 100644 index 00000000000..b912f5f0596 --- /dev/null +++ b/tests/cases/conformance/es6/newTarget/newTarget.es5.ts @@ -0,0 +1,32 @@ +// @target: es5 +class A { + constructor() { + const a = new.target; + const b = () => new.target; + } + static c = function () { return new.target; } + d = function () { return new.target; } +} + +class B extends A { + constructor() { + super(); + const e = new.target; + const f = () => new.target; + } +} + +function f1() { + const g = new.target; + const h = () => new.target; +} + +const f2 = function () { + const i = new.target; + const j = () => new.target; +} + +const O = { + k: function () { return new.target; } +}; + diff --git a/tests/cases/conformance/es6/newTarget/newTarget.es6.ts b/tests/cases/conformance/es6/newTarget/newTarget.es6.ts new file mode 100644 index 00000000000..de61a49334a --- /dev/null +++ b/tests/cases/conformance/es6/newTarget/newTarget.es6.ts @@ -0,0 +1,32 @@ +// @target: es6 +class A { + constructor() { + const a = new.target; + const b = () => new.target; + } + static c = function () { return new.target; } + d = function () { return new.target; } +} + +class B extends A { + constructor() { + super(); + const e = new.target; + const f = () => new.target; + } +} + +function f1() { + const g = new.target; + const h = () => new.target; +} + +const f2 = function () { + const i = new.target; + const j = () => new.target; +} + +const O = { + k: function () { return new.target; } +}; + diff --git a/tests/cases/fourslash/importNameCodeFixUMDGlobal0.ts b/tests/cases/fourslash/importNameCodeFixUMDGlobal0.ts new file mode 100644 index 00000000000..3c780dc0af6 --- /dev/null +++ b/tests/cases/fourslash/importNameCodeFixUMDGlobal0.ts @@ -0,0 +1,16 @@ +/// + +// @Filename: a/f1.ts +//// [|export function test() { }; +//// bar1/*0*/.bar;|] + +// @Filename: a/foo.d.ts +//// export declare function bar(): number; +//// export as namespace bar1; + +verify.importFixAtPosition([ +`import * as bar1 from "./foo"; + +export function test() { }; +bar1.bar;` +]); \ No newline at end of file diff --git a/tests/cases/fourslash/importNameCodeFixUMDGlobal1.ts b/tests/cases/fourslash/importNameCodeFixUMDGlobal1.ts new file mode 100644 index 00000000000..96671ad6f91 --- /dev/null +++ b/tests/cases/fourslash/importNameCodeFixUMDGlobal1.ts @@ -0,0 +1,19 @@ +/// + +// @Filename: a/f1.ts +//// [|import { bar } from "./foo"; +//// +//// export function test() { }; +//// bar1/*0*/.bar();|] + +// @Filename: a/foo.d.ts +//// export declare function bar(): number; +//// export as namespace bar1; + +verify.importFixAtPosition([ +`import { bar } from "./foo"; +import * as bar1 from "./foo"; + +export function test() { }; +bar1.bar();` +]); \ No newline at end of file