Skip to content

Commit 15206c2

Browse files
mheiberMax Heiber
authored andcommitted
update checker for private names
accessiblity modifiers cannot be used with private names rm del no delete permitted update checker to disallow delete of private name move private names cases private constructor class field invalid compiler error on #constructor
1 parent 9af9da8 commit 15206c2

24 files changed

+194
-12
lines changed

src/compiler/binder.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1793,6 +1793,18 @@ namespace ts {
17931793
return Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode;
17941794
}
17951795

1796+
// The binder visits every node, so this is a good place to check for
1797+
// the reserved private name (there is only one)
1798+
function checkPrivateName(node: PrivateName) {
1799+
if (node.escapedText === "#constructor") {
1800+
// Report error only if there are no parse errors in file
1801+
if (!file.parseDiagnostics.length) {
1802+
file.bindDiagnostics.push(createDiagnosticForNode(node,
1803+
Diagnostics.constructor_is_a_reserved_word, declarationNameToString(node)));
1804+
}
1805+
}
1806+
}
1807+
17961808
function checkStrictModeBinaryExpression(node: BinaryExpression) {
17971809
if (inStrictMode && isLeftHandSideExpression(node.left) && isAssignmentOperator(node.operatorToken.kind)) {
17981810
// ECMA 262 (Annex C) The identifier eval or arguments may not appear as the LeftHandSideExpression of an
@@ -2065,6 +2077,8 @@ namespace ts {
20652077
node.flowNode = currentFlow;
20662078
}
20672079
return checkStrictModeIdentifier(<Identifier>node);
2080+
case SyntaxKind.PrivateName:
2081+
return checkPrivateName(node as PrivateName);
20682082
case SyntaxKind.PropertyAccessExpression:
20692083
if (currentFlow && isNarrowableReference(<Expression>node)) {
20702084
node.flowNode = currentFlow;

src/compiler/checker.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20746,10 +20746,16 @@ namespace ts {
2074620746
error(expr, Diagnostics.The_operand_of_a_delete_operator_must_be_a_property_reference);
2074720747
return booleanType;
2074820748
}
20749+
if (expr.kind === SyntaxKind.PropertyAccessExpression && isPrivateName((expr as PropertyAccessExpression).name)) {
20750+
error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_private_name);
20751+
20752+
}
2074920753
const links = getNodeLinks(expr);
2075020754
const symbol = getExportSymbolOfValueSymbolIfExported(links.resolvedSymbol);
20751-
if (symbol && isReadonlySymbol(symbol)) {
20752-
error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_read_only_property);
20755+
if (symbol) {
20756+
if (isReadonlySymbol(symbol)) {
20757+
error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_read_only_property);
20758+
}
2075320759
}
2075420760
return booleanType;
2075520761
}
@@ -28462,6 +28468,9 @@ namespace ts {
2846228468
else if (node.kind === SyntaxKind.Parameter && (flags & ModifierFlags.ParameterPropertyModifier) && (<ParameterDeclaration>node).dotDotDotToken) {
2846328469
return grammarErrorOnNode(node, Diagnostics.A_parameter_property_cannot_be_declared_using_a_rest_parameter);
2846428470
}
28471+
else if (isNamedDeclaration(node) && (flags & ModifierFlags.AccessibilityModifier) && node.name.kind === SyntaxKind.PrivateName) {
28472+
return grammarErrorOnNode(node, Diagnostics.Accessibility_modifiers_cannot_be_used_with_private_names);
28473+
}
2846528474
if (flags & ModifierFlags.Async) {
2846628475
return checkGrammarAsyncModifier(node, lastAsync!);
2846728476
}

src/compiler/diagnosticMessages.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4142,6 +4142,19 @@
41424142
"category": "Error",
41434143
"code": 18005
41444144
},
4145+
"Accessibility modifiers cannot be used with private names.": {
4146+
"category": "Error",
4147+
"code": 18006
4148+
},
4149+
"The operand of a delete operator cannot be a private name.": {
4150+
"category": "Error",
4151+
"code": 18007
4152+
},
4153+
"#constructor is a reserved word.": {
4154+
"category": "Error",
4155+
"code": 18008
4156+
},
4157+
41454158

