Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #31119 from andrewbranch/bug/31020
Emit grammar error on quoted constructors and class fields named “constructor”
  • Loading branch information
andrewbranch committed May 1, 2019
2 parents c9eb846 + 67a9029 commit 56b19c9
Show file tree
Hide file tree
Showing 13 changed files with 259 additions and 1 deletion.
6 changes: 6 additions & 0 deletions src/compiler/checker.ts
Expand Up @@ -31785,6 +31785,9 @@ namespace ts {
return grammarErrorAtPos(node, node.end - 1, ";".length, Diagnostics._0_expected, "{");
}
}
else if (isClassLike(node.parent) && isStringLiteral(node.name) && node.name.text === "constructor" && (!compilerOptions.target || compilerOptions.target < ScriptTarget.ES5)) {
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);
}
if (checkGrammarForGenerator(node)) {
return true;
}
Expand Down Expand Up @@ -32103,6 +32106,9 @@ namespace ts {

function checkGrammarProperty(node: PropertyDeclaration | PropertySignature) {
if (isClassLike(node.parent)) {
if (isStringLiteral(node.name) && node.name.text === "constructor") {
return grammarErrorOnNode(node.name, Diagnostics.Classes_may_not_have_a_field_named_constructor);
}
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)) {
return true;
}
Expand Down
8 changes: 8 additions & 0 deletions src/compiler/diagnosticMessages.json
Expand Up @@ -4965,5 +4965,13 @@
"No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer." :{
"category": "Error",
"code": 18004
},
"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.": {
"category": "Error",
"code": 18005
},
"Classes may not have a field named 'constructor'.": {
"category": "Error",
"code": 18006
}
}
5 changes: 4 additions & 1 deletion tests/baselines/reference/convertKeywordsYes.errors.txt
@@ -1,3 +1,4 @@
tests/cases/compiler/convertKeywordsYes.ts(175,12): error TS18006: Classes may not have a field named 'constructor'.
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.
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.
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.
Expand All @@ -9,7 +10,7 @@ tests/cases/compiler/convertKeywordsYes.ts(301,11): error TS1213: Identifier exp
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.


==== tests/cases/compiler/convertKeywordsYes.ts (9 errors) ====
==== tests/cases/compiler/convertKeywordsYes.ts (10 errors) ====
// reserved ES5 future in strict mode

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

