From c38d664d590eb3b6d50b22b8048934940c47d458 Mon Sep 17 00:00:00 2001 From: Max Heiber Date: Fri, 27 Jul 2018 15:39:57 -0400 Subject: [PATCH 1/4] begin update checker for private names - [x] Private name accesses not allowed outside of the defining class - [x] delete #foo not allowed - [x] private names not allowed as params - [x] private names not allowed in variable declarations - [x] #constructor is reserved - [x] Private names in class hierarchies don't conflict Signed-off-by: Max Heiber --- src/compiler/binder.ts | 17 +++++++-- src/compiler/checker.ts | 34 +++++++++++++----- src/compiler/diagnosticMessages.json | 13 +++++-- .../privateNameContructorReserved.errors.txt | 22 ++++++++++++ .../privateNameContructorReserved.js | 22 ++++++++++++ .../privateNameContructorReserved.symbols | 14 ++++++++ .../privateNameContructorReserved.types | 15 ++++++++ ...tAccessibleOutsideDefiningClass.errors.txt | 12 +++++++ ...teNameNotAccessibleOutsideDefiningClass.js | 16 +++++++++ ...eNotAccessibleOutsideDefiningClass.symbols | 12 +++++++ ...ameNotAccessibleOutsideDefiningClass.types | 16 +++++++++ ...ivateNameNotAllowedOutsideClass.errors.txt | 13 +++++++ .../privateNameNotAllowedOutsideClass.js | 6 ++++ .../privateNameNotAllowedOutsideClass.symbols | 3 ++ .../privateNameNotAllowedOutsideClass.types | 4 +++ .../privateNamesNoConflictWhenInheriting.js | 36 +++++++++++++++++++ ...ivateNamesNoConflictWhenInheriting.symbols | 16 +++++++++ ...privateNamesNoConflictWhenInheriting.types | 16 +++++++++ .../reference/privateNamesNoDelete.errors.txt | 13 +++++++ .../reference/privateNamesNoDelete.js | 17 +++++++++ .../reference/privateNamesNoDelete.symbols | 14 ++++++++ .../reference/privateNamesNoDelete.types | 16 +++++++++ ...vateNamesNotAllowedAsParameters.errors.txt | 19 ++++++++++ .../privateNamesNotAllowedAsParameters.js | 14 ++++++++ ...privateNamesNotAllowedAsParameters.symbols | 9 +++++ .../privateNamesNotAllowedAsParameters.types | 9 +++++ ...otAllowedInVariableDeclarations.errors.txt | 13 +++++++ ...teNamesNotAllowedInVariableDeclarations.js | 6 ++++ ...esNotAllowedInVariableDeclarations.symbols | 3 ++ ...amesNotAllowedInVariableDeclarations.types | 4 +++ .../privateNameContructorReserved.ts | 7 ++++ ...teNameNotAccessibleOutsideDefiningClass.ts | 5 +++ .../privateNameNotAllowedOutsideClass.ts | 1 + .../privateNamesNoConflictWhenInheriting.ts | 7 ++++ .../privateNames/privateNamesNoDelete.ts | 6 ++++ .../privateNamesNotAllowedAsParameters.ts | 3 ++ ...teNamesNotAllowedInVariableDeclarations.ts | 1 + 37 files changed, 440 insertions(+), 14 deletions(-) create mode 100644 tests/baselines/reference/privateNameContructorReserved.errors.txt create mode 100644 tests/baselines/reference/privateNameContructorReserved.js create mode 100644 tests/baselines/reference/privateNameContructorReserved.symbols create mode 100644 tests/baselines/reference/privateNameContructorReserved.types create mode 100644 tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.errors.txt create mode 100644 tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.js create mode 100644 tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.symbols create mode 100644 tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.types create mode 100644 tests/baselines/reference/privateNameNotAllowedOutsideClass.errors.txt create mode 100644 tests/baselines/reference/privateNameNotAllowedOutsideClass.js create mode 100644 tests/baselines/reference/privateNameNotAllowedOutsideClass.symbols create mode 100644 tests/baselines/reference/privateNameNotAllowedOutsideClass.types create mode 100644 tests/baselines/reference/privateNamesNoConflictWhenInheriting.js create mode 100644 tests/baselines/reference/privateNamesNoConflictWhenInheriting.symbols create mode 100644 tests/baselines/reference/privateNamesNoConflictWhenInheriting.types create mode 100644 tests/baselines/reference/privateNamesNoDelete.errors.txt create mode 100644 tests/baselines/reference/privateNamesNoDelete.js create mode 100644 tests/baselines/reference/privateNamesNoDelete.symbols create mode 100644 tests/baselines/reference/privateNamesNoDelete.types create mode 100644 tests/baselines/reference/privateNamesNotAllowedAsParameters.errors.txt create mode 100644 tests/baselines/reference/privateNamesNotAllowedAsParameters.js create mode 100644 tests/baselines/reference/privateNamesNotAllowedAsParameters.symbols create mode 100644 tests/baselines/reference/privateNamesNotAllowedAsParameters.types create mode 100644 tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.errors.txt create mode 100644 tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.js create mode 100644 tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.symbols create mode 100644 tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.types create mode 100644 tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts create mode 100644 tests/cases/conformance/classes/members/privateNames/privateNameNotAccessibleOutsideDefiningClass.ts create mode 100644 tests/cases/conformance/classes/members/privateNames/privateNameNotAllowedOutsideClass.ts create mode 100644 tests/cases/conformance/classes/members/privateNames/privateNamesNoConflictWhenInheriting.ts create mode 100644 tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts create mode 100644 tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts create mode 100644 tests/cases/conformance/classes/privateNames/privateNamesNotAllowedInVariableDeclarations.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index ebc43e006bdfc..dfa3368bf5ed8 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -266,9 +266,6 @@ 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) { @@ -1798,6 +1795,18 @@ namespace ts { return Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode; } + // The binder visits every node, so this is a good place to check for + // the reserved private name (there is only one) + function checkPrivateName(node: PrivateName) { + if (node.escapedText === "#constructor") { + // Report error only if there are no parse errors in file + if (!file.parseDiagnostics.length) { + file.bindDiagnostics.push(createDiagnosticForNode(node, + Diagnostics.constructor_is_a_reserved_word, declarationNameToString(node))); + } + } + } + function checkStrictModeBinaryExpression(node: BinaryExpression) { if (inStrictMode && isLeftHandSideExpression(node.left) && isAssignmentOperator(node.operatorToken.kind)) { // ECMA 262 (Annex C) The identifier eval or arguments may not appear as the LeftHandSideExpression of an @@ -2070,6 +2079,8 @@ namespace ts { node.flowNode = currentFlow; } return checkStrictModeIdentifier(node); + case SyntaxKind.PrivateName: + return checkPrivateName(node as PrivateName); case SyntaxKind.PropertyAccessExpression: case SyntaxKind.ElementAccessExpression: if (currentFlow && isNarrowableReference(node)) { diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bb68b71a02e2d..5876206d0fabc 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17860,6 +17860,16 @@ namespace ts { } } + if (node.kind === SyntaxKind.PropertyAccessExpression && isPrivateName(node.name)) { + const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(getParentOfSymbol(prop)!)!; + if (!isNodeWithinClass(node, declaringClassDeclaration)) { + error(errorNode, Diagnostics.Property_0_is_only_accessible_within_class_1_because_it_has_a_private_name, symbolToString(prop), typeToString(getDeclaringClass(prop)!)); + return false; + } + return true; + } + + // Public properties are otherwise accessible. if (!(flags & ModifierFlags.NonPublicAccessibilityModifier)) { return true; @@ -20725,10 +20735,16 @@ namespace ts { error(expr, Diagnostics.The_operand_of_a_delete_operator_must_be_a_property_reference); return booleanType; } + if (expr.kind === SyntaxKind.PropertyAccessExpression && isPrivateName((expr as PropertyAccessExpression).name)) { + error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_private_name); + + } const links = getNodeLinks(expr); const symbol = getExportSymbolOfValueSymbolIfExported(links.resolvedSymbol); - if (symbol && isReadonlySymbol(symbol)) { - error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_read_only_property); + if (symbol) { + if (isReadonlySymbol(symbol)) { + error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_read_only_property); + } } return booleanType; } @@ -21878,9 +21894,6 @@ 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))) { @@ -25426,6 +25439,10 @@ namespace ts { const declaredProp = member.name && getSymbolAtLocation(member.name) || getSymbolAtLocation(member); if (declaredProp) { const prop = getPropertyOfType(typeWithThis, declaredProp.escapedName); + // skip inheritance checks because private names are unique to each class + if (member.name && isPrivateName(member.name)) { + return; + } const baseProp = getPropertyOfType(baseWithThis, declaredProp.escapedName); if (prop && baseProp) { const rootChain = () => chainDiagnosticMessages( @@ -28515,6 +28532,9 @@ namespace ts { else if (node.kind === SyntaxKind.Parameter && (flags & ModifierFlags.ParameterPropertyModifier) && (node).dotDotDotToken) { return grammarErrorOnNode(node, Diagnostics.A_parameter_property_cannot_be_declared_using_a_rest_parameter); } + else if (isNamedDeclaration(node) && (flags & ModifierFlags.AccessibilityModifier) && node.name.kind === SyntaxKind.PrivateName) { + return grammarErrorOnNode(node, Diagnostics.Accessibility_modifiers_cannot_be_used_with_private_names); + } if (flags & ModifierFlags.Async) { return checkGrammarAsyncModifier(node, lastAsync!); } @@ -29293,10 +29313,6 @@ 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 a1d6859db7154..aeba5834bd8c8 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -4166,14 +4166,23 @@ "category": "Error", "code": 18003 }, - "Private names are not allowed in variable declarations.": { + "Accessibility modifiers cannot be used with private names.": { "category": "Error", "code": 18004 }, - "Private names cannot be used as parameters": { + "The operand of a delete operator cannot be a private name.": { "category": "Error", "code": 18005 }, + "#constructor is a reserved word.": { + "category": "Error", + "code": 18006 + }, + "Property '{0}' is only accessible within class '{1}' because it has a private name.": { + "category": "Error", + "code": 18007 + }, + "File is a CommonJS module; it may be converted to an ES6 module.": { "category": "Suggestion", diff --git a/tests/baselines/reference/privateNameContructorReserved.errors.txt b/tests/baselines/reference/privateNameContructorReserved.errors.txt new file mode 100644 index 0000000000000..ae8c3ab782cd8 --- /dev/null +++ b/tests/baselines/reference/privateNameContructorReserved.errors.txt @@ -0,0 +1,22 @@ +tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts(1,7): error TS2300: Duplicate identifier 'A'. +tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts(2,5): error TS18006: #constructor is a reserved word. +tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts(5,7): error TS2300: Duplicate identifier 'A'. +tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts(6,5): error TS18006: #constructor is a reserved word. + + +==== tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts (4 errors) ==== + class A { + ~ +!!! error TS2300: Duplicate identifier 'A'. + #constructor() {} // Error: `#constructor` is a reserved word. + ~~~~~~~~~~~~ +!!! error TS18006: #constructor is a reserved word. + } + + class A { + ~ +!!! error TS2300: Duplicate identifier 'A'. + #constructor = 5 // Error: `#constructor` is a reserved word. + ~~~~~~~~~~~~ +!!! error TS18006: #constructor is a reserved word. + } \ No newline at end of file diff --git a/tests/baselines/reference/privateNameContructorReserved.js b/tests/baselines/reference/privateNameContructorReserved.js new file mode 100644 index 0000000000000..9dcaf326c42f8 --- /dev/null +++ b/tests/baselines/reference/privateNameContructorReserved.js @@ -0,0 +1,22 @@ +//// [privateNameContructorReserved.ts] +class A { + #constructor() {} // Error: `#constructor` is a reserved word. +} + +class A { + #constructor = 5 // Error: `#constructor` is a reserved word. +} + +//// [privateNameContructorReserved.js] +var A = /** @class */ (function () { + function A() { + } + A.prototype.#constructor = function () { }; // Error: `#constructor` is a reserved word. + return A; +}()); +var A = /** @class */ (function () { + function A() { + this.#constructor = 5; // Error: `#constructor` is a reserved word. + } + return A; +}()); diff --git a/tests/baselines/reference/privateNameContructorReserved.symbols b/tests/baselines/reference/privateNameContructorReserved.symbols new file mode 100644 index 0000000000000..a9eabce603054 --- /dev/null +++ b/tests/baselines/reference/privateNameContructorReserved.symbols @@ -0,0 +1,14 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts === +class A { +>A : Symbol(A, Decl(privateNameContructorReserved.ts, 0, 0)) + + #constructor() {} // Error: `#constructor` is a reserved word. +>#constructor : Symbol(A[#constructor], Decl(privateNameContructorReserved.ts, 0, 9)) +} + +class A { +>A : Symbol(A, Decl(privateNameContructorReserved.ts, 2, 1)) + + #constructor = 5 // Error: `#constructor` is a reserved word. +>#constructor : Symbol(A[#constructor], Decl(privateNameContructorReserved.ts, 4, 9)) +} diff --git a/tests/baselines/reference/privateNameContructorReserved.types b/tests/baselines/reference/privateNameContructorReserved.types new file mode 100644 index 0000000000000..bd8eadcce5506 --- /dev/null +++ b/tests/baselines/reference/privateNameContructorReserved.types @@ -0,0 +1,15 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts === +class A { +>A : A + + #constructor() {} // Error: `#constructor` is a reserved word. +>#constructor : () => void +} + +class A { +>A : A + + #constructor = 5 // Error: `#constructor` is a reserved word. +>#constructor : number +>5 : 5 +} diff --git a/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.errors.txt b/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.errors.txt new file mode 100644 index 0000000000000..61b892d67ddc4 --- /dev/null +++ b/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.errors.txt @@ -0,0 +1,12 @@ +tests/cases/conformance/classes/members/privateNames/privateNameNotAccessibleOutsideDefiningClass.ts(5,9): error TS18007: Property '#foo' is only accessible within class 'A' because it has a private name. + + +==== tests/cases/conformance/classes/members/privateNames/privateNameNotAccessibleOutsideDefiningClass.ts (1 errors) ==== + class A { + #foo: number = 3; + } + + new A().#foo = 4; // Error + ~~~~ +!!! error TS18007: Property '#foo' is only accessible within class 'A' because it has a private name. + \ No newline at end of file diff --git a/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.js b/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.js new file mode 100644 index 0000000000000..c096ffe8efe41 --- /dev/null +++ b/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.js @@ -0,0 +1,16 @@ +//// [privateNameNotAccessibleOutsideDefiningClass.ts] +class A { + #foo: number = 3; +} + +new A().#foo = 4; // Error + + +//// [privateNameNotAccessibleOutsideDefiningClass.js] +var A = /** @class */ (function () { + function A() { + this.#foo = 3; + } + return A; +}()); +new A().#foo = 4; // Error diff --git a/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.symbols b/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.symbols new file mode 100644 index 0000000000000..8c2ae13977053 --- /dev/null +++ b/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.symbols @@ -0,0 +1,12 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameNotAccessibleOutsideDefiningClass.ts === +class A { +>A : Symbol(A, Decl(privateNameNotAccessibleOutsideDefiningClass.ts, 0, 0)) + + #foo: number = 3; +>#foo : Symbol(A[#foo], Decl(privateNameNotAccessibleOutsideDefiningClass.ts, 0, 9)) +} + +new A().#foo = 4; // Error +>new A().#foo : Symbol(A[#foo], Decl(privateNameNotAccessibleOutsideDefiningClass.ts, 0, 9)) +>A : Symbol(A, Decl(privateNameNotAccessibleOutsideDefiningClass.ts, 0, 0)) + diff --git a/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.types b/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.types new file mode 100644 index 0000000000000..5ffbd2187c765 --- /dev/null +++ b/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.types @@ -0,0 +1,16 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameNotAccessibleOutsideDefiningClass.ts === +class A { +>A : A + + #foo: number = 3; +>#foo : number +>3 : 3 +} + +new A().#foo = 4; // Error +>new A().#foo = 4 : 4 +>new A().#foo : number +>new A() : A +>A : typeof A +>4 : 4 + diff --git a/tests/baselines/reference/privateNameNotAllowedOutsideClass.errors.txt b/tests/baselines/reference/privateNameNotAllowedOutsideClass.errors.txt new file mode 100644 index 0000000000000..f4b6a6364f6b8 --- /dev/null +++ b/tests/baselines/reference/privateNameNotAllowedOutsideClass.errors.txt @@ -0,0 +1,13 @@ +tests/cases/conformance/classes/members/privateNames/privateNameNotAllowedOutsideClass.ts(1,7): error TS1134: Variable declaration expected. +tests/cases/conformance/classes/members/privateNames/privateNameNotAllowedOutsideClass.ts(1,12): error TS1134: Variable declaration expected. +tests/cases/conformance/classes/members/privateNames/privateNameNotAllowedOutsideClass.ts(1,14): error TS1134: Variable declaration expected. + + +==== tests/cases/conformance/classes/members/privateNames/privateNameNotAllowedOutsideClass.ts (3 errors) ==== + const #foo = 3; + ~~~~ +!!! error TS1134: Variable declaration expected. + ~ +!!! error TS1134: Variable declaration expected. + ~ +!!! error TS1134: Variable declaration expected. \ No newline at end of file diff --git a/tests/baselines/reference/privateNameNotAllowedOutsideClass.js b/tests/baselines/reference/privateNameNotAllowedOutsideClass.js new file mode 100644 index 0000000000000..ff289b3d29c54 --- /dev/null +++ b/tests/baselines/reference/privateNameNotAllowedOutsideClass.js @@ -0,0 +1,6 @@ +//// [privateNameNotAllowedOutsideClass.ts] +const #foo = 3; + +//// [privateNameNotAllowedOutsideClass.js] +var ; +3; diff --git a/tests/baselines/reference/privateNameNotAllowedOutsideClass.symbols b/tests/baselines/reference/privateNameNotAllowedOutsideClass.symbols new file mode 100644 index 0000000000000..b604786dda640 --- /dev/null +++ b/tests/baselines/reference/privateNameNotAllowedOutsideClass.symbols @@ -0,0 +1,3 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameNotAllowedOutsideClass.ts === +const #foo = 3; +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/privateNameNotAllowedOutsideClass.types b/tests/baselines/reference/privateNameNotAllowedOutsideClass.types new file mode 100644 index 0000000000000..20826f41a55e1 --- /dev/null +++ b/tests/baselines/reference/privateNameNotAllowedOutsideClass.types @@ -0,0 +1,4 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameNotAllowedOutsideClass.ts === +const #foo = 3; +>3 : 3 + diff --git a/tests/baselines/reference/privateNamesNoConflictWhenInheriting.js b/tests/baselines/reference/privateNamesNoConflictWhenInheriting.js new file mode 100644 index 0000000000000..0dbc7ec223be7 --- /dev/null +++ b/tests/baselines/reference/privateNamesNoConflictWhenInheriting.js @@ -0,0 +1,36 @@ +//// [privateNamesNoConflictWhenInheriting.ts] +class A { + #foo: number; +} + +class B extends A { + #foo: string; // OK: private names are unique to each class +} + + +//// [privateNamesNoConflictWhenInheriting.js] +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + } + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var A = /** @class */ (function () { + function A() { + } + return A; +}()); +var B = /** @class */ (function (_super) { + __extends(B, _super); + function B() { + return _super !== null && _super.apply(this, arguments) || this; + } + return B; +}(A)); diff --git a/tests/baselines/reference/privateNamesNoConflictWhenInheriting.symbols b/tests/baselines/reference/privateNamesNoConflictWhenInheriting.symbols new file mode 100644 index 0000000000000..7ce208e54b3c0 --- /dev/null +++ b/tests/baselines/reference/privateNamesNoConflictWhenInheriting.symbols @@ -0,0 +1,16 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesNoConflictWhenInheriting.ts === +class A { +>A : Symbol(A, Decl(privateNamesNoConflictWhenInheriting.ts, 0, 0)) + + #foo: number; +>#foo : Symbol(A[#foo], Decl(privateNamesNoConflictWhenInheriting.ts, 0, 9)) +} + +class B extends A { +>B : Symbol(B, Decl(privateNamesNoConflictWhenInheriting.ts, 2, 1)) +>A : Symbol(A, Decl(privateNamesNoConflictWhenInheriting.ts, 0, 0)) + + #foo: string; // OK: private names are unique to each class +>#foo : Symbol(B[#foo], Decl(privateNamesNoConflictWhenInheriting.ts, 4, 19)) +} + diff --git a/tests/baselines/reference/privateNamesNoConflictWhenInheriting.types b/tests/baselines/reference/privateNamesNoConflictWhenInheriting.types new file mode 100644 index 0000000000000..3b7213ae2a97e --- /dev/null +++ b/tests/baselines/reference/privateNamesNoConflictWhenInheriting.types @@ -0,0 +1,16 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesNoConflictWhenInheriting.ts === +class A { +>A : A + + #foo: number; +>#foo : number +} + +class B extends A { +>B : B +>A : A + + #foo: string; // OK: private names are unique to each class +>#foo : string +} + diff --git a/tests/baselines/reference/privateNamesNoDelete.errors.txt b/tests/baselines/reference/privateNamesNoDelete.errors.txt new file mode 100644 index 0000000000000..ae45010321430 --- /dev/null +++ b/tests/baselines/reference/privateNamesNoDelete.errors.txt @@ -0,0 +1,13 @@ +tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts(4,16): error TS18005: The operand of a delete operator cannot be a private name. + + +==== tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts (1 errors) ==== + class A { + #v = 1; + constructor() { + delete this.#v; // Error: The operand of a delete operator cannot be a private name. + ~~~~~~~ +!!! error TS18005: The operand of a delete operator cannot be a private name. + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/privateNamesNoDelete.js b/tests/baselines/reference/privateNamesNoDelete.js new file mode 100644 index 0000000000000..7266285f807b5 --- /dev/null +++ b/tests/baselines/reference/privateNamesNoDelete.js @@ -0,0 +1,17 @@ +//// [privateNamesNoDelete.ts] +class A { + #v = 1; + constructor() { + delete this.#v; // Error: The operand of a delete operator cannot be a private name. + } +} + + +//// [privateNamesNoDelete.js] +var A = /** @class */ (function () { + function A() { + this.#v = 1; + delete this.#v; // Error: The operand of a delete operator cannot be a private name. + } + return A; +}()); diff --git a/tests/baselines/reference/privateNamesNoDelete.symbols b/tests/baselines/reference/privateNamesNoDelete.symbols new file mode 100644 index 0000000000000..ae5e4315675e4 --- /dev/null +++ b/tests/baselines/reference/privateNamesNoDelete.symbols @@ -0,0 +1,14 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts === +class A { +>A : Symbol(A, Decl(privateNamesNoDelete.ts, 0, 0)) + + #v = 1; +>#v : Symbol(A[#v], Decl(privateNamesNoDelete.ts, 0, 9)) + + constructor() { + delete this.#v; // Error: The operand of a delete operator cannot be a private name. +>this.#v : Symbol(A[#v], Decl(privateNamesNoDelete.ts, 0, 9)) +>this : Symbol(A, Decl(privateNamesNoDelete.ts, 0, 0)) + } +} + diff --git a/tests/baselines/reference/privateNamesNoDelete.types b/tests/baselines/reference/privateNamesNoDelete.types new file mode 100644 index 0000000000000..d23b8712dbdcb --- /dev/null +++ b/tests/baselines/reference/privateNamesNoDelete.types @@ -0,0 +1,16 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts === +class A { +>A : A + + #v = 1; +>#v : number +>1 : 1 + + constructor() { + delete this.#v; // Error: The operand of a delete operator cannot be a private name. +>delete this.#v : boolean +>this.#v : number +>this : this + } +} + diff --git a/tests/baselines/reference/privateNamesNotAllowedAsParameters.errors.txt b/tests/baselines/reference/privateNamesNotAllowedAsParameters.errors.txt new file mode 100644 index 0000000000000..7d6b45dc9581c --- /dev/null +++ b/tests/baselines/reference/privateNamesNotAllowedAsParameters.errors.txt @@ -0,0 +1,19 @@ +tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts(2,12): error TS1138: Parameter declaration expected. +tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts(2,24): error TS1005: ';' expected. +tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts(2,26): error TS1068: Unexpected token. A constructor, method, accessor, or property was expected. +tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts(3,1): error TS1128: Declaration or statement expected. + + +==== tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts (4 errors) ==== + class A { + setFoo(#foo: string) {} + ~~~~ +!!! error TS1138: Parameter declaration expected. + ~ +!!! error TS1005: ';' expected. + ~ +!!! error TS1068: Unexpected token. A constructor, method, accessor, or property was expected. + } + ~ +!!! error TS1128: Declaration or statement expected. + \ No newline at end of file diff --git a/tests/baselines/reference/privateNamesNotAllowedAsParameters.js b/tests/baselines/reference/privateNamesNotAllowedAsParameters.js new file mode 100644 index 0000000000000..862409a851765 --- /dev/null +++ b/tests/baselines/reference/privateNamesNotAllowedAsParameters.js @@ -0,0 +1,14 @@ +//// [privateNamesNotAllowedAsParameters.ts] +class A { + setFoo(#foo: string) {} +} + + +//// [privateNamesNotAllowedAsParameters.js] +var A = /** @class */ (function () { + function A() { + } + A.prototype.setFoo = function () { }; + return A; +}()); +{ } diff --git a/tests/baselines/reference/privateNamesNotAllowedAsParameters.symbols b/tests/baselines/reference/privateNamesNotAllowedAsParameters.symbols new file mode 100644 index 0000000000000..013e0e192734c --- /dev/null +++ b/tests/baselines/reference/privateNamesNotAllowedAsParameters.symbols @@ -0,0 +1,9 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts === +class A { +>A : Symbol(A, Decl(privateNamesNotAllowedAsParameters.ts, 0, 0)) + + setFoo(#foo: string) {} +>setFoo : Symbol(A.setFoo, Decl(privateNamesNotAllowedAsParameters.ts, 0, 9)) +>#foo : Symbol(A[#foo], Decl(privateNamesNotAllowedAsParameters.ts, 1, 11)) +} + diff --git a/tests/baselines/reference/privateNamesNotAllowedAsParameters.types b/tests/baselines/reference/privateNamesNotAllowedAsParameters.types new file mode 100644 index 0000000000000..b11ecd42efe52 --- /dev/null +++ b/tests/baselines/reference/privateNamesNotAllowedAsParameters.types @@ -0,0 +1,9 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts === +class A { +>A : A + + setFoo(#foo: string) {} +>setFoo : () => any +>#foo : string +} + diff --git a/tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.errors.txt b/tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.errors.txt new file mode 100644 index 0000000000000..ad967f6b8c0ce --- /dev/null +++ b/tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.errors.txt @@ -0,0 +1,13 @@ +tests/cases/conformance/classes/privateNames/privateNamesNotAllowedInVariableDeclarations.ts(1,7): error TS1134: Variable declaration expected. +tests/cases/conformance/classes/privateNames/privateNamesNotAllowedInVariableDeclarations.ts(1,12): error TS1134: Variable declaration expected. +tests/cases/conformance/classes/privateNames/privateNamesNotAllowedInVariableDeclarations.ts(1,14): error TS1134: Variable declaration expected. + + +==== tests/cases/conformance/classes/privateNames/privateNamesNotAllowedInVariableDeclarations.ts (3 errors) ==== + const #foo = 3; + ~~~~ +!!! error TS1134: Variable declaration expected. + ~ +!!! error TS1134: Variable declaration expected. + ~ +!!! error TS1134: Variable declaration expected. \ No newline at end of file diff --git a/tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.js b/tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.js new file mode 100644 index 0000000000000..9b65ff8a3a0b0 --- /dev/null +++ b/tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.js @@ -0,0 +1,6 @@ +//// [privateNamesNotAllowedInVariableDeclarations.ts] +const #foo = 3; + +//// [privateNamesNotAllowedInVariableDeclarations.js] +var ; +3; diff --git a/tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.symbols b/tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.symbols new file mode 100644 index 0000000000000..b9b048bea1fb0 --- /dev/null +++ b/tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.symbols @@ -0,0 +1,3 @@ +=== tests/cases/conformance/classes/privateNames/privateNamesNotAllowedInVariableDeclarations.ts === +const #foo = 3; +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.types b/tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.types new file mode 100644 index 0000000000000..6c52944e553c7 --- /dev/null +++ b/tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.types @@ -0,0 +1,4 @@ +=== tests/cases/conformance/classes/privateNames/privateNamesNotAllowedInVariableDeclarations.ts === +const #foo = 3; +>3 : 3 + diff --git a/tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts b/tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts new file mode 100644 index 0000000000000..eba42c1fb991b --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts @@ -0,0 +1,7 @@ +class A { + #constructor() {} // Error: `#constructor` is a reserved word. +} + +class A { + #constructor = 5 // Error: `#constructor` is a reserved word. +} \ No newline at end of file diff --git a/tests/cases/conformance/classes/members/privateNames/privateNameNotAccessibleOutsideDefiningClass.ts b/tests/cases/conformance/classes/members/privateNames/privateNameNotAccessibleOutsideDefiningClass.ts new file mode 100644 index 0000000000000..b27069b5787ed --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNameNotAccessibleOutsideDefiningClass.ts @@ -0,0 +1,5 @@ +class A { + #foo: number = 3; +} + +new A().#foo = 4; // Error diff --git a/tests/cases/conformance/classes/members/privateNames/privateNameNotAllowedOutsideClass.ts b/tests/cases/conformance/classes/members/privateNames/privateNameNotAllowedOutsideClass.ts new file mode 100644 index 0000000000000..7af2bf989ff3b --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNameNotAllowedOutsideClass.ts @@ -0,0 +1 @@ +const #foo = 3; \ No newline at end of file diff --git a/tests/cases/conformance/classes/members/privateNames/privateNamesNoConflictWhenInheriting.ts b/tests/cases/conformance/classes/members/privateNames/privateNamesNoConflictWhenInheriting.ts new file mode 100644 index 0000000000000..edc6636fe44f6 --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNamesNoConflictWhenInheriting.ts @@ -0,0 +1,7 @@ +class A { + #foo: number; +} + +class B extends A { + #foo: string; // OK: private names are unique to each class +} diff --git a/tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts b/tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts new file mode 100644 index 0000000000000..0eec9a9ebffa3 --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts @@ -0,0 +1,6 @@ +class A { + #v = 1; + constructor() { + delete this.#v; // Error: The operand of a delete operator cannot be a private name. + } +} diff --git a/tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts b/tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts new file mode 100644 index 0000000000000..2ba9f8cab4f0f --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts @@ -0,0 +1,3 @@ +class A { + setFoo(#foo: string) {} +} diff --git a/tests/cases/conformance/classes/privateNames/privateNamesNotAllowedInVariableDeclarations.ts b/tests/cases/conformance/classes/privateNames/privateNamesNotAllowedInVariableDeclarations.ts new file mode 100644 index 0000000000000..7af2bf989ff3b --- /dev/null +++ b/tests/cases/conformance/classes/privateNames/privateNamesNotAllowedInVariableDeclarations.ts @@ -0,0 +1 @@ +const #foo = 3; \ No newline at end of file From bd52998afdd254f338726900b165fcd38b15d698 Mon Sep 17 00:00:00 2001 From: Max Heiber Date: Sat, 25 Aug 2018 13:37:20 -0400 Subject: [PATCH 2/4] nominalize in the presence of private names --- src/compiler/binder.ts | 4 ++++ src/compiler/checker.ts | 3 +++ src/compiler/types.ts | 1 + .../reference/api/tsserverlibrary.d.ts | 1 + tests/baselines/reference/api/typescript.d.ts | 1 + .../reference/privateNamesUnique.errors.txt | 18 ++++++++++++++ .../baselines/reference/privateNamesUnique.js | 24 +++++++++++++++++++ .../reference/privateNamesUnique.symbols | 20 ++++++++++++++++ .../reference/privateNamesUnique.types | 20 ++++++++++++++++ .../privateNameAndIndexSignature.ts | 12 +++++----- .../privateNameContructorReserved.ts | 12 +++++----- .../members/privateNames/privateNameField.ts | 10 ++++---- ...teNameNotAccessibleOutsideDefiningClass.ts | 10 ++++---- .../privateNamesNoConflictWhenInheriting.ts | 14 +++++------ .../privateNames/privateNamesNoDelete.ts | 12 +++++----- .../privateNamesNotAllowedAsParameters.ts | 6 ++--- .../privateNames/privateNamesUnique.ts | 9 +++++++ 17 files changed, 139 insertions(+), 38 deletions(-) create mode 100644 tests/baselines/reference/privateNamesUnique.errors.txt create mode 100644 tests/baselines/reference/privateNamesUnique.js create mode 100644 tests/baselines/reference/privateNamesUnique.symbols create mode 100644 tests/baselines/reference/privateNamesUnique.types create mode 100644 tests/cases/conformance/classes/members/privateNames/privateNamesUnique.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index dfa3368bf5ed8..5bd544035f09e 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -225,6 +225,10 @@ namespace ts { node.symbol = symbol; symbol.declarations = append(symbol.declarations, node); + if (isNamedDeclaration(node) && isPrivateName(node.name)) { + symbol.flags |= SymbolFlags.PrivateNamed; + } + if (symbolFlags & (SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.Module | SymbolFlags.Variable) && !symbol.exports) { symbol.exports = createSymbolTable(); } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5876206d0fabc..4c44a9b39ffb9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13187,6 +13187,9 @@ namespace ts { const properties = target.flags & TypeFlags.Intersection ? getPropertiesOfUnionOrIntersectionType(target) : getPropertiesOfObjectType(target); for (const targetProp of properties) { if (requireOptionalProperties || !(targetProp.flags & SymbolFlags.Optional)) { + if (targetProp.flags & SymbolFlags.PrivateNamed) { + return targetProp; + } const sourceProp = getPropertyOfType(source, targetProp.escapedName); if (!sourceProp) { return targetProp; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 4b2357bc63e77..b2ad0db07aa3f 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3433,6 +3433,7 @@ namespace ts { Transient = 1 << 25, // Transient symbol (created during type check) JSContainer = 1 << 26, // Contains Javascript special declarations ModuleExports = 1 << 27, // Symbol for CommonJS `module` of `module.exports` + PrivateNamed = 1 << 28, // Symbol's name is a private name (example: `#foo`) /* @internal */ All = FunctionScopedVariable | BlockScopedVariable | Property | EnumMember | Function | Class | Interface | ConstEnum | RegularEnum | ValueModule | NamespaceModule | TypeLiteral diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 1ab1a986d1ad1..fcc8434c0d3c0 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2063,6 +2063,7 @@ declare namespace ts { Transient = 33554432, JSContainer = 67108864, ModuleExports = 134217728, + PrivateNamed = 268435456, Enum = 384, Variable = 3, Value = 67216319, diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index ea78225538eac..03867ae19cb45 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2063,6 +2063,7 @@ declare namespace ts { Transient = 33554432, JSContainer = 67108864, ModuleExports = 134217728, + PrivateNamed = 268435456, Enum = 384, Variable = 3, Value = 67216319, diff --git a/tests/baselines/reference/privateNamesUnique.errors.txt b/tests/baselines/reference/privateNamesUnique.errors.txt new file mode 100644 index 0000000000000..43b7b7790e5d4 --- /dev/null +++ b/tests/baselines/reference/privateNamesUnique.errors.txt @@ -0,0 +1,18 @@ +tests/cases/conformance/classes/members/privateNames/privateNamesUnique.ts(9,7): error TS2322: Type 'B' is not assignable to type 'A'. + Property '#foo' is missing in type 'B'. + + +==== tests/cases/conformance/classes/members/privateNames/privateNamesUnique.ts (1 errors) ==== + class A { + #foo: number; + } + + class B { + #foo: number; + } + + const b: A = new B() // Error: Property #foo is missing + ~ +!!! error TS2322: Type 'B' is not assignable to type 'A'. +!!! error TS2322: Property '#foo' is missing in type 'B'. + \ No newline at end of file diff --git a/tests/baselines/reference/privateNamesUnique.js b/tests/baselines/reference/privateNamesUnique.js new file mode 100644 index 0000000000000..a5b5a2dad7b3e --- /dev/null +++ b/tests/baselines/reference/privateNamesUnique.js @@ -0,0 +1,24 @@ +//// [privateNamesUnique.ts] +class A { + #foo: number; +} + +class B { + #foo: number; +} + +const b: A = new B() // Error: Property #foo is missing + + +//// [privateNamesUnique.js] +var A = /** @class */ (function () { + function A() { + } + return A; +}()); +var B = /** @class */ (function () { + function B() { + } + return B; +}()); +var b = new B(); // Error: Property #foo is missing diff --git a/tests/baselines/reference/privateNamesUnique.symbols b/tests/baselines/reference/privateNamesUnique.symbols new file mode 100644 index 0000000000000..224785a388fca --- /dev/null +++ b/tests/baselines/reference/privateNamesUnique.symbols @@ -0,0 +1,20 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesUnique.ts === +class A { +>A : Symbol(A, Decl(privateNamesUnique.ts, 0, 0)) + + #foo: number; +>#foo : Symbol(A[#foo], Decl(privateNamesUnique.ts, 0, 9)) +} + +class B { +>B : Symbol(B, Decl(privateNamesUnique.ts, 2, 1)) + + #foo: number; +>#foo : Symbol(B[#foo], Decl(privateNamesUnique.ts, 4, 9)) +} + +const b: A = new B() // Error: Property #foo is missing +>b : Symbol(b, Decl(privateNamesUnique.ts, 8, 5)) +>A : Symbol(A, Decl(privateNamesUnique.ts, 0, 0)) +>B : Symbol(B, Decl(privateNamesUnique.ts, 2, 1)) + diff --git a/tests/baselines/reference/privateNamesUnique.types b/tests/baselines/reference/privateNamesUnique.types new file mode 100644 index 0000000000000..16fdb5a6f1629 --- /dev/null +++ b/tests/baselines/reference/privateNamesUnique.types @@ -0,0 +1,20 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesUnique.ts === +class A { +>A : A + + #foo: number; +>#foo : number +} + +class B { +>B : B + + #foo: number; +>#foo : number +} + +const b: A = new B() // Error: Property #foo is missing +>b : A +>new B() : B +>B : typeof B + diff --git a/tests/cases/conformance/classes/members/privateNames/privateNameAndIndexSignature.ts b/tests/cases/conformance/classes/members/privateNames/privateNameAndIndexSignature.ts index d4c0b8ad46efb..0efb1813fcefa 100644 --- a/tests/cases/conformance/classes/members/privateNames/privateNameAndIndexSignature.ts +++ b/tests/cases/conformance/classes/members/privateNames/privateNameAndIndexSignature.ts @@ -1,6 +1,6 @@ -class A { - [k: string]: any; - constructor(message: string) { - this.#f = 3 // Error Property '#f' does not exist on type 'A'. - } -} +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/privateNameContructorReserved.ts b/tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts index eba42c1fb991b..4a4c1525c852a 100644 --- a/tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts +++ b/tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts @@ -1,7 +1,7 @@ -class A { - #constructor() {} // Error: `#constructor` is a reserved word. -} - -class A { - #constructor = 5 // Error: `#constructor` is a reserved word. +class A { + #constructor() {} // Error: `#constructor` is a reserved word. +} + +class A { + #constructor = 5 // Error: `#constructor` is a reserved word. } \ No newline at end of file diff --git a/tests/cases/conformance/classes/members/privateNames/privateNameField.ts b/tests/cases/conformance/classes/members/privateNames/privateNameField.ts index 02e449fb3e002..3d38a3d651453 100644 --- a/tests/cases/conformance/classes/members/privateNames/privateNameField.ts +++ b/tests/cases/conformance/classes/members/privateNames/privateNameField.ts @@ -1,6 +1,6 @@ -class A { - #name: string; - constructor(name: string) { - this.#name = name; - } +class A { + #name: string; + constructor(name: string) { + this.#name = name; + } } \ No newline at end of file diff --git a/tests/cases/conformance/classes/members/privateNames/privateNameNotAccessibleOutsideDefiningClass.ts b/tests/cases/conformance/classes/members/privateNames/privateNameNotAccessibleOutsideDefiningClass.ts index b27069b5787ed..1d213d7e54509 100644 --- a/tests/cases/conformance/classes/members/privateNames/privateNameNotAccessibleOutsideDefiningClass.ts +++ b/tests/cases/conformance/classes/members/privateNames/privateNameNotAccessibleOutsideDefiningClass.ts @@ -1,5 +1,5 @@ -class A { - #foo: number = 3; -} - -new A().#foo = 4; // Error +class A { + #foo: number = 3; +} + +new A().#foo = 4; // Error diff --git a/tests/cases/conformance/classes/members/privateNames/privateNamesNoConflictWhenInheriting.ts b/tests/cases/conformance/classes/members/privateNames/privateNamesNoConflictWhenInheriting.ts index edc6636fe44f6..dae3d40cea03c 100644 --- a/tests/cases/conformance/classes/members/privateNames/privateNamesNoConflictWhenInheriting.ts +++ b/tests/cases/conformance/classes/members/privateNames/privateNamesNoConflictWhenInheriting.ts @@ -1,7 +1,7 @@ -class A { - #foo: number; -} - -class B extends A { - #foo: string; // OK: private names are unique to each class -} +class A { + #foo: number; +} + +class B extends A { + #foo: string; // OK: private names are unique to each class +} diff --git a/tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts b/tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts index 0eec9a9ebffa3..a71a733371023 100644 --- a/tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts +++ b/tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts @@ -1,6 +1,6 @@ -class A { - #v = 1; - constructor() { - delete this.#v; // Error: The operand of a delete operator cannot be a private name. - } -} +class A { + #v = 1; + constructor() { + delete this.#v; // Error: The operand of a delete operator cannot be a private name. + } +} diff --git a/tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts b/tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts index 2ba9f8cab4f0f..edc846a0bf35d 100644 --- a/tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts +++ b/tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts @@ -1,3 +1,3 @@ -class A { - setFoo(#foo: string) {} -} +class A { + setFoo(#foo: string) {} +} diff --git a/tests/cases/conformance/classes/members/privateNames/privateNamesUnique.ts b/tests/cases/conformance/classes/members/privateNames/privateNamesUnique.ts new file mode 100644 index 0000000000000..cee206eacd201 --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNamesUnique.ts @@ -0,0 +1,9 @@ +class A { + #foo: number; +} + +class B { + #foo: number; +} + +const b: A = new B() // Error: Property #foo is missing From b9a3d26a3c11df1e471f6b7b303a67618cbd3be2 Mon Sep 17 00:00:00 2001 From: Max Heiber Date: Sat, 25 Aug 2018 16:37:46 -0400 Subject: [PATCH 3/4] test cases for accessibility modifiers --- ...privateNameConstructorReserved.errors.txt} | 10 +++++----- ...d.js => privateNameConstructorReserved.js} | 4 ++-- .../privateNameConstructorReserved.symbols | 14 ++++++++++++++ ...s => privateNameConstructorReserved.types} | 2 +- .../privateNameContructorReserved.symbols | 14 -------------- ...teNamesNoAccessibilityModifiers.errors.txt | 19 +++++++++++++++++++ .../privateNamesNoAccessibilityModifiers.js | 15 +++++++++++++++ ...ivateNamesNoAccessibilityModifiers.symbols | 17 +++++++++++++++++ ...privateNamesNoAccessibilityModifiers.types | 17 +++++++++++++++++ ...d.ts => privateNameConstructorReserved.ts} | 0 .../privateNamesNoAccessibilityModifiers.ts | 6 ++++++ 11 files changed, 96 insertions(+), 22 deletions(-) rename tests/baselines/reference/{privateNameContructorReserved.errors.txt => privateNameConstructorReserved.errors.txt} (68%) rename tests/baselines/reference/{privateNameContructorReserved.js => privateNameConstructorReserved.js} (83%) create mode 100644 tests/baselines/reference/privateNameConstructorReserved.symbols rename tests/baselines/reference/{privateNameContructorReserved.types => privateNameConstructorReserved.types} (86%) delete mode 100644 tests/baselines/reference/privateNameContructorReserved.symbols create mode 100644 tests/baselines/reference/privateNamesNoAccessibilityModifiers.errors.txt create mode 100644 tests/baselines/reference/privateNamesNoAccessibilityModifiers.js create mode 100644 tests/baselines/reference/privateNamesNoAccessibilityModifiers.symbols create mode 100644 tests/baselines/reference/privateNamesNoAccessibilityModifiers.types rename tests/cases/conformance/classes/members/privateNames/{privateNameContructorReserved.ts => privateNameConstructorReserved.ts} (100%) create mode 100644 tests/cases/conformance/classes/members/privateNames/privateNamesNoAccessibilityModifiers.ts diff --git a/tests/baselines/reference/privateNameContructorReserved.errors.txt b/tests/baselines/reference/privateNameConstructorReserved.errors.txt similarity index 68% rename from tests/baselines/reference/privateNameContructorReserved.errors.txt rename to tests/baselines/reference/privateNameConstructorReserved.errors.txt index ae8c3ab782cd8..0e19a569e8fbe 100644 --- a/tests/baselines/reference/privateNameContructorReserved.errors.txt +++ b/tests/baselines/reference/privateNameConstructorReserved.errors.txt @@ -1,10 +1,10 @@ -tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts(1,7): error TS2300: Duplicate identifier 'A'. -tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts(2,5): error TS18006: #constructor is a reserved word. -tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts(5,7): error TS2300: Duplicate identifier 'A'. -tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts(6,5): error TS18006: #constructor is a reserved word. +tests/cases/conformance/classes/members/privateNames/privateNameConstructorReserved.ts(1,7): error TS2300: Duplicate identifier 'A'. +tests/cases/conformance/classes/members/privateNames/privateNameConstructorReserved.ts(2,5): error TS18006: #constructor is a reserved word. +tests/cases/conformance/classes/members/privateNames/privateNameConstructorReserved.ts(5,7): error TS2300: Duplicate identifier 'A'. +tests/cases/conformance/classes/members/privateNames/privateNameConstructorReserved.ts(6,5): error TS18006: #constructor is a reserved word. -==== tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts (4 errors) ==== +==== tests/cases/conformance/classes/members/privateNames/privateNameConstructorReserved.ts (4 errors) ==== class A { ~ !!! error TS2300: Duplicate identifier 'A'. diff --git a/tests/baselines/reference/privateNameContructorReserved.js b/tests/baselines/reference/privateNameConstructorReserved.js similarity index 83% rename from tests/baselines/reference/privateNameContructorReserved.js rename to tests/baselines/reference/privateNameConstructorReserved.js index 9dcaf326c42f8..e393334154560 100644 --- a/tests/baselines/reference/privateNameContructorReserved.js +++ b/tests/baselines/reference/privateNameConstructorReserved.js @@ -1,4 +1,4 @@ -//// [privateNameContructorReserved.ts] +//// [privateNameConstructorReserved.ts] class A { #constructor() {} // Error: `#constructor` is a reserved word. } @@ -7,7 +7,7 @@ class A { #constructor = 5 // Error: `#constructor` is a reserved word. } -//// [privateNameContructorReserved.js] +//// [privateNameConstructorReserved.js] var A = /** @class */ (function () { function A() { } diff --git a/tests/baselines/reference/privateNameConstructorReserved.symbols b/tests/baselines/reference/privateNameConstructorReserved.symbols new file mode 100644 index 0000000000000..d61e750acb600 --- /dev/null +++ b/tests/baselines/reference/privateNameConstructorReserved.symbols @@ -0,0 +1,14 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameConstructorReserved.ts === +class A { +>A : Symbol(A, Decl(privateNameConstructorReserved.ts, 0, 0)) + + #constructor() {} // Error: `#constructor` is a reserved word. +>#constructor : Symbol(A[#constructor], Decl(privateNameConstructorReserved.ts, 0, 9)) +} + +class A { +>A : Symbol(A, Decl(privateNameConstructorReserved.ts, 2, 1)) + + #constructor = 5 // Error: `#constructor` is a reserved word. +>#constructor : Symbol(A[#constructor], Decl(privateNameConstructorReserved.ts, 4, 9)) +} diff --git a/tests/baselines/reference/privateNameContructorReserved.types b/tests/baselines/reference/privateNameConstructorReserved.types similarity index 86% rename from tests/baselines/reference/privateNameContructorReserved.types rename to tests/baselines/reference/privateNameConstructorReserved.types index bd8eadcce5506..008329efd5e30 100644 --- a/tests/baselines/reference/privateNameContructorReserved.types +++ b/tests/baselines/reference/privateNameConstructorReserved.types @@ -1,4 +1,4 @@ -=== tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts === +=== tests/cases/conformance/classes/members/privateNames/privateNameConstructorReserved.ts === class A { >A : A diff --git a/tests/baselines/reference/privateNameContructorReserved.symbols b/tests/baselines/reference/privateNameContructorReserved.symbols deleted file mode 100644 index a9eabce603054..0000000000000 --- a/tests/baselines/reference/privateNameContructorReserved.symbols +++ /dev/null @@ -1,14 +0,0 @@ -=== tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts === -class A { ->A : Symbol(A, Decl(privateNameContructorReserved.ts, 0, 0)) - - #constructor() {} // Error: `#constructor` is a reserved word. ->#constructor : Symbol(A[#constructor], Decl(privateNameContructorReserved.ts, 0, 9)) -} - -class A { ->A : Symbol(A, Decl(privateNameContructorReserved.ts, 2, 1)) - - #constructor = 5 // Error: `#constructor` is a reserved word. ->#constructor : Symbol(A[#constructor], Decl(privateNameContructorReserved.ts, 4, 9)) -} diff --git a/tests/baselines/reference/privateNamesNoAccessibilityModifiers.errors.txt b/tests/baselines/reference/privateNamesNoAccessibilityModifiers.errors.txt new file mode 100644 index 0000000000000..5ce9be967beca --- /dev/null +++ b/tests/baselines/reference/privateNamesNoAccessibilityModifiers.errors.txt @@ -0,0 +1,19 @@ +tests/cases/conformance/classes/members/privateNames/privateNamesNoAccessibilityModifiers.ts(2,12): error TS18004: Accessibility modifiers cannot be used with private names. +tests/cases/conformance/classes/members/privateNames/privateNamesNoAccessibilityModifiers.ts(3,13): error TS18004: Accessibility modifiers cannot be used with private names. +tests/cases/conformance/classes/members/privateNames/privateNamesNoAccessibilityModifiers.ts(4,15): error TS18004: Accessibility modifiers cannot be used with private names. + + +==== tests/cases/conformance/classes/members/privateNames/privateNamesNoAccessibilityModifiers.ts (3 errors) ==== + class A { + public #foo; // Error + ~~~~ +!!! error TS18004: Accessibility modifiers cannot be used with private names. + private #bar; // Error + ~~~~ +!!! error TS18004: Accessibility modifiers cannot be used with private names. + protected #baz; // Error + ~~~~ +!!! error TS18004: Accessibility modifiers cannot be used with private names. + readonly #qux; // OK + } + \ No newline at end of file diff --git a/tests/baselines/reference/privateNamesNoAccessibilityModifiers.js b/tests/baselines/reference/privateNamesNoAccessibilityModifiers.js new file mode 100644 index 0000000000000..43227f2b84ee6 --- /dev/null +++ b/tests/baselines/reference/privateNamesNoAccessibilityModifiers.js @@ -0,0 +1,15 @@ +//// [privateNamesNoAccessibilityModifiers.ts] +class A { + public #foo; // Error + private #bar; // Error + protected #baz; // Error + readonly #qux; // OK +} + + +//// [privateNamesNoAccessibilityModifiers.js] +var A = /** @class */ (function () { + function A() { + } + return A; +}()); diff --git a/tests/baselines/reference/privateNamesNoAccessibilityModifiers.symbols b/tests/baselines/reference/privateNamesNoAccessibilityModifiers.symbols new file mode 100644 index 0000000000000..7586d7c5bd6c1 --- /dev/null +++ b/tests/baselines/reference/privateNamesNoAccessibilityModifiers.symbols @@ -0,0 +1,17 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesNoAccessibilityModifiers.ts === +class A { +>A : Symbol(A, Decl(privateNamesNoAccessibilityModifiers.ts, 0, 0)) + + public #foo; // Error +>#foo : Symbol(A[#foo], Decl(privateNamesNoAccessibilityModifiers.ts, 0, 9)) + + private #bar; // Error +>#bar : Symbol(A[#bar], Decl(privateNamesNoAccessibilityModifiers.ts, 1, 16)) + + protected #baz; // Error +>#baz : Symbol(A[#baz], Decl(privateNamesNoAccessibilityModifiers.ts, 2, 17)) + + readonly #qux; // OK +>#qux : Symbol(A[#qux], Decl(privateNamesNoAccessibilityModifiers.ts, 3, 19)) +} + diff --git a/tests/baselines/reference/privateNamesNoAccessibilityModifiers.types b/tests/baselines/reference/privateNamesNoAccessibilityModifiers.types new file mode 100644 index 0000000000000..fd1b35c1ded35 --- /dev/null +++ b/tests/baselines/reference/privateNamesNoAccessibilityModifiers.types @@ -0,0 +1,17 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesNoAccessibilityModifiers.ts === +class A { +>A : A + + public #foo; // Error +>#foo : any + + private #bar; // Error +>#bar : any + + protected #baz; // Error +>#baz : any + + readonly #qux; // OK +>#qux : any +} + diff --git a/tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts b/tests/cases/conformance/classes/members/privateNames/privateNameConstructorReserved.ts similarity index 100% rename from tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts rename to tests/cases/conformance/classes/members/privateNames/privateNameConstructorReserved.ts diff --git a/tests/cases/conformance/classes/members/privateNames/privateNamesNoAccessibilityModifiers.ts b/tests/cases/conformance/classes/members/privateNames/privateNamesNoAccessibilityModifiers.ts new file mode 100644 index 0000000000000..cd3f748196950 --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNamesNoAccessibilityModifiers.ts @@ -0,0 +1,6 @@ +class A { + public #foo; // Error + private #bar; // Error + protected #baz; // Error + readonly #qux; // OK +} From f142b989c08047e346b2c0a4bd15ac361b992fe4 Mon Sep 17 00:00:00 2001 From: Max Heiber Date: Mon, 3 Sep 2018 22:06:27 +0100 Subject: [PATCH 4/4] more tests for private names --- .../reference/api/tsserverlibrary.d.ts | 1 - tests/baselines/reference/api/typescript.d.ts | 1 - .../reference/privateNamesAndkeyof.js | 16 ++++++ .../reference/privateNamesAndkeyof.symbols | 18 +++++++ .../reference/privateNamesAndkeyof.types | 17 ++++++ .../privateNamesInGenericClasses.errors.txt | 29 +++++++++++ .../reference/privateNamesInGenericClasses.js | 27 ++++++++++ .../privateNamesInGenericClasses.symbols | 52 +++++++++++++++++++ .../privateNamesInGenericClasses.types | 46 ++++++++++++++++ .../reference/privateNamesInNestedClasses.js | 33 ++++++++++++ .../privateNamesInNestedClasses.symbols | 36 +++++++++++++ .../privateNamesInNestedClasses.types | 35 +++++++++++++ .../privateNamesNoConflictWhenInheriting.js | 5 +- ...ivateNamesNoConflictWhenInheriting.symbols | 7 ++- ...privateNamesNoConflictWhenInheriting.types | 7 ++- .../privateNames/privateNamesAndkeyof.ts | 7 +++ .../privateNamesInGenericClasses.ts | 12 +++++ .../privateNamesInNestedClasses.ts | 13 +++++ .../privateNamesNoConflictWhenInheriting.ts | 4 +- 19 files changed, 360 insertions(+), 6 deletions(-) create mode 100644 tests/baselines/reference/privateNamesAndkeyof.js create mode 100644 tests/baselines/reference/privateNamesAndkeyof.symbols create mode 100644 tests/baselines/reference/privateNamesAndkeyof.types create mode 100644 tests/baselines/reference/privateNamesInGenericClasses.errors.txt create mode 100644 tests/baselines/reference/privateNamesInGenericClasses.js create mode 100644 tests/baselines/reference/privateNamesInGenericClasses.symbols create mode 100644 tests/baselines/reference/privateNamesInGenericClasses.types create mode 100644 tests/baselines/reference/privateNamesInNestedClasses.js create mode 100644 tests/baselines/reference/privateNamesInNestedClasses.symbols create mode 100644 tests/baselines/reference/privateNamesInNestedClasses.types create mode 100644 tests/cases/conformance/classes/members/privateNames/privateNamesAndkeyof.ts create mode 100644 tests/cases/conformance/classes/members/privateNames/privateNamesInGenericClasses.ts create mode 100644 tests/cases/conformance/classes/members/privateNames/privateNamesInNestedClasses.ts diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index fcc8434c0d3c0..1ab1a986d1ad1 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2063,7 +2063,6 @@ declare namespace ts { Transient = 33554432, JSContainer = 67108864, ModuleExports = 134217728, - PrivateNamed = 268435456, Enum = 384, Variable = 3, Value = 67216319, diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 03867ae19cb45..ea78225538eac 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2063,7 +2063,6 @@ declare namespace ts { Transient = 33554432, JSContainer = 67108864, ModuleExports = 134217728, - PrivateNamed = 268435456, Enum = 384, Variable = 3, Value = 67216319, diff --git a/tests/baselines/reference/privateNamesAndkeyof.js b/tests/baselines/reference/privateNamesAndkeyof.js new file mode 100644 index 0000000000000..90d72a3b62944 --- /dev/null +++ b/tests/baselines/reference/privateNamesAndkeyof.js @@ -0,0 +1,16 @@ +//// [privateNamesAndkeyof.ts] +class A { + #foo; + bar; + baz; +} + +type T = keyof A // should not include '#foo' + + +//// [privateNamesAndkeyof.js] +var A = /** @class */ (function () { + function A() { + } + return A; +}()); diff --git a/tests/baselines/reference/privateNamesAndkeyof.symbols b/tests/baselines/reference/privateNamesAndkeyof.symbols new file mode 100644 index 0000000000000..67a7d46b52dd7 --- /dev/null +++ b/tests/baselines/reference/privateNamesAndkeyof.symbols @@ -0,0 +1,18 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesAndkeyof.ts === +class A { +>A : Symbol(A, Decl(privateNamesAndkeyof.ts, 0, 0)) + + #foo; +>#foo : Symbol(A[#foo], Decl(privateNamesAndkeyof.ts, 0, 9)) + + bar; +>bar : Symbol(A.bar, Decl(privateNamesAndkeyof.ts, 1, 9)) + + baz; +>baz : Symbol(A.baz, Decl(privateNamesAndkeyof.ts, 2, 8)) +} + +type T = keyof A // should not include '#foo' +>T : Symbol(T, Decl(privateNamesAndkeyof.ts, 4, 1)) +>A : Symbol(A, Decl(privateNamesAndkeyof.ts, 0, 0)) + diff --git a/tests/baselines/reference/privateNamesAndkeyof.types b/tests/baselines/reference/privateNamesAndkeyof.types new file mode 100644 index 0000000000000..a43c7dcd6c534 --- /dev/null +++ b/tests/baselines/reference/privateNamesAndkeyof.types @@ -0,0 +1,17 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesAndkeyof.ts === +class A { +>A : A + + #foo; +>#foo : any + + bar; +>bar : any + + baz; +>baz : any +} + +type T = keyof A // should not include '#foo' +>T : "bar" | "baz" + diff --git a/tests/baselines/reference/privateNamesInGenericClasses.errors.txt b/tests/baselines/reference/privateNamesInGenericClasses.errors.txt new file mode 100644 index 0000000000000..82435199292ee --- /dev/null +++ b/tests/baselines/reference/privateNamesInGenericClasses.errors.txt @@ -0,0 +1,29 @@ +tests/cases/conformance/classes/members/privateNames/privateNamesInGenericClasses.ts(10,3): error TS18007: Property '#foo' is only accessible within class 'C' because it has a private name. +tests/cases/conformance/classes/members/privateNames/privateNamesInGenericClasses.ts(11,1): error TS2322: Type 'C' is not assignable to type 'C'. + Type 'string' is not assignable to type 'number'. +tests/cases/conformance/classes/members/privateNames/privateNamesInGenericClasses.ts(12,1): error TS2322: Type 'C' is not assignable to type 'C'. + Type 'number' is not assignable to type 'string'. + + +==== tests/cases/conformance/classes/members/privateNames/privateNamesInGenericClasses.ts (3 errors) ==== + class C { + #foo: T; + bar(x: C) { return x.#foo; } // OK + baz(x: C) { return x.#foo; } // OK + quux(x: C) { return x.#foo; } // OK + } + + declare let a: C; + declare let b: C; + a.#foo; // OK + ~~~~ +!!! error TS18007: Property '#foo' is only accessible within class 'C' because it has a private name. + a = b; // Error + ~ +!!! error TS2322: Type 'C' is not assignable to type 'C'. +!!! error TS2322: Type 'string' is not assignable to type 'number'. + b = a; // Error + ~ +!!! error TS2322: Type 'C' is not assignable to type 'C'. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + \ No newline at end of file diff --git a/tests/baselines/reference/privateNamesInGenericClasses.js b/tests/baselines/reference/privateNamesInGenericClasses.js new file mode 100644 index 0000000000000..dcee4e0fd82ef --- /dev/null +++ b/tests/baselines/reference/privateNamesInGenericClasses.js @@ -0,0 +1,27 @@ +//// [privateNamesInGenericClasses.ts] +class C { + #foo: T; + bar(x: C) { return x.#foo; } // OK + baz(x: C) { return x.#foo; } // OK + quux(x: C) { return x.#foo; } // OK +} + +declare let a: C; +declare let b: C; +a.#foo; // OK +a = b; // Error +b = a; // Error + + +//// [privateNamesInGenericClasses.js] +var C = /** @class */ (function () { + function C() { + } + C.prototype.bar = function (x) { return x.#foo; }; // OK + C.prototype.baz = function (x) { return x.#foo; }; // OK + C.prototype.quux = function (x) { return x.#foo; }; // OK + return C; +}()); +a.#foo; // OK +a = b; // Error +b = a; // Error diff --git a/tests/baselines/reference/privateNamesInGenericClasses.symbols b/tests/baselines/reference/privateNamesInGenericClasses.symbols new file mode 100644 index 0000000000000..a07fa125d37dd --- /dev/null +++ b/tests/baselines/reference/privateNamesInGenericClasses.symbols @@ -0,0 +1,52 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesInGenericClasses.ts === +class C { +>C : Symbol(C, Decl(privateNamesInGenericClasses.ts, 0, 0)) +>T : Symbol(T, Decl(privateNamesInGenericClasses.ts, 0, 8)) + + #foo: T; +>#foo : Symbol(C[#foo], Decl(privateNamesInGenericClasses.ts, 0, 12)) +>T : Symbol(T, Decl(privateNamesInGenericClasses.ts, 0, 8)) + + bar(x: C) { return x.#foo; } // OK +>bar : Symbol(C.bar, Decl(privateNamesInGenericClasses.ts, 1, 10)) +>x : Symbol(x, Decl(privateNamesInGenericClasses.ts, 2, 6)) +>C : Symbol(C, Decl(privateNamesInGenericClasses.ts, 0, 0)) +>T : Symbol(T, Decl(privateNamesInGenericClasses.ts, 0, 8)) +>x.#foo : Symbol(C[#foo], Decl(privateNamesInGenericClasses.ts, 0, 12)) +>x : Symbol(x, Decl(privateNamesInGenericClasses.ts, 2, 6)) + + baz(x: C) { return x.#foo; } // OK +>baz : Symbol(C.baz, Decl(privateNamesInGenericClasses.ts, 2, 33)) +>x : Symbol(x, Decl(privateNamesInGenericClasses.ts, 3, 6)) +>C : Symbol(C, Decl(privateNamesInGenericClasses.ts, 0, 0)) +>x.#foo : Symbol(C[#foo], Decl(privateNamesInGenericClasses.ts, 0, 12)) +>x : Symbol(x, Decl(privateNamesInGenericClasses.ts, 3, 6)) + + quux(x: C) { return x.#foo; } // OK +>quux : Symbol(C.quux, Decl(privateNamesInGenericClasses.ts, 3, 38)) +>x : Symbol(x, Decl(privateNamesInGenericClasses.ts, 4, 7)) +>C : Symbol(C, Decl(privateNamesInGenericClasses.ts, 0, 0)) +>x.#foo : Symbol(C[#foo], Decl(privateNamesInGenericClasses.ts, 0, 12)) +>x : Symbol(x, Decl(privateNamesInGenericClasses.ts, 4, 7)) +} + +declare let a: C; +>a : Symbol(a, Decl(privateNamesInGenericClasses.ts, 7, 11)) +>C : Symbol(C, Decl(privateNamesInGenericClasses.ts, 0, 0)) + +declare let b: C; +>b : Symbol(b, Decl(privateNamesInGenericClasses.ts, 8, 11)) +>C : Symbol(C, Decl(privateNamesInGenericClasses.ts, 0, 0)) + +a.#foo; // OK +>a.#foo : Symbol(C[#foo], Decl(privateNamesInGenericClasses.ts, 0, 12)) +>a : Symbol(a, Decl(privateNamesInGenericClasses.ts, 7, 11)) + +a = b; // Error +>a : Symbol(a, Decl(privateNamesInGenericClasses.ts, 7, 11)) +>b : Symbol(b, Decl(privateNamesInGenericClasses.ts, 8, 11)) + +b = a; // Error +>b : Symbol(b, Decl(privateNamesInGenericClasses.ts, 8, 11)) +>a : Symbol(a, Decl(privateNamesInGenericClasses.ts, 7, 11)) + diff --git a/tests/baselines/reference/privateNamesInGenericClasses.types b/tests/baselines/reference/privateNamesInGenericClasses.types new file mode 100644 index 0000000000000..41f33670836c3 --- /dev/null +++ b/tests/baselines/reference/privateNamesInGenericClasses.types @@ -0,0 +1,46 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesInGenericClasses.ts === +class C { +>C : C + + #foo: T; +>#foo : T + + bar(x: C) { return x.#foo; } // OK +>bar : (x: C) => T +>x : C +>x.#foo : T +>x : C + + baz(x: C) { return x.#foo; } // OK +>baz : (x: C) => number +>x : C +>x.#foo : number +>x : C + + quux(x: C) { return x.#foo; } // OK +>quux : (x: C) => string +>x : C +>x.#foo : string +>x : C +} + +declare let a: C; +>a : C + +declare let b: C; +>b : C + +a.#foo; // OK +>a.#foo : number +>a : C + +a = b; // Error +>a = b : C +>a : C +>b : C + +b = a; // Error +>b = a : C +>b : C +>a : C + diff --git a/tests/baselines/reference/privateNamesInNestedClasses.js b/tests/baselines/reference/privateNamesInNestedClasses.js new file mode 100644 index 0000000000000..fc699787bfdd9 --- /dev/null +++ b/tests/baselines/reference/privateNamesInNestedClasses.js @@ -0,0 +1,33 @@ +//// [privateNamesInNestedClasses.ts] +class A { + #foo: number; + #bar: number; + method() { + class B { + #foo: string; + methodNested(a: A) { + a.#foo; // error: shadowed + a.#bar; // OK + } + } + } +} + + +//// [privateNamesInNestedClasses.js] +var A = /** @class */ (function () { + function A() { + } + A.prototype.method = function () { + var B = /** @class */ (function () { + function B() { + } + B.prototype.methodNested = function (a) { + a.#foo; // error: shadowed + a.#bar; // OK + }; + return B; + }()); + }; + return A; +}()); diff --git a/tests/baselines/reference/privateNamesInNestedClasses.symbols b/tests/baselines/reference/privateNamesInNestedClasses.symbols new file mode 100644 index 0000000000000..e9f84e3895ff9 --- /dev/null +++ b/tests/baselines/reference/privateNamesInNestedClasses.symbols @@ -0,0 +1,36 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesInNestedClasses.ts === +class A { +>A : Symbol(A, Decl(privateNamesInNestedClasses.ts, 0, 0)) + + #foo: number; +>#foo : Symbol(A[#foo], Decl(privateNamesInNestedClasses.ts, 0, 9)) + + #bar: number; +>#bar : Symbol(A[#bar], Decl(privateNamesInNestedClasses.ts, 1, 17)) + + method() { +>method : Symbol(A.method, Decl(privateNamesInNestedClasses.ts, 2, 17)) + + class B { +>B : Symbol(B, Decl(privateNamesInNestedClasses.ts, 3, 14)) + + #foo: string; +>#foo : Symbol(B[#foo], Decl(privateNamesInNestedClasses.ts, 4, 17)) + + methodNested(a: A) { +>methodNested : Symbol(B.methodNested, Decl(privateNamesInNestedClasses.ts, 5, 25)) +>a : Symbol(a, Decl(privateNamesInNestedClasses.ts, 6, 25)) +>A : Symbol(A, Decl(privateNamesInNestedClasses.ts, 0, 0)) + + a.#foo; // error: shadowed +>a.#foo : Symbol(A[#foo], Decl(privateNamesInNestedClasses.ts, 0, 9)) +>a : Symbol(a, Decl(privateNamesInNestedClasses.ts, 6, 25)) + + a.#bar; // OK +>a.#bar : Symbol(A[#bar], Decl(privateNamesInNestedClasses.ts, 1, 17)) +>a : Symbol(a, Decl(privateNamesInNestedClasses.ts, 6, 25)) + } + } + } +} + diff --git a/tests/baselines/reference/privateNamesInNestedClasses.types b/tests/baselines/reference/privateNamesInNestedClasses.types new file mode 100644 index 0000000000000..ea333bed37eda --- /dev/null +++ b/tests/baselines/reference/privateNamesInNestedClasses.types @@ -0,0 +1,35 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesInNestedClasses.ts === +class A { +>A : A + + #foo: number; +>#foo : number + + #bar: number; +>#bar : number + + method() { +>method : () => void + + class B { +>B : B + + #foo: string; +>#foo : string + + methodNested(a: A) { +>methodNested : (a: A) => void +>a : A + + a.#foo; // error: shadowed +>a.#foo : number +>a : A + + a.#bar; // OK +>a.#bar : number +>a : A + } + } + } +} + diff --git a/tests/baselines/reference/privateNamesNoConflictWhenInheriting.js b/tests/baselines/reference/privateNamesNoConflictWhenInheriting.js index 0dbc7ec223be7..7d17373ace173 100644 --- a/tests/baselines/reference/privateNamesNoConflictWhenInheriting.js +++ b/tests/baselines/reference/privateNamesNoConflictWhenInheriting.js @@ -4,8 +4,10 @@ class A { } class B extends A { - #foo: string; // OK: private names are unique to each class + #foo: string; // OK: private names are unique to each class } + +const b: A = new B() // OK //// [privateNamesNoConflictWhenInheriting.js] @@ -34,3 +36,4 @@ var B = /** @class */ (function (_super) { } return B; }(A)); +var b = new B(); // OK diff --git a/tests/baselines/reference/privateNamesNoConflictWhenInheriting.symbols b/tests/baselines/reference/privateNamesNoConflictWhenInheriting.symbols index 7ce208e54b3c0..11ee25651c95f 100644 --- a/tests/baselines/reference/privateNamesNoConflictWhenInheriting.symbols +++ b/tests/baselines/reference/privateNamesNoConflictWhenInheriting.symbols @@ -10,7 +10,12 @@ class B extends A { >B : Symbol(B, Decl(privateNamesNoConflictWhenInheriting.ts, 2, 1)) >A : Symbol(A, Decl(privateNamesNoConflictWhenInheriting.ts, 0, 0)) - #foo: string; // OK: private names are unique to each class + #foo: string; // OK: private names are unique to each class >#foo : Symbol(B[#foo], Decl(privateNamesNoConflictWhenInheriting.ts, 4, 19)) } +const b: A = new B() // OK +>b : Symbol(b, Decl(privateNamesNoConflictWhenInheriting.ts, 8, 5)) +>A : Symbol(A, Decl(privateNamesNoConflictWhenInheriting.ts, 0, 0)) +>B : Symbol(B, Decl(privateNamesNoConflictWhenInheriting.ts, 2, 1)) + diff --git a/tests/baselines/reference/privateNamesNoConflictWhenInheriting.types b/tests/baselines/reference/privateNamesNoConflictWhenInheriting.types index 3b7213ae2a97e..40459f74d2e63 100644 --- a/tests/baselines/reference/privateNamesNoConflictWhenInheriting.types +++ b/tests/baselines/reference/privateNamesNoConflictWhenInheriting.types @@ -10,7 +10,12 @@ class B extends A { >B : B >A : A - #foo: string; // OK: private names are unique to each class + #foo: string; // OK: private names are unique to each class >#foo : string } +const b: A = new B() // OK +>b : A +>new B() : B +>B : typeof B + diff --git a/tests/cases/conformance/classes/members/privateNames/privateNamesAndkeyof.ts b/tests/cases/conformance/classes/members/privateNames/privateNamesAndkeyof.ts new file mode 100644 index 0000000000000..93edade95ce9e --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNamesAndkeyof.ts @@ -0,0 +1,7 @@ +class A { + #foo; + bar; + baz; +} + +type T = keyof A // should not include '#foo' diff --git a/tests/cases/conformance/classes/members/privateNames/privateNamesInGenericClasses.ts b/tests/cases/conformance/classes/members/privateNames/privateNamesInGenericClasses.ts new file mode 100644 index 0000000000000..c1369caf48594 --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNamesInGenericClasses.ts @@ -0,0 +1,12 @@ +class C { + #foo: T; + bar(x: C) { return x.#foo; } // OK + baz(x: C) { return x.#foo; } // OK + quux(x: C) { return x.#foo; } // OK +} + +declare let a: C; +declare let b: C; +a.#foo; // OK +a = b; // Error +b = a; // Error diff --git a/tests/cases/conformance/classes/members/privateNames/privateNamesInNestedClasses.ts b/tests/cases/conformance/classes/members/privateNames/privateNamesInNestedClasses.ts new file mode 100644 index 0000000000000..7b38006930eab --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNamesInNestedClasses.ts @@ -0,0 +1,13 @@ +class A { + #foo: number; + #bar: number; + method() { + class B { + #foo: string; + methodNested(a: A) { + a.#foo; // error: shadowed + a.#bar; // OK + } + } + } +} diff --git a/tests/cases/conformance/classes/members/privateNames/privateNamesNoConflictWhenInheriting.ts b/tests/cases/conformance/classes/members/privateNames/privateNamesNoConflictWhenInheriting.ts index dae3d40cea03c..bb55edd9b3dfc 100644 --- a/tests/cases/conformance/classes/members/privateNames/privateNamesNoConflictWhenInheriting.ts +++ b/tests/cases/conformance/classes/members/privateNames/privateNamesNoConflictWhenInheriting.ts @@ -3,5 +3,7 @@ class A { } class B extends A { - #foo: string; // OK: private names are unique to each class + #foo: string; // OK: private names are unique to each class } + +const b: A = new B() // OK