41464159
"File is a CommonJS module; it may be converted to an ES6 module.": {
41474160
"category": "Suggestion",
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts(1,7): error TS2300: Duplicate identifier 'A'.
2+
tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts(2,5): error TS18008: #constructor is a reserved word.
3+
tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts(5,7): error TS2300: Duplicate identifier 'A'.
4+
tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts(6,5): error TS18008: #constructor is a reserved word.
5+
6+
7+
==== tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts (4 errors) ====
8+
class A {
9+
~
10+
!!! error TS2300: Duplicate identifier 'A'.
11+
#constructor() {} // Error: `#constructor` is a reserved word.
12+
~~~~~~~~~~~~
13+
!!! error TS18008: #constructor is a reserved word.
14+
}
15+
16+
class A {
17+
~
18+
!!! error TS2300: Duplicate identifier 'A'.
19+
#constructor = 5 // Error: `#constructor` is a reserved word.
20+
~~~~~~~~~~~~
21+
!!! error TS18008: #constructor is a reserved word.
22+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//// [privateNameContructorReserved.ts]
2+
class A {
3+
#constructor() {} // Error: `#constructor` is a reserved word.
4+
}
5+
6+
class A {
7+
#constructor = 5 // Error: `#constructor` is a reserved word.
8+
}
9+
10+
//// [privateNameContructorReserved.js]
11+
var A = /** @class */ (function () {
12+
function A() {
13+
}
14+
A.prototype.#constructor = function () { }; // Error: `#constructor` is a reserved word.
15+
return A;
16+
}());
17+
var A = /** @class */ (function () {
18+
function A() {
19+
this.#constructor = 5; // Error: `#constructor` is a reserved word.
20+
}
21+
return A;
22+
}());
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
=== tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts ===
2+
class A {
3+
>A : Symbol(A, Decl(privateNameContructorReserved.ts, 0, 0))
4+
5+
#constructor() {} // Error: `#constructor` is a reserved word.
6+
>#constructor : Symbol(A[#constructor], Decl(privateNameContructorReserved.ts, 0, 9))
7+
}
8+
9+
class A {
10+
>A : Symbol(A, Decl(privateNameContructorReserved.ts, 2, 1))
11+
12+
#constructor = 5 // Error: `#constructor` is a reserved word.
13+
>#constructor : Symbol(A[#constructor], Decl(privateNameContructorReserved.ts, 4, 9))
14+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
=== tests/cases/conformance/classes/members/privateNames/privateNameContructorReserved.ts ===
2+
class A {
3+
>A : A
4+
5+
#constructor() {} // Error: `#constructor` is a reserved word.
6+
>#constructor : () => void
7+
}
8+
9+
class A {
10+
>A : A
11+
12+
#constructor = 5 // Error: `#constructor` is a reserved word.
13+
>#constructor : number
14+
>5 : 5
15+
}

tests/baselines/reference/privateNameField.symbols

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
=== tests/cases/conformance/classes/privateNames/privateNameField.ts ===
1+
=== tests/cases/conformance/classes/members/privateNames/privateNameField.ts ===
22
class A {
33
>A : Symbol(A, Decl(privateNameField.ts, 0, 0))
44

tests/baselines/reference/privateNameField.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
=== tests/cases/conformance/classes/privateNames/privateNameField.ts ===
1+
=== tests/cases/conformance/classes/members/privateNames/privateNameField.ts ===
22
class A {
33
>A : A
44

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
tests/cases/conformance/classes/privateNames/privateNameNotAllowedOutsideClass.ts(1,7): error TS18004: Private names are not allowed outside class bodies.
1+
tests/cases/conformance/classes/members/privateNames/privateNameNotAllowedOutsideClass.ts(1,7): error TS18004: Private names are not allowed outside class bodies.
22

33

4-
==== tests/cases/conformance/classes/privateNames/privateNameNotAllowedOutsideClass.ts (1 errors) ====
4+
==== tests/cases/conformance/classes/members/privateNames/privateNameNotAllowedOutsideClass.ts (1 errors) ====
55
const #foo = 3;
66
~~~~
77
!!! error TS18004: Private names are not allowed outside class bodies.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
=== tests/cases/conformance/classes/privateNames/privateNameNotAllowedOutsideClass.ts ===
1+
=== tests/cases/conformance/classes/members/privateNames/privateNameNotAllowedOutsideClass.ts ===
22
const #foo = 3;
33
>#foo : Symbol(#foo, Decl(privateNameNotAllowedOutsideClass.ts, 0, 5))
44

tests/baselines/reference/privateNameNotAllowedOutsideClass.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
=== tests/cases/conformance/classes/privateNames/privateNameNotAllowedOutsideClass.ts ===
1+
=== tests/cases/conformance/classes/members/privateNames/privateNameNotAllowedOutsideClass.ts ===
22
const #foo = 3;
33
>#foo : 3
44
>3 : 3
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts(4,16): error TS18007: The operand of a delete operator cannot be a private name.
2+
3+
4+
==== tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts (1 errors) ====
5+
class A {
6+
#v = 1;
7+
constructor() {
8+
delete this.#v; // Error: The operand of a delete operator cannot be a private name.
9+
~~~~~~~
10+
!!! error TS18007: The operand of a delete operator cannot be a private name.
11+
}
12+
}
13+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//// [privateNamesNoDelete.ts]
2+
class A {
3+
#v = 1;
4+
constructor() {
5+
delete this.#v; // Error: The operand of a delete operator cannot be a private name.
6+
}
7+
}
8+
9+
10+
//// [privateNamesNoDelete.js]
11+
var A = /** @class */ (function () {
12+
function A() {
13+
this.#v = 1;
14+
delete this.#v; // Error: The operand of a delete operator cannot be a private name.
15+
}
16+
return A;
17+
}());
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
=== tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts ===
2+
class A {
3+
>A : Symbol(A, Decl(privateNamesNoDelete.ts, 0, 0))
4+
5+
#v = 1;
6+
>#v : Symbol(A[#v], Decl(privateNamesNoDelete.ts, 0, 9))
7+
8+
constructor() {
9+
delete this.#v; // Error: The operand of a delete operator cannot be a private name.
10+
>this.#v : Symbol(A[#v], Decl(privateNamesNoDelete.ts, 0, 9))
11+
>this : Symbol(A, Decl(privateNamesNoDelete.ts, 0, 0))
12+
}
13+
}
14+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
=== tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts ===
2+
class A {
3+
>A : A
4+
5+
#v = 1;
6+
>#v : number
7+
>1 : 1
8+
9+
constructor() {
10+
delete this.#v; // Error: The operand of a delete operator cannot be a private name.
11+
>delete this.#v : boolean
12+
>this.#v : number
13+
>this : this
14+
}
15+
}
16+

tests/baselines/reference/privateNamesNotAllowedAsParameters.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
tests/cases/conformance/classes/privateNames/privateNamesNotAllowedAsParameters.ts(2,12): error TS18005: Private names cannot be used as parameters
1+
tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts(2,12): error TS18005: Private names cannot be used as parameters
22

33

4-
==== tests/cases/conformance/classes/privateNames/privateNamesNotAllowedAsParameters.ts (1 errors) ====
4+
==== tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts (1 errors) ====
55
class A {
66
setFoo(#foo: string) {}
77
~~~~~~~~~~~~

tests/baselines/reference/privateNamesNotAllowedAsParameters.symbols

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
=== tests/cases/conformance/classes/privateNames/privateNamesNotAllowedAsParameters.ts ===
1+
=== tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts ===
22
class A {
33
>A : Symbol(A, Decl(privateNamesNotAllowedAsParameters.ts, 0, 0))
44

tests/baselines/reference/privateNamesNotAllowedAsParameters.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
=== tests/cases/conformance/classes/privateNames/privateNamesNotAllowedAsParameters.ts ===
1+
=== tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts ===
22
class A {
33
>A : A
44

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class A {
2+
#constructor() {} // Error: `#constructor` is a reserved word.
3+
}
4+
5+
class A {
6+
#constructor = 5 // Error: `#constructor` is a reserved word.
7+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
class A {
2+
#v = 1;
3+
constructor() {
4+
delete this.#v; // Error: The operand of a delete operator cannot be a private name.
5+
}
6+
}

0 commit comments

Comments
 (0)