Skip to content

Commit 56b19c9

Browse files
authored
Merge pull request #31119 from andrewbranch/bug/31020
Emit grammar error on quoted constructors and class fields named “constructor”
2 parents c9eb846 + 67a9029 commit 56b19c9

13 files changed

+259
-1
lines changed

src/compiler/checker.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31785,6 +31785,9 @@ namespace ts {
3178531785
return grammarErrorAtPos(node, node.end - 1, ";".length, Diagnostics._0_expected, "{");
3178631786
}
3178731787
}
31788+
else if (isClassLike(node.parent) && isStringLiteral(node.name) && node.name.text === "constructor" && (!compilerOptions.target || compilerOptions.target < ScriptTarget.ES5)) {
31789+
return grammarErrorOnNode(node.name, Diagnostics.Quoted_constructors_have_previously_been_interpreted_as_methods_which_is_incorrect_In_TypeScript_3_6_they_will_be_correctly_parsed_as_constructors_In_the_meantime_consider_using_constructor_to_write_a_constructor_or_constructor_to_write_a_method);
31790+
}
3178831791
if (checkGrammarForGenerator(node)) {
3178931792
return true;
3179031793
}
@@ -32103,6 +32106,9 @@ namespace ts {
3210332106

3210432107
function checkGrammarProperty(node: PropertyDeclaration | PropertySignature) {
3210532108
if (isClassLike(node.parent)) {
32109+
if (isStringLiteral(node.name) && node.name.text === "constructor") {
32110+
return grammarErrorOnNode(node.name, Diagnostics.Classes_may_not_have_a_field_named_constructor);
32111+
}
3210632112
if (checkGrammarForInvalidDynamicName(node.name, Diagnostics.A_computed_property_name_in_a_class_property_declaration_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type)) {
3210732113
return true;
3210832114
}

src/compiler/diagnosticMessages.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4965,5 +4965,13 @@
49654965
"No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer." :{
49664966
"category": "Error",
49674967
"code": 18004
4968+
},
4969+
"Quoted constructors have previously been interpreted as methods, which is incorrect. In TypeScript 3.6, they will be correctly parsed as constructors. In the meantime, consider using 'constructor()' to write a constructor, or '[\"constructor\"]()' to write a method.": {
4970+
"category": "Error",
4971+
"code": 18005
4972+
},
4973+
"Classes may not have a field named 'constructor'.": {
4974+
"category": "Error",
4975+
"code": 18006
49684976
}
49694977
}

tests/baselines/reference/convertKeywordsYes.errors.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
tests/cases/compiler/convertKeywordsYes.ts(175,12): error TS18006: Classes may not have a field named 'constructor'.
12
tests/cases/compiler/convertKeywordsYes.ts(292,11): error TS1213: Identifier expected. 'implements' is a reserved word in strict mode. Class definitions are automatically in strict mode.
23
tests/cases/compiler/convertKeywordsYes.ts(293,11): error TS1213: Identifier expected. 'interface' is a reserved word in strict mode. Class definitions are automatically in strict mode.
34
tests/cases/compiler/convertKeywordsYes.ts(294,11): error TS1213: Identifier expected. 'let' is a reserved word in strict mode. Class definitions are automatically in strict mode.
@@ -9,7 +10,7 @@ tests/cases/compiler/convertKeywordsYes.ts(301,11): error TS1213: Identifier exp
910
tests/cases/compiler/convertKeywordsYes.ts(303,11): error TS1213: Identifier expected. 'yield' is a reserved word in strict mode. Class definitions are automatically in strict mode.
1011

1112

12-
==== tests/cases/compiler/convertKeywordsYes.ts (9 errors) ====
13+
==== tests/cases/compiler/convertKeywordsYes.ts (10 errors) ====
1314
// reserved ES5 future in strict mode
1415

1516
var constructor = 0;
@@ -185,6 +186,8 @@ tests/cases/compiler/convertKeywordsYes.ts(303,11): error TS1213: Identifier exp
185186

186187
class bigClass {
187188
public "constructor" = 0;
189+
~~~~~~~~~~~~~
190+
!!! error TS18006: Classes may not have a field named 'constructor'.
188191
public any = 0;
189192
public boolean = 0;
190193
public implements = 0;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
tests/cases/conformance/classes/propertyMemberDeclarations/propertyNamedConstructor.ts(2,3): error TS18006: Classes may not have a field named 'constructor'.
2+
3+
4+
==== tests/cases/conformance/classes/propertyMemberDeclarations/propertyNamedConstructor.ts (1 errors) ====
5+
class X1 {
6+
"constructor" = 3; // Error
7+
~~~~~~~~~~~~~
8+
!!! error TS18006: Classes may not have a field named 'constructor'.
9+
}
10+
11+
class X2 {
12+
["constructor"] = 3;
13+
}
14+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//// [propertyNamedConstructor.ts]
2+
class X1 {
3+
"constructor" = 3; // Error
4+
}
5+
6+
class X2 {
7+
["constructor"] = 3;
8+
}
9+
10+
11+
//// [propertyNamedConstructor.js]
12+
var X1 = /** @class */ (function () {
13+
function X1() {
14+
this["constructor"] = 3; // Error
15+
}
16+
return X1;
17+
}());
18+
var X2 = /** @class */ (function () {
19+
function X2() {
20+
this["constructor"] = 3;
21+
}
22+
return X2;
23+
}());
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
=== tests/cases/conformance/classes/propertyMemberDeclarations/propertyNamedConstructor.ts ===
2+
class X1 {
3+
>X1 : Symbol(X1, Decl(propertyNamedConstructor.ts, 0, 0))
4+
5+
"constructor" = 3; // Error
6+
>"constructor" : Symbol(X1["constructor"], Decl(propertyNamedConstructor.ts, 0, 10))
7+
}
8+
9+
class X2 {
10+
>X2 : Symbol(X2, Decl(propertyNamedConstructor.ts, 2, 1))
11+
12+
["constructor"] = 3;
13+
>["constructor"] : Symbol(X2["constructor"], Decl(propertyNamedConstructor.ts, 4, 10))
14+
>"constructor" : Symbol(X2["constructor"], Decl(propertyNamedConstructor.ts, 4, 10))
15+
}
16+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
=== tests/cases/conformance/classes/propertyMemberDeclarations/propertyNamedConstructor.ts ===
2+
class X1 {
3+
>X1 : X1
4+
5+
"constructor" = 3; // Error
6+
>"constructor" : number
7+
>3 : 3
8+
}
9+
10+
class X2 {
11+
>X2 : X2
12+
13+
["constructor"] = 3;
14+
>["constructor"] : number
15+
>"constructor" : "constructor"
16+
>3 : 3
17+
}
18+
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
tests/cases/conformance/classes/constructorDeclarations/quotedConstructors.ts(2,5): error TS18005: Quoted constructors have previously been interpreted as methods, which is incorrect. In TypeScript 3.6, they will be correctly parsed as constructors. In the meantime, consider using 'constructor()' to write a constructor, or '["constructor"]()' to write a method.
2+
tests/cases/conformance/classes/constructorDeclarations/quotedConstructors.ts(6,5): error TS18005: Quoted constructors have previously been interpreted as methods, which is incorrect. In TypeScript 3.6, they will be correctly parsed as constructors. In the meantime, consider using 'constructor()' to write a constructor, or '["constructor"]()' to write a method.
3+
tests/cases/conformance/classes/constructorDeclarations/quotedConstructors.ts(14,5): error TS18005: Quoted constructors have previously been interpreted as methods, which is incorrect. In TypeScript 3.6, they will be correctly parsed as constructors. In the meantime, consider using 'constructor()' to write a constructor, or '["constructor"]()' to write a method.
4+
5+
6+
==== tests/cases/conformance/classes/constructorDeclarations/quotedConstructors.ts (3 errors) ====
7+
class C {
8+
"constructor"() {} // Error in 3.5
9+
~~~~~~~~~~~~~
10+
!!! error TS18005: Quoted constructors have previously been interpreted as methods, which is incorrect. In TypeScript 3.6, they will be correctly parsed as constructors. In the meantime, consider using 'constructor()' to write a constructor, or '["constructor"]()' to write a method.
11+
}
12+
13+
class D {
14+
'constructor'() {} // Error in 3.5
15+
~~~~~~~~~~~~~
16+
!!! error TS18005: Quoted constructors have previously been interpreted as methods, which is incorrect. In TypeScript 3.6, they will be correctly parsed as constructors. In the meantime, consider using 'constructor()' to write a constructor, or '["constructor"]()' to write a method.
17+
}
18+
19+
class E {
20+
['constructor']() {}
21+
}
22+
23+
new class {
24+
"constructor"() {} // Error in 3.5
25+
~~~~~~~~~~~~~
26+
!!! error TS18005: Quoted constructors have previously been interpreted as methods, which is incorrect. In TypeScript 3.6, they will be correctly parsed as constructors. In the meantime, consider using 'constructor()' to write a constructor, or '["constructor"]()' to write a method.
27+
};
28+
29+
var o = { "constructor"() {} };
30+
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//// [quotedConstructors.ts]
2+
class C {
3+
"constructor"() {} // Error in 3.5
4+
}
5+
6+
class D {
7+
'constructor'() {} // Error in 3.5
8+
}
9+
10+
class E {
11+
['constructor']() {}
12+
}
13+
14+
new class {
15+
"constructor"() {} // Error in 3.5
16+
};
17+
18+
var o = { "constructor"() {} };
19+
20+
21+
//// [quotedConstructors.js]
22+
var C = /** @class */ (function () {
23+
function C() {
24+
}
25+
C.prototype["constructor"] = function () { }; // Error in 3.5
26+
return C;
27+
}());
28+
var D = /** @class */ (function () {
29+
function D() {
30+
}
31+
D.prototype['constructor'] = function () { }; // Error in 3.5
32+
return D;
33+
}());
34+
var E = /** @class */ (function () {
35+
function E() {
36+
}
37+
E.prototype['constructor'] = function () { };
38+
return E;
39+
}());
40+
new /** @class */ (function () {
41+
function class_1() {
42+
}
43+
class_1.prototype["constructor"] = function () { }; // Error in 3.5
44+
return class_1;
45+
}());
46+
var o = { "constructor": function () { } };
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
=== tests/cases/conformance/classes/constructorDeclarations/quotedConstructors.ts ===
2+
class C {
3+
>C : Symbol(C, Decl(quotedConstructors.ts, 0, 0))
4+
5+
"constructor"() {} // Error in 3.5
6+
>"constructor" : Symbol(C["constructor"], Decl(quotedConstructors.ts, 0, 9))
7+
}
8+
9+
class D {
10+
>D : Symbol(D, Decl(quotedConstructors.ts, 2, 1))
11+
12+
'constructor'() {} // Error in 3.5
13+
>'constructor' : Symbol(D['constructor'], Decl(quotedConstructors.ts, 4, 9))
14+
}
15+
16+
class E {
17+
>E : Symbol(E, Decl(quotedConstructors.ts, 6, 1))
18+
19+
['constructor']() {}
20+
>['constructor'] : Symbol(E['constructor'], Decl(quotedConstructors.ts, 8, 9))
21+
>'constructor' : Symbol(E['constructor'], Decl(quotedConstructors.ts, 8, 9))
22+
}
23+
24+
new class {
25+
"constructor"() {} // Error in 3.5
26+
>"constructor" : Symbol((Anonymous class)["constructor"], Decl(quotedConstructors.ts, 12, 11))
27+
28+
};
29+
30+
var o = { "constructor"() {} };
31+
>o : Symbol(o, Decl(quotedConstructors.ts, 16, 3))
32+
>"constructor" : Symbol("constructor", Decl(quotedConstructors.ts, 16, 9))
33+
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
=== tests/cases/conformance/classes/constructorDeclarations/quotedConstructors.ts ===
2+
class C {
3+
>C : C
4+
5+
"constructor"() {} // Error in 3.5
6+
>"constructor" : () => void
7+
}
8+
9+
class D {
10+
>D : D
11+
12+
'constructor'() {} // Error in 3.5
13+
>'constructor' : () => void
14+
}
15+
16+
class E {
17+
>E : E
18+
19+
['constructor']() {}
20+
>['constructor'] : () => void
21+
>'constructor' : "constructor"
22+
}
23+
24+
new class {
25+
>new class { "constructor"() {} // Error in 3.5} : (Anonymous class)
26+
>class { "constructor"() {} // Error in 3.5} : typeof (Anonymous class)
27+
28+
"constructor"() {} // Error in 3.5
29+
>"constructor" : () => void
30+
31+
};
32+
33+
var o = { "constructor"() {} };
34+
>o : { "constructor"(): void; }
35+
>{ "constructor"() {} } : { "constructor"(): void; }
36+
>"constructor" : () => void
37+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
class C {
2+
"constructor"() {} // Error in 3.5
3+
}
4+
5+
class D {
6+
'constructor'() {} // Error in 3.5
7+
}
8+
9+
class E {
10+
['constructor']() {}
11+
}
12+
13+
new class {
14+
"constructor"() {} // Error in 3.5
15+
};
16+
17+
var o = { "constructor"() {} };
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class X1 {
2+
"constructor" = 3; // Error
3+
}
4+
5+
class X2 {
6+
["constructor"] = 3;
7+
}

0 commit comments

Comments
 (0)