Parse quoted constructors as constructors, not methods (#31949)

* Parse quoted constructors as constructors, not methods

* Update baselines

* Fix disambiguation between quoted constructor and property named constructor

* Clean up parsing a bit

* Support escapes in constructor name

* Update baselines
This commit is contained in:
Andrew Branch
2019-07-12 14:01:57 -07:00
committed by GitHub
parent 37f2e5972f
commit 4f3412153a
10 changed files with 186 additions and 98 deletions
-3
View File
@@ -33017,9 +33017,6 @@ 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;
}
-4
View File
@@ -5113,10 +5113,6 @@
"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
+26 -8
View File
@@ -5656,12 +5656,27 @@ namespace ts {
return finishNode(node);
}
function parseConstructorDeclaration(node: ConstructorDeclaration): ConstructorDeclaration {
node.kind = SyntaxKind.Constructor;
parseExpected(SyntaxKind.ConstructorKeyword);
fillSignature(SyntaxKind.ColonToken, SignatureFlags.None, node);
node.body = parseFunctionBlockOrSemicolon(SignatureFlags.None, Diagnostics.or_expected);
return finishNode(node);
function parseConstructorName() {
if (token() === SyntaxKind.ConstructorKeyword) {
return parseExpected(SyntaxKind.ConstructorKeyword);
}
if (token() === SyntaxKind.StringLiteral && lookAhead(nextToken) === SyntaxKind.OpenParenToken) {
return tryParse(() => {
const literalNode = parseLiteralNode();
return literalNode.text === "constructor" ? literalNode : undefined;
});
}
}
function tryParseConstructorDeclaration(node: ConstructorDeclaration): ConstructorDeclaration | undefined {
return tryParse(() => {
if (parseConstructorName()) {
node.kind = SyntaxKind.Constructor;
fillSignature(SyntaxKind.ColonToken, SignatureFlags.None, node);
node.body = parseFunctionBlockOrSemicolon(SignatureFlags.None, Diagnostics.or_expected);
return finishNode(node);
}
});
}
function parseMethodDeclaration(node: MethodDeclaration, asteriskToken: AsteriskToken, diagnosticMessage?: DiagnosticMessage): MethodDeclaration {
@@ -5867,8 +5882,11 @@ namespace ts {
return parseAccessorDeclaration(<AccessorDeclaration>node, SyntaxKind.SetAccessor);
}
if (token() === SyntaxKind.ConstructorKeyword) {
return parseConstructorDeclaration(<ConstructorDeclaration>node);
if (token() === SyntaxKind.ConstructorKeyword || token() === SyntaxKind.StringLiteral) {
const constructorDeclaration = tryParseConstructorDeclaration(<ConstructorDeclaration>node);
if (constructorDeclaration) {
return constructorDeclaration;
}
}
if (isIndexSignature()) {
+17
View File
@@ -3150,6 +3150,23 @@ namespace ts {
return s.replace(escapedCharsRegExp, getReplacement);
}
/**
* Strip off existed single quotes or double quotes from a given string
*
* @return non-quoted string
*/
export function stripQuotes(name: string) {
const length = name.length;
if (length >= 2 && name.charCodeAt(0) === name.charCodeAt(length - 1) && startsWithQuote(name)) {
return name.substring(1, length - 1);
}
return name;
}
export function startsWithQuote(name: string): boolean {
return isSingleOrDoubleQuote(name.charCodeAt(0));
}
function getReplacement(c: string, offset: number, input: string) {
if (c.charCodeAt(0) === CharacterCodes.nullCharacter) {
const lookAhead = input.charCodeAt(offset + c.length);
-17
View File
@@ -1636,23 +1636,6 @@ namespace ts {
return !!location.parent && isImportOrExportSpecifier(location.parent) && location.parent.propertyName === location;
}
/**
* Strip off existed single quotes or double quotes from a given string
*
* @return non-quoted string
*/
export function stripQuotes(name: string) {
const length = name.length;
if (length >= 2 && name.charCodeAt(0) === name.charCodeAt(length - 1) && startsWithQuote(name)) {
return name.substring(1, length - 1);
}
return name;
}
export function startsWithQuote(name: string): boolean {
return isSingleOrDoubleQuote(name.charCodeAt(0));
}
export function scriptKindIs(fileName: string, host: LanguageServiceHost, ...scriptKinds: ScriptKind[]): boolean {
const scriptKind = getScriptKind(fileName, host);
return some(scriptKinds, k => k === scriptKind);
@@ -1,30 +0,0 @@
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"() {} };
@@ -1,46 +1,68 @@
//// [quotedConstructors.ts]
class C {
"constructor"() {} // Error in 3.5
"constructor"() {
console.log(this);
}
}
class D {
'constructor'() {} // Error in 3.5
'constructor'() {
console.log(this);
}
}
class E {
['constructor']() {}
['constructor']() {
console.log(this);
}
}
new class {
"constructor"() {} // Error in 3.5
"constructor"() {
console.log(this);
}
};
var o = { "constructor"() {} };
class F {
"\x63onstructor"() {
console.log(this);
}
}
//// [quotedConstructors.js]
var C = /** @class */ (function () {
function C() {
console.log(this);
}
C.prototype["constructor"] = function () { }; // Error in 3.5
return C;
}());
var D = /** @class */ (function () {
function D() {
console.log(this);
}
D.prototype['constructor'] = function () { }; // Error in 3.5
return D;
}());
var E = /** @class */ (function () {
function E() {
}
E.prototype['constructor'] = function () { };
E.prototype['constructor'] = function () {
console.log(this);
};
return E;
}());
new /** @class */ (function () {
function class_1() {
console.log(this);
}
class_1.prototype["constructor"] = function () { }; // Error in 3.5
return class_1;
}());
var o = { "constructor": function () { } };
var F = /** @class */ (function () {
function F() {
console.log(this);
}
return F;
}());
@@ -2,32 +2,65 @@
class C {
>C : Symbol(C, Decl(quotedConstructors.ts, 0, 0))
"constructor"() {} // Error in 3.5
>"constructor" : Symbol(C["constructor"], Decl(quotedConstructors.ts, 0, 9))
"constructor"() {
console.log(this);
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>this : Symbol(C, Decl(quotedConstructors.ts, 0, 0))
}
}
class D {
>D : Symbol(D, Decl(quotedConstructors.ts, 2, 1))
>D : Symbol(D, Decl(quotedConstructors.ts, 4, 1))
'constructor'() {} // Error in 3.5
>'constructor' : Symbol(D['constructor'], Decl(quotedConstructors.ts, 4, 9))
'constructor'() {
console.log(this);
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>this : Symbol(D, Decl(quotedConstructors.ts, 4, 1))
}
}
class E {
>E : Symbol(E, Decl(quotedConstructors.ts, 6, 1))
>E : Symbol(E, Decl(quotedConstructors.ts, 10, 1))
['constructor']() {}
>['constructor'] : Symbol(E['constructor'], Decl(quotedConstructors.ts, 8, 9))
>'constructor' : Symbol(E['constructor'], Decl(quotedConstructors.ts, 8, 9))
['constructor']() {
>['constructor'] : Symbol(E['constructor'], Decl(quotedConstructors.ts, 12, 9))
>'constructor' : Symbol(E['constructor'], Decl(quotedConstructors.ts, 12, 9))
console.log(this);
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>this : Symbol(E, Decl(quotedConstructors.ts, 10, 1))
}
}
new class {
"constructor"() {} // Error in 3.5
>"constructor" : Symbol((Anonymous class)["constructor"], Decl(quotedConstructors.ts, 12, 11))
"constructor"() {
console.log(this);
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>this : Symbol((Anonymous class), Decl(quotedConstructors.ts, 18, 3))
}
};
var o = { "constructor"() {} };
>o : Symbol(o, Decl(quotedConstructors.ts, 16, 3))
>"constructor" : Symbol("constructor", Decl(quotedConstructors.ts, 16, 9))
>o : Symbol(o, Decl(quotedConstructors.ts, 24, 3))
>"constructor" : Symbol("constructor", Decl(quotedConstructors.ts, 24, 9))
class F {
>F : Symbol(F, Decl(quotedConstructors.ts, 24, 31))
"\x63onstructor"() {
console.log(this);
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>this : Symbol(F, Decl(quotedConstructors.ts, 24, 31))
}
}
@@ -2,32 +2,57 @@
class C {
>C : C
"constructor"() {} // Error in 3.5
>"constructor" : () => void
"constructor"() {
console.log(this);
>console.log(this) : void
>console.log : (message?: any, ...optionalParams: any[]) => void
>console : Console
>log : (message?: any, ...optionalParams: any[]) => void
>this : this
}
}
class D {
>D : D
'constructor'() {} // Error in 3.5
>'constructor' : () => void
'constructor'() {
console.log(this);
>console.log(this) : void
>console.log : (message?: any, ...optionalParams: any[]) => void
>console : Console
>log : (message?: any, ...optionalParams: any[]) => void
>this : this
}
}
class E {
>E : E
['constructor']() {}
['constructor']() {
>['constructor'] : () => void
>'constructor' : "constructor"
console.log(this);
>console.log(this) : void
>console.log : (message?: any, ...optionalParams: any[]) => void
>console : Console
>log : (message?: any, ...optionalParams: any[]) => void
>this : this
}
}
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
>new class { "constructor"() { console.log(this); }} : (Anonymous class)
>class { "constructor"() { console.log(this); }} : typeof (Anonymous class)
"constructor"() {
console.log(this);
>console.log(this) : void
>console.log : (message?: any, ...optionalParams: any[]) => void
>console : Console
>log : (message?: any, ...optionalParams: any[]) => void
>this : this
}
};
var o = { "constructor"() {} };
@@ -35,3 +60,16 @@ var o = { "constructor"() {} };
>{ "constructor"() {} } : { "constructor"(): void; }
>"constructor" : () => void
class F {
>F : F
"\x63onstructor"() {
console.log(this);
>console.log(this) : void
>console.log : (message?: any, ...optionalParams: any[]) => void
>console : Console
>log : (message?: any, ...optionalParams: any[]) => void
>this : this
}
}
@@ -1,17 +1,31 @@
class C {
"constructor"() {} // Error in 3.5
"constructor"() {
console.log(this);
}
}
class D {
'constructor'() {} // Error in 3.5
'constructor'() {
console.log(this);
}
}
class E {
['constructor']() {}
['constructor']() {
console.log(this);
}
}
new class {
"constructor"() {} // Error in 3.5
"constructor"() {
console.log(this);
}
};
var o = { "constructor"() {} };
class F {
"\x63onstructor"() {
console.log(this);
}
}