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/15] 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/15] 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 0b0199aca8630ebb01774b749e34e3120a2f0e04 Mon Sep 17 00:00:00 2001 From: Joseph Watts Date: Thu, 28 Jun 2018 14:14:40 -0400 Subject: [PATCH 03/15] Start ES2015 transformation Signed-off-by: Joseph Watts --- src/compiler/binder.ts | 10 + src/compiler/transformers/es2015.ts | 12 +- src/compiler/transformers/esnext.ts | 277 ++++++++++++++++++ src/compiler/transformers/generators.ts | 22 -- src/compiler/transformers/ts.ts | 14 +- src/compiler/types.ts | 4 + src/compiler/utilities.ts | 26 ++ .../reference/api/tsserverlibrary.d.ts | 4 + tests/baselines/reference/api/typescript.d.ts | 4 + tests/baselines/reference/privateNameField.js | 5 +- .../reference/privateNameFieldAccess.js | 21 ++ .../reference/privateNameFieldAccess.symbols | 19 ++ .../reference/privateNameFieldAccess.types | 20 ++ .../reference/privateNameFieldInitializer.js | 16 + .../privateNameFieldInitializer.symbols | 8 + .../privateNameFieldInitializer.types | 9 + .../reference/privateNameFieldMutate.js | 19 ++ .../reference/privateNameFieldMutate.symbols | 14 + .../reference/privateNameFieldMutate.types | 16 + .../privateNameFieldMutateBinaryOp.js | 42 +++ .../privateNameFieldMutateBinaryOp.symbols | 58 ++++ .../privateNameFieldMutateBinaryOp.types | 82 ++++++ ...rivateNameFieldMutateNontrivialReceiver.js | 47 +++ ...eNameFieldMutateNontrivialReceiver.symbols | 66 +++++ ...ateNameFieldMutateNontrivialReceiver.types | 104 +++++++ .../privateNameInitializationOrder.js | 25 ++ .../privateNameInitializationOrder.symbols | 21 ++ .../privateNameInitializationOrder.types | 26 ++ .../privateNames/privateNameFieldAccess.ts | 6 + .../privateNameFieldInitializer.ts | 3 + .../privateNames/privateNameFieldMutate.ts | 6 + .../privateNameFieldMutateBinaryOp.ts | 17 ++ ...rivateNameFieldMutateNontrivialReceiver.ts | 18 ++ .../privateNameInitializationOrder.ts | 6 + 34 files changed, 1021 insertions(+), 26 deletions(-) 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/baselines/reference/privateNameFieldInitializer.js create mode 100644 tests/baselines/reference/privateNameFieldInitializer.symbols create mode 100644 tests/baselines/reference/privateNameFieldInitializer.types 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/baselines/reference/privateNameFieldMutateBinaryOp.js create mode 100644 tests/baselines/reference/privateNameFieldMutateBinaryOp.symbols create mode 100644 tests/baselines/reference/privateNameFieldMutateBinaryOp.types 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/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/privateNameFieldAccess.ts create mode 100644 tests/cases/conformance/classes/members/privateNames/privateNameFieldInitializer.ts create mode 100644 tests/cases/conformance/classes/members/privateNames/privateNameFieldMutate.ts create mode 100644 tests/cases/conformance/classes/members/privateNames/privateNameFieldMutateBinaryOp.ts create mode 100644 tests/cases/conformance/classes/members/privateNames/privateNameFieldMutateNontrivialReceiver.ts create mode 100644 tests/cases/conformance/classes/members/privateNames/privateNameInitializationOrder.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index ebc43e006bdfc..713708952ffae 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 (isPrivateName(node.name)) { + 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 (isPrivateName(node.name)) { + transformFlags |= TransformFlags.AssertESNext; + } + node.transformFlags = transformFlags | TransformFlags.HasComputedFlags; return transformFlags & ~TransformFlags.PropertyAccessExcludes; } 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 b121eb315db84..3c3234b174817 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -26,6 +26,19 @@ namespace ts { let enclosingFunctionFlags: FunctionFlags; let enclosingSuperContainerFlags: NodeCheckFlags = 0; + + /** + * Maps private names to the generated name of the WeakMap. + */ + interface PrivateNameEnvironment { + [name: string]: { + weakMap: Identifier; + initializer?: Expression; + }; + } + const privateNameEnvironmentStack: PrivateNameEnvironment[] = []; + let privateNameEnvironmentIndex = -1; + return chainBundle(transformSourceFile); function transformSourceFile(node: SourceFile) { @@ -101,11 +114,204 @@ namespace ts { return visitParenthesizedExpression(node as ParenthesizedExpression, noDestructuringValue); case SyntaxKind.CatchClause: return visitCatchClause(node as CatchClause); + case SyntaxKind.PropertyAccessExpression: + return visitPropertyAccessExpression(node as PropertyAccessExpression); + case SyntaxKind.ClassDeclaration: + return visitClassDeclaration(node as ClassDeclaration); + case SyntaxKind.ClassExpression: + return visitClassExpression(node as ClassExpression); default: return visitEachChild(node, visitor, context); } } + function currentPrivateNameEnvironment() { + return privateNameEnvironmentStack[privateNameEnvironmentIndex]; + } + + function addPrivateName(name: PrivateName, initializer?: Expression) { + const environment = currentPrivateNameEnvironment(); + const nameString = name.escapedText as string; + if (nameString in environment) { + throw new Error("Redeclaring private name " + nameString + "."); + } + const weakMap = createFileLevelUniqueName("_" + nameString.substring(1)); + environment[nameString] = { + weakMap, + initializer + }; + return weakMap; + } + + function accessPrivateName(name: PrivateName) { + const environment = currentPrivateNameEnvironment(); + const nameString = name.escapedText as string; + if (nameString in environment) { + return environment[nameString].weakMap; + } + // 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), + /* location */ node + ), + node + ); + } + return visitEachChild(node, visitor, context); + } + + function visitorCollectPrivateNames(node: Node): VisitResult { + if (isPrivateNamedPropertyDeclaration(node)) { + addPrivateName(node.name); + return undefined; + } + // 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); + const statements = createPrivateNameWeakMapDeclarations( + currentPrivateNameEnvironment() + ); + if (statements.length) { + node = updateClassDeclaration( + node, + node.decorators, + node.modifiers, + node.name, + node.typeParameters, + node.heritageClauses, + transformClassMembers(node.members) + ); + } + statements.unshift(node); + endPrivateNameEnvironment(); + return statements; + } + + function visitClassExpression(node: ClassExpression) { + startPrivateNameEnvironment(); + node = visitEachChild(node, visitorCollectPrivateNames, context); + node = visitEachChild(node, visitor, context); + const expressions = createPrivateNameWeakMapAssignments( + currentPrivateNameEnvironment() + ); + if (expressions.length) { + node = updateClassExpression( + node, + node.modifiers, + node.name, + node.typeParameters, + node.heritageClauses, + transformClassMembers(node.members) + ); + } + expressions.push(node); + endPrivateNameEnvironment(); + return expressions.length > 1 ? createCommaList(expressions) : expressions[0]; + } + + function startPrivateNameEnvironment() { + // Create private name environment. + privateNameEnvironmentStack[++privateNameEnvironmentIndex] = {}; + return currentPrivateNameEnvironment(); + } + + function endPrivateNameEnvironment(): PrivateNameEnvironment { + const privateNameEnvironment = currentPrivateNameEnvironment(); + // 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"), + /* 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) + ); + }); + } + + function transformClassMembers(members: ReadonlyArray): ClassElement[] { + // Rewrite constructor with private name initializers. + const privateNameEnvironment = currentPrivateNameEnvironment(); + // Initialize private properties. + const initializerStatements = Object.keys(privateNameEnvironment).map(name => { + const privateName = privateNameEnvironment[name]; + return createStatement( + createCall( + createPropertyAccess(privateName.weakMap, "set"), + /* typeArguments */ undefined, + [createThis(), privateName.initializer || createVoidZero()] + ) + ); + }); + const ctor = find( + members, + (member) => isConstructorDeclaration(member) && !!member.body + ) as ConstructorDeclaration | undefined; + if (ctor) { + const body = updateBlock(ctor.body!, [...initializerStatements, ...ctor.body!.statements]); + return members.map(member => { + if (member === ctor) { + return updateConstructor( + ctor, + ctor.decorators, + ctor.modifiers, + ctor.parameters, + body + ); + } + return member; + }); + } + return [ + createConstructor( + /* decorators */ undefined, + /* modifiers */ undefined, + /* parameters */ [], + createBlock(initializerStatements) + ), + ...members + ]; + } + function visitAwaitExpression(node: AwaitExpression): Expression { if (enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator) { return setOriginalNode( @@ -266,6 +472,55 @@ namespace ts { visitNode(node.right, noDestructuringValue ? visitorNoDestructuringValue : visitor, isExpression) ); } + else if (isAssignmentOperator(node.operatorToken.kind) && + isPropertyAccessExpression(node.left) && + 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; + 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; + setReceiver = node.left.expression; + } + return setOriginalNode( + createClassPrivateFieldSetHelper( + context, + setReceiver, + weakMapName, + createBinary( + createClassPrivateFieldGetHelper(context, getReceiver, weakMapName), + getOperatorForCompoundAssignment(node.operatorToken.kind), + visitNode(node.right, visitor) + ) + ), + node + ); + } + else { + return setOriginalNode( + createClassPrivateFieldSetHelper( + context, + node.left.expression, + weakMapName, + visitNode(node.right, visitor) + ), + node + ); + } + } return visitEachChild(node, visitor, context); } @@ -917,6 +1172,28 @@ namespace ts { ); } + 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); };` + }; + + 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; };` + }; + + function createClassPrivateFieldSetHelper(context: TransformationContext, receiver: Expression, privateField: Identifier, value: Expression) { + context.requestEmitHelper(classPrivateFieldSetHelper); + return createCall(getHelperName("_classPrivateFieldSet"), /* typeArguments */ undefined, [ receiver, privateField, value ]); + } + const awaitHelper: EmitHelper = { name: "typescript:await", scoped: false, 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/transformers/ts.ts b/src/compiler/transformers/ts.ts index 6eb8b6e0ef634..3ce50892297a0 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -2237,7 +2237,19 @@ 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 (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)) { (pendingExpressions || (pendingExpressions = [])).push(expr); 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 b8e12539e07da..74c1e6086514f 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; @@ -6069,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 { 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; 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; 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/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/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/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/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/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/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); + } +} 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; +} 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; + } +} 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; + } +} 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; + } +} 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 8149e5e6f14242e12171735228816775e125a06e Mon Sep 17 00:00:00 2001 From: Max Heiber Date: Wed, 10 Oct 2018 22:03:57 -0400 Subject: [PATCH 04/15] WIP --- src/compiler/transformers/esnext.ts | 116 ++++++++++++++++++++-------- src/compiler/types.ts | 2 +- src/compiler/utilities.ts | 4 +- 3 files changed, 85 insertions(+), 37 deletions(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 3c3234b174817..564a1722e6230 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -27,15 +27,19 @@ namespace ts { let enclosingSuperContainerFlags: NodeCheckFlags = 0; + const enum PrivateNamePlacement { InstancePropertyLike, InstanceMethod }; + /** - * Maps private names to the generated name of the WeakMap. + * Maps private names to the generated name and (if applicable) accessor */ interface PrivateNameEnvironment { [name: string]: { - weakMap: Identifier; + placement: PrivateNamePlacement + accumulator: Identifier; initializer?: Expression; - }; + } } + const privateNameEnvironmentStack: PrivateNameEnvironment[] = []; let privateNameEnvironmentIndex = -1; @@ -129,25 +133,53 @@ namespace ts { return privateNameEnvironmentStack[privateNameEnvironmentIndex]; } - function addPrivateName(name: PrivateName, initializer?: Expression) { + function getPrivateNamePlacement (declaration: PrivateNamedDeclaration): PrivateNamePlacement | undefined { + if (declaration.kind === SyntaxKind.PropertyDeclaration) { + if (hasModifier(declaration, ModifierFlags.Static)) { + // todo: static property + return undefined; + } + else { + return PrivateNamePlacement.InstancePropertyLike; + } + } + else if (declaration.kind === SyntaxKind.MethodDeclaration) { + if (hasModifier(declaration, ModifierFlags.Static)) { + // todo: static method + return undefined; + } + else { + return PrivateNamePlacement.InstanceMethod; + } + } + else { + return undefined; + } + } + + function addPrivateName(declaration: PrivateNamedDeclaration, initializer?: Expression): void { const environment = currentPrivateNameEnvironment(); - const nameString = name.escapedText as string; + const nameString = declaration.name.escapedText as string; if (nameString in environment) { throw new Error("Redeclaring private name " + nameString + "."); } - const weakMap = createFileLevelUniqueName("_" + nameString.substring(1)); + const accumulator = createFileLevelUniqueName("_" + nameString.substring(1)); + const placement = getPrivateNamePlacement(declaration); + if (!placement) { + return; + } environment[nameString] = { - weakMap, + placement, + accumulator, initializer }; - return weakMap; } - function accessPrivateName(name: PrivateName) { + function getPrivateNameRecord(name: PrivateName) { const environment = currentPrivateNameEnvironment(); const nameString = name.escapedText as string; if (nameString in environment) { - return environment[nameString].weakMap; + return environment[nameString]; } // Undeclared private name. return undefined; @@ -155,24 +187,40 @@ namespace ts { function visitPropertyAccessExpression(node: PropertyAccessExpression): Expression { if (isPrivateName(node.name)) { - const weakMapName = accessPrivateName(node.name); - if (!weakMapName) { + const record = getPrivateNameRecord(node.name); + if (!record) { return node; } - return setOriginalNode( - setTextRange( - createClassPrivateFieldGetHelper(context, node.expression, weakMapName), - /* location */ node - ), - node - ); + const { placement, accumulator } = record; + + switch (placement) { + case PrivateNamePlacement.InstancePropertyLike: + return setOriginalNode( + setTextRange( + createClassPrivateFieldGetHelper(context, node.expression, accumulator), + /* location */ node + ), + node + ); + case PrivateNamePlacement.InstanceMethod: + // TODO: use private instance method helper instead here + return setOriginalNode( + setTextRange( + createClassPrivateFieldGetHelper(context, node.expression, accumulator), + /* location */ node + ), + node + ); + default: + Debug.assertNever(placement); + } } return visitEachChild(node, visitor, context); } function visitorCollectPrivateNames(node: Node): VisitResult { - if (isPrivateNamedPropertyDeclaration(node)) { - addPrivateName(node.name); + if (isPrivateNamedDeclaration(node)) { + addPrivateName(node); return undefined; } // Don't collect private names from nested classes. @@ -186,7 +234,7 @@ namespace ts { startPrivateNameEnvironment(); node = visitEachChild(node, visitorCollectPrivateNames, context); node = visitEachChild(node, visitor, context); - const statements = createPrivateNameWeakMapDeclarations( + const statements = createPrivateNameaccumulatorDeclarations( currentPrivateNameEnvironment() ); if (statements.length) { @@ -209,7 +257,7 @@ namespace ts { startPrivateNameEnvironment(); node = visitEachChild(node, visitorCollectPrivateNames, context); node = visitEachChild(node, visitor, context); - const expressions = createPrivateNameWeakMapAssignments( + const expressions = createPrivateNameaccumulatorAssignments( currentPrivateNameEnvironment() ); if (expressions.length) { @@ -240,12 +288,12 @@ namespace ts { return privateNameEnvironment; } - function createPrivateNameWeakMapDeclarations(environment: PrivateNameEnvironment): Statement[] { + function createPrivateNameaccumulatorDeclarations(environment: PrivateNameEnvironment): Statement[] { return Object.keys(environment).map(name => { const privateName = environment[name]; return createVariableStatement( /* modifiers */ undefined, - [createVariableDeclaration(privateName.weakMap, + [createVariableDeclaration(privateName.accumulator, /* typeNode */ undefined, createNew( createIdentifier("WeakMap"), @@ -256,12 +304,12 @@ namespace ts { }); } - function createPrivateNameWeakMapAssignments(environment: PrivateNameEnvironment): Expression[] { + function createPrivateNameaccumulatorAssignments(environment: PrivateNameEnvironment): Expression[] { return Object.keys(environment).map(name => { const privateName = environment[name]; - hoistVariableDeclaration(privateName.weakMap); + hoistVariableDeclaration(privateName.accumulator); return createBinary( - privateName.weakMap, + privateName.accumulator, SyntaxKind.EqualsToken, createNew(createIdentifier("WeakMap"), /* typeArguments */ undefined, /* argumentsArray */ undefined) ); @@ -276,7 +324,7 @@ namespace ts { const privateName = privateNameEnvironment[name]; return createStatement( createCall( - createPropertyAccess(privateName.weakMap, "set"), + createPropertyAccess(privateName.accumulator, "set"), /* typeArguments */ undefined, [createThis(), privateName.initializer || createVoidZero()] ) @@ -476,8 +524,8 @@ namespace ts { isPropertyAccessExpression(node.left) && isPrivateName(node.left.name)) { - const weakMapName = accessPrivateName(node.left.name); - if (!weakMapName) { + const accumulatorName = getPrivateNameRecord(node.left.name); + if (!accumulatorName) { // Don't change output for undeclared private names (error). return node; } @@ -499,9 +547,9 @@ namespace ts { createClassPrivateFieldSetHelper( context, setReceiver, - weakMapName, + accumulatorName, createBinary( - createClassPrivateFieldGetHelper(context, getReceiver, weakMapName), + createClassPrivateFieldGetHelper(context, getReceiver, accumulatorName), getOperatorForCompoundAssignment(node.operatorToken.kind), visitNode(node.right, visitor) ) @@ -514,7 +562,7 @@ namespace ts { createClassPrivateFieldSetHelper( context, node.left.expression, - weakMapName, + accumulatorName, visitNode(node.right, visitor) ), node diff --git a/src/compiler/types.ts b/src/compiler/types.ts index a86badd2c56a4..87ff3a38a98fb 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -864,7 +864,7 @@ namespace ts { initializer?: Expression; // Optional initializer } - export interface PrivateNamedPropertyDeclaration extends PropertyDeclaration { + export interface PrivateNamedDeclaration extends PropertyDeclaration { name: PrivateName; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 74c1e6086514f..e58c394b91f47 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -6091,8 +6091,8 @@ namespace ts { } } - export function isPrivateNamedPropertyDeclaration(node: Node): node is PrivateNamedPropertyDeclaration { - return node && isPropertyDeclaration(node) && isPrivateName(node.name); + export function isPrivateNamedDeclaration(node: Node): node is PrivateNamedDeclaration { + return node && isNamedDeclaration(node) && isPrivateName(node.name); } // Type members From df2bb615a88849bb35f14ff1be356745151e2e21 Mon Sep 17 00:00:00 2001 From: Max Heiber Date: Thu, 11 Oct 2018 21:05:52 -0400 Subject: [PATCH 05/15] WIP --- src/compiler/transformers/esnext.ts | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 564a1722e6230..de1fa6a3c575b 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -197,6 +197,7 @@ namespace ts { case PrivateNamePlacement.InstancePropertyLike: return setOriginalNode( setTextRange( + // todo: rename createClassPrivateFieldGetHelper(context, node.expression, accumulator), /* location */ node ), @@ -206,7 +207,7 @@ namespace ts { // TODO: use private instance method helper instead here return setOriginalNode( setTextRange( - createClassPrivateFieldGetHelper(context, node.expression, accumulator), + createClassPrivateNamedCallHelper(context, node.expression, accumulator), /* location */ node ), node @@ -219,7 +220,7 @@ namespace ts { } function visitorCollectPrivateNames(node: Node): VisitResult { - if (isPrivateNamedDeclaration(node)) { + if (isPrivateNamedDeclaration(node) && (isPropertyDeclaration(node) || isMethodDeclaration(node))) { addPrivateName(node); return undefined; } @@ -524,11 +525,12 @@ namespace ts { isPropertyAccessExpression(node.left) && isPrivateName(node.left.name)) { - const accumulatorName = getPrivateNameRecord(node.left.name); - if (!accumulatorName) { + const privateNameRecord = getPrivateNameRecord(node.left.name); + if (!privateNameRecord) { // Don't change output for undeclared private names (error). return node; } + const accumulatorName = privateNameRecord.accumulator; if (isCompoundAssignment(node.operatorToken.kind)) { let setReceiver: Expression; let getReceiver: Expression; @@ -1231,6 +1233,17 @@ namespace ts { return createCall(getHelperName("_classPrivateFieldGet"), /* typeArguments */ undefined, [ receiver, privateField ]); } + const classPrivateNamedCallHelper: EmitHelper = { + name: "typescript:classPrivateNamedCall", + scoped: false, + text: `var _classPrivateNamedCall = function classPrivateNamedCall (receiver, privateMap) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return privateMap.get(receiver); };` + }; + + function createClassPrivateNamedCallHelper(context: TransformationContext, receiver: Expression, privateField: Identifier) { + context.requestEmitHelper(classPrivateNamedCallHelper); + return createCall(getHelperName("_classPrivateNamedCall"), /* typeArguments */ undefined, [ receiver, privateField ]); + } + const classPrivateFieldSetHelper: EmitHelper = { name: "typescript:classPrivateFieldSet", scoped: false, From 6282e2b45c0ee4a7eea70307ddb038661d7c6aba Mon Sep 17 00:00:00 2001 From: Max Heiber Date: Fri, 12 Oct 2018 09:49:30 -0400 Subject: [PATCH 06/15] WIP --- src/compiler/transformers/esnext.ts | 56 ++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index de1fa6a3c575b..b1022e983484e 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -165,7 +165,7 @@ namespace ts { } const accumulator = createFileLevelUniqueName("_" + nameString.substring(1)); const placement = getPrivateNamePlacement(declaration); - if (!placement) { + if (placement === undefined) { return; } environment[nameString] = { @@ -220,7 +220,15 @@ namespace ts { } function visitorCollectPrivateNames(node: Node): VisitResult { - if (isPrivateNamedDeclaration(node) && (isPropertyDeclaration(node) || isMethodDeclaration(node))) { + if ( + isPrivateNamedDeclaration(node) + && (isPropertyDeclaration(node) + || isMethodDeclaration(node) + // TODO: getters/setters + ) + // TODO: statics + && !hasModifier(node, ModifierFlags.Static) + ) { addPrivateName(node); return undefined; } @@ -291,26 +299,42 @@ namespace ts { function createPrivateNameaccumulatorDeclarations(environment: PrivateNameEnvironment): Statement[] { return Object.keys(environment).map(name => { - const privateName = environment[name]; - return createVariableStatement( - /* modifiers */ undefined, - [createVariableDeclaration(privateName.accumulator, - /* typeNode */ undefined, - createNew( - createIdentifier("WeakMap"), - /* typeArguments */ undefined, - /* argumentsArray */ undefined - ))] - ); + const { placement, accumulator } = environment[name]; + switch (placement) { + case PrivateNamePlacement.InstancePropertyLike: + return createVariableStatement( + /* modifiers */ undefined, + [createVariableDeclaration(accumulator, + /* typeNode */ undefined, + createNew( + createIdentifier("WeakMap"), + /* typeArguments */ undefined, + /* argumentsArray */ undefined + ))] + ); + case PrivateNamePlacement.InstanceMethod: + return createVariableStatement( + /* modifiers */ undefined, + [createVariableDeclaration(accumulator, + /* typeNode */ undefined, + createNew( + createIdentifier("WeakSet"), + /* typeArguments */ undefined, + /* argumentsArray */ undefined + ))] + ); + default: + return Debug.assertNever(placement); + } }); } function createPrivateNameaccumulatorAssignments(environment: PrivateNameEnvironment): Expression[] { return Object.keys(environment).map(name => { - const privateName = environment[name]; - hoistVariableDeclaration(privateName.accumulator); + const { accumulator } = environment[name]; + hoistVariableDeclaration(accumulator); return createBinary( - privateName.accumulator, + accumulator, SyntaxKind.EqualsToken, createNew(createIdentifier("WeakMap"), /* typeArguments */ undefined, /* argumentsArray */ undefined) ); From 3f21455b63e1ef4e3bc8fbee08c972fb688c670a Mon Sep 17 00:00:00 2001 From: Max Heiber Date: Fri, 12 Oct 2018 12:42:36 -0400 Subject: [PATCH 07/15] WIP --- src/compiler/transformers/esnext.ts | 44 ++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index b1022e983484e..1afb02925e257 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -207,7 +207,7 @@ namespace ts { // TODO: use private instance method helper instead here return setOriginalNode( setTextRange( - createClassPrivateNamedCallHelper(context, node.expression, accumulator), + createClassPrivateNamedCallCheckHelper(context, node.expression, accumulator), /* location */ node ), node @@ -346,14 +346,30 @@ namespace ts { const privateNameEnvironment = currentPrivateNameEnvironment(); // Initialize private properties. const initializerStatements = Object.keys(privateNameEnvironment).map(name => { - const privateName = privateNameEnvironment[name]; - return createStatement( - createCall( - createPropertyAccess(privateName.accumulator, "set"), - /* typeArguments */ undefined, - [createThis(), privateName.initializer || createVoidZero()] - ) - ); + const { accumulator, placement, initializer} = privateNameEnvironment[name]; + + switch(placement) { + case PrivateNamePlacement.InstancePropertyLike: + return createStatement( + createCall( + createPropertyAccess(accumulator, "set"), + /* typeArguments */ undefined, + [createThis(), initializer || createVoidZero()] + ) + ); + case PrivateNamePlacement.InstanceMethod: + return createStatement( + createCall( + createPropertyAccess(accumulator, "add"), + /* typeArguments */ undefined, + [createThis()] + ) + ); + default: + return Debug.assertNever(placement); + + } + }); const ctor = find( members, @@ -1257,15 +1273,15 @@ namespace ts { return createCall(getHelperName("_classPrivateFieldGet"), /* typeArguments */ undefined, [ receiver, privateField ]); } - const classPrivateNamedCallHelper: EmitHelper = { + const classPrivateNamedCallCheckHelper: EmitHelper = { name: "typescript:classPrivateNamedCall", scoped: false, - text: `var _classPrivateNamedCall = function classPrivateNamedCall (receiver, privateMap) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return privateMap.get(receiver); };` + text: `var _classPrivateNamedCall = function (receiver, privateSet) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); }};` }; - function createClassPrivateNamedCallHelper(context: TransformationContext, receiver: Expression, privateField: Identifier) { - context.requestEmitHelper(classPrivateNamedCallHelper); - return createCall(getHelperName("_classPrivateNamedCall"), /* typeArguments */ undefined, [ receiver, privateField ]); + function createClassPrivateNamedCallCheckHelper(context: TransformationContext, receiver: Expression, privateField: Identifier) { + context.requestEmitHelper(classPrivateNamedCallCheckHelper); + return createCall(getHelperName("_classPrivateNamedCallCheck"), /* typeArguments */ undefined, [ receiver, privateField ]); } const classPrivateFieldSetHelper: EmitHelper = { From bd58d07c4c49b94a4c39f0b1748d53de40f980c0 Mon Sep 17 00:00:00 2001 From: Max Heiber Date: Sat, 13 Oct 2018 14:09:13 -0400 Subject: [PATCH 08/15] WIP borken --- src/compiler/factory.ts | 10 +++++++ src/compiler/transformers/esnext.ts | 46 +++++++++++++++-------------- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 154416b78567c..f5b26cb406793 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -3025,6 +3025,16 @@ namespace ts { return node; } + export function replaceNode(original: Node | undefined, node: T) : T { + return setOriginalNode( + setTextRange( + node, + /* location */ original + ), + original + ); + } + function mergeEmitNode(sourceEmitNode: EmitNode, destEmitNode: EmitNode | undefined) { const { flags, diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 1afb02925e257..0cd362674e53d 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -27,19 +27,28 @@ namespace ts { let enclosingSuperContainerFlags: NodeCheckFlags = 0; - const enum PrivateNamePlacement { InstancePropertyLike, InstanceMethod }; + const enum PrivateNamePlacement { InstanceField, InstanceMethod }; /** * Maps private names to the generated name and (if applicable) accessor */ interface PrivateNameEnvironment { - [name: string]: { - placement: PrivateNamePlacement - accumulator: Identifier; - initializer?: Expression; - } + [name: string]: PrivateNamedInstanceFieldEntry | PrivateNamedInstanceMethodEntry; + } + + interface PrivateNamedInstanceFieldEntry { + placement: PrivateNamePlacement.InstanceField; + accumulator: Identifier; + initializer?: Expression; } + interface PrivateNamedInstanceMethodEntry { + accumulator: Identifier; + placement: PrivateNamePlacement.InstanceField; + parameters + } + + const privateNameEnvironmentStack: PrivateNameEnvironment[] = []; let privateNameEnvironmentIndex = -1; @@ -195,22 +204,15 @@ namespace ts { switch (placement) { case PrivateNamePlacement.InstancePropertyLike: - return setOriginalNode( - setTextRange( - // todo: rename + return replaceNode( createClassPrivateFieldGetHelper(context, node.expression, accumulator), - /* location */ node - ), - node - ); + node + ); case PrivateNamePlacement.InstanceMethod: // TODO: use private instance method helper instead here - return setOriginalNode( - setTextRange( + return replaceNode( createClassPrivateNamedCallCheckHelper(context, node.expression, accumulator), - /* location */ node - ), - node + node ); default: Debug.assertNever(placement); @@ -1274,14 +1276,14 @@ namespace ts { } const classPrivateNamedCallCheckHelper: EmitHelper = { - name: "typescript:classPrivateNamedCall", + name: "typescript:classPrivateNamedCallCheck", scoped: false, - text: `var _classPrivateNamedCall = function (receiver, privateSet) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); }};` + text: `var _classPrivateNamedCall = function (receiver, weakSet) { if (!weakSet.has(receiver)) { throw new TypeError("attempted to get weak field on non-instance"); }};` }; - function createClassPrivateNamedCallCheckHelper(context: TransformationContext, receiver: Expression, privateField: Identifier) { + function createClassPrivateNamedCallCheckHelper(context: TransformationContext, receiver: Expression, weakSet: Identifier) { context.requestEmitHelper(classPrivateNamedCallCheckHelper); - return createCall(getHelperName("_classPrivateNamedCallCheck"), /* typeArguments */ undefined, [ receiver, privateField ]); + return createCall(getHelperName("_classPrivateNamedCallCheck"), /* typeArguments */ undefined, [ receiver, weakSet ]); } const classPrivateFieldSetHelper: EmitHelper = { From dbcd840c74e1e78763a4f449c7cfd88cd3ddfda3 Mon Sep 17 00:00:00 2001 From: Max Heiber Date: Sun, 14 Oct 2018 20:58:18 -0400 Subject: [PATCH 09/15] WIP --- src/compiler/transformers/esnext.ts | 74 ++++++++++++++--------------- 1 file changed, 36 insertions(+), 38 deletions(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 0cd362674e53d..f9f7f924b2e68 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -43,12 +43,12 @@ namespace ts { } interface PrivateNamedInstanceMethodEntry { + placement: PrivateNamePlacement.InstanceMethod; accumulator: Identifier; - placement: PrivateNamePlacement.InstanceField; - parameters + parameters: NodeArray; + functionBody: FunctionBody; } - const privateNameEnvironmentStack: PrivateNameEnvironment[] = []; let privateNameEnvironmentIndex = -1; @@ -142,46 +142,43 @@ namespace ts { return privateNameEnvironmentStack[privateNameEnvironmentIndex]; } - function getPrivateNamePlacement (declaration: PrivateNamedDeclaration): PrivateNamePlacement | undefined { + function addPrivateName(declaration: PrivateNamedDeclaration, initializer?: Expression): void { + const environment = currentPrivateNameEnvironment(); + const nameString = declaration.name.escapedText as string; + if (nameString in environment) { + throw new Error("Redeclaring private name " + nameString + "."); + } + const accumulator = createFileLevelUniqueName("_" + nameString.substring(1)); if (declaration.kind === SyntaxKind.PropertyDeclaration) { if (hasModifier(declaration, ModifierFlags.Static)) { // todo: static property - return undefined; + return; } else { - return PrivateNamePlacement.InstancePropertyLike; + environment[nameString] = { + placement: PrivateNamePlacement.InstanceField, + accumulator: accumulator, + initializer + }; } } - else if (declaration.kind === SyntaxKind.MethodDeclaration) { + else if (isMethodDeclaration(declaration)) { if (hasModifier(declaration, ModifierFlags.Static)) { // todo: static method - return undefined; + return; + } + else if (!declaration.body) { + return; } else { - return PrivateNamePlacement.InstanceMethod; + environment[nameString] = { + placement: PrivateNamePlacement.InstanceMethod, + accumulator: accumulator, + parameters: declaration.parameters, + functionBody: declaration.body + } } } - else { - return undefined; - } - } - - function addPrivateName(declaration: PrivateNamedDeclaration, initializer?: Expression): void { - const environment = currentPrivateNameEnvironment(); - const nameString = declaration.name.escapedText as string; - if (nameString in environment) { - throw new Error("Redeclaring private name " + nameString + "."); - } - const accumulator = createFileLevelUniqueName("_" + nameString.substring(1)); - const placement = getPrivateNamePlacement(declaration); - if (placement === undefined) { - return; - } - environment[nameString] = { - placement, - accumulator, - initializer - }; } function getPrivateNameRecord(name: PrivateName) { @@ -196,14 +193,14 @@ namespace ts { function visitPropertyAccessExpression(node: PropertyAccessExpression): Expression { if (isPrivateName(node.name)) { - const record = getPrivateNameRecord(node.name); - if (!record) { + const entry = getPrivateNameRecord(node.name); + if (!entry) { return node; } - const { placement, accumulator } = record; + const { placement, accumulator } = entry; switch (placement) { - case PrivateNamePlacement.InstancePropertyLike: + case PrivateNamePlacement.InstanceField: return replaceNode( createClassPrivateFieldGetHelper(context, node.expression, accumulator), node @@ -303,7 +300,7 @@ namespace ts { return Object.keys(environment).map(name => { const { placement, accumulator } = environment[name]; switch (placement) { - case PrivateNamePlacement.InstancePropertyLike: + case PrivateNamePlacement.InstanceField: return createVariableStatement( /* modifiers */ undefined, [createVariableDeclaration(accumulator, @@ -348,15 +345,16 @@ namespace ts { const privateNameEnvironment = currentPrivateNameEnvironment(); // Initialize private properties. const initializerStatements = Object.keys(privateNameEnvironment).map(name => { - const { accumulator, placement, initializer} = privateNameEnvironment[name]; + const entry = privateNameEnvironment[name]; + const { accumulator, placement } = entry; switch(placement) { - case PrivateNamePlacement.InstancePropertyLike: + case PrivateNamePlacement.InstanceField: return createStatement( createCall( createPropertyAccess(accumulator, "set"), /* typeArguments */ undefined, - [createThis(), initializer || createVoidZero()] + [createThis(), (entry as PrivateNamedInstanceFieldEntry).initializer || createVoidZero()] ) ); case PrivateNamePlacement.InstanceMethod: From ea818be084c5778c002e1f0ba78945ba3faf0f50 Mon Sep 17 00:00:00 2001 From: Max Heiber Date: Sun, 14 Oct 2018 21:10:43 -0400 Subject: [PATCH 10/15] WIP --- 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 f9f7f924b2e68..26ac0d109cb4c 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -202,14 +202,14 @@ namespace ts { switch (placement) { case PrivateNamePlacement.InstanceField: return replaceNode( + node, createClassPrivateFieldGetHelper(context, node.expression, accumulator), - node ); case PrivateNamePlacement.InstanceMethod: // TODO: use private instance method helper instead here return replaceNode( + node, createClassPrivateNamedCallCheckHelper(context, node.expression, accumulator), - node ); default: Debug.assertNever(placement); @@ -1276,7 +1276,7 @@ namespace ts { const classPrivateNamedCallCheckHelper: EmitHelper = { name: "typescript:classPrivateNamedCallCheck", scoped: false, - text: `var _classPrivateNamedCall = function (receiver, weakSet) { if (!weakSet.has(receiver)) { throw new TypeError("attempted to get weak field on non-instance"); }};` + text: `var _classPrivateNamedCallCheck = function (receiver, weakSet) { if (!weakSet.has(receiver)) { throw new TypeError("attempted to get weak field on non-instance"); }};` }; function createClassPrivateNamedCallCheckHelper(context: TransformationContext, receiver: Expression, weakSet: Identifier) { From 81d38115486e75712569972bfdbe1b5c896fcdc6 Mon Sep 17 00:00:00 2001 From: Max Heiber Date: Sun, 14 Oct 2018 21:46:39 -0400 Subject: [PATCH 11/15] WIP --- src/compiler/transformers/esnext.ts | 35 ++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 26ac0d109cb4c..92f7d4709c0c2 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -45,8 +45,7 @@ namespace ts { interface PrivateNamedInstanceMethodEntry { placement: PrivateNamePlacement.InstanceMethod; accumulator: Identifier; - parameters: NodeArray; - functionBody: FunctionBody; + func: FunctionDeclaration; } const privateNameEnvironmentStack: PrivateNameEnvironment[] = []; @@ -171,11 +170,28 @@ namespace ts { return; } else { + const params = declaration.parameters; + const body = getMutableClone(declaration.body); + body.statements = setTextRange( + createNodeArray([ + startOnNewLine(createStatement(createLiteral("use strict"))), + ...body.statements + ]), + body.statements + ); + const func = createFunctionDeclaration( + undefined, + undefined, + undefined, + "foo", // TODO: max + undefined, + params, // TODO: max + undefined, + body) environment[nameString] = { placement: PrivateNamePlacement.InstanceMethod, - accumulator: accumulator, - parameters: declaration.parameters, - functionBody: declaration.body + accumulator, + func } } } @@ -255,6 +271,15 @@ namespace ts { node.heritageClauses, transformClassMembers(node.members) ); + Object.keys( + currentPrivateNameEnvironment() + ) + .map(key => currentPrivateNameEnvironment()[key]) + .filter(x => x.placement === PrivateNamePlacement.InstanceMethod) + .forEach(e => { + const entry = e as PrivateNamedInstanceMethodEntry; + statements.push(entry.func) + }); } statements.unshift(node); endPrivateNameEnvironment(); From 6d0c54916ead1aaa553c18a047c273de66fa1d33 Mon Sep 17 00:00:00 2001 From: Max Heiber Date: Sun, 14 Oct 2018 22:11:11 -0400 Subject: [PATCH 12/15] WIP --- src/compiler/transformers/esnext.ts | 32 ++++++++++++++++++----------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 92f7d4709c0c2..e336ec6e8749a 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -45,7 +45,7 @@ namespace ts { interface PrivateNamedInstanceMethodEntry { placement: PrivateNamePlacement.InstanceMethod; accumulator: Identifier; - func: FunctionDeclaration; + func: FunctionDeclaration & {name: Identifier}; } const privateNameEnvironmentStack: PrivateNameEnvironment[] = []; @@ -172,27 +172,33 @@ namespace ts { else { const params = declaration.parameters; const body = getMutableClone(declaration.body); + const toPrepend = startOnNewLine( + createStatement( + createClassPrivateNamedCallCheckHelper(context, createThis(), accumulator) + ) + ); body.statements = setTextRange( createNodeArray([ - startOnNewLine(createStatement(createLiteral("use strict"))), + toPrepend, ...body.statements ]), body.statements ); + const funcName = createFileLevelUniqueName(`_${nameString.slice(1)}Func`); const func = createFunctionDeclaration( - undefined, - undefined, - undefined, - "foo", // TODO: max - undefined, - params, // TODO: max - undefined, - body) + /* decorators */ undefined, + /* modifiers */ undefined, + /* asteriskToken */ undefined, + funcName, + /* typeParameters */ undefined, + params, + /* type */ undefined, + body) as FunctionDeclaration & {name: Identifier}; environment[nameString] = { placement: PrivateNamePlacement.InstanceMethod, accumulator, func - } + }; } } } @@ -222,10 +228,12 @@ namespace ts { createClassPrivateFieldGetHelper(context, node.expression, accumulator), ); case PrivateNamePlacement.InstanceMethod: + + const { func } = entry as PrivateNamedInstanceMethodEntry; // TODO: use private instance method helper instead here return replaceNode( node, - createClassPrivateNamedCallCheckHelper(context, node.expression, accumulator), + createCall(func.name, undefined, []) ); default: Debug.assertNever(placement); From 8186a4770708bbeb0587c2123350ba115a2f5d3e Mon Sep 17 00:00:00 2001 From: Max Heiber Date: Sun, 14 Oct 2018 22:30:18 -0400 Subject: [PATCH 13/15] WIP --- src/compiler/transformers/esnext.ts | 39 +++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index e336ec6e8749a..a5c5085a27af2 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -132,6 +132,8 @@ namespace ts { return visitClassDeclaration(node as ClassDeclaration); case SyntaxKind.ClassExpression: return visitClassExpression(node as ClassExpression); + case SyntaxKind.CallExpression: + return visitCallExpression(node as CallExpression); default: return visitEachChild(node, visitor, context); } @@ -213,13 +215,39 @@ namespace ts { return undefined; } + function visitCallExpression(node: CallExpression): Expression { + if (isPropertyAccessExpression(node.expression) + && isPrivateName(node.expression.name)) { + const entry = getPrivateNameRecord(node.expression.name); + if (!entry) { + return node; + } + const { placement } = entry; + + switch (placement) { + case PrivateNamePlacement.InstanceField: + // handled by visitPropertyAccessExpression + return node; + case PrivateNamePlacement.InstanceMethod: + const { func } = entry as PrivateNamedInstanceMethodEntry; + return replaceNode( + node, + createCall(func.name, undefined, node.arguments) + ); + return node; + default: + return Debug.assertNever(placement); + } + } + return visitEachChild(node, visitor, context); + } + function visitPropertyAccessExpression(node: PropertyAccessExpression): Expression { if (isPrivateName(node.name)) { const entry = getPrivateNameRecord(node.name); if (!entry) { return node; } - const { placement, accumulator } = entry; switch (placement) { case PrivateNamePlacement.InstanceField: @@ -228,13 +256,8 @@ namespace ts { createClassPrivateFieldGetHelper(context, node.expression, accumulator), ); case PrivateNamePlacement.InstanceMethod: - - const { func } = entry as PrivateNamedInstanceMethodEntry; - // TODO: use private instance method helper instead here - return replaceNode( - node, - createCall(func.name, undefined, []) - ); + // handled by visitCallExpression + return node; default: Debug.assertNever(placement); } From ccf98cf9a67440a5b73f1a78caf7ec746a9b3150 Mon Sep 17 00:00:00 2001 From: Max Heiber Date: Sun, 14 Oct 2018 22:30:50 -0400 Subject: [PATCH 14/15] WIP --- src/compiler/transformers/esnext.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index a5c5085a27af2..c2d1fc626cb69 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -234,7 +234,6 @@ namespace ts { node, createCall(func.name, undefined, node.arguments) ); - return node; default: return Debug.assertNever(placement); } From ea3800245e368576e1059fd997dbf358f00e7dd6 Mon Sep 17 00:00:00 2001 From: Max Heiber Date: Sun, 14 Oct 2018 23:31:15 -0400 Subject: [PATCH 15/15] WIP --- src/compiler/transformers/esnext.ts | 49 +++++++++++++---------------- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index c2d1fc626cb69..8508d28bafd5a 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -149,7 +149,7 @@ namespace ts { if (nameString in environment) { throw new Error("Redeclaring private name " + nameString + "."); } - const accumulator = createFileLevelUniqueName("_" + nameString.substring(1)); + const accumulator = createFileLevelUniqueName(`_accumulator_${nameString.slice(1)}`); if (declaration.kind === SyntaxKind.PropertyDeclaration) { if (hasModifier(declaration, ModifierFlags.Static)) { // todo: static property @@ -174,9 +174,10 @@ namespace ts { else { const params = declaration.parameters; const body = getMutableClone(declaration.body); + const receiver = createIdentifier("receiver"); const toPrepend = startOnNewLine( createStatement( - createClassPrivateNamedCallCheckHelper(context, createThis(), accumulator) + createClassPrivateNamedCallCheckHelper(context, receiver, accumulator) ) ); body.statements = setTextRange( @@ -186,14 +187,17 @@ namespace ts { ]), body.statements ); - const funcName = createFileLevelUniqueName(`_${nameString.slice(1)}Func`); + const funcName = createFileLevelUniqueName(`_${nameString.slice(1)}`); const func = createFunctionDeclaration( /* decorators */ undefined, /* modifiers */ undefined, /* asteriskToken */ undefined, funcName, /* typeParameters */ undefined, - params, + [ + createParameter(undefined, undefined, undefined, receiver), + ...params + ], /* type */ undefined, body) as FunctionDeclaration & {name: Identifier}; environment[nameString] = { @@ -222,20 +226,15 @@ namespace ts { if (!entry) { return node; } + const receiver = node.expression.expression; const { placement } = entry; + if (placement === PrivateNamePlacement.InstanceMethod) { + const { func } = entry as PrivateNamedInstanceMethodEntry; + return replaceNode( + node, + createCall(func.name, undefined, [receiver, ...node.arguments]) + ); - switch (placement) { - case PrivateNamePlacement.InstanceField: - // handled by visitPropertyAccessExpression - return node; - case PrivateNamePlacement.InstanceMethod: - const { func } = entry as PrivateNamedInstanceMethodEntry; - return replaceNode( - node, - createCall(func.name, undefined, node.arguments) - ); - default: - return Debug.assertNever(placement); } } return visitEachChild(node, visitor, context); @@ -248,17 +247,11 @@ namespace ts { return node; } const { placement, accumulator } = entry; - switch (placement) { - case PrivateNamePlacement.InstanceField: - return replaceNode( - node, - createClassPrivateFieldGetHelper(context, node.expression, accumulator), - ); - case PrivateNamePlacement.InstanceMethod: - // handled by visitCallExpression - return node; - default: - Debug.assertNever(placement); + if (placement === PrivateNamePlacement.InstanceField) { + return replaceNode( + node, + createClassPrivateFieldGetHelper(context, node.expression, accumulator), + ); } } return visitEachChild(node, visitor, context); @@ -1331,7 +1324,7 @@ namespace ts { const classPrivateNamedCallCheckHelper: EmitHelper = { name: "typescript:classPrivateNamedCallCheck", scoped: false, - text: `var _classPrivateNamedCallCheck = function (receiver, weakSet) { if (!weakSet.has(receiver)) { throw new TypeError("attempted to get weak field on non-instance"); }};` + text: `var _classPrivateNamedCallCheck = function (receiver, privateSet) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get weak field on non-instance"); }};` }; function createClassPrivateNamedCallCheckHelper(context: TransformationContext, receiver: Expression, weakSet: Identifier) {