class bigClass {
public "constructor" = 0;
~~~~~~~~~~~~~
!!! error TS18006: Classes may not have a field named 'constructor'.
public any = 0;
public boolean = 0;
public implements = 0;
Expand Down
14 changes: 14 additions & 0 deletions tests/baselines/reference/propertyNamedConstructor.errors.txt
@@ -0,0 +1,14 @@
tests/cases/conformance/classes/propertyMemberDeclarations/propertyNamedConstructor.ts(2,3): error TS18006: Classes may not have a field named 'constructor'.


==== tests/cases/conformance/classes/propertyMemberDeclarations/propertyNamedConstructor.ts (1 errors) ====
class X1 {
"constructor" = 3; // Error
~~~~~~~~~~~~~
!!! error TS18006: Classes may not have a field named 'constructor'.
}

class X2 {
["constructor"] = 3;
}

23 changes: 23 additions & 0 deletions tests/baselines/reference/propertyNamedConstructor.js
@@ -0,0 +1,23 @@
//// [propertyNamedConstructor.ts]
class X1 {
"constructor" = 3; // Error
}

class X2 {
["constructor"] = 3;
}


//// [propertyNamedConstructor.js]
var X1 = /** @class */ (function () {
function X1() {
this["constructor"] = 3; // Error
}
return X1;
}());
var X2 = /** @class */ (function () {
function X2() {
this["constructor"] = 3;
}
return X2;
}());
16 changes: 16 additions & 0 deletions tests/baselines/reference/propertyNamedConstructor.symbols
@@ -0,0 +1,16 @@
=== tests/cases/conformance/classes/propertyMemberDeclarations/propertyNamedConstructor.ts ===
class X1 {
>X1 : Symbol(X1, Decl(propertyNamedConstructor.ts, 0, 0))

"constructor" = 3; // Error
>"constructor" : Symbol(X1["constructor"], Decl(propertyNamedConstructor.ts, 0, 10))
}

class X2 {
>X2 : Symbol(X2, Decl(propertyNamedConstructor.ts, 2, 1))

["constructor"] = 3;
>["constructor"] : Symbol(X2["constructor"], Decl(propertyNamedConstructor.ts, 4, 10))
>"constructor" : Symbol(X2["constructor"], Decl(propertyNamedConstructor.ts, 4, 10))
}

18 changes: 18 additions & 0 deletions tests/baselines/reference/propertyNamedConstructor.types
@@ -0,0 +1,18 @@
=== tests/cases/conformance/classes/propertyMemberDeclarations/propertyNamedConstructor.ts ===
class X1 {
>X1 : X1

"constructor" = 3; // Error
>"constructor" : number
>3 : 3
}

class X2 {
>X2 : X2

["constructor"] = 3;
>["constructor"] : number
>"constructor" : "constructor"
>3 : 3
}

30 changes: 30 additions & 0 deletions tests/baselines/reference/quotedConstructors.errors.txt
@@ -0,0 +1,30 @@
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.
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.
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.


==== tests/cases/conformance/classes/constructorDeclarations/quotedConstructors.ts (3 errors) ====
class C {
"constructor"() {} // Error in 3.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.
}

class D {
'constructor'() {} // Error in 3.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.
}

class E {
['constructor']() {}
}

new class {
"constructor"() {} // Error in 3.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.
};

var o = { "constructor"() {} };

46 changes: 46 additions & 0 deletions tests/baselines/reference/quotedConstructors.js
@@ -0,0 +1,46 @@
//// [quotedConstructors.ts]
class C {
"constructor"() {} // Error in 3.5
}

class D {
'constructor'() {} // Error in 3.5
}

class E {
['constructor']() {}
}

new class {
"constructor"() {} // Error in 3.5
};

var o = { "constructor"() {} };


//// [quotedConstructors.js]
var C = /** @class */ (function () {
function C() {
}
C.prototype["constructor"] = function () { }; // Error in 3.5
return C;
}());
var D = /** @class */ (function () {
function D() {
}
D.prototype['constructor'] = function () { }; // Error in 3.5
return D;
}());
var E = /** @class */ (function () {
function E() {
}
E.prototype['constructor'] = function () { };
return E;
}());
new /** @class */ (function () {
function class_1() {
}
class_1.prototype["constructor"] = function () { }; // Error in 3.5
return class_1;
}());
var o = { "constructor": function () { } };
33 changes: 33 additions & 0 deletions tests/baselines/reference/quotedConstructors.symbols
@@ -0,0 +1,33 @@
=== tests/cases/conformance/classes/constructorDeclarations/quotedConstructors.ts ===
class C {
>C : Symbol(C, Decl(quotedConstructors.ts, 0, 0))

"constructor"() {} // Error in 3.5
>"constructor" : Symbol(C["constructor"], Decl(quotedConstructors.ts, 0, 9))
}

class D {
>D : Symbol(D, Decl(quotedConstructors.ts, 2, 1))

'constructor'() {} // Error in 3.5
>'constructor' : Symbol(D['constructor'], Decl(quotedConstructors.ts, 4, 9))
}

class E {
>E : Symbol(E, Decl(quotedConstructors.ts, 6, 1))

['constructor']() {}
>['constructor'] : Symbol(E['constructor'], Decl(quotedConstructors.ts, 8, 9))
>'constructor' : Symbol(E['constructor'], Decl(quotedConstructors.ts, 8, 9))
}

new class {
"constructor"() {} // Error in 3.5
>"constructor" : Symbol((Anonymous class)["constructor"], Decl(quotedConstructors.ts, 12, 11))

};

var o = { "constructor"() {} };
>o : Symbol(o, Decl(quotedConstructors.ts, 16, 3))
>"constructor" : Symbol("constructor", Decl(quotedConstructors.ts, 16, 9))

37 changes: 37 additions & 0 deletions tests/baselines/reference/quotedConstructors.types
@@ -0,0 +1,37 @@
=== tests/cases/conformance/classes/constructorDeclarations/quotedConstructors.ts ===
class C {
>C : C

"constructor"() {} // Error in 3.5
>"constructor" : () => void
}

class D {
>D : D

'constructor'() {} // Error in 3.5
>'constructor' : () => void
}

class E {
>E : E

['constructor']() {}
>['constructor'] : () => void
>'constructor' : "constructor"
}

new class {
>new class { "constructor"() {} // Error in 3.5} : (Anonymous class)
>class { "constructor"() {} // Error in 3.5} : typeof (Anonymous class)

"constructor"() {} // Error in 3.5
>"constructor" : () => void

};

var o = { "constructor"() {} };
>o : { "constructor"(): void; }
>{ "constructor"() {} } : { "constructor"(): void; }
>"constructor" : () => void

@@ -0,0 +1,17 @@
class C {
"constructor"() {} // Error in 3.5
}

class D {
'constructor'() {} // Error in 3.5
}

class E {
['constructor']() {}
}

new class {
"constructor"() {} // Error in 3.5
};

var o = { "constructor"() {} };
@@ -0,0 +1,7 @@
class X1 {
"constructor" = 3; // Error
}

class X2 {
["constructor"] = 3;
}

0 comments on commit 56b19c9

Please sign in to comment.