From eac1bf80224374bf50206b777d6483b193b7cbf5 Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Tue, 21 Aug 2018 13:45:15 -0400 Subject: [PATCH 01/32] Update Travis-CI configuration to build es-private-fields branch --- .travis.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9479fffe76331..b2880174e294f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,11 +15,7 @@ matrix: branches: only: - - master - - release-2.7 - - release-2.8 - - release-2.9 - - release-3.0 + - es-private-fields install: - npm uninstall typescript --no-save From 548c9f8bebd51e912c78e4c722eb5deb78256989 Mon Sep 17 00:00:00 2001 From: Max Heiber Date: Sun, 8 Jul 2018 17:53:36 -0400 Subject: [PATCH 02/32] Parse Private Names and check that private names not used in parameters Signed-off-by: Max Heiber --- src/compiler/binder.ts | 13 +- src/compiler/checker.ts | 31 +- src/compiler/diagnosticMessages.json | 8 + src/compiler/emitter.ts | 16 +- src/compiler/factory.ts | 22 +- src/compiler/parser.ts | 29 +- src/compiler/scanner.ts | 14 + src/compiler/transformers/destructuring.ts | 3 +- src/compiler/transformers/es2015.ts | 3 +- src/compiler/transformers/es5.ts | 5 +- src/compiler/transformers/ts.ts | 2 +- src/compiler/types.ts | 18 +- src/compiler/utilities.ts | 40 +- src/compiler/visitor.ts | 2 +- src/services/codefixes/convertToEs6Module.ts | 2 +- src/services/refactors/moveToNewFile.ts | 2 +- src/services/types.ts | 4 + .../MemberFunctionDeclaration8_es6.errors.txt | 5 +- .../MemberFunctionDeclaration8_es6.js | 5 +- .../MemberFunctionDeclaration8_es6.symbols | 3 +- .../MemberFunctionDeclaration8_es6.types | 3 +- .../reference/api/tsserverlibrary.d.ts | 530 +++++++++--------- tests/baselines/reference/api/typescript.d.ts | 530 +++++++++--------- .../parseErrorInHeritageClause1.errors.txt | 5 +- .../reference/parseErrorInHeritageClause1.js | 5 +- .../parseErrorInHeritageClause1.symbols | 3 +- .../parseErrorInHeritageClause1.types | 3 +- .../parserErrorRecovery_Block2.errors.txt | 5 +- .../reference/parserErrorRecovery_Block2.js | 5 +- .../parserErrorRecovery_Block2.symbols | 3 +- .../parserErrorRecovery_Block2.types | 3 +- ...rserErrorRecovery_ClassElement3.errors.txt | 9 +- .../parserErrorRecovery_ClassElement3.js | 5 +- .../parserErrorRecovery_ClassElement3.symbols | 5 +- .../parserErrorRecovery_ClassElement3.types | 5 +- ...serErrorRecovery_ParameterList4.errors.txt | 5 +- .../parserErrorRecovery_ParameterList4.js | 5 +- ...parserErrorRecovery_ParameterList4.symbols | 3 +- .../parserErrorRecovery_ParameterList4.types | 3 +- .../parserSkippedTokens16.errors.txt | 5 +- .../reference/parserSkippedTokens16.js | 5 +- .../reference/parserSkippedTokens16.symbols | 2 +- .../reference/parserSkippedTokens16.types | 3 +- .../privateNameAndIndexSignature.errors.txt | 13 + .../reference/privateNameAndIndexSignature.js | 16 + .../privateNameAndIndexSignature.symbols | 15 + .../privateNameAndIndexSignature.types | 18 + tests/baselines/reference/privateNameField.js | 15 + .../reference/privateNameField.symbols | 16 + .../reference/privateNameField.types | 17 + .../reference/shebangError.errors.txt | 9 +- .../compiler/parseErrorInHeritageClause1.ts | 4 +- .../privateNameAndIndexSignature.ts | 6 + .../members/privateNames/privateNameField.ts | 6 + .../MemberFunctionDeclaration8_es6.ts | 4 +- .../Blocks/parserErrorRecovery_Block2.ts | 4 +- .../parserErrorRecovery_ClassElement3.ts | 4 +- .../parserErrorRecovery_ParameterList4.ts | 4 +- .../SkippedTokens/parserSkippedTokens16.ts | 4 +- tests/cases/fourslash/hoverOverPrivateName.ts | 15 + 60 files changed, 920 insertions(+), 627 deletions(-) create mode 100644 tests/baselines/reference/privateNameAndIndexSignature.errors.txt create mode 100644 tests/baselines/reference/privateNameAndIndexSignature.js create mode 100644 tests/baselines/reference/privateNameAndIndexSignature.symbols create mode 100644 tests/baselines/reference/privateNameAndIndexSignature.types create mode 100644 tests/baselines/reference/privateNameField.js create mode 100644 tests/baselines/reference/privateNameField.symbols create mode 100644 tests/baselines/reference/privateNameField.types create mode 100644 tests/cases/conformance/classes/members/privateNames/privateNameAndIndexSignature.ts create mode 100644 tests/cases/conformance/classes/members/privateNames/privateNameField.ts create mode 100644 tests/cases/fourslash/hoverOverPrivateName.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 44e6487c7c423..ebc43e006bdfc 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -266,6 +266,9 @@ namespace ts { Debug.assert(isWellKnownSymbolSyntactically(nameExpression)); return getPropertyNameForKnownSymbolName(idText((nameExpression).name)); } + if (isPrivateName(node)) { + return nodePosToString(node) as __String; + } return isPropertyNameLiteral(name) ? getEscapedTextOfIdentifierOrLiteral(name) : undefined; } switch (node.kind) { @@ -1394,7 +1397,7 @@ namespace ts { } if (node.expression.kind === SyntaxKind.PropertyAccessExpression) { const propertyAccess = node.expression; - if (isNarrowableOperand(propertyAccess.expression) && isPushOrUnshiftIdentifier(propertyAccess.name)) { + if (isIdentifier(propertyAccess.name) && isNarrowableOperand(propertyAccess.expression) && isPushOrUnshiftIdentifier(propertyAccess.name)) { currentFlow = createFlowArrayMutation(currentFlow, node); } } @@ -2359,7 +2362,7 @@ namespace ts { return; } const lhs = node.left as PropertyAccessEntityNameExpression; - const symbol = forEachIdentifierInEntityName(lhs.expression, /*parent*/ undefined, (id, symbol) => { + const symbol = forEachIdentifierOrPrivateNameInEntityName(lhs.expression, /*parent*/ undefined, (id, symbol) => { if (symbol) { addDeclarationToSymbol(symbol, id, SymbolFlags.Module | SymbolFlags.JSContainer); } @@ -2518,7 +2521,7 @@ namespace ts { // make symbols or add declarations for intermediate containers const flags = SymbolFlags.Module | SymbolFlags.JSContainer; const excludeFlags = SymbolFlags.ValueModuleExcludes & ~SymbolFlags.JSContainer; - namespaceSymbol = forEachIdentifierInEntityName(propertyAccess.expression, namespaceSymbol, (id, symbol, parent) => { + namespaceSymbol = forEachIdentifierOrPrivateNameInEntityName(propertyAccess.expression, namespaceSymbol, (id, symbol, parent) => { if (symbol) { addDeclarationToSymbol(symbol, id, flags); return symbol; @@ -2590,7 +2593,7 @@ namespace ts { } } - function forEachIdentifierInEntityName(e: EntityNameExpression, parent: Symbol | undefined, action: (e: Identifier, symbol: Symbol | undefined, parent: Symbol | undefined) => Symbol | undefined): Symbol | undefined { + function forEachIdentifierOrPrivateNameInEntityName(e: EntityNameExpression, parent: Symbol | undefined, action: (e: Identifier | PrivateName, symbol: Symbol | undefined, parent: Symbol | undefined) => Symbol | undefined): Symbol | undefined { if (isExportsOrModuleExportsOrAlias(file, e)) { return file.symbol; } @@ -2598,7 +2601,7 @@ namespace ts { return action(e, lookupSymbolForPropertyAccess(e), parent); } else { - const s = forEachIdentifierInEntityName(e.expression, parent, action); + const s = forEachIdentifierOrPrivateNameInEntityName(e.expression, parent, action); if (!s || !s.exports) return Debug.fail(); return action(e.name, s.exports.get(e.name.escapedText), s); } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0b357bd771da4..bb68b71a02e2d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14346,8 +14346,10 @@ namespace ts { const root = getReferenceRoot(node); const parent = root.parent; const isLengthPushOrUnshift = parent.kind === SyntaxKind.PropertyAccessExpression && ( - (parent).name.escapedText === "length" || - parent.parent.kind === SyntaxKind.CallExpression && isPushOrUnshiftIdentifier((parent).name)); + (parent).name.escapedText === "length" || ( + parent.parent.kind === SyntaxKind.CallExpression + && isIdentifier((parent as PropertyAccessExpression).name) + && isPushOrUnshiftIdentifier((parent as PropertyAccessExpression).name as Identifier))); const isElementAssignment = parent.kind === SyntaxKind.ElementAccessExpression && (parent).expression === root && parent.parent.kind === SyntaxKind.BinaryExpression && @@ -17972,7 +17974,7 @@ namespace ts { return checkPropertyAccessExpressionOrQualifiedName(node, node.left, node.right); } - function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, right: Identifier) { + function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, right: Identifier | PrivateName) { let propType: Type; const leftType = checkNonNullExpression(left); const parentSymbol = getNodeLinks(left).resolvedSymbol; @@ -17990,7 +17992,7 @@ namespace ts { } if (!prop) { const indexInfo = getIndexInfoOfType(apparentType, IndexKind.String); - if (!(indexInfo && indexInfo.type)) { + if (!(indexInfo && indexInfo.type) || isPrivateName(right)) { if (isJSLiteralType(leftType)) { return anyType; } @@ -18048,7 +18050,7 @@ namespace ts { return assignmentKind ? getBaseTypeOfLiteralType(flowType) : flowType; } - function checkPropertyNotUsedBeforeDeclaration(prop: Symbol, node: PropertyAccessExpression | QualifiedName, right: Identifier): void { + function checkPropertyNotUsedBeforeDeclaration(prop: Symbol, node: PropertyAccessExpression | QualifiedName, right: Identifier | PrivateName): void { const { valueDeclaration } = prop; if (!valueDeclaration) { return; @@ -18118,7 +18120,7 @@ namespace ts { return getIntersectionType(x); } - function reportNonexistentProperty(propNode: Identifier, containingType: Type) { + function reportNonexistentProperty(propNode: Identifier | PrivateName, containingType: Type) { let errorInfo: DiagnosticMessageChain | undefined; let relatedInfo: Diagnostic | undefined; if (containingType.flags & TypeFlags.Union && !(containingType.flags & TypeFlags.Primitive)) { @@ -18161,11 +18163,11 @@ namespace ts { return prop !== undefined && prop.valueDeclaration && hasModifier(prop.valueDeclaration, ModifierFlags.Static); } - function getSuggestedSymbolForNonexistentProperty(name: Identifier | string, containingType: Type): Symbol | undefined { + function getSuggestedSymbolForNonexistentProperty(name: Identifier | PrivateName | string, containingType: Type): Symbol | undefined { return getSpellingSuggestionForName(isString(name) ? name : idText(name), getPropertiesOfType(containingType), SymbolFlags.Value); } - function getSuggestionForNonexistentProperty(name: Identifier | string, containingType: Type): string | undefined { + function getSuggestionForNonexistentProperty(name: Identifier | PrivateName | string, containingType: Type): string | undefined { const suggestion = getSuggestedSymbolForNonexistentProperty(name, containingType); return suggestion && symbolName(suggestion); } @@ -21876,6 +21878,9 @@ namespace ts { checkGrammarDecoratorsAndModifiers(node); checkVariableLikeDeclaration(node); + if (node.name && isIdentifier(node.name) && node.name.originalKeywordKind === SyntaxKind.PrivateName) { + error(node, Diagnostics.Private_names_cannot_be_used_as_parameters); + } const func = getContainingFunction(node)!; if (hasModifier(node, ModifierFlags.ParameterPropertyModifier)) { if (!(func.kind === SyntaxKind.Constructor && nodeIsPresent(func.body))) { @@ -23523,9 +23528,9 @@ namespace ts { } } - function getIdentifierFromEntityNameExpression(node: Identifier | PropertyAccessExpression): Identifier; - function getIdentifierFromEntityNameExpression(node: Expression): Identifier | undefined; - function getIdentifierFromEntityNameExpression(node: Expression): Identifier | undefined { + function getIdentifierFromEntityNameExpression(node: Identifier | PropertyAccessExpression): Identifier | PrivateName; + function getIdentifierFromEntityNameExpression(node: Expression): Identifier | PrivateName | undefined; + function getIdentifierFromEntityNameExpression(node: Expression): Identifier | PrivateName | undefined { switch (node.kind) { case SyntaxKind.Identifier: return node as Identifier; @@ -29288,6 +29293,10 @@ namespace ts { checkESModuleMarker(node.name); } + if (isIdentifier(node.name) && node.name.originalKeywordKind === SyntaxKind.PrivateName) { + return grammarErrorOnNode(node.name, Diagnostics.Private_names_are_not_allowed_in_variable_declarations); + } + const checkLetConstNames = (isLet(node) || isVarConst(node)); // 1. LexicalDeclaration : LetOrConst BindingList ; diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 6000c48de4dc3..a1d6859db7154 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -4166,6 +4166,14 @@ "category": "Error", "code": 18003 }, + "Private names are not allowed in variable declarations.": { + "category": "Error", + "code": 18004 + }, + "Private names cannot be used as parameters": { + "category": "Error", + "code": 18005 + }, "File is a CommonJS module; it may be converted to an ES6 module.": { "category": "Suggestion", diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index badbfc4fa3fa6..a9abafc38123e 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -609,6 +609,10 @@ namespace ts { case SyntaxKind.Identifier: return emitIdentifier(node); + // PrivateNames + case SyntaxKind.PrivateName: + return emitPrivateName(node as PrivateName); + // Parse tree nodes // Names @@ -878,6 +882,10 @@ namespace ts { case SyntaxKind.Identifier: return emitIdentifier(node); + // Private Names + case SyntaxKind.PrivateName: + return emitPrivateName(node as PrivateName); + // Reserved words case SyntaxKind.FalseKeyword: case SyntaxKind.NullKeyword: @@ -1067,6 +1075,12 @@ namespace ts { emitList(node, node.typeArguments, ListFormat.TypeParameters); // Call emitList directly since it could be an array of TypeParameterDeclarations _or_ type arguments } + function emitPrivateName(node: PrivateName) { + const writeText = node.symbol ? writeSymbol : write; + writeText(getTextOfNode(node, /*includeTrivia*/ false), node.symbol); + emitList(node, /*typeArguments*/ undefined, ListFormat.TypeParameters); // Call emitList directly since it could be an array of TypeParameterDeclarations _or_ type arguments + } + // // Names // @@ -3302,7 +3316,7 @@ namespace ts { function getLiteralTextOfNode(node: LiteralLikeNode): string { if (node.kind === SyntaxKind.StringLiteral && (node).textSourceNode) { const textSourceNode = (node).textSourceNode!; - if (isIdentifier(textSourceNode)) { + if (isIdentifierOrPrivateName(textSourceNode)) { return getEmitFlags(node) & EmitFlags.NoAsciiEscaping ? `"${escapeString(getTextOfNode(textSourceNode))}"` : `"${escapeNonAsciiString(getTextOfNode(textSourceNode))}"`; diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 4bb374682e087..154416b78567c 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -105,7 +105,7 @@ namespace ts { return node; } - function createLiteralFromNode(sourceNode: PropertyNameLiteral): StringLiteral { + function createLiteralFromNode(sourceNode: Exclude): StringLiteral { const node = createStringLiteral(getTextOfIdentifierOrLiteral(sourceNode)); node.textSourceNode = sourceNode; return node; @@ -995,7 +995,7 @@ namespace ts { : node; } - export function createPropertyAccess(expression: Expression, name: string | Identifier | undefined) { + export function createPropertyAccess(expression: Expression, name: string | Identifier | PrivateName | undefined) { const node = createSynthesizedNode(SyntaxKind.PropertyAccessExpression); node.expression = parenthesizeForAccess(expression); node.name = asName(name)!; // TODO: GH#18217 @@ -1003,7 +1003,7 @@ namespace ts { return node; } - export function updatePropertyAccess(node: PropertyAccessExpression, expression: Expression, name: Identifier) { + export function updatePropertyAccess(node: PropertyAccessExpression, expression: Expression, name: Identifier | PrivateName) { // Because we are updating existed propertyAccess we want to inherit its emitFlags // instead of using the default from createPropertyAccess return node.expression !== expression @@ -2714,7 +2714,7 @@ namespace ts { // Utilities - function asName(name: string | T): T | Identifier { + function asName(name: string | T): T | Identifier { return isString(name) ? createIdentifier(name) : name; } @@ -3099,7 +3099,7 @@ namespace ts { } else { const expression = setTextRange( - isIdentifier(memberName) + (isIdentifier(memberName) || isPrivateName(memberName)) ? createPropertyAccess(target, memberName) : createElementAccess(target, memberName), memberName @@ -3529,7 +3529,7 @@ namespace ts { } } - export function createExpressionForPropertyName(memberName: PropertyName): Expression { + export function createExpressionForPropertyName(memberName: Exclude): Expression { if (isIdentifier(memberName)) { return createLiteral(memberName); } @@ -3541,11 +3541,17 @@ namespace ts { } } + /** + * accessor declaration that can be converted to an expression (`name` field cannot be a `PrivateName`) + */ + type ExpressionableAccessorDeclaration = AccessorDeclaration & {name: Exclude}; + export function createExpressionForObjectLiteralElementLike(node: ObjectLiteralExpression, property: ObjectLiteralElementLike, receiver: Expression): Expression | undefined { switch (property.kind) { case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: - return createExpressionForAccessorDeclaration(node.properties, property, receiver, !!node.multiLine); + // type assertion `as ExpressionableAccessorDeclaration` is safe because PrivateNames are not allowed in object literals + return createExpressionForAccessorDeclaration(node.properties, property as ExpressionableAccessorDeclaration, receiver, !!node.multiLine); case SyntaxKind.PropertyAssignment: return createExpressionForPropertyAssignment(property, receiver); case SyntaxKind.ShorthandPropertyAssignment: @@ -3555,7 +3561,7 @@ namespace ts { } } - function createExpressionForAccessorDeclaration(properties: NodeArray, property: AccessorDeclaration, receiver: Expression, multiLine: boolean) { + function createExpressionForAccessorDeclaration(properties: NodeArray, property: ExpressionableAccessorDeclaration, receiver: Expression, multiLine: boolean) { const { firstAccessor, getAccessor, setAccessor } = getAllAccessorDeclarations(properties, property); if (property === firstAccessor) { const properties: ObjectLiteralElementLike[] = []; diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 096c3f163543c..bf7454d46c296 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1365,6 +1365,9 @@ namespace ts { if (allowComputedPropertyNames && token() === SyntaxKind.OpenBracketToken) { return parseComputedPropertyName(); } + if (token() === SyntaxKind.PrivateName) { + return parsePrivateName(); + } return parseIdentifierName(); } @@ -1388,6 +1391,17 @@ namespace ts { return finishNode(node); } + function createPrivateName(): PrivateName { + const node = createNode(SyntaxKind.PrivateName) as PrivateName; + node.escapedText = escapeLeadingUnderscores(scanner.getTokenText()); + nextToken(); + return finishNode(node); + } + + function parsePrivateName(): PrivateName { + return createPrivateName(); + } + function parseContextualModifier(t: SyntaxKind): boolean { return token() === t && tryParse(nextTokenCanFollowModifier); } @@ -2131,7 +2145,7 @@ namespace ts { break; } dotPos = scanner.getStartPos(); - entity = createQualifiedName(entity, parseRightSideOfDot(allowReservedWords)); + entity = createQualifiedName(entity, parseRightSideOfDot(allowReservedWords, /* allowPrivateNames */ false) as Identifier); } return entity; } @@ -2143,7 +2157,7 @@ namespace ts { return finishNode(node); } - function parseRightSideOfDot(allowIdentifierNames: boolean): Identifier { + function parseRightSideOfDot(allowIdentifierNames: boolean, allowPrivateNames: boolean): Identifier | PrivateName { // Technically a keyword is valid here as all identifiers and keywords are identifier names. // However, often we'll encounter this in error situations when the identifier or keyword // is actually starting another valid construct. @@ -2174,6 +2188,10 @@ namespace ts { } } + if (allowPrivateNames && token() === SyntaxKind.PrivateName) { + return parsePrivateName(); + } + return allowIdentifierNames ? parseIdentifierName() : parseIdentifier(); } @@ -4169,7 +4187,8 @@ namespace ts { const node = createNode(SyntaxKind.PropertyAccessExpression, expression.pos); node.expression = expression; parseExpectedToken(SyntaxKind.DotToken, Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access); - node.name = parseRightSideOfDot(/*allowIdentifierNames*/ true); + // private names will never work with `super` (`super.#foo`), but that's a semantic error, not syntactic + node.name = parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateNames*/ true); return finishNode(node); } @@ -4339,7 +4358,7 @@ namespace ts { while (parseOptional(SyntaxKind.DotToken)) { const propertyAccess: JsxTagNamePropertyAccess = createNode(SyntaxKind.PropertyAccessExpression, expression.pos); propertyAccess.expression = expression; - propertyAccess.name = parseRightSideOfDot(/*allowIdentifierNames*/ true); + propertyAccess.name = parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateNames*/ true); expression = finishNode(propertyAccess); } return expression; @@ -4442,7 +4461,7 @@ namespace ts { if (dotToken) { const propertyAccess = createNode(SyntaxKind.PropertyAccessExpression, expression.pos); propertyAccess.expression = expression; - propertyAccess.name = parseRightSideOfDot(/*allowIdentifierNames*/ true); + propertyAccess.name = parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateNames*/ true); expression = finishNode(propertyAccess); continue; } diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 61ce8330bff77..98a3c6c96cdb6 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -1723,6 +1723,20 @@ namespace ts { error(Diagnostics.Invalid_character); pos++; return token = SyntaxKind.Unknown; + case CharacterCodes.hash: + pos++; + if (isIdentifierStart(ch = text.charCodeAt(pos), languageVersion)) { + pos++; + while (pos < end && isIdentifierPart(ch = text.charCodeAt(pos), languageVersion)) pos++; + tokenValue = text.substring(tokenPos, pos); + if (ch === CharacterCodes.backslash) { + tokenValue += scanIdentifierParts(); + } + return token = SyntaxKind.PrivateName; + } + error(Diagnostics.Invalid_character); + // no `pos++` because already advanced at beginning of this `case` statement + return token = SyntaxKind.Unknown; default: if (isIdentifierStart(ch, languageVersion)) { pos++; diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index 14d1659dc7626..115cb76663c8d 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -535,7 +535,8 @@ namespace ts { const propertyNames: Expression[] = []; let computedTempVariableOffset = 0; for (let i = 0; i < elements.length - 1; i++) { - const propertyName = getPropertyNameOfBindingOrAssignmentElement(elements[i]); + // can safely assume property name is not a PrivateName because PrivateNames are not allowed in object literals + const propertyName = getPropertyNameOfBindingOrAssignmentElement(elements[i]) as Exclude; if (propertyName) { if (isComputedPropertyName(propertyName)) { const temp = computedTempVariables[computedTempVariableOffset]; diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index bffdc5809b0e8..da0de696608fd 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -1642,7 +1642,8 @@ namespace ts { setEmitFlags(target, EmitFlags.NoComments | EmitFlags.NoTrailingSourceMap); setSourceMapRange(target, firstAccessor.name); // TODO: GH#18217 - const propertyName = createExpressionForPropertyName(visitNode(firstAccessor.name, visitor, isPropertyName)); + // TODO: GH#9950 get rid of this type assertion and handle private names + const propertyName = createExpressionForPropertyName(visitNode(firstAccessor.name, visitor, isPropertyName) as Exclude); setEmitFlags(propertyName, EmitFlags.NoComments | EmitFlags.NoLeadingSourceMap); setSourceMapRange(propertyName, firstAccessor.name); diff --git a/src/compiler/transformers/es5.ts b/src/compiler/transformers/es5.ts index 1c85e684e8cba..36ff996dca594 100644 --- a/src/compiler/transformers/es5.ts +++ b/src/compiler/transformers/es5.ts @@ -82,7 +82,10 @@ namespace ts { * @param node A PropertyAccessExpression */ function substitutePropertyAccessExpression(node: PropertyAccessExpression): Expression { - const literalName = trySubstituteReservedName(node.name); + if (isPrivateName(node)) { + return node; + } + const literalName = trySubstituteReservedName(node.name as Identifier); if (literalName) { return setTextRange(createElementAccess(node.expression, literalName), node); } diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 7af0b7c5ad77c..6eb8b6e0ef634 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -2136,7 +2136,7 @@ namespace ts { ? getGeneratedNameForNode(name) : name.expression; } - else if (isIdentifier(name)) { + else if (isIdentifier(name) || isPrivateName(name)) { return createLiteral(idText(name)); } else { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 8696512071d54..4b2357bc63e77 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -116,8 +116,9 @@ namespace ts { AmpersandEqualsToken, BarEqualsToken, CaretEqualsToken, - // Identifiers + // Identifiers and PrivateNames Identifier, + PrivateName, // Reserved words BreakKeyword, CaseKeyword, @@ -711,9 +712,9 @@ namespace ts { export type EntityName = Identifier | QualifiedName; - export type PropertyName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName; + export type PropertyName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName | PrivateName; - export type DeclarationName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName | BindingPattern; + export type DeclarationName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName | PrivateName | BindingPattern; export interface Declaration extends Node { _declarationBrand: any; @@ -743,6 +744,13 @@ namespace ts { expression: Expression; } + export interface PrivateName extends Declaration { + kind: SyntaxKind.PrivateName; + // escaping not strictly necessary + // avoids gotchas in transforms and utils + escapedText: __String; + } + /* @internal */ // A name that supports late-binding (used in checker) export interface LateBoundName extends ComputedPropertyName { @@ -1180,7 +1188,7 @@ namespace ts { export interface StringLiteral extends LiteralExpression { kind: SyntaxKind.StringLiteral; - /* @internal */ textSourceNode?: Identifier | StringLiteralLike | NumericLiteral; // Allows a StringLiteral to get its text from another node (used by transforms). + /* @internal */ textSourceNode?: Identifier | PrivateName | StringLiteralLike | NumericLiteral; // Allows a StringLiteral to get its text from another node (used by transforms). /** Note: this is only set when synthesizing a node, not during parsing. */ /* @internal */ singleQuote?: boolean; } @@ -1661,7 +1669,7 @@ namespace ts { export interface PropertyAccessExpression extends MemberExpression, NamedDeclaration { kind: SyntaxKind.PropertyAccessExpression; expression: LeftHandSideExpression; - name: Identifier; + name: Identifier | PrivateName; } export interface SuperPropertyAccessExpression extends PropertyAccessExpression { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 33dfd2617c979..b8e12539e07da 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -766,6 +766,7 @@ namespace ts { export function getTextOfPropertyName(name: PropertyName): __String { switch (name.kind) { case SyntaxKind.Identifier: + case SyntaxKind.PrivateName: return name.escapedText; case SyntaxKind.StringLiteral: case SyntaxKind.NumericLiteral: @@ -784,7 +785,15 @@ namespace ts { case SyntaxKind.QualifiedName: return entityNameToString(name.left) + "." + entityNameToString(name.right); case SyntaxKind.PropertyAccessExpression: - return entityNameToString(name.expression) + "." + entityNameToString(name.name); + if (isIdentifier(name.name)) { + return entityNameToString(name.expression) + "." + entityNameToString(name.name); + } + else if (isPrivateName(name.name)) { + return getTextOfNode(name); + } + else { + throw Debug.assertNever(name.name); + } default: throw Debug.assertNever(name); } @@ -1869,7 +1878,7 @@ namespace ts { (initializer.expression.escapedText === "window" as __String || initializer.expression.escapedText === "self" as __String || initializer.expression.escapedText === "global" as __String)) && - isSameEntityName(name, initializer.name); + isSameEntityName(name, initializer.name as Identifier); } if (isPropertyAccessExpression(name) && isPropertyAccessExpression(initializer)) { return name.name.escapedText === initializer.name.escapedText && isSameEntityName(name.expression, initializer.expression); @@ -2618,6 +2627,7 @@ namespace ts { export function getPropertyNameForPropertyNameNode(name: PropertyName): __String | undefined { switch (name.kind) { case SyntaxKind.Identifier: + case SyntaxKind.PrivateName: return name.escapedText; case SyntaxKind.StringLiteral: case SyntaxKind.NumericLiteral: @@ -2636,10 +2646,12 @@ namespace ts { } } - export type PropertyNameLiteral = Identifier | StringLiteralLike | NumericLiteral; + export type PropertyNameLiteral = Identifier | PrivateName | StringLiteralLike | NumericLiteral; export function isPropertyNameLiteral(node: Node): node is PropertyNameLiteral { switch (node.kind) { case SyntaxKind.Identifier: + // TODO: should this be here? + case SyntaxKind.PrivateName: case SyntaxKind.StringLiteral: case SyntaxKind.NoSubstitutionTemplateLiteral: case SyntaxKind.NumericLiteral: @@ -2649,11 +2661,11 @@ namespace ts { } } export function getTextOfIdentifierOrLiteral(node: PropertyNameLiteral): string { - return node.kind === SyntaxKind.Identifier ? idText(node) : node.text; + return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.PrivateName ? idText(node) : node.text; } export function getEscapedTextOfIdentifierOrLiteral(node: PropertyNameLiteral): __String { - return node.kind === SyntaxKind.Identifier ? node.escapedText : escapeLeadingUnderscores(node.text); + return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.PrivateName ? node.escapedText : escapeLeadingUnderscores(node.text); } export function getPropertyNameForKnownSymbolName(symbolName: string): __String { @@ -3313,7 +3325,7 @@ namespace ts { } export function isThisIdentifier(node: Node | undefined): boolean { - return !!node && node.kind === SyntaxKind.Identifier && identifierIsThisKeyword(node as Identifier); + return !!node && isIdentifier(node) && identifierIsThisKeyword(node); } export function identifierIsThisKeyword(id: Identifier): boolean { @@ -4832,8 +4844,8 @@ namespace ts { return id.length >= 3 && id.charCodeAt(0) === CharacterCodes._ && id.charCodeAt(1) === CharacterCodes._ && id.charCodeAt(2) === CharacterCodes._ ? id.substr(1) : id; } - export function idText(identifier: Identifier): string { - return unescapeLeadingUnderscores(identifier.escapedText); + export function idText(identifierOrPrivateName: Identifier | PrivateName): string { + return unescapeLeadingUnderscores(identifierOrPrivateName.escapedText); } export function symbolName(symbol: Symbol): string { return unescapeLeadingUnderscores(symbol.escapedName); @@ -4844,7 +4856,7 @@ namespace ts { * attempt to draw the name from the node the declaration is on (as that declaration is what its' symbol * will be merged with) */ - function nameForNamelessJSDocTypedef(declaration: JSDocTypedefTag): Identifier | undefined { + function nameForNamelessJSDocTypedef(declaration: JSDocTypedefTag): Identifier | PrivateName | undefined { const hostNode = declaration.parent.parent; if (!hostNode) { return undefined; @@ -4893,7 +4905,7 @@ namespace ts { return name && isIdentifier(name) ? name : undefined; } - export function getNameOfJSDocTypedef(declaration: JSDocTypedefTag): Identifier | undefined { + export function getNameOfJSDocTypedef(declaration: JSDocTypedefTag): Identifier | PrivateName | undefined { return declaration.name || nameForNamelessJSDocTypedef(declaration); } @@ -5172,6 +5184,10 @@ namespace ts { return node.kind === SyntaxKind.Identifier; } + export function isIdentifierOrPrivateName(node: Node): node is Identifier | PrivateName { + return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.PrivateName; + } + // Names export function isQualifiedName(node: Node): node is QualifiedName { @@ -5182,6 +5198,10 @@ namespace ts { return node.kind === SyntaxKind.ComputedPropertyName; } + export function isPrivateName(node: Node): node is PrivateName { + return node.kind === SyntaxKind.PrivateName; + } + // Signature elements export function isTypeParameterDeclaration(node: Node): node is TypeParameterDeclaration { diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index 2cfb469f15296..f4cfacda7d87a 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -464,7 +464,7 @@ namespace ts { case SyntaxKind.PropertyAccessExpression: return updatePropertyAccess(node, visitNode((node).expression, visitor, isExpression), - visitNode((node).name, visitor, isIdentifier)); + visitNode((node).name, visitor, isIdentifierOrPrivateName)); case SyntaxKind.ElementAccessExpression: return updateElementAccess(node, diff --git a/src/services/codefixes/convertToEs6Module.ts b/src/services/codefixes/convertToEs6Module.ts index 87a1f49cc4864..da486b47b1192 100644 --- a/src/services/codefixes/convertToEs6Module.ts +++ b/src/services/codefixes/convertToEs6Module.ts @@ -65,7 +65,7 @@ namespace ts.codefix { function collectExportRenames(sourceFile: SourceFile, checker: TypeChecker, identifiers: Identifiers): ExportRenames { const res = createMap(); forEachExportReference(sourceFile, node => { - const { text, originalKeywordKind } = node.name; + const { text, originalKeywordKind } = node.name as Identifier; if (!res.has(text) && (originalKeywordKind !== undefined && isNonContextualKeyword(originalKeywordKind) || checker.resolveName(node.name.text, node, SymbolFlags.Value, /*excludeGlobals*/ true))) { // Unconditionally add an underscore in case `text` is a keyword. diff --git a/src/services/refactors/moveToNewFile.ts b/src/services/refactors/moveToNewFile.ts index 9953293e3d1fa..7161e26f28ace 100644 --- a/src/services/refactors/moveToNewFile.ts +++ b/src/services/refactors/moveToNewFile.ts @@ -665,7 +665,7 @@ namespace ts.refactor { } function nameOfTopLevelDeclaration(d: TopLevelDeclaration): Identifier | undefined { - return d.kind === SyntaxKind.ExpressionStatement ? d.expression.left.name : tryCast(d.name, isIdentifier); + return d.kind === SyntaxKind.ExpressionStatement ? d.expression.left.name as Identifier : tryCast(d.name, isIdentifier); } function getTopLevelDeclarationStatement(d: TopLevelDeclaration): TopLevelDeclarationStatement { diff --git a/src/services/types.ts b/src/services/types.ts index 51c98724c0957..6f919b07ec6c0 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -28,6 +28,10 @@ namespace ts { readonly text: string; } + export interface PrivateName { + readonly text: string; + } + export interface Symbol { readonly name: string; getFlags(): SymbolFlags; diff --git a/tests/baselines/reference/MemberFunctionDeclaration8_es6.errors.txt b/tests/baselines/reference/MemberFunctionDeclaration8_es6.errors.txt index 94198b36c9033..00b2ae4b02942 100644 --- a/tests/baselines/reference/MemberFunctionDeclaration8_es6.errors.txt +++ b/tests/baselines/reference/MemberFunctionDeclaration8_es6.errors.txt @@ -9,7 +9,7 @@ tests/cases/conformance/es6/memberFunctionDeclarations/MemberFunctionDeclaration class C { foo() { // Make sure we don't think of *bar as the start of a generator method. - if (a) # * bar; + if (a) ¬ * bar; ~ !!! error TS2304: Cannot find name 'a'. @@ -22,4 +22,5 @@ tests/cases/conformance/es6/memberFunctionDeclarations/MemberFunctionDeclaration ~~~ !!! error TS2304: Cannot find name 'bar'. } - } \ No newline at end of file + } + \ No newline at end of file diff --git a/tests/baselines/reference/MemberFunctionDeclaration8_es6.js b/tests/baselines/reference/MemberFunctionDeclaration8_es6.js index 853310e5a3efe..4fba30e9659b8 100644 --- a/tests/baselines/reference/MemberFunctionDeclaration8_es6.js +++ b/tests/baselines/reference/MemberFunctionDeclaration8_es6.js @@ -2,10 +2,11 @@ class C { foo() { // Make sure we don't think of *bar as the start of a generator method. - if (a) # * bar; + if (a) ¬ * bar; return bar; } -} +} + //// [MemberFunctionDeclaration8_es6.js] class C { diff --git a/tests/baselines/reference/MemberFunctionDeclaration8_es6.symbols b/tests/baselines/reference/MemberFunctionDeclaration8_es6.symbols index 0229450477c63..35041420d6aa5 100644 --- a/tests/baselines/reference/MemberFunctionDeclaration8_es6.symbols +++ b/tests/baselines/reference/MemberFunctionDeclaration8_es6.symbols @@ -6,7 +6,8 @@ class C { >foo : Symbol(C.foo, Decl(MemberFunctionDeclaration8_es6.ts, 0, 9)) // Make sure we don't think of *bar as the start of a generator method. - if (a) # * bar; + if (a) ¬ * bar; return bar; } } + diff --git a/tests/baselines/reference/MemberFunctionDeclaration8_es6.types b/tests/baselines/reference/MemberFunctionDeclaration8_es6.types index b0234b4135ee3..9eacffd080c9d 100644 --- a/tests/baselines/reference/MemberFunctionDeclaration8_es6.types +++ b/tests/baselines/reference/MemberFunctionDeclaration8_es6.types @@ -6,7 +6,7 @@ class C { >foo : () => any // Make sure we don't think of *bar as the start of a generator method. - if (a) # * bar; + if (a) ¬ * bar; >a : any > : any >* bar : number @@ -17,3 +17,4 @@ class C { >bar : any } } + diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 5e992f3847a8b..1ab1a986d1ad1 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -144,261 +144,262 @@ declare namespace ts { BarEqualsToken = 69, CaretEqualsToken = 70, Identifier = 71, - BreakKeyword = 72, - CaseKeyword = 73, - CatchKeyword = 74, - ClassKeyword = 75, - ConstKeyword = 76, - ContinueKeyword = 77, - DebuggerKeyword = 78, - DefaultKeyword = 79, - DeleteKeyword = 80, - DoKeyword = 81, - ElseKeyword = 82, - EnumKeyword = 83, - ExportKeyword = 84, - ExtendsKeyword = 85, - FalseKeyword = 86, - FinallyKeyword = 87, - ForKeyword = 88, - FunctionKeyword = 89, - IfKeyword = 90, - ImportKeyword = 91, - InKeyword = 92, - InstanceOfKeyword = 93, - NewKeyword = 94, - NullKeyword = 95, - ReturnKeyword = 96, - SuperKeyword = 97, - SwitchKeyword = 98, - ThisKeyword = 99, - ThrowKeyword = 100, - TrueKeyword = 101, - TryKeyword = 102, - TypeOfKeyword = 103, - VarKeyword = 104, - VoidKeyword = 105, - WhileKeyword = 106, - WithKeyword = 107, - ImplementsKeyword = 108, - InterfaceKeyword = 109, - LetKeyword = 110, - PackageKeyword = 111, - PrivateKeyword = 112, - ProtectedKeyword = 113, - PublicKeyword = 114, - StaticKeyword = 115, - YieldKeyword = 116, - AbstractKeyword = 117, - AsKeyword = 118, - AnyKeyword = 119, - AsyncKeyword = 120, - AwaitKeyword = 121, - BooleanKeyword = 122, - ConstructorKeyword = 123, - DeclareKeyword = 124, - GetKeyword = 125, - InferKeyword = 126, - IsKeyword = 127, - KeyOfKeyword = 128, - ModuleKeyword = 129, - NamespaceKeyword = 130, - NeverKeyword = 131, - ReadonlyKeyword = 132, - RequireKeyword = 133, - NumberKeyword = 134, - ObjectKeyword = 135, - SetKeyword = 136, - StringKeyword = 137, - SymbolKeyword = 138, - TypeKeyword = 139, - UndefinedKeyword = 140, - UniqueKeyword = 141, - UnknownKeyword = 142, - FromKeyword = 143, - GlobalKeyword = 144, - OfKeyword = 145, - QualifiedName = 146, - ComputedPropertyName = 147, - TypeParameter = 148, - Parameter = 149, - Decorator = 150, - PropertySignature = 151, - PropertyDeclaration = 152, - MethodSignature = 153, - MethodDeclaration = 154, - Constructor = 155, - GetAccessor = 156, - SetAccessor = 157, - CallSignature = 158, - ConstructSignature = 159, - IndexSignature = 160, - TypePredicate = 161, - TypeReference = 162, - FunctionType = 163, - ConstructorType = 164, - TypeQuery = 165, - TypeLiteral = 166, - ArrayType = 167, - TupleType = 168, - OptionalType = 169, - RestType = 170, - UnionType = 171, - IntersectionType = 172, - ConditionalType = 173, - InferType = 174, - ParenthesizedType = 175, - ThisType = 176, - TypeOperator = 177, - IndexedAccessType = 178, - MappedType = 179, - LiteralType = 180, - ImportType = 181, - ObjectBindingPattern = 182, - ArrayBindingPattern = 183, - BindingElement = 184, - ArrayLiteralExpression = 185, - ObjectLiteralExpression = 186, - PropertyAccessExpression = 187, - ElementAccessExpression = 188, - CallExpression = 189, - NewExpression = 190, - TaggedTemplateExpression = 191, - TypeAssertionExpression = 192, - ParenthesizedExpression = 193, - FunctionExpression = 194, - ArrowFunction = 195, - DeleteExpression = 196, - TypeOfExpression = 197, - VoidExpression = 198, - AwaitExpression = 199, - PrefixUnaryExpression = 200, - PostfixUnaryExpression = 201, - BinaryExpression = 202, - ConditionalExpression = 203, - TemplateExpression = 204, - YieldExpression = 205, - SpreadElement = 206, - ClassExpression = 207, - OmittedExpression = 208, - ExpressionWithTypeArguments = 209, - AsExpression = 210, - NonNullExpression = 211, - MetaProperty = 212, - SyntheticExpression = 213, - TemplateSpan = 214, - SemicolonClassElement = 215, - Block = 216, - VariableStatement = 217, - EmptyStatement = 218, - ExpressionStatement = 219, - IfStatement = 220, - DoStatement = 221, - WhileStatement = 222, - ForStatement = 223, - ForInStatement = 224, - ForOfStatement = 225, - ContinueStatement = 226, - BreakStatement = 227, - ReturnStatement = 228, - WithStatement = 229, - SwitchStatement = 230, - LabeledStatement = 231, - ThrowStatement = 232, - TryStatement = 233, - DebuggerStatement = 234, - VariableDeclaration = 235, - VariableDeclarationList = 236, - FunctionDeclaration = 237, - ClassDeclaration = 238, - InterfaceDeclaration = 239, - TypeAliasDeclaration = 240, - EnumDeclaration = 241, - ModuleDeclaration = 242, - ModuleBlock = 243, - CaseBlock = 244, - NamespaceExportDeclaration = 245, - ImportEqualsDeclaration = 246, - ImportDeclaration = 247, - ImportClause = 248, - NamespaceImport = 249, - NamedImports = 250, - ImportSpecifier = 251, - ExportAssignment = 252, - ExportDeclaration = 253, - NamedExports = 254, - ExportSpecifier = 255, - MissingDeclaration = 256, - ExternalModuleReference = 257, - JsxElement = 258, - JsxSelfClosingElement = 259, - JsxOpeningElement = 260, - JsxClosingElement = 261, - JsxFragment = 262, - JsxOpeningFragment = 263, - JsxClosingFragment = 264, - JsxAttribute = 265, - JsxAttributes = 266, - JsxSpreadAttribute = 267, - JsxExpression = 268, - CaseClause = 269, - DefaultClause = 270, - HeritageClause = 271, - CatchClause = 272, - PropertyAssignment = 273, - ShorthandPropertyAssignment = 274, - SpreadAssignment = 275, - EnumMember = 276, - SourceFile = 277, - Bundle = 278, - UnparsedSource = 279, - InputFiles = 280, - JSDocTypeExpression = 281, - JSDocAllType = 282, - JSDocUnknownType = 283, - JSDocNullableType = 284, - JSDocNonNullableType = 285, - JSDocOptionalType = 286, - JSDocFunctionType = 287, - JSDocVariadicType = 288, - JSDocComment = 289, - JSDocTypeLiteral = 290, - JSDocSignature = 291, - JSDocTag = 292, - JSDocAugmentsTag = 293, - JSDocClassTag = 294, - JSDocCallbackTag = 295, - JSDocEnumTag = 296, - JSDocParameterTag = 297, - JSDocReturnTag = 298, - JSDocThisTag = 299, - JSDocTypeTag = 300, - JSDocTemplateTag = 301, - JSDocTypedefTag = 302, - JSDocPropertyTag = 303, - SyntaxList = 304, - NotEmittedStatement = 305, - PartiallyEmittedExpression = 306, - CommaListExpression = 307, - MergeDeclarationMarker = 308, - EndOfDeclarationMarker = 309, - Count = 310, + PrivateName = 72, + BreakKeyword = 73, + CaseKeyword = 74, + CatchKeyword = 75, + ClassKeyword = 76, + ConstKeyword = 77, + ContinueKeyword = 78, + DebuggerKeyword = 79, + DefaultKeyword = 80, + DeleteKeyword = 81, + DoKeyword = 82, + ElseKeyword = 83, + EnumKeyword = 84, + ExportKeyword = 85, + ExtendsKeyword = 86, + FalseKeyword = 87, + FinallyKeyword = 88, + ForKeyword = 89, + FunctionKeyword = 90, + IfKeyword = 91, + ImportKeyword = 92, + InKeyword = 93, + InstanceOfKeyword = 94, + NewKeyword = 95, + NullKeyword = 96, + ReturnKeyword = 97, + SuperKeyword = 98, + SwitchKeyword = 99, + ThisKeyword = 100, + ThrowKeyword = 101, + TrueKeyword = 102, + TryKeyword = 103, + TypeOfKeyword = 104, + VarKeyword = 105, + VoidKeyword = 106, + WhileKeyword = 107, + WithKeyword = 108, + ImplementsKeyword = 109, + InterfaceKeyword = 110, + LetKeyword = 111, + PackageKeyword = 112, + PrivateKeyword = 113, + ProtectedKeyword = 114, + PublicKeyword = 115, + StaticKeyword = 116, + YieldKeyword = 117, + AbstractKeyword = 118, + AsKeyword = 119, + AnyKeyword = 120, + AsyncKeyword = 121, + AwaitKeyword = 122, + BooleanKeyword = 123, + ConstructorKeyword = 124, + DeclareKeyword = 125, + GetKeyword = 126, + InferKeyword = 127, + IsKeyword = 128, + KeyOfKeyword = 129, + ModuleKeyword = 130, + NamespaceKeyword = 131, + NeverKeyword = 132, + ReadonlyKeyword = 133, + RequireKeyword = 134, + NumberKeyword = 135, + ObjectKeyword = 136, + SetKeyword = 137, + StringKeyword = 138, + SymbolKeyword = 139, + TypeKeyword = 140, + UndefinedKeyword = 141, + UniqueKeyword = 142, + UnknownKeyword = 143, + FromKeyword = 144, + GlobalKeyword = 145, + OfKeyword = 146, + QualifiedName = 147, + ComputedPropertyName = 148, + TypeParameter = 149, + Parameter = 150, + Decorator = 151, + PropertySignature = 152, + PropertyDeclaration = 153, + MethodSignature = 154, + MethodDeclaration = 155, + Constructor = 156, + GetAccessor = 157, + SetAccessor = 158, + CallSignature = 159, + ConstructSignature = 160, + IndexSignature = 161, + TypePredicate = 162, + TypeReference = 163, + FunctionType = 164, + ConstructorType = 165, + TypeQuery = 166, + TypeLiteral = 167, + ArrayType = 168, + TupleType = 169, + OptionalType = 170, + RestType = 171, + UnionType = 172, + IntersectionType = 173, + ConditionalType = 174, + InferType = 175, + ParenthesizedType = 176, + ThisType = 177, + TypeOperator = 178, + IndexedAccessType = 179, + MappedType = 180, + LiteralType = 181, + ImportType = 182, + ObjectBindingPattern = 183, + ArrayBindingPattern = 184, + BindingElement = 185, + ArrayLiteralExpression = 186, + ObjectLiteralExpression = 187, + PropertyAccessExpression = 188, + ElementAccessExpression = 189, + CallExpression = 190, + NewExpression = 191, + TaggedTemplateExpression = 192, + TypeAssertionExpression = 193, + ParenthesizedExpression = 194, + FunctionExpression = 195, + ArrowFunction = 196, + DeleteExpression = 197, + TypeOfExpression = 198, + VoidExpression = 199, + AwaitExpression = 200, + PrefixUnaryExpression = 201, + PostfixUnaryExpression = 202, + BinaryExpression = 203, + ConditionalExpression = 204, + TemplateExpression = 205, + YieldExpression = 206, + SpreadElement = 207, + ClassExpression = 208, + OmittedExpression = 209, + ExpressionWithTypeArguments = 210, + AsExpression = 211, + NonNullExpression = 212, + MetaProperty = 213, + SyntheticExpression = 214, + TemplateSpan = 215, + SemicolonClassElement = 216, + Block = 217, + VariableStatement = 218, + EmptyStatement = 219, + ExpressionStatement = 220, + IfStatement = 221, + DoStatement = 222, + WhileStatement = 223, + ForStatement = 224, + ForInStatement = 225, + ForOfStatement = 226, + ContinueStatement = 227, + BreakStatement = 228, + ReturnStatement = 229, + WithStatement = 230, + SwitchStatement = 231, + LabeledStatement = 232, + ThrowStatement = 233, + TryStatement = 234, + DebuggerStatement = 235, + VariableDeclaration = 236, + VariableDeclarationList = 237, + FunctionDeclaration = 238, + ClassDeclaration = 239, + InterfaceDeclaration = 240, + TypeAliasDeclaration = 241, + EnumDeclaration = 242, + ModuleDeclaration = 243, + ModuleBlock = 244, + CaseBlock = 245, + NamespaceExportDeclaration = 246, + ImportEqualsDeclaration = 247, + ImportDeclaration = 248, + ImportClause = 249, + NamespaceImport = 250, + NamedImports = 251, + ImportSpecifier = 252, + ExportAssignment = 253, + ExportDeclaration = 254, + NamedExports = 255, + ExportSpecifier = 256, + MissingDeclaration = 257, + ExternalModuleReference = 258, + JsxElement = 259, + JsxSelfClosingElement = 260, + JsxOpeningElement = 261, + JsxClosingElement = 262, + JsxFragment = 263, + JsxOpeningFragment = 264, + JsxClosingFragment = 265, + JsxAttribute = 266, + JsxAttributes = 267, + JsxSpreadAttribute = 268, + JsxExpression = 269, + CaseClause = 270, + DefaultClause = 271, + HeritageClause = 272, + CatchClause = 273, + PropertyAssignment = 274, + ShorthandPropertyAssignment = 275, + SpreadAssignment = 276, + EnumMember = 277, + SourceFile = 278, + Bundle = 279, + UnparsedSource = 280, + InputFiles = 281, + JSDocTypeExpression = 282, + JSDocAllType = 283, + JSDocUnknownType = 284, + JSDocNullableType = 285, + JSDocNonNullableType = 286, + JSDocOptionalType = 287, + JSDocFunctionType = 288, + JSDocVariadicType = 289, + JSDocComment = 290, + JSDocTypeLiteral = 291, + JSDocSignature = 292, + JSDocTag = 293, + JSDocAugmentsTag = 294, + JSDocClassTag = 295, + JSDocCallbackTag = 296, + JSDocEnumTag = 297, + JSDocParameterTag = 298, + JSDocReturnTag = 299, + JSDocThisTag = 300, + JSDocTypeTag = 301, + JSDocTemplateTag = 302, + JSDocTypedefTag = 303, + JSDocPropertyTag = 304, + SyntaxList = 305, + NotEmittedStatement = 306, + PartiallyEmittedExpression = 307, + CommaListExpression = 308, + MergeDeclarationMarker = 309, + EndOfDeclarationMarker = 310, + Count = 311, FirstAssignment = 58, LastAssignment = 70, FirstCompoundAssignment = 59, LastCompoundAssignment = 70, - FirstReservedWord = 72, - LastReservedWord = 107, - FirstKeyword = 72, - LastKeyword = 145, - FirstFutureReservedWord = 108, - LastFutureReservedWord = 116, - FirstTypeNode = 161, - LastTypeNode = 181, + FirstReservedWord = 73, + LastReservedWord = 108, + FirstKeyword = 73, + LastKeyword = 146, + FirstFutureReservedWord = 109, + LastFutureReservedWord = 117, + FirstTypeNode = 162, + LastTypeNode = 182, FirstPunctuation = 17, LastPunctuation = 70, FirstToken = 0, - LastToken = 145, + LastToken = 146, FirstTriviaToken = 2, LastTriviaToken = 7, FirstLiteralToken = 8, @@ -407,11 +408,11 @@ declare namespace ts { LastTemplateToken = 16, FirstBinaryOperator = 27, LastBinaryOperator = 70, - FirstNode = 146, - FirstJSDocNode = 281, - LastJSDocNode = 303, - FirstJSDocTagNode = 292, - LastJSDocTagNode = 303 + FirstNode = 147, + FirstJSDocNode = 282, + LastJSDocNode = 304, + FirstJSDocTagNode = 293, + LastJSDocTagNode = 304 } enum NodeFlags { None = 0, @@ -524,8 +525,8 @@ declare namespace ts { right: Identifier; } type EntityName = Identifier | QualifiedName; - type PropertyName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName; - type DeclarationName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName | BindingPattern; + type PropertyName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName | PrivateName; + type DeclarationName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName | PrivateName | BindingPattern; interface Declaration extends Node { _declarationBrand: any; } @@ -539,6 +540,10 @@ declare namespace ts { kind: SyntaxKind.ComputedPropertyName; expression: Expression; } + interface PrivateName extends Declaration { + kind: SyntaxKind.PrivateName; + escapedText: __String; + } interface Decorator extends Node { kind: SyntaxKind.Decorator; parent: NamedDeclaration; @@ -1046,7 +1051,7 @@ declare namespace ts { interface PropertyAccessExpression extends MemberExpression, NamedDeclaration { kind: SyntaxKind.PropertyAccessExpression; expression: LeftHandSideExpression; - name: Identifier; + name: Identifier | PrivateName; } interface SuperPropertyAccessExpression extends PropertyAccessExpression { expression: SuperExpression; @@ -3194,9 +3199,9 @@ declare namespace ts { * @returns The unescaped identifier text. */ function unescapeLeadingUnderscores(identifier: __String): string; - function idText(identifier: Identifier): string; + function idText(identifierOrPrivateName: Identifier | PrivateName): string; function symbolName(symbol: Symbol): string; - function getNameOfJSDocTypedef(declaration: JSDocTypedefTag): Identifier | undefined; + function getNameOfJSDocTypedef(declaration: JSDocTypedefTag): Identifier | PrivateName | undefined; function getNameOfDeclaration(declaration: Declaration | Expression): DeclarationName | undefined; /** * Gets the JSDoc parameter tags for the node if present. @@ -3273,8 +3278,10 @@ declare namespace ts { function isTemplateMiddle(node: Node): node is TemplateMiddle; function isTemplateTail(node: Node): node is TemplateTail; function isIdentifier(node: Node): node is Identifier; + function isIdentifierOrPrivateName(node: Node): node is Identifier | PrivateName; function isQualifiedName(node: Node): node is QualifiedName; function isComputedPropertyName(node: Node): node is ComputedPropertyName; + function isPrivateName(node: Node): node is PrivateName; function isTypeParameterDeclaration(node: Node): node is TypeParameterDeclaration; function isParameter(node: Node): node is ParameterDeclaration; function isDecorator(node: Node): node is Decorator; @@ -3734,8 +3741,8 @@ declare namespace ts { function updateArrayLiteral(node: ArrayLiteralExpression, elements: ReadonlyArray): ArrayLiteralExpression; function createObjectLiteral(properties?: ReadonlyArray, multiLine?: boolean): ObjectLiteralExpression; function updateObjectLiteral(node: ObjectLiteralExpression, properties: ReadonlyArray): ObjectLiteralExpression; - function createPropertyAccess(expression: Expression, name: string | Identifier | undefined): PropertyAccessExpression; - function updatePropertyAccess(node: PropertyAccessExpression, expression: Expression, name: Identifier): PropertyAccessExpression; + function createPropertyAccess(expression: Expression, name: string | Identifier | PrivateName | undefined): PropertyAccessExpression; + function updatePropertyAccess(node: PropertyAccessExpression, expression: Expression, name: Identifier | PrivateName): PropertyAccessExpression; function createElementAccess(expression: Expression, index: number | Expression): ElementAccessExpression; function updateElementAccess(node: ElementAccessExpression, expression: Expression, argumentExpression: Expression): ElementAccessExpression; function createCall(expression: Expression, typeArguments: ReadonlyArray | undefined, argumentsArray: ReadonlyArray | undefined): CallExpression; @@ -4510,6 +4517,9 @@ declare namespace ts { interface Identifier { readonly text: string; } + interface PrivateName { + readonly text: string; + } interface Symbol { readonly name: string; getFlags(): SymbolFlags; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 32761156558fd..ea78225538eac 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -144,261 +144,262 @@ declare namespace ts { BarEqualsToken = 69, CaretEqualsToken = 70, Identifier = 71, - BreakKeyword = 72, - CaseKeyword = 73, - CatchKeyword = 74, - ClassKeyword = 75, - ConstKeyword = 76, - ContinueKeyword = 77, - DebuggerKeyword = 78, - DefaultKeyword = 79, - DeleteKeyword = 80, - DoKeyword = 81, - ElseKeyword = 82, - EnumKeyword = 83, - ExportKeyword = 84, - ExtendsKeyword = 85, - FalseKeyword = 86, - FinallyKeyword = 87, - ForKeyword = 88, - FunctionKeyword = 89, - IfKeyword = 90, - ImportKeyword = 91, - InKeyword = 92, - InstanceOfKeyword = 93, - NewKeyword = 94, - NullKeyword = 95, - ReturnKeyword = 96, - SuperKeyword = 97, - SwitchKeyword = 98, - ThisKeyword = 99, - ThrowKeyword = 100, - TrueKeyword = 101, - TryKeyword = 102, - TypeOfKeyword = 103, - VarKeyword = 104, - VoidKeyword = 105, - WhileKeyword = 106, - WithKeyword = 107, - ImplementsKeyword = 108, - InterfaceKeyword = 109, - LetKeyword = 110, - PackageKeyword = 111, - PrivateKeyword = 112, - ProtectedKeyword = 113, - PublicKeyword = 114, - StaticKeyword = 115, - YieldKeyword = 116, - AbstractKeyword = 117, - AsKeyword = 118, - AnyKeyword = 119, - AsyncKeyword = 120, - AwaitKeyword = 121, - BooleanKeyword = 122, - ConstructorKeyword = 123, - DeclareKeyword = 124, - GetKeyword = 125, - InferKeyword = 126, - IsKeyword = 127, - KeyOfKeyword = 128, - ModuleKeyword = 129, - NamespaceKeyword = 130, - NeverKeyword = 131, - ReadonlyKeyword = 132, - RequireKeyword = 133, - NumberKeyword = 134, - ObjectKeyword = 135, - SetKeyword = 136, - StringKeyword = 137, - SymbolKeyword = 138, - TypeKeyword = 139, - UndefinedKeyword = 140, - UniqueKeyword = 141, - UnknownKeyword = 142, - FromKeyword = 143, - GlobalKeyword = 144, - OfKeyword = 145, - QualifiedName = 146, - ComputedPropertyName = 147, - TypeParameter = 148, - Parameter = 149, - Decorator = 150, - PropertySignature = 151, - PropertyDeclaration = 152, - MethodSignature = 153, - MethodDeclaration = 154, - Constructor = 155, - GetAccessor = 156, - SetAccessor = 157, - CallSignature = 158, - ConstructSignature = 159, - IndexSignature = 160, - TypePredicate = 161, - TypeReference = 162, - FunctionType = 163, - ConstructorType = 164, - TypeQuery = 165, - TypeLiteral = 166, - ArrayType = 167, - TupleType = 168, - OptionalType = 169, - RestType = 170, - UnionType = 171, - IntersectionType = 172, - ConditionalType = 173, - InferType = 174, - ParenthesizedType = 175, - ThisType = 176, - TypeOperator = 177, - IndexedAccessType = 178, - MappedType = 179, - LiteralType = 180, - ImportType = 181, - ObjectBindingPattern = 182, - ArrayBindingPattern = 183, - BindingElement = 184, - ArrayLiteralExpression = 185, - ObjectLiteralExpression = 186, - PropertyAccessExpression = 187, - ElementAccessExpression = 188, - CallExpression = 189, - NewExpression = 190, - TaggedTemplateExpression = 191, - TypeAssertionExpression = 192, - ParenthesizedExpression = 193, - FunctionExpression = 194, - ArrowFunction = 195, - DeleteExpression = 196, - TypeOfExpression = 197, - VoidExpression = 198, - AwaitExpression = 199, - PrefixUnaryExpression = 200, - PostfixUnaryExpression = 201, - BinaryExpression = 202, - ConditionalExpression = 203, - TemplateExpression = 204, - YieldExpression = 205, - SpreadElement = 206, - ClassExpression = 207, - OmittedExpression = 208, - ExpressionWithTypeArguments = 209, - AsExpression = 210, - NonNullExpression = 211, - MetaProperty = 212, - SyntheticExpression = 213, - TemplateSpan = 214, - SemicolonClassElement = 215, - Block = 216, - VariableStatement = 217, - EmptyStatement = 218, - ExpressionStatement = 219, - IfStatement = 220, - DoStatement = 221, - WhileStatement = 222, - ForStatement = 223, - ForInStatement = 224, - ForOfStatement = 225, - ContinueStatement = 226, - BreakStatement = 227, - ReturnStatement = 228, - WithStatement = 229, - SwitchStatement = 230, - LabeledStatement = 231, - ThrowStatement = 232, - TryStatement = 233, - DebuggerStatement = 234, - VariableDeclaration = 235, - VariableDeclarationList = 236, - FunctionDeclaration = 237, - ClassDeclaration = 238, - InterfaceDeclaration = 239, - TypeAliasDeclaration = 240, - EnumDeclaration = 241, - ModuleDeclaration = 242, - ModuleBlock = 243, - CaseBlock = 244, - NamespaceExportDeclaration = 245, - ImportEqualsDeclaration = 246, - ImportDeclaration = 247, - ImportClause = 248, - NamespaceImport = 249, - NamedImports = 250, - ImportSpecifier = 251, - ExportAssignment = 252, - ExportDeclaration = 253, - NamedExports = 254, - ExportSpecifier = 255, - MissingDeclaration = 256, - ExternalModuleReference = 257, - JsxElement = 258, - JsxSelfClosingElement = 259, - JsxOpeningElement = 260, - JsxClosingElement = 261, - JsxFragment = 262, - JsxOpeningFragment = 263, - JsxClosingFragment = 264, - JsxAttribute = 265, - JsxAttributes = 266, - JsxSpreadAttribute = 267, - JsxExpression = 268, - CaseClause = 269, - DefaultClause = 270, - HeritageClause = 271, - CatchClause = 272, - PropertyAssignment = 273, - ShorthandPropertyAssignment = 274, - SpreadAssignment = 275, - EnumMember = 276, - SourceFile = 277, - Bundle = 278, - UnparsedSource = 279, - InputFiles = 280, - JSDocTypeExpression = 281, - JSDocAllType = 282, - JSDocUnknownType = 283, - JSDocNullableType = 284, - JSDocNonNullableType = 285, - JSDocOptionalType = 286, - JSDocFunctionType = 287, - JSDocVariadicType = 288, - JSDocComment = 289, - JSDocTypeLiteral = 290, - JSDocSignature = 291, - JSDocTag = 292, - JSDocAugmentsTag = 293, - JSDocClassTag = 294, - JSDocCallbackTag = 295, - JSDocEnumTag = 296, - JSDocParameterTag = 297, - JSDocReturnTag = 298, - JSDocThisTag = 299, - JSDocTypeTag = 300, - JSDocTemplateTag = 301, - JSDocTypedefTag = 302, - JSDocPropertyTag = 303, - SyntaxList = 304, - NotEmittedStatement = 305, - PartiallyEmittedExpression = 306, - CommaListExpression = 307, - MergeDeclarationMarker = 308, - EndOfDeclarationMarker = 309, - Count = 310, + PrivateName = 72, + BreakKeyword = 73, + CaseKeyword = 74, + CatchKeyword = 75, + ClassKeyword = 76, + ConstKeyword = 77, + ContinueKeyword = 78, + DebuggerKeyword = 79, + DefaultKeyword = 80, + DeleteKeyword = 81, + DoKeyword = 82, + ElseKeyword = 83, + EnumKeyword = 84, + ExportKeyword = 85, + ExtendsKeyword = 86, + FalseKeyword = 87, + FinallyKeyword = 88, + ForKeyword = 89, + FunctionKeyword = 90, + IfKeyword = 91, + ImportKeyword = 92, + InKeyword = 93, + InstanceOfKeyword = 94, + NewKeyword = 95, + NullKeyword = 96, + ReturnKeyword = 97, + SuperKeyword = 98, + SwitchKeyword = 99, + ThisKeyword = 100, + ThrowKeyword = 101, + TrueKeyword = 102, + TryKeyword = 103, + TypeOfKeyword = 104, + VarKeyword = 105, + VoidKeyword = 106, + WhileKeyword = 107, + WithKeyword = 108, + ImplementsKeyword = 109, + InterfaceKeyword = 110, + LetKeyword = 111, + PackageKeyword = 112, + PrivateKeyword = 113, + ProtectedKeyword = 114, + PublicKeyword = 115, + StaticKeyword = 116, + YieldKeyword = 117, + AbstractKeyword = 118, + AsKeyword = 119, + AnyKeyword = 120, + AsyncKeyword = 121, + AwaitKeyword = 122, + BooleanKeyword = 123, + ConstructorKeyword = 124, + DeclareKeyword = 125, + GetKeyword = 126, + InferKeyword = 127, + IsKeyword = 128, + KeyOfKeyword = 129, + ModuleKeyword = 130, + NamespaceKeyword = 131, + NeverKeyword = 132, + ReadonlyKeyword = 133, + RequireKeyword = 134, + NumberKeyword = 135, + ObjectKeyword = 136, + SetKeyword = 137, + StringKeyword = 138, + SymbolKeyword = 139, + TypeKeyword = 140, + UndefinedKeyword = 141, + UniqueKeyword = 142, + UnknownKeyword = 143, + FromKeyword = 144, + GlobalKeyword = 145, + OfKeyword = 146, + QualifiedName = 147, + ComputedPropertyName = 148, + TypeParameter = 149, + Parameter = 150, + Decorator = 151, + PropertySignature = 152, + PropertyDeclaration = 153, + MethodSignature = 154, + MethodDeclaration = 155, + Constructor = 156, + GetAccessor = 157, + SetAccessor = 158, + CallSignature = 159, + ConstructSignature = 160, + IndexSignature = 161, + TypePredicate = 162, + TypeReference = 163, + FunctionType = 164, + ConstructorType = 165, + TypeQuery = 166, + TypeLiteral = 167, + ArrayType = 168, + TupleType = 169, + OptionalType = 170, + RestType = 171, + UnionType = 172, + IntersectionType = 173, + ConditionalType = 174, + InferType = 175, + ParenthesizedType = 176, + ThisType = 177, + TypeOperator = 178, + IndexedAccessType = 179, + MappedType = 180, + LiteralType = 181, + ImportType = 182, + ObjectBindingPattern = 183, + ArrayBindingPattern = 184, + BindingElement = 185, + ArrayLiteralExpression = 186, + ObjectLiteralExpression = 187, + PropertyAccessExpression = 188, + ElementAccessExpression = 189, + CallExpression = 190, + NewExpression = 191, + TaggedTemplateExpression = 192, + TypeAssertionExpression = 193, + ParenthesizedExpression = 194, + FunctionExpression = 195, + ArrowFunction = 196, + DeleteExpression = 197, + TypeOfExpression = 198, + VoidExpression = 199, + AwaitExpression = 200, + PrefixUnaryExpression = 201, + PostfixUnaryExpression = 202, + BinaryExpression = 203, + ConditionalExpression = 204, + TemplateExpression = 205, + YieldExpression = 206, + SpreadElement = 207, + ClassExpression = 208, + OmittedExpression = 209, + ExpressionWithTypeArguments = 210, + AsExpression = 211, + NonNullExpression = 212, + MetaProperty = 213, + SyntheticExpression = 214, + TemplateSpan = 215, + SemicolonClassElement = 216, + Block = 217, + VariableStatement = 218, + EmptyStatement = 219, + ExpressionStatement = 220, + IfStatement = 221, + DoStatement = 222, + WhileStatement = 223, + ForStatement = 224, + ForInStatement = 225, + ForOfStatement = 226, + ContinueStatement = 227, + BreakStatement = 228, + ReturnStatement = 229, + WithStatement = 230, + SwitchStatement = 231, + LabeledStatement = 232, + ThrowStatement = 233, + TryStatement = 234, + DebuggerStatement = 235, + VariableDeclaration = 236, + VariableDeclarationList = 237, + FunctionDeclaration = 238, + ClassDeclaration = 239, + InterfaceDeclaration = 240, + TypeAliasDeclaration = 241, + EnumDeclaration = 242, + ModuleDeclaration = 243, + ModuleBlock = 244, + CaseBlock = 245, + NamespaceExportDeclaration = 246, + ImportEqualsDeclaration = 247, + ImportDeclaration = 248, + ImportClause = 249, + NamespaceImport = 250, + NamedImports = 251, + ImportSpecifier = 252, + ExportAssignment = 253, + ExportDeclaration = 254, + NamedExports = 255, + ExportSpecifier = 256, + MissingDeclaration = 257, + ExternalModuleReference = 258, + JsxElement = 259, + JsxSelfClosingElement = 260, + JsxOpeningElement = 261, + JsxClosingElement = 262, + JsxFragment = 263, + JsxOpeningFragment = 264, + JsxClosingFragment = 265, + JsxAttribute = 266, + JsxAttributes = 267, + JsxSpreadAttribute = 268, + JsxExpression = 269, + CaseClause = 270, + DefaultClause = 271, + HeritageClause = 272, + CatchClause = 273, + PropertyAssignment = 274, + ShorthandPropertyAssignment = 275, + SpreadAssignment = 276, + EnumMember = 277, + SourceFile = 278, + Bundle = 279, + UnparsedSource = 280, + InputFiles = 281, + JSDocTypeExpression = 282, + JSDocAllType = 283, + JSDocUnknownType = 284, + JSDocNullableType = 285, + JSDocNonNullableType = 286, + JSDocOptionalType = 287, + JSDocFunctionType = 288, + JSDocVariadicType = 289, + JSDocComment = 290, + JSDocTypeLiteral = 291, + JSDocSignature = 292, + JSDocTag = 293, + JSDocAugmentsTag = 294, + JSDocClassTag = 295, + JSDocCallbackTag = 296, + JSDocEnumTag = 297, + JSDocParameterTag = 298, + JSDocReturnTag = 299, + JSDocThisTag = 300, + JSDocTypeTag = 301, + JSDocTemplateTag = 302, + JSDocTypedefTag = 303, + JSDocPropertyTag = 304, + SyntaxList = 305, + NotEmittedStatement = 306, + PartiallyEmittedExpression = 307, + CommaListExpression = 308, + MergeDeclarationMarker = 309, + EndOfDeclarationMarker = 310, + Count = 311, FirstAssignment = 58, LastAssignment = 70, FirstCompoundAssignment = 59, LastCompoundAssignment = 70, - FirstReservedWord = 72, - LastReservedWord = 107, - FirstKeyword = 72, - LastKeyword = 145, - FirstFutureReservedWord = 108, - LastFutureReservedWord = 116, - FirstTypeNode = 161, - LastTypeNode = 181, + FirstReservedWord = 73, + LastReservedWord = 108, + FirstKeyword = 73, + LastKeyword = 146, + FirstFutureReservedWord = 109, + LastFutureReservedWord = 117, + FirstTypeNode = 162, + LastTypeNode = 182, FirstPunctuation = 17, LastPunctuation = 70, FirstToken = 0, - LastToken = 145, + LastToken = 146, FirstTriviaToken = 2, LastTriviaToken = 7, FirstLiteralToken = 8, @@ -407,11 +408,11 @@ declare namespace ts { LastTemplateToken = 16, FirstBinaryOperator = 27, LastBinaryOperator = 70, - FirstNode = 146, - FirstJSDocNode = 281, - LastJSDocNode = 303, - FirstJSDocTagNode = 292, - LastJSDocTagNode = 303 + FirstNode = 147, + FirstJSDocNode = 282, + LastJSDocNode = 304, + FirstJSDocTagNode = 293, + LastJSDocTagNode = 304 } enum NodeFlags { None = 0, @@ -524,8 +525,8 @@ declare namespace ts { right: Identifier; } type EntityName = Identifier | QualifiedName; - type PropertyName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName; - type DeclarationName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName | BindingPattern; + type PropertyName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName | PrivateName; + type DeclarationName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName | PrivateName | BindingPattern; interface Declaration extends Node { _declarationBrand: any; } @@ -539,6 +540,10 @@ declare namespace ts { kind: SyntaxKind.ComputedPropertyName; expression: Expression; } + interface PrivateName extends Declaration { + kind: SyntaxKind.PrivateName; + escapedText: __String; + } interface Decorator extends Node { kind: SyntaxKind.Decorator; parent: NamedDeclaration; @@ -1046,7 +1051,7 @@ declare namespace ts { interface PropertyAccessExpression extends MemberExpression, NamedDeclaration { kind: SyntaxKind.PropertyAccessExpression; expression: LeftHandSideExpression; - name: Identifier; + name: Identifier | PrivateName; } interface SuperPropertyAccessExpression extends PropertyAccessExpression { expression: SuperExpression; @@ -3194,9 +3199,9 @@ declare namespace ts { * @returns The unescaped identifier text. */ function unescapeLeadingUnderscores(identifier: __String): string; - function idText(identifier: Identifier): string; + function idText(identifierOrPrivateName: Identifier | PrivateName): string; function symbolName(symbol: Symbol): string; - function getNameOfJSDocTypedef(declaration: JSDocTypedefTag): Identifier | undefined; + function getNameOfJSDocTypedef(declaration: JSDocTypedefTag): Identifier | PrivateName | undefined; function getNameOfDeclaration(declaration: Declaration | Expression): DeclarationName | undefined; /** * Gets the JSDoc parameter tags for the node if present. @@ -3273,8 +3278,10 @@ declare namespace ts { function isTemplateMiddle(node: Node): node is TemplateMiddle; function isTemplateTail(node: Node): node is TemplateTail; function isIdentifier(node: Node): node is Identifier; + function isIdentifierOrPrivateName(node: Node): node is Identifier | PrivateName; function isQualifiedName(node: Node): node is QualifiedName; function isComputedPropertyName(node: Node): node is ComputedPropertyName; + function isPrivateName(node: Node): node is PrivateName; function isTypeParameterDeclaration(node: Node): node is TypeParameterDeclaration; function isParameter(node: Node): node is ParameterDeclaration; function isDecorator(node: Node): node is Decorator; @@ -3734,8 +3741,8 @@ declare namespace ts { function updateArrayLiteral(node: ArrayLiteralExpression, elements: ReadonlyArray): ArrayLiteralExpression; function createObjectLiteral(properties?: ReadonlyArray, multiLine?: boolean): ObjectLiteralExpression; function updateObjectLiteral(node: ObjectLiteralExpression, properties: ReadonlyArray): ObjectLiteralExpression; - function createPropertyAccess(expression: Expression, name: string | Identifier | undefined): PropertyAccessExpression; - function updatePropertyAccess(node: PropertyAccessExpression, expression: Expression, name: Identifier): PropertyAccessExpression; + function createPropertyAccess(expression: Expression, name: string | Identifier | PrivateName | undefined): PropertyAccessExpression; + function updatePropertyAccess(node: PropertyAccessExpression, expression: Expression, name: Identifier | PrivateName): PropertyAccessExpression; function createElementAccess(expression: Expression, index: number | Expression): ElementAccessExpression; function updateElementAccess(node: ElementAccessExpression, expression: Expression, argumentExpression: Expression): ElementAccessExpression; function createCall(expression: Expression, typeArguments: ReadonlyArray | undefined, argumentsArray: ReadonlyArray | undefined): CallExpression; @@ -4510,6 +4517,9 @@ declare namespace ts { interface Identifier { readonly text: string; } + interface PrivateName { + readonly text: string; + } interface Symbol { readonly name: string; getFlags(): SymbolFlags; diff --git a/tests/baselines/reference/parseErrorInHeritageClause1.errors.txt b/tests/baselines/reference/parseErrorInHeritageClause1.errors.txt index 67564442b3abc..722004686f23c 100644 --- a/tests/baselines/reference/parseErrorInHeritageClause1.errors.txt +++ b/tests/baselines/reference/parseErrorInHeritageClause1.errors.txt @@ -3,9 +3,10 @@ tests/cases/compiler/parseErrorInHeritageClause1.ts(1,19): error TS1127: Invalid ==== tests/cases/compiler/parseErrorInHeritageClause1.ts (2 errors) ==== - class C extends A # { + class C extends A ¬ { ~ !!! error TS2304: Cannot find name 'A'. !!! error TS1127: Invalid character. - } \ No newline at end of file + } + \ No newline at end of file diff --git a/tests/baselines/reference/parseErrorInHeritageClause1.js b/tests/baselines/reference/parseErrorInHeritageClause1.js index 25724868d7acb..570eb51200a20 100644 --- a/tests/baselines/reference/parseErrorInHeritageClause1.js +++ b/tests/baselines/reference/parseErrorInHeritageClause1.js @@ -1,6 +1,7 @@ //// [parseErrorInHeritageClause1.ts] -class C extends A # { -} +class C extends A ¬ { +} + //// [parseErrorInHeritageClause1.js] var __extends = (this && this.__extends) || (function () { diff --git a/tests/baselines/reference/parseErrorInHeritageClause1.symbols b/tests/baselines/reference/parseErrorInHeritageClause1.symbols index 5e0d3d26d38da..45d6ba5f5fac3 100644 --- a/tests/baselines/reference/parseErrorInHeritageClause1.symbols +++ b/tests/baselines/reference/parseErrorInHeritageClause1.symbols @@ -1,4 +1,5 @@ === tests/cases/compiler/parseErrorInHeritageClause1.ts === -class C extends A # { +class C extends A ¬ { >C : Symbol(C, Decl(parseErrorInHeritageClause1.ts, 0, 0)) } + diff --git a/tests/baselines/reference/parseErrorInHeritageClause1.types b/tests/baselines/reference/parseErrorInHeritageClause1.types index 53f0a622054d3..0a8c72e1f8c92 100644 --- a/tests/baselines/reference/parseErrorInHeritageClause1.types +++ b/tests/baselines/reference/parseErrorInHeritageClause1.types @@ -1,5 +1,6 @@ === tests/cases/compiler/parseErrorInHeritageClause1.ts === -class C extends A # { +class C extends A ¬ { >C : C >A : any } + diff --git a/tests/baselines/reference/parserErrorRecovery_Block2.errors.txt b/tests/baselines/reference/parserErrorRecovery_Block2.errors.txt index 53279be443f66..ff29d9389760b 100644 --- a/tests/baselines/reference/parserErrorRecovery_Block2.errors.txt +++ b/tests/baselines/reference/parserErrorRecovery_Block2.errors.txt @@ -3,8 +3,9 @@ tests/cases/conformance/parser/ecmascript5/ErrorRecovery/Blocks/parserErrorRecov ==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/Blocks/parserErrorRecovery_Block2.ts (1 errors) ==== function f() { - # + ¬ !!! error TS1127: Invalid character. return; - } \ No newline at end of file + } + \ No newline at end of file diff --git a/tests/baselines/reference/parserErrorRecovery_Block2.js b/tests/baselines/reference/parserErrorRecovery_Block2.js index 24ddaf0db3f2a..024684a9e2b03 100644 --- a/tests/baselines/reference/parserErrorRecovery_Block2.js +++ b/tests/baselines/reference/parserErrorRecovery_Block2.js @@ -1,8 +1,9 @@ //// [parserErrorRecovery_Block2.ts] function f() { - # + ¬ return; -} +} + //// [parserErrorRecovery_Block2.js] function f() { diff --git a/tests/baselines/reference/parserErrorRecovery_Block2.symbols b/tests/baselines/reference/parserErrorRecovery_Block2.symbols index 3d5a09d567ce6..ce4725e609a64 100644 --- a/tests/baselines/reference/parserErrorRecovery_Block2.symbols +++ b/tests/baselines/reference/parserErrorRecovery_Block2.symbols @@ -2,6 +2,7 @@ function f() { >f : Symbol(f, Decl(parserErrorRecovery_Block2.ts, 0, 0)) - # + ¬ return; } + diff --git a/tests/baselines/reference/parserErrorRecovery_Block2.types b/tests/baselines/reference/parserErrorRecovery_Block2.types index 9850dc1cf0ea2..0a0a0fbec23c8 100644 --- a/tests/baselines/reference/parserErrorRecovery_Block2.types +++ b/tests/baselines/reference/parserErrorRecovery_Block2.types @@ -2,6 +2,7 @@ function f() { >f : () => void - # + ¬ return; } + diff --git a/tests/baselines/reference/parserErrorRecovery_ClassElement3.errors.txt b/tests/baselines/reference/parserErrorRecovery_ClassElement3.errors.txt index 7f81c6114f6d2..52f99265d2c51 100644 --- a/tests/baselines/reference/parserErrorRecovery_ClassElement3.errors.txt +++ b/tests/baselines/reference/parserErrorRecovery_ClassElement3.errors.txt @@ -1,12 +1,12 @@ tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ClassElements/parserErrorRecovery_ClassElement3.ts(2,4): error TS1127: Invalid character. tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ClassElements/parserErrorRecovery_ClassElement3.ts(6,4): error TS1109: Expression expected. tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ClassElements/parserErrorRecovery_ClassElement3.ts(7,4): error TS1127: Invalid character. -tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ClassElements/parserErrorRecovery_ClassElement3.ts(7,5): error TS1005: '}' expected. +tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ClassElements/parserErrorRecovery_ClassElement3.ts(8,1): error TS1005: '}' expected. ==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ClassElements/parserErrorRecovery_ClassElement3.ts (4 errors) ==== module M { - # + ¬ !!! error TS1127: Invalid character. class C { @@ -15,8 +15,9 @@ tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ClassElements/parserErr enum E { ~~~~ !!! error TS1109: Expression expected. - # + ¬ !!! error TS1127: Invalid character. - + + !!! error TS1005: '}' expected. \ No newline at end of file diff --git a/tests/baselines/reference/parserErrorRecovery_ClassElement3.js b/tests/baselines/reference/parserErrorRecovery_ClassElement3.js index 36d98fa54003e..ef9afde66f7f0 100644 --- a/tests/baselines/reference/parserErrorRecovery_ClassElement3.js +++ b/tests/baselines/reference/parserErrorRecovery_ClassElement3.js @@ -1,11 +1,12 @@ //// [parserErrorRecovery_ClassElement3.ts] module M { - # + ¬ class C { } @ enum E { - # + ¬ + //// [parserErrorRecovery_ClassElement3.js] var M; diff --git a/tests/baselines/reference/parserErrorRecovery_ClassElement3.symbols b/tests/baselines/reference/parserErrorRecovery_ClassElement3.symbols index 5c1edc5b8f09f..5ea7444c974c9 100644 --- a/tests/baselines/reference/parserErrorRecovery_ClassElement3.symbols +++ b/tests/baselines/reference/parserErrorRecovery_ClassElement3.symbols @@ -2,7 +2,7 @@ module M { >M : Symbol(M, Decl(parserErrorRecovery_ClassElement3.ts, 0, 0)) - # + ¬ class C { >C : Symbol(C, Decl(parserErrorRecovery_ClassElement3.ts, 1, 4)) } @@ -10,4 +10,5 @@ module M { enum E { >E : Symbol(E, Decl(parserErrorRecovery_ClassElement3.ts, 3, 4)) - # + ¬ + diff --git a/tests/baselines/reference/parserErrorRecovery_ClassElement3.types b/tests/baselines/reference/parserErrorRecovery_ClassElement3.types index 68df4b2bbe22b..f509a0d4fb574 100644 --- a/tests/baselines/reference/parserErrorRecovery_ClassElement3.types +++ b/tests/baselines/reference/parserErrorRecovery_ClassElement3.types @@ -2,7 +2,7 @@ module M { >M : typeof M - # + ¬ class C { >C : C } @@ -11,4 +11,5 @@ module M { > : any >E : E - # + ¬ + diff --git a/tests/baselines/reference/parserErrorRecovery_ParameterList4.errors.txt b/tests/baselines/reference/parserErrorRecovery_ParameterList4.errors.txt index fa97550dd192f..9e404df184199 100644 --- a/tests/baselines/reference/parserErrorRecovery_ParameterList4.errors.txt +++ b/tests/baselines/reference/parserErrorRecovery_ParameterList4.errors.txt @@ -2,7 +2,8 @@ tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserEr ==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList4.ts (1 errors) ==== - function f(a,#) { + function f(a,¬) { !!! error TS1127: Invalid character. - } \ No newline at end of file + } + \ No newline at end of file diff --git a/tests/baselines/reference/parserErrorRecovery_ParameterList4.js b/tests/baselines/reference/parserErrorRecovery_ParameterList4.js index 53775cad92ea3..1a1a124eb493d 100644 --- a/tests/baselines/reference/parserErrorRecovery_ParameterList4.js +++ b/tests/baselines/reference/parserErrorRecovery_ParameterList4.js @@ -1,6 +1,7 @@ //// [parserErrorRecovery_ParameterList4.ts] -function f(a,#) { -} +function f(a,¬) { +} + //// [parserErrorRecovery_ParameterList4.js] function f(a) { diff --git a/tests/baselines/reference/parserErrorRecovery_ParameterList4.symbols b/tests/baselines/reference/parserErrorRecovery_ParameterList4.symbols index df48ebfe04dec..7c433c8c3b461 100644 --- a/tests/baselines/reference/parserErrorRecovery_ParameterList4.symbols +++ b/tests/baselines/reference/parserErrorRecovery_ParameterList4.symbols @@ -1,5 +1,6 @@ === tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList4.ts === -function f(a,#) { +function f(a,¬) { >f : Symbol(f, Decl(parserErrorRecovery_ParameterList4.ts, 0, 0)) >a : Symbol(a, Decl(parserErrorRecovery_ParameterList4.ts, 0, 11)) } + diff --git a/tests/baselines/reference/parserErrorRecovery_ParameterList4.types b/tests/baselines/reference/parserErrorRecovery_ParameterList4.types index 77b105f1d4cef..093d99193d21f 100644 --- a/tests/baselines/reference/parserErrorRecovery_ParameterList4.types +++ b/tests/baselines/reference/parserErrorRecovery_ParameterList4.types @@ -1,5 +1,6 @@ === tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList4.ts === -function f(a,#) { +function f(a,¬) { >f : (a: any) => void >a : any } + diff --git a/tests/baselines/reference/parserSkippedTokens16.errors.txt b/tests/baselines/reference/parserSkippedTokens16.errors.txt index c35e013a22852..d27faccd2c9e7 100644 --- a/tests/baselines/reference/parserSkippedTokens16.errors.txt +++ b/tests/baselines/reference/parserSkippedTokens16.errors.txt @@ -19,7 +19,7 @@ tests/cases/conformance/parser/ecmascript5/SkippedTokens/parserSkippedTokens16.t !!! error TS2304: Cannot find name 'Bar'. ~ !!! error TS1005: ';' expected. - function Foo () # { } + function Foo () ¬ { } !!! error TS1127: Invalid character. 4+:5 @@ -33,4 +33,5 @@ tests/cases/conformance/parser/ecmascript5/SkippedTokens/parserSkippedTokens16.t } var x = -!!! error TS1109: Expression expected. \ No newline at end of file +!!! error TS1109: Expression expected. + \ No newline at end of file diff --git a/tests/baselines/reference/parserSkippedTokens16.js b/tests/baselines/reference/parserSkippedTokens16.js index 2c3a9be876df5..cf5b8c55ecc8a 100644 --- a/tests/baselines/reference/parserSkippedTokens16.js +++ b/tests/baselines/reference/parserSkippedTokens16.js @@ -1,12 +1,13 @@ //// [parserSkippedTokens16.ts] foo(): Bar { } -function Foo () # { } +function Foo () ¬ { } 4+:5 module M { function a( : T) { } } -var x = +var x = + //// [parserSkippedTokens16.js] foo(); diff --git a/tests/baselines/reference/parserSkippedTokens16.symbols b/tests/baselines/reference/parserSkippedTokens16.symbols index 213dc9965f98f..576a1dfd97d8d 100644 --- a/tests/baselines/reference/parserSkippedTokens16.symbols +++ b/tests/baselines/reference/parserSkippedTokens16.symbols @@ -1,6 +1,6 @@ === tests/cases/conformance/parser/ecmascript5/SkippedTokens/parserSkippedTokens16.ts === foo(): Bar { } -function Foo () # { } +function Foo () ¬ { } >Foo : Symbol(Foo, Decl(parserSkippedTokens16.ts, 0, 14)) 4+:5 diff --git a/tests/baselines/reference/parserSkippedTokens16.types b/tests/baselines/reference/parserSkippedTokens16.types index b9c24cfafbaf0..cb62505802fe9 100644 --- a/tests/baselines/reference/parserSkippedTokens16.types +++ b/tests/baselines/reference/parserSkippedTokens16.types @@ -4,7 +4,7 @@ foo(): Bar { } >foo : any >Bar : any -function Foo () # { } +function Foo () ¬ { } >Foo : () => any 4+:5 @@ -24,5 +24,6 @@ function a( } var x = >x : any + > : any diff --git a/tests/baselines/reference/privateNameAndIndexSignature.errors.txt b/tests/baselines/reference/privateNameAndIndexSignature.errors.txt new file mode 100644 index 0000000000000..1b4895bf23d64 --- /dev/null +++ b/tests/baselines/reference/privateNameAndIndexSignature.errors.txt @@ -0,0 +1,13 @@ +tests/cases/conformance/classes/members/privateNames/privateNameAndIndexSignature.ts(4,14): error TS2339: Property '#f' does not exist on type 'A'. + + +==== tests/cases/conformance/classes/members/privateNames/privateNameAndIndexSignature.ts (1 errors) ==== + class A { + [k: string]: any; + constructor(message: string) { + this.#f = 3 // Error Property '#f' does not exist on type 'A'. + ~~ +!!! error TS2339: Property '#f' does not exist on type 'A'. + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/privateNameAndIndexSignature.js b/tests/baselines/reference/privateNameAndIndexSignature.js new file mode 100644 index 0000000000000..d1271acca8ce9 --- /dev/null +++ b/tests/baselines/reference/privateNameAndIndexSignature.js @@ -0,0 +1,16 @@ +//// [privateNameAndIndexSignature.ts] +class A { + [k: string]: any; + constructor(message: string) { + this.#f = 3 // Error Property '#f' does not exist on type 'A'. + } +} + + +//// [privateNameAndIndexSignature.js] +var A = /** @class */ (function () { + function A(message) { + this.#f = 3; // Error Property '#f' does not exist on type 'A'. + } + return A; +}()); diff --git a/tests/baselines/reference/privateNameAndIndexSignature.symbols b/tests/baselines/reference/privateNameAndIndexSignature.symbols new file mode 100644 index 0000000000000..d8a153c04270e --- /dev/null +++ b/tests/baselines/reference/privateNameAndIndexSignature.symbols @@ -0,0 +1,15 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameAndIndexSignature.ts === +class A { +>A : Symbol(A, Decl(privateNameAndIndexSignature.ts, 0, 0)) + + [k: string]: any; +>k : Symbol(k, Decl(privateNameAndIndexSignature.ts, 1, 5)) + + constructor(message: string) { +>message : Symbol(message, Decl(privateNameAndIndexSignature.ts, 2, 16)) + + this.#f = 3 // Error Property '#f' does not exist on type 'A'. +>this : Symbol(A, Decl(privateNameAndIndexSignature.ts, 0, 0)) + } +} + diff --git a/tests/baselines/reference/privateNameAndIndexSignature.types b/tests/baselines/reference/privateNameAndIndexSignature.types new file mode 100644 index 0000000000000..d663d5b9517cc --- /dev/null +++ b/tests/baselines/reference/privateNameAndIndexSignature.types @@ -0,0 +1,18 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameAndIndexSignature.ts === +class A { +>A : A + + [k: string]: any; +>k : string + + constructor(message: string) { +>message : string + + this.#f = 3 // Error Property '#f' does not exist on type 'A'. +>this.#f = 3 : 3 +>this.#f : any +>this : this +>3 : 3 + } +} + diff --git a/tests/baselines/reference/privateNameField.js b/tests/baselines/reference/privateNameField.js new file mode 100644 index 0000000000000..f432be2b3d336 --- /dev/null +++ b/tests/baselines/reference/privateNameField.js @@ -0,0 +1,15 @@ +//// [privateNameField.ts] +class A { + #name: string; + constructor(name: string) { + this.#name = name; + } +} + +//// [privateNameField.js] +var A = /** @class */ (function () { + function A(name) { + this.#name = name; + } + return A; +}()); diff --git a/tests/baselines/reference/privateNameField.symbols b/tests/baselines/reference/privateNameField.symbols new file mode 100644 index 0000000000000..a9ab08325a0e1 --- /dev/null +++ b/tests/baselines/reference/privateNameField.symbols @@ -0,0 +1,16 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameField.ts === +class A { +>A : Symbol(A, Decl(privateNameField.ts, 0, 0)) + + #name: string; +>#name : Symbol(A[#name], Decl(privateNameField.ts, 0, 9)) + + constructor(name: string) { +>name : Symbol(name, Decl(privateNameField.ts, 2, 16)) + + this.#name = name; +>this.#name : Symbol(A[#name], Decl(privateNameField.ts, 0, 9)) +>this : Symbol(A, Decl(privateNameField.ts, 0, 0)) +>name : Symbol(name, Decl(privateNameField.ts, 2, 16)) + } +} diff --git a/tests/baselines/reference/privateNameField.types b/tests/baselines/reference/privateNameField.types new file mode 100644 index 0000000000000..1eb30eda52590 --- /dev/null +++ b/tests/baselines/reference/privateNameField.types @@ -0,0 +1,17 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameField.ts === +class A { +>A : A + + #name: string; +>#name : string + + constructor(name: string) { +>name : string + + this.#name = name; +>this.#name = name : string +>this.#name : string +>this : this +>name : string + } +} diff --git a/tests/baselines/reference/shebangError.errors.txt b/tests/baselines/reference/shebangError.errors.txt index e8197d8bc5f53..894739d5a4170 100644 --- a/tests/baselines/reference/shebangError.errors.txt +++ b/tests/baselines/reference/shebangError.errors.txt @@ -1,14 +1,17 @@ -tests/cases/compiler/shebangError.ts(2,1): error TS1127: Invalid character. +tests/cases/compiler/shebangError.ts(2,1): error TS1128: Declaration or statement expected. +tests/cases/compiler/shebangError.ts(2,2): error TS1127: Invalid character. tests/cases/compiler/shebangError.ts(2,2): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type. tests/cases/compiler/shebangError.ts(2,12): error TS2304: Cannot find name 'env'. tests/cases/compiler/shebangError.ts(2,16): error TS1005: ';' expected. tests/cases/compiler/shebangError.ts(2,16): error TS2304: Cannot find name 'node'. -==== tests/cases/compiler/shebangError.ts (5 errors) ==== +==== tests/cases/compiler/shebangError.ts (6 errors) ==== var foo = 'Shebang is only allowed on the first line'; #!/usr/bin/env node - + ~ +!!! error TS1128: Declaration or statement expected. + !!! error TS1127: Invalid character. ~~~~~~~~~ !!! error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type. diff --git a/tests/cases/compiler/parseErrorInHeritageClause1.ts b/tests/cases/compiler/parseErrorInHeritageClause1.ts index 84223192c7ad1..5c4a21e4f9371 100644 --- a/tests/cases/compiler/parseErrorInHeritageClause1.ts +++ b/tests/cases/compiler/parseErrorInHeritageClause1.ts @@ -1,2 +1,2 @@ -class C extends A # { -} \ No newline at end of file +class C extends A ¬ { +} diff --git a/tests/cases/conformance/classes/members/privateNames/privateNameAndIndexSignature.ts b/tests/cases/conformance/classes/members/privateNames/privateNameAndIndexSignature.ts new file mode 100644 index 0000000000000..d4c0b8ad46efb --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNameAndIndexSignature.ts @@ -0,0 +1,6 @@ +class A { + [k: string]: any; + constructor(message: string) { + this.#f = 3 // Error Property '#f' does not exist on type 'A'. + } +} diff --git a/tests/cases/conformance/classes/members/privateNames/privateNameField.ts b/tests/cases/conformance/classes/members/privateNames/privateNameField.ts new file mode 100644 index 0000000000000..02e449fb3e002 --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNameField.ts @@ -0,0 +1,6 @@ +class A { + #name: string; + constructor(name: string) { + this.#name = name; + } +} \ No newline at end of file diff --git a/tests/cases/conformance/es6/memberFunctionDeclarations/MemberFunctionDeclaration8_es6.ts b/tests/cases/conformance/es6/memberFunctionDeclarations/MemberFunctionDeclaration8_es6.ts index e698257e94068..f75eaaa1aca5c 100644 --- a/tests/cases/conformance/es6/memberFunctionDeclarations/MemberFunctionDeclaration8_es6.ts +++ b/tests/cases/conformance/es6/memberFunctionDeclarations/MemberFunctionDeclaration8_es6.ts @@ -2,7 +2,7 @@ class C { foo() { // Make sure we don't think of *bar as the start of a generator method. - if (a) # * bar; + if (a) ¬ * bar; return bar; } -} \ No newline at end of file +} diff --git a/tests/cases/conformance/parser/ecmascript5/ErrorRecovery/Blocks/parserErrorRecovery_Block2.ts b/tests/cases/conformance/parser/ecmascript5/ErrorRecovery/Blocks/parserErrorRecovery_Block2.ts index 2473a9d1ffb1c..2652211f3ea50 100644 --- a/tests/cases/conformance/parser/ecmascript5/ErrorRecovery/Blocks/parserErrorRecovery_Block2.ts +++ b/tests/cases/conformance/parser/ecmascript5/ErrorRecovery/Blocks/parserErrorRecovery_Block2.ts @@ -1,4 +1,4 @@ function f() { - # + ¬ return; -} \ No newline at end of file +} diff --git a/tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ClassElements/parserErrorRecovery_ClassElement3.ts b/tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ClassElements/parserErrorRecovery_ClassElement3.ts index d4ea9d6078719..0f81401c1b8b2 100644 --- a/tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ClassElements/parserErrorRecovery_ClassElement3.ts +++ b/tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ClassElements/parserErrorRecovery_ClassElement3.ts @@ -1,7 +1,7 @@ module M { - # + ¬ class C { } @ enum E { - # \ No newline at end of file + ¬ diff --git a/tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList4.ts b/tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList4.ts index f46e46951454e..9eb5c87804e11 100644 --- a/tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList4.ts +++ b/tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList4.ts @@ -1,2 +1,2 @@ -function f(a,#) { -} \ No newline at end of file +function f(a,¬) { +} diff --git a/tests/cases/conformance/parser/ecmascript5/SkippedTokens/parserSkippedTokens16.ts b/tests/cases/conformance/parser/ecmascript5/SkippedTokens/parserSkippedTokens16.ts index c583fc13d8229..a12294be4bb9e 100644 --- a/tests/cases/conformance/parser/ecmascript5/SkippedTokens/parserSkippedTokens16.ts +++ b/tests/cases/conformance/parser/ecmascript5/SkippedTokens/parserSkippedTokens16.ts @@ -1,8 +1,8 @@ foo(): Bar { } -function Foo () # { } +function Foo () ¬ { } 4+:5 module M { function a( : T) { } } -var x = \ No newline at end of file +var x = diff --git a/tests/cases/fourslash/hoverOverPrivateName.ts b/tests/cases/fourslash/hoverOverPrivateName.ts new file mode 100644 index 0000000000000..28e748b9aa43c --- /dev/null +++ b/tests/cases/fourslash/hoverOverPrivateName.ts @@ -0,0 +1,15 @@ +/// + +////class A { +//// #foo: number; +//// +//// constructor () { +//// this./**/#foo = 3; +//// } +//// +////} + +goTo.marker(); +verify.quickInfoIs(""); +verify.goToDefinitionIs([]); +verify.noReferences(); \ No newline at end of file From 136e2181bf8c2e115158173192eebacb33e93804 Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Thu, 28 Jun 2018 14:14:40 -0400 Subject: [PATCH 03/32] Start ES2015 transformation Signed-off-by: Joseph Watts --- src/compiler/transformers/esnext.ts | 54 +++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index b121eb315db84..e68fa123b9881 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -101,11 +101,35 @@ namespace ts { return visitParenthesizedExpression(node as ParenthesizedExpression, noDestructuringValue); case SyntaxKind.CatchClause: return visitCatchClause(node as CatchClause); + case SyntaxKind.PropertyDeclaration: + return visitPropertyDeclaration(node as PropertyDeclaration); + case SyntaxKind.PropertyAccessExpression: + return visitPropertyAccessExpression(node as PropertyAccessExpression); default: return visitEachChild(node, visitor, context); } } + function visitPropertyAccessExpression(node: PropertyAccessExpression): Expression { + if (node.name.isPrivateName) { + return setOriginalNode( + setTextRange( + createClassPrivateFieldGetHelper(context, node.expression, node.name), + /* location */ node + ), + node + ); + } + return visitEachChild(node, visitor, context); + } + + function visitPropertyDeclaration(node: PropertyDeclaration): VisitResult { + if (isIdentifier(node.name) && node.name.isPrivateName) { + createClassPrivateFieldHelper(context, node.name); + } + return visitEachChild(node, visitor, context); + } + function visitAwaitExpression(node: AwaitExpression): Expression { if (enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator) { return setOriginalNode( @@ -917,6 +941,36 @@ namespace ts { ); } + export function createClassPrivateFieldHelper(context: TransformationContext, privateField: Identifier) { + context.requestEmitHelper({ + name: 'typescript:classPrivateField', + scoped: true, + text: helperString`var ${"_" + privateField.escapedText} = new WeakMap();` + }); + } + + const classPrivateFieldGetHelper: EmitHelper = { + name: "typescript:classPrivateFieldGet", + scoped: false, + text: `var _classPrivateFieldGet = function (receiver, privateMap) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return privateMap.get(receiver); };` + } + + export function createClassPrivateFieldGetHelper(context: TransformationContext, receiver: Expression, privateField: Identifier) { + context.requestEmitHelper(classPrivateFieldGetHelper); + return createCall(getHelperName("_classPrivateFieldGet"), /* typeArguments */ undefined, [ receiver, privateField ]); + } + + const classPrivateFieldSetHelper: EmitHelper = { + name: "typescript:classPrivateFieldSet", + scoped: false, + text: `var _classPrivateFieldSet = function (receiver, privateMap, value) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to set private field on non-instance"); } privateMap.set(receiver, value); return value; };` + } + + export function createClassPrivateFieldSetHelper(context: TransformationContext, expression: Expression) { + context.requestEmitHelper(classPrivateFieldSetHelper); + return createCall(getHelperName("_classPrivateFieldSet"), /* typeArguments */ undefined, [ expression ]); + } + const awaitHelper: EmitHelper = { name: "typescript:await", scoped: false, From d0a89b8f349583e7ad1f36383820677060080f04 Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Thu, 28 Jun 2018 14:33:50 -0400 Subject: [PATCH 04/32] Fix lint errors Signed-off-by: Joseph Watts --- src/compiler/transformers/esnext.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index e68fa123b9881..ce28293aa7ba1 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -943,7 +943,7 @@ namespace ts { export function createClassPrivateFieldHelper(context: TransformationContext, privateField: Identifier) { context.requestEmitHelper({ - name: 'typescript:classPrivateField', + name: "typescript:classPrivateField", scoped: true, text: helperString`var ${"_" + privateField.escapedText} = new WeakMap();` }); @@ -953,7 +953,7 @@ namespace ts { name: "typescript:classPrivateFieldGet", scoped: false, text: `var _classPrivateFieldGet = function (receiver, privateMap) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return privateMap.get(receiver); };` - } + }; export function createClassPrivateFieldGetHelper(context: TransformationContext, receiver: Expression, privateField: Identifier) { context.requestEmitHelper(classPrivateFieldGetHelper); @@ -964,7 +964,7 @@ namespace ts { name: "typescript:classPrivateFieldSet", scoped: false, text: `var _classPrivateFieldSet = function (receiver, privateMap, value) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to set private field on non-instance"); } privateMap.set(receiver, value); return value; };` - } + }; export function createClassPrivateFieldSetHelper(context: TransformationContext, expression: Expression) { context.requestEmitHelper(classPrivateFieldSetHelper); From 1e7326d88ab4af82aa7eebe1915a8f11cd3fd0b6 Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Fri, 29 Jun 2018 11:43:39 -0400 Subject: [PATCH 05/32] Transform private name references. Generate private field initializers. Signed-off-by: Joseph Watts --- src/compiler/binder.ts | 10 ++ src/compiler/transformers/esnext.ts | 154 +++++++++++++++++++++++++++- 2 files changed, 159 insertions(+), 5 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index ebc43e006bdfc..9b5fff3eb26d7 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -3311,6 +3311,11 @@ namespace ts { transformFlags |= TransformFlags.ContainsPropertyInitializer; } + // Private names are an ESNext feature. + if (isIdentifier(node.name) && node.name.isPrivateName) { + transformFlags |= TransformFlags.AssertESNext; + } + node.transformFlags = transformFlags | TransformFlags.HasComputedFlags; return transformFlags & ~TransformFlags.NodeExcludes; } @@ -3448,6 +3453,11 @@ namespace ts { transformFlags |= TransformFlags.ContainsSuper; } + // Private names are an ESNext feature. + if (isIdentifier(node.name) && node.name.isPrivateName) { + transformFlags |= TransformFlags.AssertESNext; + } + node.transformFlags = transformFlags | TransformFlags.HasComputedFlags; return transformFlags & ~TransformFlags.PropertyAccessExcludes; } diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index ce28293aa7ba1..fdf5dedce1d4a 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -26,6 +26,16 @@ namespace ts { let enclosingFunctionFlags: FunctionFlags; let enclosingSuperContainerFlags: NodeCheckFlags = 0; + + /** + * Maps private names to the generated name of the WeakMap. + */ + interface PrivateNameEnvironment { + [name: string]: { weakMapName: Identifier, initializer: Expression | undefined } + } + let privateNameEnvironmentStack: PrivateNameEnvironment[] = []; + let privateNameEnvironmentIndex = -1; + return chainBundle(transformSourceFile); function transformSourceFile(node: SourceFile) { @@ -105,16 +115,41 @@ namespace ts { return visitPropertyDeclaration(node as PropertyDeclaration); case SyntaxKind.PropertyAccessExpression: return visitPropertyAccessExpression(node as PropertyAccessExpression); + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + return visitClassLikeDeclaration(node as ClassLikeDeclaration); default: return visitEachChild(node, visitor, context); } } + function currentPrivateNameEnvironment() { + return privateNameEnvironmentStack[privateNameEnvironmentIndex]; + } + + function addPrivateNameToEnvironment(name: Identifier, + initializer?: Expression, + environment: PrivateNameEnvironment = currentPrivateNameEnvironment()) { + const nameString = getTextOfIdentifierOrLiteral(name); + if (nameString in environment) { + if (initializer) { + environment[nameString].initializer = initializer; + } + return environment[nameString].weakMapName; + } + const weakMapName = createFileLevelUniqueName('_' + nameString.substring(1)); + environment[nameString] = { + weakMapName, initializer + }; + return weakMapName; + } + function visitPropertyAccessExpression(node: PropertyAccessExpression): Expression { if (node.name.isPrivateName) { + const weakMapName = addPrivateNameToEnvironment(node.name); return setOriginalNode( setTextRange( - createClassPrivateFieldGetHelper(context, node.expression, node.name), + createClassPrivateFieldGetHelper(context, node.expression, weakMapName), /* location */ node ), node @@ -125,11 +160,99 @@ namespace ts { function visitPropertyDeclaration(node: PropertyDeclaration): VisitResult { if (isIdentifier(node.name) && node.name.isPrivateName) { - createClassPrivateFieldHelper(context, node.name); + addPrivateNameToEnvironment(node.name); } return visitEachChild(node, visitor, context); } + function visitClassLikeDeclaration(node: ClassLikeDeclaration): VisitResult { + // Create private name environment. + privateNameEnvironmentStack[++privateNameEnvironmentIndex] = {}; + // Visit children. + node = visitEachChild(node, visitor, context); + // Create WeakMaps for private properties. + // TODO: insert these WeakMap statements somewhere in the code... + const privateNameEnvironment = currentPrivateNameEnvironment(); + for (let propertyName in privateNameEnvironment) { + const { weakMapName } = privateNameEnvironment[propertyName]; + /*const weakMapStatement = */createVariableStatement( + /* modifiers */ undefined, + [ + createVariableDeclaration(weakMapName, + /* typeNode */ undefined, + createNew( + createIdentifier('WeakMap'), + /* typeArguments */ undefined, + /* argumentsArray */ undefined + )) + ] + ); + } + const initializerStatements = Object.keys(privateNameEnvironment).map(name => { + return createStatement( + createCall( + createPropertyAccess(privateNameEnvironment[name].weakMapName, 'set'), + /* typeArguments */ undefined, + [privateNameEnvironment[name].initializer || createVoidZero()] + ) + ); + }); + let members = [...node.members]; + let ctor = find(members, (member) => isConstructorDeclaration(member)); + if (!ctor) { + // Create constructor with private field initializers. + ctor = createConstructor( + /* decorators */ undefined, + /* modifiers */ undefined, + /* parameters */ [], + createBlock(initializerStatements) + ); + members.unshift(ctor); + } else { + // Update existing constructor to add private field initializers. + members = members.map(member => { + if (isConstructorDeclaration(member)) { + let statements = member.body ? + [...initializerStatements, ...member.body.statements] : + initializerStatements; + return updateConstructor( + member, + member.decorators, + member.modifiers, + member.parameters, + createBlock(statements, member.body ? member.body.multiLine : undefined) + ); + } + return member; + }) + } + + // Update class members. + if (isClassDeclaration(node)) { + node = updateClassDeclaration( + node, + node.decorators, + node.modifiers, + node.name, + node.typeParameters, + node.heritageClauses, + members + ); + } else if (isClassExpression(node)) { + node = updateClassExpression( + node, + node.modifiers, + node.name, + node.typeParameters, + node.heritageClauses, + members + ); + } + // Destroy private name environment. + delete privateNameEnvironmentStack[privateNameEnvironmentIndex--]; + return node; + } + function visitAwaitExpression(node: AwaitExpression): Expression { if (enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator) { return setOriginalNode( @@ -290,6 +413,18 @@ namespace ts { visitNode(node.right, noDestructuringValue ? visitorNoDestructuringValue : visitor, isExpression) ); } + else if (isAssignmentOperator(node.operatorToken.kind) && + isPropertyAccessExpression(node.left) && + isIdentifier(node.left.name) && + node.left.name.isPrivateName) + { + // If assigning to a private property, rewrite it as a call to the helper function. + const weakMapName = addPrivateNameToEnvironment(node.left.name); + return setOriginalNode( + createClassPrivateFieldSetHelper(context, node.left.expression, weakMapName, node.right), + node + ); + } return visitEachChild(node, visitor, context); } @@ -942,11 +1077,20 @@ namespace ts { } export function createClassPrivateFieldHelper(context: TransformationContext, privateField: Identifier) { + let mapName = null; + const text = (uniqueName: EmitHelperUniqueNameCallback) => { + const str = helperString`var ${"_" + privateField.escapedText} = new WeakMap();`; + return str(name => { + mapName = name; + return uniqueName(name); + }); + }; context.requestEmitHelper({ name: "typescript:classPrivateField", scoped: true, - text: helperString`var ${"_" + privateField.escapedText} = new WeakMap();` + text }); + return mapName; } const classPrivateFieldGetHelper: EmitHelper = { @@ -966,9 +1110,9 @@ namespace ts { text: `var _classPrivateFieldSet = function (receiver, privateMap, value) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to set private field on non-instance"); } privateMap.set(receiver, value); return value; };` }; - export function createClassPrivateFieldSetHelper(context: TransformationContext, expression: Expression) { + export function createClassPrivateFieldSetHelper(context: TransformationContext, receiver: Expression, privateField: Identifier, value: Expression) { context.requestEmitHelper(classPrivateFieldSetHelper); - return createCall(getHelperName("_classPrivateFieldSet"), /* typeArguments */ undefined, [ expression ]); + return createCall(getHelperName("_classPrivateFieldSet"), /* typeArguments */ undefined, [ receiver, privateField, value ]); } const awaitHelper: EmitHelper = { From 4abc3542e7c5c67afade4cefda5bce5dcf865e3d Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Fri, 29 Jun 2018 12:17:23 -0400 Subject: [PATCH 06/32] Generate WeakMap instances for private fields. Fix field initialization. Signed-off-by: Joseph Watts --- src/compiler/transformers/esnext.ts | 31 +++++++++++++---------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index fdf5dedce1d4a..848a92985d499 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -165,35 +165,32 @@ namespace ts { return visitEachChild(node, visitor, context); } - function visitClassLikeDeclaration(node: ClassLikeDeclaration): VisitResult { + function visitClassLikeDeclaration(node: ClassLikeDeclaration): Node[] { // Create private name environment. privateNameEnvironmentStack[++privateNameEnvironmentIndex] = {}; // Visit children. node = visitEachChild(node, visitor, context); // Create WeakMaps for private properties. - // TODO: insert these WeakMap statements somewhere in the code... const privateNameEnvironment = currentPrivateNameEnvironment(); - for (let propertyName in privateNameEnvironment) { - const { weakMapName } = privateNameEnvironment[propertyName]; - /*const weakMapStatement = */createVariableStatement( + const weakMapDeclarations = Object.keys(privateNameEnvironment).map(name => { + const { weakMapName } = privateNameEnvironment[name]; + return createVariableStatement( /* modifiers */ undefined, - [ - createVariableDeclaration(weakMapName, - /* typeNode */ undefined, - createNew( - createIdentifier('WeakMap'), - /* typeArguments */ undefined, - /* argumentsArray */ undefined - )) - ] + [createVariableDeclaration(weakMapName, + /* typeNode */ undefined, + createNew( + createIdentifier('WeakMap'), + /* typeArguments */ undefined, + /* argumentsArray */ undefined + ))] ); - } + }); const initializerStatements = Object.keys(privateNameEnvironment).map(name => { return createStatement( createCall( createPropertyAccess(privateNameEnvironment[name].weakMapName, 'set'), /* typeArguments */ undefined, - [privateNameEnvironment[name].initializer || createVoidZero()] + [createThis(), privateNameEnvironment[name].initializer || createVoidZero()] ) ); }); @@ -250,7 +247,7 @@ namespace ts { } // Destroy private name environment. delete privateNameEnvironmentStack[privateNameEnvironmentIndex--]; - return node; + return [ ...weakMapDeclarations, node ]; } function visitAwaitExpression(node: AwaitExpression): Expression { From f7fc9afbffb8fa479cdab5d8843e944e7478b96e Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Fri, 29 Jun 2018 12:19:11 -0400 Subject: [PATCH 07/32] Remove unused function. Signed-off-by: Joseph Watts --- src/compiler/transformers/esnext.ts | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 848a92985d499..bdc28eb824c9e 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -1073,23 +1073,6 @@ namespace ts { ); } - export function createClassPrivateFieldHelper(context: TransformationContext, privateField: Identifier) { - let mapName = null; - const text = (uniqueName: EmitHelperUniqueNameCallback) => { - const str = helperString`var ${"_" + privateField.escapedText} = new WeakMap();`; - return str(name => { - mapName = name; - return uniqueName(name); - }); - }; - context.requestEmitHelper({ - name: "typescript:classPrivateField", - scoped: true, - text - }); - return mapName; - } - const classPrivateFieldGetHelper: EmitHelper = { name: "typescript:classPrivateFieldGet", scoped: false, From f65b7bbbfe91546df36b8e4f3c6cb9d60d5f5b49 Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Mon, 2 Jul 2018 15:35:04 -0400 Subject: [PATCH 08/32] Clean up private name initializer code Signed-off-by: Joseph Watts --- src/compiler/transformers/esnext.ts | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index bdc28eb824c9e..51e6f3a13ebbb 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -31,7 +31,7 @@ namespace ts { * Maps private names to the generated name of the WeakMap. */ interface PrivateNameEnvironment { - [name: string]: { weakMapName: Identifier, initializer: Expression | undefined } + [name: string]: Identifier } let privateNameEnvironmentStack: PrivateNameEnvironment[] = []; let privateNameEnvironmentIndex = -1; @@ -128,19 +128,13 @@ namespace ts { } function addPrivateNameToEnvironment(name: Identifier, - initializer?: Expression, environment: PrivateNameEnvironment = currentPrivateNameEnvironment()) { const nameString = getTextOfIdentifierOrLiteral(name); if (nameString in environment) { - if (initializer) { - environment[nameString].initializer = initializer; - } - return environment[nameString].weakMapName; + return environment[nameString]; } const weakMapName = createFileLevelUniqueName('_' + nameString.substring(1)); - environment[nameString] = { - weakMapName, initializer - }; + environment[nameString] = weakMapName; return weakMapName; } @@ -173,7 +167,7 @@ namespace ts { // Create WeakMaps for private properties. const privateNameEnvironment = currentPrivateNameEnvironment(); const weakMapDeclarations = Object.keys(privateNameEnvironment).map(name => { - const { weakMapName } = privateNameEnvironment[name]; + const weakMapName = privateNameEnvironment[name]; return createVariableStatement( /* modifiers */ undefined, [createVariableDeclaration(weakMapName, @@ -188,9 +182,9 @@ namespace ts { const initializerStatements = Object.keys(privateNameEnvironment).map(name => { return createStatement( createCall( - createPropertyAccess(privateNameEnvironment[name].weakMapName, 'set'), + createPropertyAccess(privateNameEnvironment[name], 'set'), /* typeArguments */ undefined, - [createThis(), privateNameEnvironment[name].initializer || createVoidZero()] + [createThis(), createVoidZero()] ) ); }); From 23a8d6058231ce05eb8dcadaee6b3ae49f68e13e Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Tue, 3 Jul 2018 13:36:00 -0400 Subject: [PATCH 09/32] Clean up private field class transformation. Signed-off-by: Joseph Watts --- src/compiler/transformers/esnext.ts | 119 +++++++++++++++------------- 1 file changed, 66 insertions(+), 53 deletions(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 51e6f3a13ebbb..fdeb76af70c72 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -116,8 +116,9 @@ namespace ts { case SyntaxKind.PropertyAccessExpression: return visitPropertyAccessExpression(node as PropertyAccessExpression); case SyntaxKind.ClassDeclaration: + return visitClassDeclaration(node as ClassDeclaration); case SyntaxKind.ClassExpression: - return visitClassLikeDeclaration(node as ClassLikeDeclaration); + return visitClassExpression(node as ClassExpression); default: return visitEachChild(node, visitor, context); } @@ -159,12 +160,42 @@ namespace ts { return visitEachChild(node, visitor, context); } - function visitClassLikeDeclaration(node: ClassLikeDeclaration): Node[] { + function visitClassDeclaration(node: ClassDeclaration) { + startPrivateNameEnvironment(); + node = visitEachChild(node, visitor, context); + node = updateClassDeclaration( + node, + node.decorators, + node.modifiers, + node.name, + node.typeParameters, + node.heritageClauses, + transformClassMembers(node.members) + ); + return [...endPrivateNameEnvironment(), node]; + } + + function visitClassExpression(node: ClassExpression) { + startPrivateNameEnvironment(); + node = visitEachChild(node, visitor, context); + node = updateClassExpression( + node, + node.modifiers, + node.name, + node.typeParameters, + node.heritageClauses, + transformClassMembers(node.members) + ); + return [...endPrivateNameEnvironment(), node]; + } + + function startPrivateNameEnvironment() { // Create private name environment. privateNameEnvironmentStack[++privateNameEnvironmentIndex] = {}; - // Visit children. - node = visitEachChild(node, visitor, context); - // Create WeakMaps for private properties. + return currentPrivateNameEnvironment(); + } + + function endPrivateNameEnvironment(): Statement[] { const privateNameEnvironment = currentPrivateNameEnvironment(); const weakMapDeclarations = Object.keys(privateNameEnvironment).map(name => { const weakMapName = privateNameEnvironment[name]; @@ -179,6 +210,15 @@ namespace ts { ))] ); }); + // Destroy private name environment. + delete privateNameEnvironmentStack[privateNameEnvironmentIndex--]; + return weakMapDeclarations; + } + + function transformClassMembers(members: ReadonlyArray): ClassElement[] { + // Rewrite constructor with private name initializers. + const privateNameEnvironment = currentPrivateNameEnvironment(); + // Initialize private properties. const initializerStatements = Object.keys(privateNameEnvironment).map(name => { return createStatement( createCall( @@ -188,60 +228,33 @@ namespace ts { ) ); }); - let members = [...node.members]; - let ctor = find(members, (member) => isConstructorDeclaration(member)); - if (!ctor) { - // Create constructor with private field initializers. - ctor = createConstructor( - /* decorators */ undefined, - /* modifiers */ undefined, - /* parameters */ [], - createBlock(initializerStatements) - ); - members.unshift(ctor); - } else { - // Update existing constructor to add private field initializers. - members = members.map(member => { + const ctor = find(members, (member) => isConstructorDeclaration(member)) as ConstructorDeclaration | undefined; + if (ctor) { + const body = ctor.body ? + updateBlock(ctor.body, [...initializerStatements, ...ctor.body.statements]) : + createBlock(initializerStatements, /* multiLine */ undefined); + return members.map(member => { if (isConstructorDeclaration(member)) { - let statements = member.body ? - [...initializerStatements, ...member.body.statements] : - initializerStatements; return updateConstructor( - member, - member.decorators, - member.modifiers, - member.parameters, - createBlock(statements, member.body ? member.body.multiLine : undefined) + ctor, + ctor.decorators, + ctor.modifiers, + ctor.parameters, + body ); } return member; - }) - } - - // Update class members. - if (isClassDeclaration(node)) { - node = updateClassDeclaration( - node, - node.decorators, - node.modifiers, - node.name, - node.typeParameters, - node.heritageClauses, - members - ); - } else if (isClassExpression(node)) { - node = updateClassExpression( - node, - node.modifiers, - node.name, - node.typeParameters, - node.heritageClauses, - members - ); + }); } - // Destroy private name environment. - delete privateNameEnvironmentStack[privateNameEnvironmentIndex--]; - return [ ...weakMapDeclarations, node ]; + return [ + createConstructor( + /* decorators */ undefined, + /* modifiers */ undefined, + /* parameters */ [], + createBlock(initializerStatements) + ), + ...members + ]; } function visitAwaitExpression(node: AwaitExpression): Expression { From 7c63b54fec92598cb3533b2731c0e24ce617dc87 Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Tue, 3 Jul 2018 15:00:16 -0400 Subject: [PATCH 10/32] Fix private name transformation clash with constructor overload list Signed-off-by: Joseph Watts --- src/compiler/transformers/esnext.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index fdeb76af70c72..0154b37a96b2b 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -228,13 +228,14 @@ namespace ts { ) ); }); - const ctor = find(members, (member) => isConstructorDeclaration(member)) as ConstructorDeclaration | undefined; + const ctor = find( + members, + (member) => isConstructorDeclaration(member) && !!member.body + ) as ConstructorDeclaration | undefined; if (ctor) { - const body = ctor.body ? - updateBlock(ctor.body, [...initializerStatements, ...ctor.body.statements]) : - createBlock(initializerStatements, /* multiLine */ undefined); + const body = updateBlock(ctor.body!, [...initializerStatements, ...ctor.body!.statements]); return members.map(member => { - if (isConstructorDeclaration(member)) { + if (member === ctor) { return updateConstructor( ctor, ctor.decorators, From 832f457b90cac3f073a82e42f4cce637ee1b46fe Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Thu, 5 Jul 2018 17:33:26 -0400 Subject: [PATCH 11/32] Remove unnecessary exporting of private name helper functions. Signed-off-by: Joseph Watts --- src/compiler/transformers/esnext.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 0154b37a96b2b..0c23c3a1a671a 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -1087,7 +1087,7 @@ namespace ts { text: `var _classPrivateFieldGet = function (receiver, privateMap) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return privateMap.get(receiver); };` }; - export function createClassPrivateFieldGetHelper(context: TransformationContext, receiver: Expression, privateField: Identifier) { + function createClassPrivateFieldGetHelper(context: TransformationContext, receiver: Expression, privateField: Identifier) { context.requestEmitHelper(classPrivateFieldGetHelper); return createCall(getHelperName("_classPrivateFieldGet"), /* typeArguments */ undefined, [ receiver, privateField ]); } @@ -1098,7 +1098,7 @@ namespace ts { text: `var _classPrivateFieldSet = function (receiver, privateMap, value) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to set private field on non-instance"); } privateMap.set(receiver, value); return value; };` }; - export function createClassPrivateFieldSetHelper(context: TransformationContext, receiver: Expression, privateField: Identifier, value: Expression) { + function createClassPrivateFieldSetHelper(context: TransformationContext, receiver: Expression, privateField: Identifier, value: Expression) { context.requestEmitHelper(classPrivateFieldSetHelper); return createCall(getHelperName("_classPrivateFieldSet"), /* typeArguments */ undefined, [ receiver, privateField, value ]); } From fe4f98a1e7fe1b680330da67c02e039093b056bf Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Thu, 19 Jul 2018 16:53:31 -0400 Subject: [PATCH 12/32] Transform compound assignment expressions Signed-off-by: Joseph Watts --- src/compiler/transformers/esnext.ts | 35 +++++++++++++++++++++---- src/compiler/transformers/generators.ts | 22 ---------------- src/compiler/utilities.ts | 22 ++++++++++++++++ 3 files changed, 52 insertions(+), 27 deletions(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 0c23c3a1a671a..5c738e34c2ed4 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -423,12 +423,37 @@ namespace ts { isIdentifier(node.left.name) && node.left.name.isPrivateName) { - // If assigning to a private property, rewrite it as a call to the helper function. const weakMapName = addPrivateNameToEnvironment(node.left.name); - return setOriginalNode( - createClassPrivateFieldSetHelper(context, node.left.expression, weakMapName, node.right), - node - ); + if (isCompoundAssignment(node.operatorToken.kind)) { + let setReceiver: Expression; + let getReceiver: Identifier; + if (!isIdentifier(node.left.expression) && !isKeyword(node.left.expression.kind)) { + getReceiver = createTempVariable(/* recordTempVariable */ undefined); + hoistVariableDeclaration(getReceiver); + setReceiver = createBinary(getReceiver, SyntaxKind.EqualsToken, node.left.expression); + } else { + getReceiver = node.left.expression as Identifier; + setReceiver = node.left.expression as Identifier; + } + return setOriginalNode( + createClassPrivateFieldSetHelper( + context, + setReceiver, + weakMapName, + createBinary( + createClassPrivateFieldGetHelper(context, getReceiver, weakMapName), + getOperatorForCompoundAssignment(node.operatorToken.kind), + node.right + ) + ), + node + ); + } else { + return setOriginalNode( + createClassPrivateFieldSetHelper(context, node.left.expression, weakMapName, node.right), + node + ); + } } return visitEachChild(node, visitor, context); } diff --git a/src/compiler/transformers/generators.ts b/src/compiler/transformers/generators.ts index 5778b47a4f8b4..66089c15388d3 100644 --- a/src/compiler/transformers/generators.ts +++ b/src/compiler/transformers/generators.ts @@ -667,28 +667,6 @@ namespace ts { } } - function isCompoundAssignment(kind: BinaryOperator): kind is CompoundAssignmentOperator { - return kind >= SyntaxKind.FirstCompoundAssignment - && kind <= SyntaxKind.LastCompoundAssignment; - } - - function getOperatorForCompoundAssignment(kind: CompoundAssignmentOperator): BitwiseOperatorOrHigher { - switch (kind) { - case SyntaxKind.PlusEqualsToken: return SyntaxKind.PlusToken; - case SyntaxKind.MinusEqualsToken: return SyntaxKind.MinusToken; - case SyntaxKind.AsteriskEqualsToken: return SyntaxKind.AsteriskToken; - case SyntaxKind.AsteriskAsteriskEqualsToken: return SyntaxKind.AsteriskAsteriskToken; - case SyntaxKind.SlashEqualsToken: return SyntaxKind.SlashToken; - case SyntaxKind.PercentEqualsToken: return SyntaxKind.PercentToken; - case SyntaxKind.LessThanLessThanEqualsToken: return SyntaxKind.LessThanLessThanToken; - case SyntaxKind.GreaterThanGreaterThanEqualsToken: return SyntaxKind.GreaterThanGreaterThanToken; - case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: return SyntaxKind.GreaterThanGreaterThanGreaterThanToken; - case SyntaxKind.AmpersandEqualsToken: return SyntaxKind.AmpersandToken; - case SyntaxKind.BarEqualsToken: return SyntaxKind.BarToken; - case SyntaxKind.CaretEqualsToken: return SyntaxKind.CaretToken; - } - } - /** * Visits a right-associative binary expression containing `yield`. * diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index b8e12539e07da..a7fa1b63b438e 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3738,6 +3738,28 @@ namespace ts { && isLeftHandSideExpression(node.left); } + export function isCompoundAssignment(kind: BinaryOperator): kind is CompoundAssignmentOperator { + return kind >= SyntaxKind.FirstCompoundAssignment + && kind <= SyntaxKind.LastCompoundAssignment; + } + + export function getOperatorForCompoundAssignment(kind: CompoundAssignmentOperator): BitwiseOperatorOrHigher { + switch (kind) { + case SyntaxKind.PlusEqualsToken: return SyntaxKind.PlusToken; + case SyntaxKind.MinusEqualsToken: return SyntaxKind.MinusToken; + case SyntaxKind.AsteriskEqualsToken: return SyntaxKind.AsteriskToken; + case SyntaxKind.AsteriskAsteriskEqualsToken: return SyntaxKind.AsteriskAsteriskToken; + case SyntaxKind.SlashEqualsToken: return SyntaxKind.SlashToken; + case SyntaxKind.PercentEqualsToken: return SyntaxKind.PercentToken; + case SyntaxKind.LessThanLessThanEqualsToken: return SyntaxKind.LessThanLessThanToken; + case SyntaxKind.GreaterThanGreaterThanEqualsToken: return SyntaxKind.GreaterThanGreaterThanToken; + case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: return SyntaxKind.GreaterThanGreaterThanGreaterThanToken; + case SyntaxKind.AmpersandEqualsToken: return SyntaxKind.AmpersandToken; + case SyntaxKind.BarEqualsToken: return SyntaxKind.BarToken; + case SyntaxKind.CaretEqualsToken: return SyntaxKind.CaretToken; + } + } + export function isDestructuringAssignment(node: Node): node is DestructuringAssignment { if (isAssignmentExpression(node, /*excludeCompoundAssignment*/ true)) { const kind = node.left.kind; From 82932482acbdc24add7fa03fc52e64b14905f24b Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Thu, 19 Jul 2018 16:58:59 -0400 Subject: [PATCH 13/32] Fix linter errors Signed-off-by: Joseph Watts --- src/compiler/transformers/esnext.ts | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 5c738e34c2ed4..97cda3a7814dc 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -31,9 +31,9 @@ namespace ts { * Maps private names to the generated name of the WeakMap. */ interface PrivateNameEnvironment { - [name: string]: Identifier + [name: string]: Identifier; } - let privateNameEnvironmentStack: PrivateNameEnvironment[] = []; + const privateNameEnvironmentStack: PrivateNameEnvironment[] = []; let privateNameEnvironmentIndex = -1; return chainBundle(transformSourceFile); @@ -134,7 +134,7 @@ namespace ts { if (nameString in environment) { return environment[nameString]; } - const weakMapName = createFileLevelUniqueName('_' + nameString.substring(1)); + const weakMapName = createFileLevelUniqueName("_" + nameString.substring(1)); environment[nameString] = weakMapName; return weakMapName; } @@ -204,7 +204,7 @@ namespace ts { [createVariableDeclaration(weakMapName, /* typeNode */ undefined, createNew( - createIdentifier('WeakMap'), + createIdentifier("WeakMap"), /* typeArguments */ undefined, /* argumentsArray */ undefined ))] @@ -222,7 +222,7 @@ namespace ts { const initializerStatements = Object.keys(privateNameEnvironment).map(name => { return createStatement( createCall( - createPropertyAccess(privateNameEnvironment[name], 'set'), + createPropertyAccess(privateNameEnvironment[name], "set"), /* typeArguments */ undefined, [createThis(), createVoidZero()] ) @@ -421,8 +421,8 @@ namespace ts { else if (isAssignmentOperator(node.operatorToken.kind) && isPropertyAccessExpression(node.left) && isIdentifier(node.left.name) && - node.left.name.isPrivateName) - { + node.left.name.isPrivateName) { + const weakMapName = addPrivateNameToEnvironment(node.left.name); if (isCompoundAssignment(node.operatorToken.kind)) { let setReceiver: Expression; @@ -431,7 +431,8 @@ namespace ts { getReceiver = createTempVariable(/* recordTempVariable */ undefined); hoistVariableDeclaration(getReceiver); setReceiver = createBinary(getReceiver, SyntaxKind.EqualsToken, node.left.expression); - } else { + } + else { getReceiver = node.left.expression as Identifier; setReceiver = node.left.expression as Identifier; } @@ -448,7 +449,8 @@ namespace ts { ), node ); - } else { + } + else { return setOriginalNode( createClassPrivateFieldSetHelper(context, node.left.expression, weakMapName, node.right), node From d6cc08c5b5e241ad42c811500e5cc2a3620f2168 Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Mon, 20 Aug 2018 16:39:35 -0400 Subject: [PATCH 14/32] Use IIFE, transform initializers for classes with private names. Signed-off-by: Joseph Watts --- src/compiler/binder.ts | 4 +- src/compiler/transformers/es2015.ts | 12 ++++- src/compiler/transformers/esnext.ts | 69 ++++++++++++++++++----------- src/compiler/transformers/ts.ts | 34 +++++++++----- 4 files changed, 80 insertions(+), 39 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 9b5fff3eb26d7..713708952ffae 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -3312,7 +3312,7 @@ namespace ts { } // Private names are an ESNext feature. - if (isIdentifier(node.name) && node.name.isPrivateName) { + if (isPrivateName(node.name)) { transformFlags |= TransformFlags.AssertESNext; } @@ -3454,7 +3454,7 @@ namespace ts { } // Private names are an ESNext feature. - if (isIdentifier(node.name) && node.name.isPrivateName) { + if (isPrivateName(node.name)) { transformFlags |= TransformFlags.AssertESNext; } diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index da0de696608fd..1822b89dbd9ad 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -3306,11 +3306,14 @@ namespace ts { // The class statements are the statements generated by visiting the first statement with initializer of the // body (1), while all other statements are added to remainingStatements (2) - const isVariableStatementWithInitializer = (stmt: Statement) => isVariableStatement(stmt) && !!first(stmt.declarationList.declarations).initializer; + const isVariableStatementWithInitializer = (stmt: Statement) => !isEndOfDeclarationMarker(stmt) && + isVariableStatement(stmt) && !!first(stmt.declarationList.declarations).initializer; + const isEndOfDeclarationMarker = (stmt: Statement) => stmt.kind === SyntaxKind.EndOfDeclarationMarker; const bodyStatements = visitNodes(body.statements, visitor, isStatement); const classStatements = filter(bodyStatements, isVariableStatementWithInitializer); const remainingStatements = filter(bodyStatements, stmt => !isVariableStatementWithInitializer(stmt)); const varStatement = cast(first(classStatements), isVariableStatement); + const endOfDeclarationMarkers = filter(bodyStatements, isEndOfDeclarationMarker); // We know there is only one variable declaration here as we verified this in an // earlier call to isTypeScriptClassWrapper @@ -3382,12 +3385,17 @@ namespace ts { addRange(statements, funcStatements, classBodyEnd + 1); } + // Add other class statements (such as the WeakMap declarations output by the 'esnext' + // transformer for private names). + addRange(statements, classStatements, /*start*/ 1); + // Add the remaining statements of the outer wrapper. addRange(statements, remainingStatements); // The 'es2015' class transform may add an end-of-declaration marker. If so we will add it // after the remaining statements from the 'ts' transformer. - addRange(statements, classStatements, /*start*/ 1); + addRange(statements, endOfDeclarationMarkers); + // Recreate any outer parentheses or partially-emitted expressions to preserve source map // and comment locations. diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 97cda3a7814dc..de640f2845eaa 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -31,7 +31,10 @@ namespace ts { * Maps private names to the generated name of the WeakMap. */ interface PrivateNameEnvironment { - [name: string]: Identifier; + [name: string]: { + weakMap: Identifier; + initializer?: Expression; + }; } const privateNameEnvironmentStack: PrivateNameEnvironment[] = []; let privateNameEnvironmentIndex = -1; @@ -111,8 +114,6 @@ namespace ts { return visitParenthesizedExpression(node as ParenthesizedExpression, noDestructuringValue); case SyntaxKind.CatchClause: return visitCatchClause(node as CatchClause); - case SyntaxKind.PropertyDeclaration: - return visitPropertyDeclaration(node as PropertyDeclaration); case SyntaxKind.PropertyAccessExpression: return visitPropertyAccessExpression(node as PropertyAccessExpression); case SyntaxKind.ClassDeclaration: @@ -128,20 +129,32 @@ namespace ts { return privateNameEnvironmentStack[privateNameEnvironmentIndex]; } - function addPrivateNameToEnvironment(name: Identifier, - environment: PrivateNameEnvironment = currentPrivateNameEnvironment()) { - const nameString = getTextOfIdentifierOrLiteral(name); + function addPrivateName(name: PrivateName, initializer?: Expression) { + const environment = currentPrivateNameEnvironment(); + const nameString = getTextOfNode(name); if (nameString in environment) { - return environment[nameString]; + throw new Error("Redeclaring private name " + nameString + "."); } - const weakMapName = createFileLevelUniqueName("_" + nameString.substring(1)); - environment[nameString] = weakMapName; - return weakMapName; + const weakMap = createFileLevelUniqueName("_" + nameString.substring(1)); + environment[nameString] = { + weakMap, + initializer + }; + return weakMap; + } + + function accessPrivateName(name: PrivateName) { + const environment = currentPrivateNameEnvironment(); + const nameString = getTextOfNode(name); + if (nameString in environment) { + return environment[nameString].weakMap; + } + throw new Error("Accessing undeclared private name."); } function visitPropertyAccessExpression(node: PropertyAccessExpression): Expression { - if (node.name.isPrivateName) { - const weakMapName = addPrivateNameToEnvironment(node.name); + if (isPrivateName(node.name)) { + const weakMapName = accessPrivateName(node.name); return setOriginalNode( setTextRange( createClassPrivateFieldGetHelper(context, node.expression, weakMapName), @@ -153,15 +166,21 @@ namespace ts { return visitEachChild(node, visitor, context); } - function visitPropertyDeclaration(node: PropertyDeclaration): VisitResult { - if (isIdentifier(node.name) && node.name.isPrivateName) { - addPrivateNameToEnvironment(node.name); + function visitorCollectPrivateNames(node: Node): VisitResult { + if (isPropertyDeclaration(node) && isPrivateName(node.name)) { + addPrivateName(node.name, node.initializer); + return undefined; } - return visitEachChild(node, visitor, context); + // Don't collect private names from nested classes. + if (isClassLike(node)) { + return node; + } + return visitEachChild(node, visitorCollectPrivateNames, context); } function visitClassDeclaration(node: ClassDeclaration) { startPrivateNameEnvironment(); + node = visitEachChild(node, visitorCollectPrivateNames, context); node = visitEachChild(node, visitor, context); node = updateClassDeclaration( node, @@ -172,7 +191,7 @@ namespace ts { node.heritageClauses, transformClassMembers(node.members) ); - return [...endPrivateNameEnvironment(), node]; + return [node, ...endPrivateNameEnvironment()]; } function visitClassExpression(node: ClassExpression) { @@ -186,7 +205,7 @@ namespace ts { node.heritageClauses, transformClassMembers(node.members) ); - return [...endPrivateNameEnvironment(), node]; + return [node, ...endPrivateNameEnvironment()]; } function startPrivateNameEnvironment() { @@ -198,10 +217,10 @@ namespace ts { function endPrivateNameEnvironment(): Statement[] { const privateNameEnvironment = currentPrivateNameEnvironment(); const weakMapDeclarations = Object.keys(privateNameEnvironment).map(name => { - const weakMapName = privateNameEnvironment[name]; + const privateName = privateNameEnvironment[name]; return createVariableStatement( /* modifiers */ undefined, - [createVariableDeclaration(weakMapName, + [createVariableDeclaration(privateName.weakMap, /* typeNode */ undefined, createNew( createIdentifier("WeakMap"), @@ -220,11 +239,12 @@ namespace ts { const privateNameEnvironment = currentPrivateNameEnvironment(); // Initialize private properties. const initializerStatements = Object.keys(privateNameEnvironment).map(name => { + const privateName = privateNameEnvironment[name]; return createStatement( createCall( - createPropertyAccess(privateNameEnvironment[name], "set"), + createPropertyAccess(privateName.weakMap, "set"), /* typeArguments */ undefined, - [createThis(), createVoidZero()] + [createThis(), privateName.initializer || createVoidZero()] ) ); }); @@ -420,10 +440,9 @@ namespace ts { } else if (isAssignmentOperator(node.operatorToken.kind) && isPropertyAccessExpression(node.left) && - isIdentifier(node.left.name) && - node.left.name.isPrivateName) { + isPrivateName(node.left.name)) { - const weakMapName = addPrivateNameToEnvironment(node.left.name); + const weakMapName = accessPrivateName(node.left.name); if (isCompoundAssignment(node.operatorToken.kind)) { let setReceiver: Expression; let getReceiver: Identifier; diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 6eb8b6e0ef634..441ef05b92494 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -593,9 +593,10 @@ namespace ts { return parameter.decorators !== undefined && parameter.decorators.length > 0; } - function getClassFacts(node: ClassDeclaration, staticProperties: ReadonlyArray) { + function getClassFacts(node: ClassDeclaration, staticProperties: ReadonlyArray, privateProperties: ReadonlyArray) { let facts = ClassFacts.None; if (some(staticProperties)) facts |= ClassFacts.HasStaticInitializedProperties; + if (languageVersion < ScriptTarget.ESNext && some(privateProperties)) facts |= ClassFacts.UseImmediatelyInvokedFunctionExpression; const extendsClauseElement = getEffectiveBaseTypeNode(node); if (extendsClauseElement && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword) facts |= ClassFacts.IsDerivedClass; if (shouldEmitDecorateCallForClass(node)) facts |= ClassFacts.HasConstructorDecorators; @@ -623,7 +624,7 @@ namespace ts { pendingExpressions = undefined; const staticProperties = getInitializedProperties(node, /*isStatic*/ true); - const facts = getClassFacts(node, staticProperties); + const facts = getClassFacts(node, staticProperties, getPrivateProperties(node)); if (facts & ClassFacts.UseImmediatelyInvokedFunctionExpression) { context.startLexicalEnvironment(); @@ -973,13 +974,13 @@ namespace ts { // Check if we have property assignment inside class declaration. // If there is a property assignment, we need to emit constructor whether users define it or not // If there is no property assignment, we can omit constructor if users do not define it - const hasInstancePropertyWithInitializer = forEach(node.members, isInstanceInitializedProperty); + const hasNonPrivateInstancePropertyWithInitializer = forEach(node.members, member => isInstanceInitializedProperty(member) && isPrivateProperty(member)); const hasParameterPropertyAssignments = node.transformFlags & TransformFlags.ContainsParameterPropertyAssignments; const constructor = getFirstConstructorWithBody(node); // If the class does not contain nodes that require a synthesized constructor, // accept the current constructor if it exists. - if (!hasInstancePropertyWithInitializer && !hasParameterPropertyAssignments) { + if (!hasNonPrivateInstancePropertyWithInitializer && !hasParameterPropertyAssignments) { return visitEachChild(constructor, visitor, context); } @@ -1194,6 +1195,14 @@ namespace ts { ); } + function isPrivateProperty(member: ClassElement): member is PropertyDeclaration { + return member.kind === SyntaxKind.PropertyDeclaration && + !!member.name && isPrivateName(member.name); + } + + function getPrivateProperties(node: ClassExpression | ClassDeclaration): ReadonlyArray { + return filter(node.members, isPrivateProperty); + } /** * Gets all property declarations with initializers on either the static or instance side of a class. * @@ -1242,11 +1251,12 @@ namespace ts { */ function addInitializedPropertyStatements(statements: Statement[], properties: ReadonlyArray, receiver: LeftHandSideExpression) { for (const property of properties) { - const statement = createExpressionStatement(transformInitializedProperty(property, receiver)); - setSourceMapRange(statement, moveRangePastModifiers(property)); - setCommentRange(statement, property); - setOriginalNode(statement, property); - statements.push(statement); + if (!isPrivateProperty(property)) { + const statement = createStatement(transformInitializedProperty(property, receiver)); + setSourceMapRange(statement, moveRangePastModifiers(property)); + setCommentRange(statement, property); + statements.push(statement); + } } } @@ -2237,7 +2247,11 @@ namespace ts { return !nodeIsMissing(node.body); } - function visitPropertyDeclaration(node: PropertyDeclaration): undefined { + function visitPropertyDeclaration(node: PropertyDeclaration): PropertyDeclaration | undefined { + if (isPrivateName(node.name)) { + // Keep the private name declaration. + return node; + } const expr = getPropertyNameExpressionIfNeeded(node.name, some(node.decorators) || !!node.initializer, /*omitSimple*/ true); if (expr && !isSimpleInlineableExpression(expr)) { (pendingExpressions || (pendingExpressions = [])).push(expr); From 0c22191fdf76d96a3e9b3f7c60e32bb788fe6921 Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Tue, 21 Aug 2018 14:34:50 -0400 Subject: [PATCH 15/32] Fix class expression transformation, punt on IIFE class wrappers Signed-off-by: Joseph Watts --- src/compiler/transformers/esnext.ts | 45 ++++++++++++++++++++++------- src/compiler/transformers/ts.ts | 26 ++++++++--------- 2 files changed, 47 insertions(+), 24 deletions(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index de640f2845eaa..eac838b5a98e8 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -191,7 +191,13 @@ namespace ts { node.heritageClauses, transformClassMembers(node.members) ); - return [node, ...endPrivateNameEnvironment()]; + const statements = [ + node, + ...createPrivateNameWeakMapDeclarations( + endPrivateNameEnvironment() + ) + ]; + return statements; } function visitClassExpression(node: ClassExpression) { @@ -205,7 +211,9 @@ namespace ts { node.heritageClauses, transformClassMembers(node.members) ); - return [node, ...endPrivateNameEnvironment()]; + const expressions = createPrivateNameWeakMapAssignments(endPrivateNameEnvironment()); + expressions.push(node); + return createCommaList(expressions); } function startPrivateNameEnvironment() { @@ -214,24 +222,39 @@ namespace ts { return currentPrivateNameEnvironment(); } - function endPrivateNameEnvironment(): Statement[] { + function endPrivateNameEnvironment(): PrivateNameEnvironment { const privateNameEnvironment = currentPrivateNameEnvironment(); - const weakMapDeclarations = Object.keys(privateNameEnvironment).map(name => { - const privateName = privateNameEnvironment[name]; + // Destroy private name environment. + delete privateNameEnvironmentStack[privateNameEnvironmentIndex--]; + return privateNameEnvironment; + } + + function createPrivateNameWeakMapDeclarations(environment: PrivateNameEnvironment): Statement[] { + return Object.keys(environment).map(name => { + const privateName = environment[name]; return createVariableStatement( /* modifiers */ undefined, [createVariableDeclaration(privateName.weakMap, /* typeNode */ undefined, - createNew( - createIdentifier("WeakMap"), + createNew( + createIdentifier("WeakMap"), /* typeArguments */ undefined, /* argumentsArray */ undefined - ))] + ))] + ); + }); + } + + function createPrivateNameWeakMapAssignments(environment: PrivateNameEnvironment): Expression[] { + return Object.keys(environment).map(name => { + const privateName = environment[name]; + hoistVariableDeclaration(privateName.weakMap); + return createBinary( + privateName.weakMap, + SyntaxKind.EqualsToken, + createNew(createIdentifier("WeakMap"), /* typeArguments */ undefined, /* argumentsArray */ undefined) ); }); - // Destroy private name environment. - delete privateNameEnvironmentStack[privateNameEnvironmentIndex--]; - return weakMapDeclarations; } function transformClassMembers(members: ReadonlyArray): ClassElement[] { diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 441ef05b92494..7a4c0f4e06e50 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -593,10 +593,9 @@ namespace ts { return parameter.decorators !== undefined && parameter.decorators.length > 0; } - function getClassFacts(node: ClassDeclaration, staticProperties: ReadonlyArray, privateProperties: ReadonlyArray) { + function getClassFacts(node: ClassDeclaration, staticProperties: ReadonlyArray) { let facts = ClassFacts.None; if (some(staticProperties)) facts |= ClassFacts.HasStaticInitializedProperties; - if (languageVersion < ScriptTarget.ESNext && some(privateProperties)) facts |= ClassFacts.UseImmediatelyInvokedFunctionExpression; const extendsClauseElement = getEffectiveBaseTypeNode(node); if (extendsClauseElement && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword) facts |= ClassFacts.IsDerivedClass; if (shouldEmitDecorateCallForClass(node)) facts |= ClassFacts.HasConstructorDecorators; @@ -624,7 +623,7 @@ namespace ts { pendingExpressions = undefined; const staticProperties = getInitializedProperties(node, /*isStatic*/ true); - const facts = getClassFacts(node, staticProperties, getPrivateProperties(node)); + const facts = getClassFacts(node, staticProperties); if (facts & ClassFacts.UseImmediatelyInvokedFunctionExpression) { context.startLexicalEnvironment(); @@ -974,13 +973,13 @@ namespace ts { // Check if we have property assignment inside class declaration. // If there is a property assignment, we need to emit constructor whether users define it or not // If there is no property assignment, we can omit constructor if users do not define it - const hasNonPrivateInstancePropertyWithInitializer = forEach(node.members, member => isInstanceInitializedProperty(member) && isPrivateProperty(member)); + const hasInstancePropertyWithInitializer = forEach(node.members, member => isInstanceInitializedProperty(member) && !isPrivateProperty(member)); const hasParameterPropertyAssignments = node.transformFlags & TransformFlags.ContainsParameterPropertyAssignments; const constructor = getFirstConstructorWithBody(node); // If the class does not contain nodes that require a synthesized constructor, // accept the current constructor if it exists. - if (!hasNonPrivateInstancePropertyWithInitializer && !hasParameterPropertyAssignments) { + if (!hasInstancePropertyWithInitializer && !hasParameterPropertyAssignments) { return visitEachChild(constructor, visitor, context); } @@ -1200,9 +1199,6 @@ namespace ts { !!member.name && isPrivateName(member.name); } - function getPrivateProperties(node: ClassExpression | ClassDeclaration): ReadonlyArray { - return filter(node.members, isPrivateProperty); - } /** * Gets all property declarations with initializers on either the static or instance side of a class. * @@ -1251,12 +1247,13 @@ namespace ts { */ function addInitializedPropertyStatements(statements: Statement[], properties: ReadonlyArray, receiver: LeftHandSideExpression) { for (const property of properties) { - if (!isPrivateProperty(property)) { - const statement = createStatement(transformInitializedProperty(property, receiver)); - setSourceMapRange(statement, moveRangePastModifiers(property)); - setCommentRange(statement, property); - statements.push(statement); + if (isPrivateProperty(property)) { + continue; } + const statement = createStatement(transformInitializedProperty(property, receiver)); + setSourceMapRange(statement, moveRangePastModifiers(property)); + setCommentRange(statement, property); + statements.push(statement); } } @@ -1269,6 +1266,9 @@ namespace ts { function generateInitializedPropertyExpressions(properties: ReadonlyArray, receiver: LeftHandSideExpression) { const expressions: Expression[] = []; for (const property of properties) { + if (isPrivateProperty(property)) { + continue; + } const expression = transformInitializedProperty(property, receiver); startOnNewLine(expression); setSourceMapRange(expression, moveRangePastModifiers(property)); From 34be11c59e029b289af24d7fff808a187430c573 Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Tue, 21 Aug 2018 15:22:06 -0400 Subject: [PATCH 16/32] Only transform classes when there are private names. Signed-off-by: Joseph Watts --- src/compiler/transformers/esnext.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index eac838b5a98e8..b3d362a4bd70d 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -182,6 +182,9 @@ namespace ts { startPrivateNameEnvironment(); node = visitEachChild(node, visitorCollectPrivateNames, context); node = visitEachChild(node, visitor, context); + if (!currentPrivateNameEnvironment().length) { + return node; + } node = updateClassDeclaration( node, node.decorators, @@ -203,6 +206,9 @@ namespace ts { function visitClassExpression(node: ClassExpression) { startPrivateNameEnvironment(); node = visitEachChild(node, visitor, context); + if (!currentPrivateNameEnvironment().length) { + return node; + } node = updateClassExpression( node, node.modifiers, From 8cbf34f1a3d672132aeec13166297208fcb14d80 Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Tue, 21 Aug 2018 16:00:16 -0400 Subject: [PATCH 17/32] Fix weak map generation and class transformation Signed-off-by: Joseph Watts --- src/compiler/transformers/esnext.ts | 59 +++++++++++++++-------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index b3d362a4bd70d..33ccaa6c06659 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -182,44 +182,45 @@ namespace ts { startPrivateNameEnvironment(); node = visitEachChild(node, visitorCollectPrivateNames, context); node = visitEachChild(node, visitor, context); - if (!currentPrivateNameEnvironment().length) { - return node; - } - node = updateClassDeclaration( - node, - node.decorators, - node.modifiers, - node.name, - node.typeParameters, - node.heritageClauses, - transformClassMembers(node.members) + const statements = createPrivateNameWeakMapDeclarations( + currentPrivateNameEnvironment() ); - const statements = [ - node, - ...createPrivateNameWeakMapDeclarations( - endPrivateNameEnvironment() - ) - ]; + if (statements.length) { + node = updateClassDeclaration( + node, + node.decorators, + node.modifiers, + node.name, + node.typeParameters, + node.heritageClauses, + transformClassMembers(node.members) + ); + } + prependStatements(statements, [node]); + endPrivateNameEnvironment(); return statements; } function visitClassExpression(node: ClassExpression) { startPrivateNameEnvironment(); + node = visitEachChild(node, visitorCollectPrivateNames, context); node = visitEachChild(node, visitor, context); - if (!currentPrivateNameEnvironment().length) { - return node; - } - node = updateClassExpression( - node, - node.modifiers, - node.name, - node.typeParameters, - node.heritageClauses, - transformClassMembers(node.members) + const expressions = createPrivateNameWeakMapAssignments( + currentPrivateNameEnvironment() ); - const expressions = createPrivateNameWeakMapAssignments(endPrivateNameEnvironment()); + if (expressions.length) { + node = updateClassExpression( + node, + node.modifiers, + node.name, + node.typeParameters, + node.heritageClauses, + transformClassMembers(node.members) + ); + } expressions.push(node); - return createCommaList(expressions); + endPrivateNameEnvironment(); + return expressions.length > 1 ? createCommaList(expressions) : expressions[0]; } function startPrivateNameEnvironment() { From 4f1a883d4dc5c97a5f0dfe63970f7f570d129f0b Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Tue, 21 Aug 2018 17:22:29 -0400 Subject: [PATCH 18/32] Fix build error and cast __String to string Signed-off-by: Joseph Watts --- src/compiler/transformers/esnext.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 33ccaa6c06659..f8f84a7cea73c 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -131,7 +131,7 @@ namespace ts { function addPrivateName(name: PrivateName, initializer?: Expression) { const environment = currentPrivateNameEnvironment(); - const nameString = getTextOfNode(name); + const nameString = name.escapedText as string; if (nameString in environment) { throw new Error("Redeclaring private name " + nameString + "."); } @@ -145,7 +145,7 @@ namespace ts { function accessPrivateName(name: PrivateName) { const environment = currentPrivateNameEnvironment(); - const nameString = getTextOfNode(name); + const nameString = name.escapedText as string; if (nameString in environment) { return environment[nameString].weakMap; } @@ -196,7 +196,7 @@ namespace ts { transformClassMembers(node.members) ); } - prependStatements(statements, [node]); + statements.unshift(node); endPrivateNameEnvironment(); return statements; } From d66e135ddef29de9b420c445e37a213b9912f981 Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Tue, 11 Sep 2018 10:51:45 -0400 Subject: [PATCH 19/32] Fix out-of-order private named property initialization Signed-off-by: Joseph Watts --- src/compiler/transformers/esnext.ts | 4 ++-- src/compiler/transformers/ts.ts | 14 ++------------ src/compiler/types.ts | 4 ++++ src/compiler/utilities.ts | 4 ++++ 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index f8f84a7cea73c..4d8dc69d26604 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -167,8 +167,8 @@ namespace ts { } function visitorCollectPrivateNames(node: Node): VisitResult { - if (isPropertyDeclaration(node) && isPrivateName(node.name)) { - addPrivateName(node.name, node.initializer); + if (isPrivateNamedPropertyDeclaration(node)) { + addPrivateName(node.name); return undefined; } // Don't collect private names from nested classes. diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 7a4c0f4e06e50..5a5c119c0d71d 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -973,7 +973,7 @@ namespace ts { // Check if we have property assignment inside class declaration. // If there is a property assignment, we need to emit constructor whether users define it or not // If there is no property assignment, we can omit constructor if users do not define it - const hasInstancePropertyWithInitializer = forEach(node.members, member => isInstanceInitializedProperty(member) && !isPrivateProperty(member)); + const hasInstancePropertyWithInitializer = forEach(node.members, member => isInstanceInitializedProperty(member)); const hasParameterPropertyAssignments = node.transformFlags & TransformFlags.ContainsParameterPropertyAssignments; const constructor = getFirstConstructorWithBody(node); @@ -1194,11 +1194,6 @@ namespace ts { ); } - function isPrivateProperty(member: ClassElement): member is PropertyDeclaration { - return member.kind === SyntaxKind.PropertyDeclaration && - !!member.name && isPrivateName(member.name); - } - /** * Gets all property declarations with initializers on either the static or instance side of a class. * @@ -1247,12 +1242,10 @@ namespace ts { */ function addInitializedPropertyStatements(statements: Statement[], properties: ReadonlyArray, receiver: LeftHandSideExpression) { for (const property of properties) { - if (isPrivateProperty(property)) { - continue; - } const statement = createStatement(transformInitializedProperty(property, receiver)); setSourceMapRange(statement, moveRangePastModifiers(property)); setCommentRange(statement, property); + setOriginalNode(statement, property); statements.push(statement); } } @@ -1266,9 +1259,6 @@ namespace ts { function generateInitializedPropertyExpressions(properties: ReadonlyArray, receiver: LeftHandSideExpression) { const expressions: Expression[] = []; for (const property of properties) { - if (isPrivateProperty(property)) { - continue; - } const expression = transformInitializedProperty(property, receiver); startOnNewLine(expression); setSourceMapRange(expression, moveRangePastModifiers(property)); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 4b2357bc63e77..a86badd2c56a4 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -864,6 +864,10 @@ namespace ts { initializer?: Expression; // Optional initializer } + export interface PrivateNamedPropertyDeclaration extends PropertyDeclaration { + name: PrivateName; + } + export interface ObjectLiteralElement extends NamedDeclaration { _objectLiteralBrandBrand: any; name?: PropertyName; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index a7fa1b63b438e..74c1e6086514f 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -6091,6 +6091,10 @@ namespace ts { } } + export function isPrivateNamedPropertyDeclaration(node: Node): node is PrivateNamedPropertyDeclaration { + return node && isPropertyDeclaration(node) && isPrivateName(node.name); + } + // Type members export function isTypeElement(node: Node): node is TypeElement { From fab8ff966e49053d9e14b4d1a9ba8bb6aafa074d Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Tue, 11 Sep 2018 12:16:34 -0400 Subject: [PATCH 20/32] Clean up private name assignment expression temp variable emit Signed-off-by: Joseph Watts --- src/compiler/transformers/esnext.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 4d8dc69d26604..f70e8f53e87fe 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -475,15 +475,17 @@ namespace ts { const weakMapName = accessPrivateName(node.left.name); if (isCompoundAssignment(node.operatorToken.kind)) { let setReceiver: Expression; - let getReceiver: Identifier; - if (!isIdentifier(node.left.expression) && !isKeyword(node.left.expression.kind)) { - getReceiver = createTempVariable(/* recordTempVariable */ undefined); - hoistVariableDeclaration(getReceiver); - setReceiver = createBinary(getReceiver, SyntaxKind.EqualsToken, node.left.expression); + let getReceiver: Expression; + const receiverExpr = node.left.expression; + if (!isIdentifier(receiverExpr) && !isThisProperty(node.left) && !isSuperProperty(node.left)) { + const tempVariable = createTempVariable(/* recordTempVariable */ undefined); + hoistVariableDeclaration(tempVariable); + setReceiver = createBinary(tempVariable, SyntaxKind.EqualsToken, node.left.expression); + getReceiver = tempVariable; } else { - getReceiver = node.left.expression as Identifier; - setReceiver = node.left.expression as Identifier; + getReceiver = node.left.expression; + setReceiver = node.left.expression; } return setOriginalNode( createClassPrivateFieldSetHelper( From 4fb90826b518df91f505bf43b7c60831223b6aac Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Tue, 11 Sep 2018 12:31:35 -0400 Subject: [PATCH 21/32] Remove private named property declaration initializer in TS transform Signed-off-by: Joseph Watts --- src/compiler/transformers/ts.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 5a5c119c0d71d..5f0a10df777ff 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -2239,8 +2239,16 @@ namespace ts { function visitPropertyDeclaration(node: PropertyDeclaration): PropertyDeclaration | undefined { if (isPrivateName(node.name)) { - // Keep the private name declaration. - return node; + // Keep the private name declaration (without the initializer - which will be moved to the constructor). + return updateProperty( + node, + node.decorators, + node.modifiers, + node.name, + node.questionToken, + node.type, + /*initializer*/ undefined + ); } const expr = getPropertyNameExpressionIfNeeded(node.name, some(node.decorators) || !!node.initializer, /*omitSimple*/ true); if (expr && !isSimpleInlineableExpression(expr)) { From fec6ad8603b011b9038f39a83aab5df8fc6397eb Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Tue, 11 Sep 2018 14:09:59 -0400 Subject: [PATCH 22/32] Emit unchanged output for undeclared private names Signed-off-by: Joseph Watts --- src/compiler/transformers/esnext.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index f70e8f53e87fe..c1860a5d6358d 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -149,12 +149,16 @@ namespace ts { if (nameString in environment) { return environment[nameString].weakMap; } - throw new Error("Accessing undeclared private name."); + // Undeclared private name. + return undefined; } function visitPropertyAccessExpression(node: PropertyAccessExpression): Expression { if (isPrivateName(node.name)) { const weakMapName = accessPrivateName(node.name); + if (!weakMapName) { + return node; + } return setOriginalNode( setTextRange( createClassPrivateFieldGetHelper(context, node.expression, weakMapName), @@ -473,6 +477,10 @@ namespace ts { isPrivateName(node.left.name)) { const weakMapName = accessPrivateName(node.left.name); + if (!weakMapName) { + // Don't change output for undeclared private names (error). + return node; + } if (isCompoundAssignment(node.operatorToken.kind)) { let setReceiver: Expression; let getReceiver: Expression; From 9916d1c9a433b3f52e2354a97658ad672521526a Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Tue, 11 Sep 2018 14:49:21 -0400 Subject: [PATCH 23/32] Update privateNameField baseline Signed-off-by: Joseph Watts --- tests/baselines/reference/privateNameField.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/baselines/reference/privateNameField.js b/tests/baselines/reference/privateNameField.js index f432be2b3d336..c65f812af0dd9 100644 --- a/tests/baselines/reference/privateNameField.js +++ b/tests/baselines/reference/privateNameField.js @@ -7,9 +7,12 @@ class A { } //// [privateNameField.js] +var _classPrivateFieldSet = function (receiver, privateMap, value) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to set private field on non-instance"); } privateMap.set(receiver, value); return value; }; var A = /** @class */ (function () { function A(name) { - this.#name = name; + _name.set(this, void 0); + _classPrivateFieldSet(this, _name, name); } return A; }()); +var _name = new WeakMap; From 3b28ff718f7077235da666fec1d71b22fa0f20b3 Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Tue, 11 Sep 2018 14:54:51 -0400 Subject: [PATCH 24/32] Accept public API changes Signed-off-by: Joseph Watts --- tests/baselines/reference/api/tsserverlibrary.d.ts | 4 ++++ tests/baselines/reference/api/typescript.d.ts | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 1ab1a986d1ad1..0918ac03f824c 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -619,6 +619,9 @@ declare namespace ts { type?: TypeNode; initializer?: Expression; } + interface PrivateNamedPropertyDeclaration extends PropertyDeclaration { + name: PrivateName; + } interface ObjectLiteralElement extends NamedDeclaration { _objectLiteralBrandBrand: any; name?: PropertyName; @@ -3458,6 +3461,7 @@ declare namespace ts { function isClassElement(node: Node): node is ClassElement; function isClassLike(node: Node): node is ClassLikeDeclaration; function isAccessor(node: Node): node is AccessorDeclaration; + function isPrivateNamedPropertyDeclaration(node: Node): node is PrivateNamedPropertyDeclaration; function isTypeElement(node: Node): node is TypeElement; function isClassOrTypeElement(node: Node): node is ClassElement | TypeElement; function isObjectLiteralElementLike(node: Node): node is ObjectLiteralElementLike; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index ea78225538eac..acafe6f5d59a1 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -619,6 +619,9 @@ declare namespace ts { type?: TypeNode; initializer?: Expression; } + interface PrivateNamedPropertyDeclaration extends PropertyDeclaration { + name: PrivateName; + } interface ObjectLiteralElement extends NamedDeclaration { _objectLiteralBrandBrand: any; name?: PropertyName; @@ -3458,6 +3461,7 @@ declare namespace ts { function isClassElement(node: Node): node is ClassElement; function isClassLike(node: Node): node is ClassLikeDeclaration; function isAccessor(node: Node): node is AccessorDeclaration; + function isPrivateNamedPropertyDeclaration(node: Node): node is PrivateNamedPropertyDeclaration; function isTypeElement(node: Node): node is TypeElement; function isClassOrTypeElement(node: Node): node is ClassElement | TypeElement; function isObjectLiteralElementLike(node: Node): node is ObjectLiteralElementLike; From 1c4554a1bc04f2ec791f240c35706565fb24c153 Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Tue, 11 Sep 2018 14:58:06 -0400 Subject: [PATCH 25/32] Create initialized private named field conformance test Signed-off-by: Joseph Watts --- .../reference/privateNameFieldInitializer.js | 16 ++++++++++++++++ .../privateNameFieldInitializer.symbols | 8 ++++++++ .../reference/privateNameFieldInitializer.types | 9 +++++++++ .../privateNames/privateNameFieldInitializer.ts | 3 +++ 4 files changed, 36 insertions(+) create mode 100644 tests/baselines/reference/privateNameFieldInitializer.js create mode 100644 tests/baselines/reference/privateNameFieldInitializer.symbols create mode 100644 tests/baselines/reference/privateNameFieldInitializer.types create mode 100644 tests/cases/conformance/classes/members/privateNames/privateNameFieldInitializer.ts diff --git a/tests/baselines/reference/privateNameFieldInitializer.js b/tests/baselines/reference/privateNameFieldInitializer.js new file mode 100644 index 0000000000000..5263b7a4e5b34 --- /dev/null +++ b/tests/baselines/reference/privateNameFieldInitializer.js @@ -0,0 +1,16 @@ +//// [privateNameFieldInitializer.ts] +class Test { + #property: number = 100; +} + + +//// [privateNameFieldInitializer.js] +var _classPrivateFieldSet = function (receiver, privateMap, value) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to set private field on non-instance"); } privateMap.set(receiver, value); return value; }; +var Test = /** @class */ (function () { + function Test() { + _property.set(this, void 0); + _classPrivateFieldSet(this, _property, 100); + } + return Test; +}()); +var _property = new WeakMap; diff --git a/tests/baselines/reference/privateNameFieldInitializer.symbols b/tests/baselines/reference/privateNameFieldInitializer.symbols new file mode 100644 index 0000000000000..ed146bda6509e --- /dev/null +++ b/tests/baselines/reference/privateNameFieldInitializer.symbols @@ -0,0 +1,8 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameFieldInitializer.ts === +class Test { +>Test : Symbol(Test, Decl(privateNameFieldInitializer.ts, 0, 0)) + + #property: number = 100; +>#property : Symbol(Test[#property], Decl(privateNameFieldInitializer.ts, 0, 12)) +} + diff --git a/tests/baselines/reference/privateNameFieldInitializer.types b/tests/baselines/reference/privateNameFieldInitializer.types new file mode 100644 index 0000000000000..2aba97086ace9 --- /dev/null +++ b/tests/baselines/reference/privateNameFieldInitializer.types @@ -0,0 +1,9 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameFieldInitializer.ts === +class Test { +>Test : Test + + #property: number = 100; +>#property : number +>100 : 100 +} + diff --git a/tests/cases/conformance/classes/members/privateNames/privateNameFieldInitializer.ts b/tests/cases/conformance/classes/members/privateNames/privateNameFieldInitializer.ts new file mode 100644 index 0000000000000..267a29c982a83 --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNameFieldInitializer.ts @@ -0,0 +1,3 @@ +class Test { + #property: number = 100; +} From 8ba9238c33ca6ce996243aff0f801b5e45fde522 Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Tue, 11 Sep 2018 15:00:09 -0400 Subject: [PATCH 26/32] Create private named field accessor conformance test Signed-off-by: Joseph Watts --- .../reference/privateNameFieldAccess.js | 21 +++++++++++++++++++ .../reference/privateNameFieldAccess.symbols | 19 +++++++++++++++++ .../reference/privateNameFieldAccess.types | 20 ++++++++++++++++++ .../privateNames/privateNameFieldAccess.ts | 6 ++++++ 4 files changed, 66 insertions(+) create mode 100644 tests/baselines/reference/privateNameFieldAccess.js create mode 100644 tests/baselines/reference/privateNameFieldAccess.symbols create mode 100644 tests/baselines/reference/privateNameFieldAccess.types create mode 100644 tests/cases/conformance/classes/members/privateNames/privateNameFieldAccess.ts diff --git a/tests/baselines/reference/privateNameFieldAccess.js b/tests/baselines/reference/privateNameFieldAccess.js new file mode 100644 index 0000000000000..60cae8f40371b --- /dev/null +++ b/tests/baselines/reference/privateNameFieldAccess.js @@ -0,0 +1,21 @@ +//// [privateNameFieldAccess.ts] +class Test { + #field: number; + method() { + console.log(this.#field); + } +} + + +//// [privateNameFieldAccess.js] +var _classPrivateFieldGet = function (receiver, privateMap) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return privateMap.get(receiver); }; +var Test = /** @class */ (function () { + function Test() { + _field.set(this, void 0); + } + Test.prototype.method = function () { + console.log(_classPrivateFieldGet(this, _field)); + }; + return Test; +}()); +var _field = new WeakMap; diff --git a/tests/baselines/reference/privateNameFieldAccess.symbols b/tests/baselines/reference/privateNameFieldAccess.symbols new file mode 100644 index 0000000000000..8410c84c92b50 --- /dev/null +++ b/tests/baselines/reference/privateNameFieldAccess.symbols @@ -0,0 +1,19 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameFieldAccess.ts === +class Test { +>Test : Symbol(Test, Decl(privateNameFieldAccess.ts, 0, 0)) + + #field: number; +>#field : Symbol(Test[#field], Decl(privateNameFieldAccess.ts, 0, 12)) + + method() { +>method : Symbol(Test.method, Decl(privateNameFieldAccess.ts, 1, 19)) + + console.log(this.#field); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>this.#field : Symbol(Test[#field], Decl(privateNameFieldAccess.ts, 0, 12)) +>this : Symbol(Test, Decl(privateNameFieldAccess.ts, 0, 0)) + } +} + diff --git a/tests/baselines/reference/privateNameFieldAccess.types b/tests/baselines/reference/privateNameFieldAccess.types new file mode 100644 index 0000000000000..c32358360be40 --- /dev/null +++ b/tests/baselines/reference/privateNameFieldAccess.types @@ -0,0 +1,20 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameFieldAccess.ts === +class Test { +>Test : Test + + #field: number; +>#field : number + + method() { +>method : () => void + + console.log(this.#field); +>console.log(this.#field) : void +>console.log : (message?: any, ...optionalParams: any[]) => void +>console : Console +>log : (message?: any, ...optionalParams: any[]) => void +>this.#field : number +>this : this + } +} + diff --git a/tests/cases/conformance/classes/members/privateNames/privateNameFieldAccess.ts b/tests/cases/conformance/classes/members/privateNames/privateNameFieldAccess.ts new file mode 100644 index 0000000000000..c1fbc86317788 --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNameFieldAccess.ts @@ -0,0 +1,6 @@ +class Test { + #field: number; + method() { + console.log(this.#field); + } +} From c1d12f28cdc38a5ccd0fd96454b569c7bf23dd2c Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Tue, 11 Sep 2018 15:02:05 -0400 Subject: [PATCH 27/32] Create private named field mutation conformance test Signed-off-by: Joseph Watts --- .../reference/privateNameFieldMutate.js | 19 +++++++++++++++++++ .../reference/privateNameFieldMutate.symbols | 14 ++++++++++++++ .../reference/privateNameFieldMutate.types | 16 ++++++++++++++++ .../privateNames/privateNameFieldMutate.ts | 6 ++++++ 4 files changed, 55 insertions(+) create mode 100644 tests/baselines/reference/privateNameFieldMutate.js create mode 100644 tests/baselines/reference/privateNameFieldMutate.symbols create mode 100644 tests/baselines/reference/privateNameFieldMutate.types create mode 100644 tests/cases/conformance/classes/members/privateNames/privateNameFieldMutate.ts diff --git a/tests/baselines/reference/privateNameFieldMutate.js b/tests/baselines/reference/privateNameFieldMutate.js new file mode 100644 index 0000000000000..d8b0fb2898113 --- /dev/null +++ b/tests/baselines/reference/privateNameFieldMutate.js @@ -0,0 +1,19 @@ +//// [privateNameFieldMutate.ts] +class Test { + #field: number; + constructor() { + this.#field = 100; + } +} + + +//// [privateNameFieldMutate.js] +var _classPrivateFieldSet = function (receiver, privateMap, value) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to set private field on non-instance"); } privateMap.set(receiver, value); return value; }; +var Test = /** @class */ (function () { + function Test() { + _field.set(this, void 0); + _classPrivateFieldSet(this, _field, 100); + } + return Test; +}()); +var _field = new WeakMap; diff --git a/tests/baselines/reference/privateNameFieldMutate.symbols b/tests/baselines/reference/privateNameFieldMutate.symbols new file mode 100644 index 0000000000000..a65469aeda9fb --- /dev/null +++ b/tests/baselines/reference/privateNameFieldMutate.symbols @@ -0,0 +1,14 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameFieldMutate.ts === +class Test { +>Test : Symbol(Test, Decl(privateNameFieldMutate.ts, 0, 0)) + + #field: number; +>#field : Symbol(Test[#field], Decl(privateNameFieldMutate.ts, 0, 12)) + + constructor() { + this.#field = 100; +>this.#field : Symbol(Test[#field], Decl(privateNameFieldMutate.ts, 0, 12)) +>this : Symbol(Test, Decl(privateNameFieldMutate.ts, 0, 0)) + } +} + diff --git a/tests/baselines/reference/privateNameFieldMutate.types b/tests/baselines/reference/privateNameFieldMutate.types new file mode 100644 index 0000000000000..68e50b8670bf1 --- /dev/null +++ b/tests/baselines/reference/privateNameFieldMutate.types @@ -0,0 +1,16 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameFieldMutate.ts === +class Test { +>Test : Test + + #field: number; +>#field : number + + constructor() { + this.#field = 100; +>this.#field = 100 : 100 +>this.#field : number +>this : this +>100 : 100 + } +} + diff --git a/tests/cases/conformance/classes/members/privateNames/privateNameFieldMutate.ts b/tests/cases/conformance/classes/members/privateNames/privateNameFieldMutate.ts new file mode 100644 index 0000000000000..f5ffdd6490c79 --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNameFieldMutate.ts @@ -0,0 +1,6 @@ +class Test { + #field: number; + constructor() { + this.#field = 100; + } +} From c8ee3708eadf04c365f7f0082471d91c22fc769f Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Tue, 11 Sep 2018 15:06:56 -0400 Subject: [PATCH 28/32] Create private named field binary mutator conformance test Signed-off-by: Joseph Watts --- .../privateNameFieldMutateBinaryOp.js | 42 ++++++++++ .../privateNameFieldMutateBinaryOp.symbols | 58 +++++++++++++ .../privateNameFieldMutateBinaryOp.types | 82 +++++++++++++++++++ .../privateNameFieldMutateBinaryOp.ts | 17 ++++ 4 files changed, 199 insertions(+) create mode 100644 tests/baselines/reference/privateNameFieldMutateBinaryOp.js create mode 100644 tests/baselines/reference/privateNameFieldMutateBinaryOp.symbols create mode 100644 tests/baselines/reference/privateNameFieldMutateBinaryOp.types create mode 100644 tests/cases/conformance/classes/members/privateNames/privateNameFieldMutateBinaryOp.ts diff --git a/tests/baselines/reference/privateNameFieldMutateBinaryOp.js b/tests/baselines/reference/privateNameFieldMutateBinaryOp.js new file mode 100644 index 0000000000000..8e2a94b89e39e --- /dev/null +++ b/tests/baselines/reference/privateNameFieldMutateBinaryOp.js @@ -0,0 +1,42 @@ +//// [privateNameFieldMutateBinaryOp.ts] +class Test { + #field: number; + constructor() { + this.#field += 1; + this.#field -= 2; + this.#field /= 3; + this.#field *= 4; + this.#field |= 5; + this.#field **= 6; + this.#field %= 7; + this.#field <<= 8; + this.#field >>= 9; + this.#field >>>= 10; + this.#field &= 11; + this.#field ^= 12; + } +} + + +//// [privateNameFieldMutateBinaryOp.js] +var _classPrivateFieldGet = function (receiver, privateMap) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return privateMap.get(receiver); }; +var _classPrivateFieldSet = function (receiver, privateMap, value) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to set private field on non-instance"); } privateMap.set(receiver, value); return value; }; +var Test = /** @class */ (function () { + function Test() { + _field.set(this, void 0); + _classPrivateFieldSet(this, _field, _classPrivateFieldGet(this, _field) + 1); + _classPrivateFieldSet(this, _field, _classPrivateFieldGet(this, _field) - 2); + _classPrivateFieldSet(this, _field, _classPrivateFieldGet(this, _field) / 3); + _classPrivateFieldSet(this, _field, _classPrivateFieldGet(this, _field) * 4); + _classPrivateFieldSet(this, _field, _classPrivateFieldGet(this, _field) | 5); + _classPrivateFieldSet(this, _field, Math.pow(_classPrivateFieldGet(this, _field), 6)); + _classPrivateFieldSet(this, _field, _classPrivateFieldGet(this, _field) % 7); + _classPrivateFieldSet(this, _field, _classPrivateFieldGet(this, _field) << 8); + _classPrivateFieldSet(this, _field, _classPrivateFieldGet(this, _field) >> 9); + _classPrivateFieldSet(this, _field, _classPrivateFieldGet(this, _field) >>> 10); + _classPrivateFieldSet(this, _field, _classPrivateFieldGet(this, _field) & 11); + _classPrivateFieldSet(this, _field, _classPrivateFieldGet(this, _field) ^ 12); + } + return Test; +}()); +var _field = new WeakMap; diff --git a/tests/baselines/reference/privateNameFieldMutateBinaryOp.symbols b/tests/baselines/reference/privateNameFieldMutateBinaryOp.symbols new file mode 100644 index 0000000000000..77dd44462f666 --- /dev/null +++ b/tests/baselines/reference/privateNameFieldMutateBinaryOp.symbols @@ -0,0 +1,58 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameFieldMutateBinaryOp.ts === +class Test { +>Test : Symbol(Test, Decl(privateNameFieldMutateBinaryOp.ts, 0, 0)) + + #field: number; +>#field : Symbol(Test[#field], Decl(privateNameFieldMutateBinaryOp.ts, 0, 12)) + + constructor() { + this.#field += 1; +>this.#field : Symbol(Test[#field], Decl(privateNameFieldMutateBinaryOp.ts, 0, 12)) +>this : Symbol(Test, Decl(privateNameFieldMutateBinaryOp.ts, 0, 0)) + + this.#field -= 2; +>this.#field : Symbol(Test[#field], Decl(privateNameFieldMutateBinaryOp.ts, 0, 12)) +>this : Symbol(Test, Decl(privateNameFieldMutateBinaryOp.ts, 0, 0)) + + this.#field /= 3; +>this.#field : Symbol(Test[#field], Decl(privateNameFieldMutateBinaryOp.ts, 0, 12)) +>this : Symbol(Test, Decl(privateNameFieldMutateBinaryOp.ts, 0, 0)) + + this.#field *= 4; +>this.#field : Symbol(Test[#field], Decl(privateNameFieldMutateBinaryOp.ts, 0, 12)) +>this : Symbol(Test, Decl(privateNameFieldMutateBinaryOp.ts, 0, 0)) + + this.#field |= 5; +>this.#field : Symbol(Test[#field], Decl(privateNameFieldMutateBinaryOp.ts, 0, 12)) +>this : Symbol(Test, Decl(privateNameFieldMutateBinaryOp.ts, 0, 0)) + + this.#field **= 6; +>this.#field : Symbol(Test[#field], Decl(privateNameFieldMutateBinaryOp.ts, 0, 12)) +>this : Symbol(Test, Decl(privateNameFieldMutateBinaryOp.ts, 0, 0)) + + this.#field %= 7; +>this.#field : Symbol(Test[#field], Decl(privateNameFieldMutateBinaryOp.ts, 0, 12)) +>this : Symbol(Test, Decl(privateNameFieldMutateBinaryOp.ts, 0, 0)) + + this.#field <<= 8; +>this.#field : Symbol(Test[#field], Decl(privateNameFieldMutateBinaryOp.ts, 0, 12)) +>this : Symbol(Test, Decl(privateNameFieldMutateBinaryOp.ts, 0, 0)) + + this.#field >>= 9; +>this.#field : Symbol(Test[#field], Decl(privateNameFieldMutateBinaryOp.ts, 0, 12)) +>this : Symbol(Test, Decl(privateNameFieldMutateBinaryOp.ts, 0, 0)) + + this.#field >>>= 10; +>this.#field : Symbol(Test[#field], Decl(privateNameFieldMutateBinaryOp.ts, 0, 12)) +>this : Symbol(Test, Decl(privateNameFieldMutateBinaryOp.ts, 0, 0)) + + this.#field &= 11; +>this.#field : Symbol(Test[#field], Decl(privateNameFieldMutateBinaryOp.ts, 0, 12)) +>this : Symbol(Test, Decl(privateNameFieldMutateBinaryOp.ts, 0, 0)) + + this.#field ^= 12; +>this.#field : Symbol(Test[#field], Decl(privateNameFieldMutateBinaryOp.ts, 0, 12)) +>this : Symbol(Test, Decl(privateNameFieldMutateBinaryOp.ts, 0, 0)) + } +} + diff --git a/tests/baselines/reference/privateNameFieldMutateBinaryOp.types b/tests/baselines/reference/privateNameFieldMutateBinaryOp.types new file mode 100644 index 0000000000000..efd935fd68c2b --- /dev/null +++ b/tests/baselines/reference/privateNameFieldMutateBinaryOp.types @@ -0,0 +1,82 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameFieldMutateBinaryOp.ts === +class Test { +>Test : Test + + #field: number; +>#field : number + + constructor() { + this.#field += 1; +>this.#field += 1 : number +>this.#field : number +>this : this +>1 : 1 + + this.#field -= 2; +>this.#field -= 2 : number +>this.#field : number +>this : this +>2 : 2 + + this.#field /= 3; +>this.#field /= 3 : number +>this.#field : number +>this : this +>3 : 3 + + this.#field *= 4; +>this.#field *= 4 : number +>this.#field : number +>this : this +>4 : 4 + + this.#field |= 5; +>this.#field |= 5 : number +>this.#field : number +>this : this +>5 : 5 + + this.#field **= 6; +>this.#field **= 6 : number +>this.#field : number +>this : this +>6 : 6 + + this.#field %= 7; +>this.#field %= 7 : number +>this.#field : number +>this : this +>7 : 7 + + this.#field <<= 8; +>this.#field <<= 8 : number +>this.#field : number +>this : this +>8 : 8 + + this.#field >>= 9; +>this.#field >>= 9 : number +>this.#field : number +>this : this +>9 : 9 + + this.#field >>>= 10; +>this.#field >>>= 10 : number +>this.#field : number +>this : this +>10 : 10 + + this.#field &= 11; +>this.#field &= 11 : number +>this.#field : number +>this : this +>11 : 11 + + this.#field ^= 12; +>this.#field ^= 12 : number +>this.#field : number +>this : this +>12 : 12 + } +} + diff --git a/tests/cases/conformance/classes/members/privateNames/privateNameFieldMutateBinaryOp.ts b/tests/cases/conformance/classes/members/privateNames/privateNameFieldMutateBinaryOp.ts new file mode 100644 index 0000000000000..056886c54e7af --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNameFieldMutateBinaryOp.ts @@ -0,0 +1,17 @@ +class Test { + #field: number; + constructor() { + this.#field += 1; + this.#field -= 2; + this.#field /= 3; + this.#field *= 4; + this.#field |= 5; + this.#field **= 6; + this.#field %= 7; + this.#field <<= 8; + this.#field >>= 9; + this.#field >>>= 10; + this.#field &= 11; + this.#field ^= 12; + } +} From ddc58f1f715bd438c655b8c3785e7db0788b48fb Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Tue, 11 Sep 2018 15:09:38 -0400 Subject: [PATCH 29/32] Create private name non-trivial receiver mutation conformance test Signed-off-by: Joseph Watts --- ...rivateNameFieldMutateNontrivialReceiver.js | 47 ++++++++ ...eNameFieldMutateNontrivialReceiver.symbols | 66 +++++++++++ ...ateNameFieldMutateNontrivialReceiver.types | 104 ++++++++++++++++++ ...rivateNameFieldMutateNontrivialReceiver.ts | 18 +++ 4 files changed, 235 insertions(+) create mode 100644 tests/baselines/reference/privateNameFieldMutateNontrivialReceiver.js create mode 100644 tests/baselines/reference/privateNameFieldMutateNontrivialReceiver.symbols create mode 100644 tests/baselines/reference/privateNameFieldMutateNontrivialReceiver.types create mode 100644 tests/cases/conformance/classes/members/privateNames/privateNameFieldMutateNontrivialReceiver.ts diff --git a/tests/baselines/reference/privateNameFieldMutateNontrivialReceiver.js b/tests/baselines/reference/privateNameFieldMutateNontrivialReceiver.js new file mode 100644 index 0000000000000..a8ce123290523 --- /dev/null +++ b/tests/baselines/reference/privateNameFieldMutateNontrivialReceiver.js @@ -0,0 +1,47 @@ +//// [privateNameFieldMutateNontrivialReceiver.ts] +class Test { + #field: number; + static mutate(getReceiver: () => Test) { + getReceiver().#field = 100; + getReceiver().#field += 1; + getReceiver().#field -= 2; + getReceiver().#field /= 3; + getReceiver().#field *= 4; + getReceiver().#field |= 5; + getReceiver().#field **= 6; + getReceiver().#field %= 7; + getReceiver().#field <<= 8; + getReceiver().#field >>= 9; + getReceiver().#field >>>= 10; + getReceiver().#field &= 11; + getReceiver().#field ^= 12; + } +} + + +//// [privateNameFieldMutateNontrivialReceiver.js] +var _classPrivateFieldSet = function (receiver, privateMap, value) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to set private field on non-instance"); } privateMap.set(receiver, value); return value; }; +var _classPrivateFieldGet = function (receiver, privateMap) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return privateMap.get(receiver); }; +var Test = /** @class */ (function () { + function Test() { + _field.set(this, void 0); + } + Test.mutate = function (getReceiver) { + var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m; + _classPrivateFieldSet(getReceiver(), _field, 100); + _classPrivateFieldSet(_a = getReceiver(), _field, _classPrivateFieldGet(_a, _field) + 1); + _classPrivateFieldSet(_b = getReceiver(), _field, _classPrivateFieldGet(_b, _field) - 2); + _classPrivateFieldSet(_c = getReceiver(), _field, _classPrivateFieldGet(_c, _field) / 3); + _classPrivateFieldSet(_d = getReceiver(), _field, _classPrivateFieldGet(_d, _field) * 4); + _classPrivateFieldSet(_e = getReceiver(), _field, _classPrivateFieldGet(_e, _field) | 5); + _classPrivateFieldSet(_f = getReceiver(), _field, Math.pow(_classPrivateFieldGet(_f, _field), 6)); + _classPrivateFieldSet(_g = getReceiver(), _field, _classPrivateFieldGet(_g, _field) % 7); + _classPrivateFieldSet(_h = getReceiver(), _field, _classPrivateFieldGet(_h, _field) << 8); + _classPrivateFieldSet(_j = getReceiver(), _field, _classPrivateFieldGet(_j, _field) >> 9); + _classPrivateFieldSet(_k = getReceiver(), _field, _classPrivateFieldGet(_k, _field) >>> 10); + _classPrivateFieldSet(_l = getReceiver(), _field, _classPrivateFieldGet(_l, _field) & 11); + _classPrivateFieldSet(_m = getReceiver(), _field, _classPrivateFieldGet(_m, _field) ^ 12); + }; + return Test; +}()); +var _field = new WeakMap; diff --git a/tests/baselines/reference/privateNameFieldMutateNontrivialReceiver.symbols b/tests/baselines/reference/privateNameFieldMutateNontrivialReceiver.symbols new file mode 100644 index 0000000000000..dc6a6487fd86f --- /dev/null +++ b/tests/baselines/reference/privateNameFieldMutateNontrivialReceiver.symbols @@ -0,0 +1,66 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameFieldMutateNontrivialReceiver.ts === +class Test { +>Test : Symbol(Test, Decl(privateNameFieldMutateNontrivialReceiver.ts, 0, 0)) + + #field: number; +>#field : Symbol(Test[#field], Decl(privateNameFieldMutateNontrivialReceiver.ts, 0, 12)) + + static mutate(getReceiver: () => Test) { +>mutate : Symbol(Test.mutate, Decl(privateNameFieldMutateNontrivialReceiver.ts, 1, 19)) +>getReceiver : Symbol(getReceiver, Decl(privateNameFieldMutateNontrivialReceiver.ts, 2, 18)) +>Test : Symbol(Test, Decl(privateNameFieldMutateNontrivialReceiver.ts, 0, 0)) + + getReceiver().#field = 100; +>getReceiver().#field : Symbol(Test[#field], Decl(privateNameFieldMutateNontrivialReceiver.ts, 0, 12)) +>getReceiver : Symbol(getReceiver, Decl(privateNameFieldMutateNontrivialReceiver.ts, 2, 18)) + + getReceiver().#field += 1; +>getReceiver().#field : Symbol(Test[#field], Decl(privateNameFieldMutateNontrivialReceiver.ts, 0, 12)) +>getReceiver : Symbol(getReceiver, Decl(privateNameFieldMutateNontrivialReceiver.ts, 2, 18)) + + getReceiver().#field -= 2; +>getReceiver().#field : Symbol(Test[#field], Decl(privateNameFieldMutateNontrivialReceiver.ts, 0, 12)) +>getReceiver : Symbol(getReceiver, Decl(privateNameFieldMutateNontrivialReceiver.ts, 2, 18)) + + getReceiver().#field /= 3; +>getReceiver().#field : Symbol(Test[#field], Decl(privateNameFieldMutateNontrivialReceiver.ts, 0, 12)) +>getReceiver : Symbol(getReceiver, Decl(privateNameFieldMutateNontrivialReceiver.ts, 2, 18)) + + getReceiver().#field *= 4; +>getReceiver().#field : Symbol(Test[#field], Decl(privateNameFieldMutateNontrivialReceiver.ts, 0, 12)) +>getReceiver : Symbol(getReceiver, Decl(privateNameFieldMutateNontrivialReceiver.ts, 2, 18)) + + getReceiver().#field |= 5; +>getReceiver().#field : Symbol(Test[#field], Decl(privateNameFieldMutateNontrivialReceiver.ts, 0, 12)) +>getReceiver : Symbol(getReceiver, Decl(privateNameFieldMutateNontrivialReceiver.ts, 2, 18)) + + getReceiver().#field **= 6; +>getReceiver().#field : Symbol(Test[#field], Decl(privateNameFieldMutateNontrivialReceiver.ts, 0, 12)) +>getReceiver : Symbol(getReceiver, Decl(privateNameFieldMutateNontrivialReceiver.ts, 2, 18)) + + getReceiver().#field %= 7; +>getReceiver().#field : Symbol(Test[#field], Decl(privateNameFieldMutateNontrivialReceiver.ts, 0, 12)) +>getReceiver : Symbol(getReceiver, Decl(privateNameFieldMutateNontrivialReceiver.ts, 2, 18)) + + getReceiver().#field <<= 8; +>getReceiver().#field : Symbol(Test[#field], Decl(privateNameFieldMutateNontrivialReceiver.ts, 0, 12)) +>getReceiver : Symbol(getReceiver, Decl(privateNameFieldMutateNontrivialReceiver.ts, 2, 18)) + + getReceiver().#field >>= 9; +>getReceiver().#field : Symbol(Test[#field], Decl(privateNameFieldMutateNontrivialReceiver.ts, 0, 12)) +>getReceiver : Symbol(getReceiver, Decl(privateNameFieldMutateNontrivialReceiver.ts, 2, 18)) + + getReceiver().#field >>>= 10; +>getReceiver().#field : Symbol(Test[#field], Decl(privateNameFieldMutateNontrivialReceiver.ts, 0, 12)) +>getReceiver : Symbol(getReceiver, Decl(privateNameFieldMutateNontrivialReceiver.ts, 2, 18)) + + getReceiver().#field &= 11; +>getReceiver().#field : Symbol(Test[#field], Decl(privateNameFieldMutateNontrivialReceiver.ts, 0, 12)) +>getReceiver : Symbol(getReceiver, Decl(privateNameFieldMutateNontrivialReceiver.ts, 2, 18)) + + getReceiver().#field ^= 12; +>getReceiver().#field : Symbol(Test[#field], Decl(privateNameFieldMutateNontrivialReceiver.ts, 0, 12)) +>getReceiver : Symbol(getReceiver, Decl(privateNameFieldMutateNontrivialReceiver.ts, 2, 18)) + } +} + diff --git a/tests/baselines/reference/privateNameFieldMutateNontrivialReceiver.types b/tests/baselines/reference/privateNameFieldMutateNontrivialReceiver.types new file mode 100644 index 0000000000000..8083ba4e510f9 --- /dev/null +++ b/tests/baselines/reference/privateNameFieldMutateNontrivialReceiver.types @@ -0,0 +1,104 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameFieldMutateNontrivialReceiver.ts === +class Test { +>Test : Test + + #field: number; +>#field : number + + static mutate(getReceiver: () => Test) { +>mutate : (getReceiver: () => Test) => void +>getReceiver : () => Test + + getReceiver().#field = 100; +>getReceiver().#field = 100 : 100 +>getReceiver().#field : number +>getReceiver() : Test +>getReceiver : () => Test +>100 : 100 + + getReceiver().#field += 1; +>getReceiver().#field += 1 : number +>getReceiver().#field : number +>getReceiver() : Test +>getReceiver : () => Test +>1 : 1 + + getReceiver().#field -= 2; +>getReceiver().#field -= 2 : number +>getReceiver().#field : number +>getReceiver() : Test +>getReceiver : () => Test +>2 : 2 + + getReceiver().#field /= 3; +>getReceiver().#field /= 3 : number +>getReceiver().#field : number +>getReceiver() : Test +>getReceiver : () => Test +>3 : 3 + + getReceiver().#field *= 4; +>getReceiver().#field *= 4 : number +>getReceiver().#field : number +>getReceiver() : Test +>getReceiver : () => Test +>4 : 4 + + getReceiver().#field |= 5; +>getReceiver().#field |= 5 : number +>getReceiver().#field : number +>getReceiver() : Test +>getReceiver : () => Test +>5 : 5 + + getReceiver().#field **= 6; +>getReceiver().#field **= 6 : number +>getReceiver().#field : number +>getReceiver() : Test +>getReceiver : () => Test +>6 : 6 + + getReceiver().#field %= 7; +>getReceiver().#field %= 7 : number +>getReceiver().#field : number +>getReceiver() : Test +>getReceiver : () => Test +>7 : 7 + + getReceiver().#field <<= 8; +>getReceiver().#field <<= 8 : number +>getReceiver().#field : number +>getReceiver() : Test +>getReceiver : () => Test +>8 : 8 + + getReceiver().#field >>= 9; +>getReceiver().#field >>= 9 : number +>getReceiver().#field : number +>getReceiver() : Test +>getReceiver : () => Test +>9 : 9 + + getReceiver().#field >>>= 10; +>getReceiver().#field >>>= 10 : number +>getReceiver().#field : number +>getReceiver() : Test +>getReceiver : () => Test +>10 : 10 + + getReceiver().#field &= 11; +>getReceiver().#field &= 11 : number +>getReceiver().#field : number +>getReceiver() : Test +>getReceiver : () => Test +>11 : 11 + + getReceiver().#field ^= 12; +>getReceiver().#field ^= 12 : number +>getReceiver().#field : number +>getReceiver() : Test +>getReceiver : () => Test +>12 : 12 + } +} + diff --git a/tests/cases/conformance/classes/members/privateNames/privateNameFieldMutateNontrivialReceiver.ts b/tests/cases/conformance/classes/members/privateNames/privateNameFieldMutateNontrivialReceiver.ts new file mode 100644 index 0000000000000..1ba92e98918e1 --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNameFieldMutateNontrivialReceiver.ts @@ -0,0 +1,18 @@ +class Test { + #field: number; + static mutate(getReceiver: () => Test) { + getReceiver().#field = 100; + getReceiver().#field += 1; + getReceiver().#field -= 2; + getReceiver().#field /= 3; + getReceiver().#field *= 4; + getReceiver().#field |= 5; + getReceiver().#field **= 6; + getReceiver().#field %= 7; + getReceiver().#field <<= 8; + getReceiver().#field >>= 9; + getReceiver().#field >>>= 10; + getReceiver().#field &= 11; + getReceiver().#field ^= 12; + } +} From 282447417f08d5a67e13f1016264fb133fe25ccb Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Tue, 11 Sep 2018 15:26:39 -0400 Subject: [PATCH 30/32] Fix private name assignment referencing private names in the RHS expr Signed-off-by: Joseph Watts --- src/compiler/transformers/esnext.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index c1860a5d6358d..3c3234b174817 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -503,7 +503,7 @@ namespace ts { createBinary( createClassPrivateFieldGetHelper(context, getReceiver, weakMapName), getOperatorForCompoundAssignment(node.operatorToken.kind), - node.right + visitNode(node.right, visitor) ) ), node @@ -511,7 +511,12 @@ namespace ts { } else { return setOriginalNode( - createClassPrivateFieldSetHelper(context, node.left.expression, weakMapName, node.right), + createClassPrivateFieldSetHelper( + context, + node.left.expression, + weakMapName, + visitNode(node.right, visitor) + ), node ); } From e2ce860f7e6cfe96a263e4797227b96c1a0e5f8a Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Tue, 11 Sep 2018 15:27:08 -0400 Subject: [PATCH 31/32] Create private named field initialization order conformance test Signed-off-by: Joseph Watts --- .../privateNameInitializationOrder.js | 25 ++++++++++++++++++ .../privateNameInitializationOrder.symbols | 21 +++++++++++++++ .../privateNameInitializationOrder.types | 26 +++++++++++++++++++ .../privateNameInitializationOrder.ts | 6 +++++ 4 files changed, 78 insertions(+) create mode 100644 tests/baselines/reference/privateNameInitializationOrder.js create mode 100644 tests/baselines/reference/privateNameInitializationOrder.symbols create mode 100644 tests/baselines/reference/privateNameInitializationOrder.types create mode 100644 tests/cases/conformance/classes/members/privateNames/privateNameInitializationOrder.ts diff --git a/tests/baselines/reference/privateNameInitializationOrder.js b/tests/baselines/reference/privateNameInitializationOrder.js new file mode 100644 index 0000000000000..daefcf894dcbe --- /dev/null +++ b/tests/baselines/reference/privateNameInitializationOrder.js @@ -0,0 +1,25 @@ +//// [privateNameInitializationOrder.ts] +let a = 0; +class Test { + #one = ++a; + normalProp = ++a; + #two = this.#one + 1; +} + + +//// [privateNameInitializationOrder.js] +var _classPrivateFieldSet = function (receiver, privateMap, value) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to set private field on non-instance"); } privateMap.set(receiver, value); return value; }; +var _classPrivateFieldGet = function (receiver, privateMap) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return privateMap.get(receiver); }; +var a = 0; +var Test = /** @class */ (function () { + function Test() { + _one.set(this, void 0); + _two.set(this, void 0); + _classPrivateFieldSet(this, _one, ++a); + this.normalProp = ++a; + _classPrivateFieldSet(this, _two, _classPrivateFieldGet(this, _one) + 1); + } + return Test; +}()); +var _one = new WeakMap; +var _two = new WeakMap; diff --git a/tests/baselines/reference/privateNameInitializationOrder.symbols b/tests/baselines/reference/privateNameInitializationOrder.symbols new file mode 100644 index 0000000000000..4e1907226bb69 --- /dev/null +++ b/tests/baselines/reference/privateNameInitializationOrder.symbols @@ -0,0 +1,21 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameInitializationOrder.ts === +let a = 0; +>a : Symbol(a, Decl(privateNameInitializationOrder.ts, 0, 3)) + +class Test { +>Test : Symbol(Test, Decl(privateNameInitializationOrder.ts, 0, 10)) + + #one = ++a; +>#one : Symbol(Test[#one], Decl(privateNameInitializationOrder.ts, 1, 12)) +>a : Symbol(a, Decl(privateNameInitializationOrder.ts, 0, 3)) + + normalProp = ++a; +>normalProp : Symbol(Test.normalProp, Decl(privateNameInitializationOrder.ts, 2, 15)) +>a : Symbol(a, Decl(privateNameInitializationOrder.ts, 0, 3)) + + #two = this.#one + 1; +>#two : Symbol(Test[#two], Decl(privateNameInitializationOrder.ts, 3, 21)) +>this.#one : Symbol(Test[#one], Decl(privateNameInitializationOrder.ts, 1, 12)) +>this : Symbol(Test, Decl(privateNameInitializationOrder.ts, 0, 10)) +} + diff --git a/tests/baselines/reference/privateNameInitializationOrder.types b/tests/baselines/reference/privateNameInitializationOrder.types new file mode 100644 index 0000000000000..5f12b7a054689 --- /dev/null +++ b/tests/baselines/reference/privateNameInitializationOrder.types @@ -0,0 +1,26 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameInitializationOrder.ts === +let a = 0; +>a : number +>0 : 0 + +class Test { +>Test : Test + + #one = ++a; +>#one : number +>++a : number +>a : number + + normalProp = ++a; +>normalProp : number +>++a : number +>a : number + + #two = this.#one + 1; +>#two : number +>this.#one + 1 : number +>this.#one : number +>this : this +>1 : 1 +} + diff --git a/tests/cases/conformance/classes/members/privateNames/privateNameInitializationOrder.ts b/tests/cases/conformance/classes/members/privateNames/privateNameInitializationOrder.ts new file mode 100644 index 0000000000000..90906299640fb --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNameInitializationOrder.ts @@ -0,0 +1,6 @@ +let a = 0; +class Test { + #one = ++a; + normalProp = ++a; + #two = this.#one + 1; +} From a63b52d8786d5404a707e96d0ac644dde6648b0a Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Tue, 11 Sep 2018 15:54:02 -0400 Subject: [PATCH 32/32] Revert unnecessary changes Signed-off-by: Joseph Watts --- src/compiler/transformers/ts.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 5f0a10df777ff..3ce50892297a0 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -973,7 +973,7 @@ namespace ts { // Check if we have property assignment inside class declaration. // If there is a property assignment, we need to emit constructor whether users define it or not // If there is no property assignment, we can omit constructor if users do not define it - const hasInstancePropertyWithInitializer = forEach(node.members, member => isInstanceInitializedProperty(member)); + const hasInstancePropertyWithInitializer = forEach(node.members, isInstanceInitializedProperty); const hasParameterPropertyAssignments = node.transformFlags & TransformFlags.ContainsParameterPropertyAssignments; const constructor = getFirstConstructorWithBody(node); @@ -1242,7 +1242,7 @@ namespace ts { */ function addInitializedPropertyStatements(statements: Statement[], properties: ReadonlyArray, receiver: LeftHandSideExpression) { for (const property of properties) { - const statement = createStatement(transformInitializedProperty(property, receiver)); + const statement = createExpressionStatement(transformInitializedProperty(property, receiver)); setSourceMapRange(statement, moveRangePastModifiers(property)); setCommentRange(statement, property); setOriginalNode(statement, property);