diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a4ad3af7d9a35..9a5a3e1d9d475 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -32053,9 +32053,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; } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index b209a878804db..59626445d33d3 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -4995,10 +4995,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 diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index c38e4f67fe287..84174079209c3 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -5650,12 +5650,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 { @@ -5861,8 +5876,11 @@ namespace ts { return parseAccessorDeclaration(node, SyntaxKind.SetAccessor); } - if (token() === SyntaxKind.ConstructorKeyword) { - return parseConstructorDeclaration(node); + if (token() === SyntaxKind.ConstructorKeyword || token() === SyntaxKind.StringLiteral) { + const constructorDeclaration = tryParseConstructorDeclaration(node); + if (constructorDeclaration) { + return constructorDeclaration; + } } if (isIndexSignature()) { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 0ec81502cf799..1a8d5a4a8c611 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3148,6 +3148,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); diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 5506b45d3808d..fa3da3def1c25 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -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); diff --git a/tests/baselines/reference/quotedConstructors.errors.txt b/tests/baselines/reference/quotedConstructors.errors.txt deleted file mode 100644 index 9e70452ff4062..0000000000000 --- a/tests/baselines/reference/quotedConstructors.errors.txt +++ /dev/null @@ -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"() {} }; - \ No newline at end of file diff --git a/tests/baselines/reference/quotedConstructors.js b/tests/baselines/reference/quotedConstructors.js index c9a662e6af526..36b57718f0a49 100644 --- a/tests/baselines/reference/quotedConstructors.js +++ b/tests/baselines/reference/quotedConstructors.js @@ -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; +}()); diff --git a/tests/baselines/reference/quotedConstructors.symbols b/tests/baselines/reference/quotedConstructors.symbols index be68e48484754..a4476a25ae5e8 100644 --- a/tests/baselines/reference/quotedConstructors.symbols +++ b/tests/baselines/reference/quotedConstructors.symbols @@ -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)) + } +} diff --git a/tests/baselines/reference/quotedConstructors.types b/tests/baselines/reference/quotedConstructors.types index 907a2152a80ac..65be89ff815a9 100644 --- a/tests/baselines/reference/quotedConstructors.types +++ b/tests/baselines/reference/quotedConstructors.types @@ -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 + } +} + diff --git a/tests/cases/conformance/classes/constructorDeclarations/quotedConstructors.ts b/tests/cases/conformance/classes/constructorDeclarations/quotedConstructors.ts index 3ab45c72810cd..c03ce26cc2f6e 100644 --- a/tests/cases/conformance/classes/constructorDeclarations/quotedConstructors.ts +++ b/tests/cases/conformance/classes/constructorDeclarations/quotedConstructors.ts @@ -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); + } +}