From d1a2ae5e12e10afcd6e7be510533030e96651782 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 17 Jun 2015 15:36:53 -0700 Subject: [PATCH 01/30] Factor switch staement into a map and create a method to add members to it --- src/server/session.ts | 258 ++++++++++++++++++++---------------------- 1 file changed, 122 insertions(+), 136 deletions(-) diff --git a/src/server/session.ts b/src/server/session.ts index c95b1a7cc1b..e0c540db18b 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -839,6 +839,127 @@ namespace ts.server { exit() { } + private handlers : Map<(request: protocol.Request) => {response?: any, responseRequired?: boolean}> = { + [CommandNames.Exit]: () => { + this.exit(); + return {}; + }, + [CommandNames.Definition]: (request: protocol.Request) => { + var defArgs = request.arguments; + return {response: this.getDefinition(defArgs.line, defArgs.offset, defArgs.file)}; + }, + [CommandNames.TypeDefinition]: (request: protocol.Request) => { + var defArgs = request.arguments; + return {response: this.getTypeDefinition(defArgs.line, defArgs.offset, defArgs.file)}; + }, + [CommandNames.References]: (request: protocol.Request) => { + var defArgs = request.arguments; + return {response: this.getReferences(defArgs.line, defArgs.offset, defArgs.file)}; + }, + [CommandNames.Rename]: (request: protocol.Request) => { + var renameArgs = request.arguments; + return {response: this.getRenameLocations(renameArgs.line, renameArgs.offset, renameArgs.file, renameArgs.findInComments, renameArgs.findInStrings)} + }, + [CommandNames.Open]: (request: protocol.Request) => { + var openArgs = request.arguments; + this.openClientFile(openArgs.file); + return {} + }, + [CommandNames.Quickinfo]: (request: protocol.Request) => { + var quickinfoArgs = request.arguments; + return {response: this.getQuickInfo(quickinfoArgs.line, quickinfoArgs.offset, quickinfoArgs.file)}; + }, + [CommandNames.Format]: (request: protocol.Request) => { + var formatArgs = request.arguments; + return {response: this.getFormattingEditsForRange(formatArgs.line, formatArgs.offset, formatArgs.endLine, formatArgs.endOffset, formatArgs.file)}; + }, + [CommandNames.Formatonkey]: (request: protocol.Request) => { + var formatOnKeyArgs = request.arguments; + return {response: this.getFormattingEditsAfterKeystroke(formatOnKeyArgs.line, formatOnKeyArgs.offset, formatOnKeyArgs.key, formatOnKeyArgs.file)}; + }, + [CommandNames.Completions]: (request: protocol.Request) => { + var completionsArgs = request.arguments; + return {response: this.getCompletions(completionsArgs.line, completionsArgs.offset, completionsArgs.prefix, completionsArgs.file)} + }, + [CommandNames.CompletionDetails]: (request: protocol.Request) => { + var completionDetailsArgs = request.arguments; + return {response: this.getCompletionEntryDetails(completionDetailsArgs.line,completionDetailsArgs.offset, + completionDetailsArgs.entryNames,completionDetailsArgs.file)} + }, + [CommandNames.SignatureHelp]: (request: protocol.Request) => { + var signatureHelpArgs = request.arguments; + return {response: this.getSignatureHelpItems(signatureHelpArgs.line, signatureHelpArgs.offset, signatureHelpArgs.file)} + }, + [CommandNames.Geterr]: (request: protocol.Request) => { + var geterrArgs = request.arguments; + return {response: this.getDiagnostics(geterrArgs.delay, geterrArgs.files), responseRequired: false}; + }, + [CommandNames.Change]: (request: protocol.Request) => { + var changeArgs = request.arguments; + this.change(changeArgs.line, changeArgs.offset, changeArgs.endLine, changeArgs.endOffset, + changeArgs.insertString, changeArgs.file); + return {responseRequired: false} + }, + [CommandNames.Configure]: (request: protocol.Request) => { + var configureArgs = request.arguments; + this.projectService.setHostConfiguration(configureArgs); + this.output(undefined, CommandNames.Configure, request.seq); + return {responseRequired: false} + }, + [CommandNames.Reload]: (request: protocol.Request) => { + var reloadArgs = request.arguments; + this.reload(reloadArgs.file, reloadArgs.tmpfile, request.seq); + return {responseRequired: false} + }, + [CommandNames.Saveto]: (request: protocol.Request) => { + var savetoArgs = request.arguments; + this.saveToTmp(savetoArgs.file, savetoArgs.tmpfile); + return {responseRequired: false} + }, + [CommandNames.Close]: (request: protocol.Request) => { + var closeArgs = request.arguments; + this.closeClientFile(closeArgs.file); + return {responseRequired: false}; + }, + [CommandNames.Navto]: (request: protocol.Request) => { + var navtoArgs = request.arguments; + return {response: this.getNavigateToItems(navtoArgs.searchValue, navtoArgs.file, navtoArgs.maxResultCount)}; + }, + [CommandNames.Brace]: (request: protocol.Request) => { + var braceArguments = request.arguments; + return {response: this.getBraceMatching(braceArguments.line, braceArguments.offset, braceArguments.file)}; + }, + [CommandNames.NavBar]: (request: protocol.Request) => { + var navBarArgs = request.arguments; + return {response: this.getNavigationBarItems(navBarArgs.file)}; + }, + [CommandNames.Occurrences]: (request: protocol.Request) => { + var { line, offset, file: fileName } = request.arguments; + return {response: this.getOccurrences(line, offset, fileName)}; + }, + [CommandNames.ProjectInfo]: (request: protocol.Request) => { + var { file, needFileNameList } = request.arguments; + return {response: this.getProjectInfo(file, needFileNameList)}; + }, + }; + addProtocolHandler(command: string, handler: (request: protocol.Request) => {response?: any, responseRequired: boolean}) { + if (this.handlers[command]) { + throw new Error(`Protocol handler already exists for command "${command}"`); + } + this.handlers[command] = handler; + } + + executeCommand(request: protocol.Request) : {response?: any, responseRequired?: boolean} { + var handler = this.handlers[request.command]; + if (handler) { + return handler(request); + } else { + this.projectService.log("Unrecognized JSON command: " + JSON.stringify(request)); + this.output(undefined, CommandNames.Unknown, request.seq, "Unrecognized JSON command: " + request.command); + return {responseRequired: false}; + } + } + onMessage(message: string) { if (this.logger.isVerbose()) { this.logger.info("request: " + message); @@ -846,142 +967,7 @@ namespace ts.server { } try { var request = JSON.parse(message); - var response: any; - var errorMessage: string; - var responseRequired = true; - switch (request.command) { - case CommandNames.Exit: { - this.exit(); - responseRequired = false; - break; - } - case CommandNames.Definition: { - var defArgs = request.arguments; - response = this.getDefinition(defArgs.line, defArgs.offset, defArgs.file); - break; - } - case CommandNames.TypeDefinition: { - var defArgs = request.arguments; - response = this.getTypeDefinition(defArgs.line, defArgs.offset, defArgs.file); - break; - } - case CommandNames.References: { - var refArgs = request.arguments; - response = this.getReferences(refArgs.line, refArgs.offset, refArgs.file); - break; - } - case CommandNames.Rename: { - var renameArgs = request.arguments; - response = this.getRenameLocations(renameArgs.line, renameArgs.offset, renameArgs.file, renameArgs.findInComments, renameArgs.findInStrings); - break; - } - case CommandNames.Open: { - var openArgs = request.arguments; - this.openClientFile(openArgs.file); - responseRequired = false; - break; - } - case CommandNames.Quickinfo: { - var quickinfoArgs = request.arguments; - response = this.getQuickInfo(quickinfoArgs.line, quickinfoArgs.offset, quickinfoArgs.file); - break; - } - case CommandNames.Format: { - var formatArgs = request.arguments; - response = this.getFormattingEditsForRange(formatArgs.line, formatArgs.offset, formatArgs.endLine, formatArgs.endOffset, formatArgs.file); - break; - } - case CommandNames.Formatonkey: { - var formatOnKeyArgs = request.arguments; - response = this.getFormattingEditsAfterKeystroke(formatOnKeyArgs.line, formatOnKeyArgs.offset, formatOnKeyArgs.key, formatOnKeyArgs.file); - break; - } - case CommandNames.Completions: { - var completionsArgs = request.arguments; - response = this.getCompletions(completionsArgs.line, completionsArgs.offset, completionsArgs.prefix, completionsArgs.file); - break; - } - case CommandNames.CompletionDetails: { - var completionDetailsArgs = request.arguments; - response = - this.getCompletionEntryDetails(completionDetailsArgs.line,completionDetailsArgs.offset, - completionDetailsArgs.entryNames,completionDetailsArgs.file); - break; - } - case CommandNames.SignatureHelp: { - var signatureHelpArgs = request.arguments; - response = this.getSignatureHelpItems(signatureHelpArgs.line, signatureHelpArgs.offset, signatureHelpArgs.file); - break; - } - case CommandNames.Geterr: { - var geterrArgs = request.arguments; - response = this.getDiagnostics(geterrArgs.delay, geterrArgs.files); - responseRequired = false; - break; - } - case CommandNames.Change: { - var changeArgs = request.arguments; - this.change(changeArgs.line, changeArgs.offset, changeArgs.endLine, changeArgs.endOffset, - changeArgs.insertString, changeArgs.file); - responseRequired = false; - break; - } - case CommandNames.Configure: { - var configureArgs = request.arguments; - this.projectService.setHostConfiguration(configureArgs); - this.output(undefined, CommandNames.Configure, request.seq); - responseRequired = false; - break; - } - case CommandNames.Reload: { - var reloadArgs = request.arguments; - this.reload(reloadArgs.file, reloadArgs.tmpfile, request.seq); - responseRequired = false; - break; - } - case CommandNames.Saveto: { - var savetoArgs = request.arguments; - this.saveToTmp(savetoArgs.file, savetoArgs.tmpfile); - responseRequired = false; - break; - } - case CommandNames.Close: { - var closeArgs = request.arguments; - this.closeClientFile(closeArgs.file); - responseRequired = false; - break; - } - case CommandNames.Navto: { - var navtoArgs = request.arguments; - response = this.getNavigateToItems(navtoArgs.searchValue, navtoArgs.file, navtoArgs.maxResultCount); - break; - } - case CommandNames.Brace: { - var braceArguments = request.arguments; - response = this.getBraceMatching(braceArguments.line, braceArguments.offset, braceArguments.file); - break; - } - case CommandNames.NavBar: { - var navBarArgs = request.arguments; - response = this.getNavigationBarItems(navBarArgs.file); - break; - } - case CommandNames.Occurrences: { - var { line, offset, file: fileName } = request.arguments; - response = this.getOccurrences(line, offset, fileName); - break; - } - case CommandNames.ProjectInfo: { - var { file, needFileNameList } = request.arguments; - response = this.getProjectInfo(file, needFileNameList); - break; - } - default: { - this.projectService.log("Unrecognized JSON command: " + message); - this.output(undefined, CommandNames.Unknown, request.seq, "Unrecognized JSON command: " + request.command); - break; - } - } + var {response, responseRequired} = this.executeCommand(request); if (this.logger.isVerbose()) { var elapsed = this.hrtime(start); From ddb60fc8ce8c3d37c7acaf588cfb8948b30c2a3a Mon Sep 17 00:00:00 2001 From: Dirk Baeumer Date: Tue, 30 Jun 2015 10:49:15 +0200 Subject: [PATCH 02/30] Node System host write - need to loop since writeSync might not write all bytes --- src/compiler/sys.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index a47d6959ba8..d5e1c77d22f 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -29,6 +29,9 @@ namespace ts { declare var process: any; declare var global: any; declare var __filename: string; + declare var Buffer: { + new (str: string, encoding ?: string): any; + } declare class Enumerator { public atEnd(): boolean; @@ -267,10 +270,17 @@ namespace ts { args: process.argv.slice(2), newLine: _os.EOL, useCaseSensitiveFileNames: useCaseSensitiveFileNames, - write(s: string): void { + write(s: string): void { + var buffer = new Buffer(s, 'utf8'); + var offset: number = 0; + var toWrite: number = buffer.length; + var written = 0; // 1 is a standard descriptor for stdout - _fs.writeSync(1, s); - }, + while ((written = _fs.writeSync(1, buffer, offset, toWrite)) < toWrite) { + offset += written; + toWrite -= written; + } + }, readFile, writeFile, watchFile: (fileName, callback) => { From e2b858dbf826a1187d5b56670633fd4aa4711e5a Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Thu, 2 Jul 2015 14:53:03 -0700 Subject: [PATCH 03/30] Check abstractness via constructor return types --- src/compiler/checker.ts | 19 +++++++++++++++---- .../diagnosticInformationMap.generated.ts | 2 +- src/compiler/diagnosticMessages.json | 2 +- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d3d8ac1bc1b..e1826901399 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4872,10 +4872,21 @@ namespace ts { return Ternary.False; } - let t = getReturnTypeOfSignature(target); - if (t === voidType) return result; - let s = getReturnTypeOfSignature(source); - return result & isRelatedTo(s, t, reportErrors); + let targetReturnType = getReturnTypeOfSignature(target); + if (targetReturnType === voidType) return result; + let sourceReturnType = getReturnTypeOfSignature(source); + + let targetReturnDecl = targetReturnType.symbol && getDeclarationOfKind(targetReturnType.symbol, SyntaxKind.ClassDeclaration); + let sourceReturnDecl = sourceReturnType.symbol && getDeclarationOfKind(sourceReturnType.symbol, SyntaxKind.ClassDeclaration); + + if(sourceReturnDecl && sourceReturnDecl.flags & NodeFlags.Abstract && (!targetReturnDecl || !(targetReturnDecl.flags & NodeFlags.Abstract))) { + if(reportErrors) { + reportError(Diagnostics.Constructor_objects_of_abstract_type_cannot_be_assigned_to_constructor_objects_of_non_abstract_type); + } + return Ternary.False; + } + + return result & isRelatedTo(sourceReturnType, targetReturnType, reportErrors); } function signaturesIdenticalTo(source: ObjectType, target: ObjectType, kind: SignatureKind): Ternary { diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index a17f8857590..fbac2f44fb5 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -407,7 +407,7 @@ namespace ts { Classes_containing_abstract_methods_must_be_marked_abstract: { code: 2514, category: DiagnosticCategory.Error, key: "Classes containing abstract methods must be marked abstract." }, Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2: { code: 2515, category: DiagnosticCategory.Error, key: "Non-abstract class '{0}' does not implement inherited abstract member '{1}' from class '{2}'." }, All_declarations_of_an_abstract_method_must_be_consecutive: { code: 2516, category: DiagnosticCategory.Error, key: "All declarations of an abstract method must be consecutive." }, - Constructor_objects_of_abstract_type_cannot_be_assigned_to_constructor_objects_of_non_abstract_type: { code: 2517, category: DiagnosticCategory.Error, key: "Constructor objects of abstract type cannot be assigned to constructor objects of non-abstract type" }, + Constructor_objects_of_abstract_type_cannot_be_assigned_to_constructor_objects_of_non_abstract_type: { code: 2517, category: DiagnosticCategory.Error, key: "Constructor objects of abstract type cannot be assigned to constructor objects of non-abstract type." }, Only_an_ambient_class_can_be_merged_with_an_interface: { code: 2518, category: DiagnosticCategory.Error, key: "Only an ambient class can be merged with an interface." }, Duplicate_identifier_0_Compiler_uses_declaration_1_to_support_async_functions: { code: 2520, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'. Compiler uses declaration '{1}' to support async functions." }, Expression_resolves_to_variable_declaration_0_that_compiler_uses_to_support_async_functions: { code: 2521, category: DiagnosticCategory.Error, key: "Expression resolves to variable declaration '{0}' that compiler uses to support async functions." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 94be4f53c97..4c9fbe2d49c 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1617,7 +1617,7 @@ "category": "Error", "code": 2516 }, - "Constructor objects of abstract type cannot be assigned to constructor objects of non-abstract type": { + "Constructor objects of abstract type cannot be assigned to constructor objects of non-abstract type.": { "category": "Error", "code":2517 }, From 0a79c9cd6649432a12cfe8ed2a2b5c06e6b8fa68 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Thu, 2 Jul 2015 15:11:25 -0700 Subject: [PATCH 04/30] updated baselines --- .../reference/classAbstractInstantiations2.errors.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/baselines/reference/classAbstractInstantiations2.errors.txt b/tests/baselines/reference/classAbstractInstantiations2.errors.txt index b3b01fd656d..43dfb9e009f 100644 --- a/tests/baselines/reference/classAbstractInstantiations2.errors.txt +++ b/tests/baselines/reference/classAbstractInstantiations2.errors.txt @@ -1,4 +1,6 @@ tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations2.ts(10,1): error TS2511: Cannot create an instance of the abstract class 'B'. +tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations2.ts(13,5): error TS2322: Type 'typeof B' is not assignable to type 'typeof A'. + Constructor objects of abstract type cannot be assigned to constructor objects of non-abstract type. tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations2.ts(17,5): error TS2511: Cannot create an instance of the abstract class 'B'. tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations2.ts(21,1): error TS2511: Cannot create an instance of the abstract class 'B'. tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations2.ts(26,7): error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'bar' from class 'B'. @@ -7,7 +9,7 @@ tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbst tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations2.ts(50,5): error TS1244: Abstract methods can only appear within an abstract class. -==== tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations2.ts (7 errors) ==== +==== tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations2.ts (8 errors) ==== class A { // ... } @@ -23,6 +25,9 @@ tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbst var BB: typeof B = B; var AA: typeof A = BB; // error, AA is not of abstract type. + ~~ +!!! error TS2322: Type 'typeof B' is not assignable to type 'typeof A'. +!!! error TS2322: Constructor objects of abstract type cannot be assigned to constructor objects of non-abstract type. new AA; function constructB(Factory : typeof B) { From a4c801d49cb39d4d6f0a349f2dd8a3b6fb069c1c Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Mon, 6 Jul 2015 10:31:01 -0700 Subject: [PATCH 05/30] New Test --- .../classAbstractClinterfaceAssignability.ts | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractClinterfaceAssignability.ts diff --git a/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractClinterfaceAssignability.ts b/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractClinterfaceAssignability.ts new file mode 100644 index 00000000000..682ad6faa0f --- /dev/null +++ b/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractClinterfaceAssignability.ts @@ -0,0 +1,23 @@ +interface I { + x: number; +} + +interface IConstructor { + new (): I; + + y: number; + prototype: I; +} + +var I: IConstructor; + +abstract class A { + x: number; + static y: number; +} + +var AA: typeof A; +AA = I; + +var AAA: typeof I; +AAA = A; \ No newline at end of file From 7494134041fe7446c10e2765e5ea06ba99d26e4d Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Mon, 6 Jul 2015 10:31:15 -0700 Subject: [PATCH 06/30] updated baselines --- ...bstractClinterfaceAssignability.errors.txt | 31 ++++++++++++++++ .../classAbstractClinterfaceAssignability.js | 36 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 tests/baselines/reference/classAbstractClinterfaceAssignability.errors.txt create mode 100644 tests/baselines/reference/classAbstractClinterfaceAssignability.js diff --git a/tests/baselines/reference/classAbstractClinterfaceAssignability.errors.txt b/tests/baselines/reference/classAbstractClinterfaceAssignability.errors.txt new file mode 100644 index 00000000000..17d08981d3e --- /dev/null +++ b/tests/baselines/reference/classAbstractClinterfaceAssignability.errors.txt @@ -0,0 +1,31 @@ +tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractClinterfaceAssignability.ts(23,1): error TS2322: Type 'typeof A' is not assignable to type 'IConstructor'. + Constructor objects of abstract type cannot be assigned to constructor objects of non-abstract type. + + +==== tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractClinterfaceAssignability.ts (1 errors) ==== + interface I { + x: number; + } + + interface IConstructor { + new (): I; + + y: number; + prototype: I; + } + + var I: IConstructor; + + abstract class A { + x: number; + static y: number; + } + + var AA: typeof A; + AA = I; + + var AAA: typeof I; + AAA = A; + ~~~ +!!! error TS2322: Type 'typeof A' is not assignable to type 'IConstructor'. +!!! error TS2322: Constructor objects of abstract type cannot be assigned to constructor objects of non-abstract type. \ No newline at end of file diff --git a/tests/baselines/reference/classAbstractClinterfaceAssignability.js b/tests/baselines/reference/classAbstractClinterfaceAssignability.js new file mode 100644 index 00000000000..cbcf9dd189c --- /dev/null +++ b/tests/baselines/reference/classAbstractClinterfaceAssignability.js @@ -0,0 +1,36 @@ +//// [classAbstractClinterfaceAssignability.ts] +interface I { + x: number; +} + +interface IConstructor { + new (): I; + + y: number; + prototype: I; +} + +var I: IConstructor; + +abstract class A { + x: number; + static y: number; +} + +var AA: typeof A; +AA = I; + +var AAA: typeof I; +AAA = A; + +//// [classAbstractClinterfaceAssignability.js] +var I; +var A = (function () { + function A() { + } + return A; +})(); +var AA; +AA = I; +var AAA; +AAA = A; From 64056005ff1ca6a6c18aa4fdc170a5543a33d08c Mon Sep 17 00:00:00 2001 From: Dan Quirk Date: Thu, 9 Jul 2015 18:04:30 -0700 Subject: [PATCH 07/30] Create top level describe block for runners so status is reported at runner level --- src/harness/compilerRunner.ts | 46 ++++---- src/harness/fourslashRunner.ts | 118 +++++++++++---------- src/harness/projectsRunner.ts | 188 +++++++++++++++++---------------- 3 files changed, 179 insertions(+), 173 deletions(-) diff --git a/src/harness/compilerRunner.ts b/src/harness/compilerRunner.ts index 1b399e1b706..1c8dccc6173 100644 --- a/src/harness/compilerRunner.ts +++ b/src/harness/compilerRunner.ts @@ -100,7 +100,7 @@ class CompilerBaselineRunner extends RunnerBase { }); beforeEach(() => { - /* The compiler doesn't handle certain flags flipping during a single compilation setting. Tests on these flags will need + /* The compiler doesn't handle certain flags flipping during a single compilation setting. Tests on these flags will need a fresh compiler instance for themselves and then create a fresh one for the next test. Would be nice to get dev fixes eventually to remove this limitation. */ for (var i = 0; i < tcSettings.length; ++i) { @@ -261,19 +261,19 @@ class CompilerBaselineRunner extends RunnerBase { // NEWTODO: Type baselines if (result.errors.length === 0) { - // The full walker simulates the types that you would get from doing a full + // The full walker simulates the types that you would get from doing a full // compile. The pull walker simulates the types you get when you just do // a type query for a random node (like how the LS would do it). Most of the // time, these will be the same. However, occasionally, they can be different. // Specifically, when the compiler internally depends on symbol IDs to order - // things, then we may see different results because symbols can be created in a + // things, then we may see different results because symbols can be created in a // different order with 'pull' operations, and thus can produce slightly differing // output. // // For example, with a full type check, we may see a type outputed as: number | string // But with a pull type check, we may see it as: string | number // - // These types are equivalent, but depend on what order the compiler observed + // These types are equivalent, but depend on what order the compiler observed // certain parts of the program. let allFiles = toBeCompiled.concat(otherFiles).filter(file => !!program.getSourceFile(file.unitName)); @@ -384,25 +384,27 @@ class CompilerBaselineRunner extends RunnerBase { } public initializeTests() { - describe("Setup compiler for compiler baselines", () => { - var harnessCompiler = Harness.Compiler.getCompiler(); - this.parseOptions(); - }); - - // this will set up a series of describe/it blocks to run between the setup and cleanup phases - if (this.tests.length === 0) { - var testFiles = this.enumerateFiles(this.basePath, /\.tsx?$/, { recursive: true }); - testFiles.forEach(fn => { - fn = fn.replace(/\\/g, "/"); - this.checkTestCodeOutput(fn); + describe('Compiler tests', () => { + describe("Setup compiler for compiler baselines", () => { + var harnessCompiler = Harness.Compiler.getCompiler(); + this.parseOptions(); }); - } - else { - this.tests.forEach(test => this.checkTestCodeOutput(test)); - } - describe("Cleanup after compiler baselines", () => { - var harnessCompiler = Harness.Compiler.getCompiler(); + // this will set up a series of describe/it blocks to run between the setup and cleanup phases + if (this.tests.length === 0) { + var testFiles = this.enumerateFiles(this.basePath, /\.tsx?$/, { recursive: true }); + testFiles.forEach(fn => { + fn = fn.replace(/\\/g, "/"); + this.checkTestCodeOutput(fn); + }); + } + else { + this.tests.forEach(test => this.checkTestCodeOutput(test)); + } + + describe("Cleanup after compiler baselines", () => { + var harnessCompiler = Harness.Compiler.getCompiler(); + }); }); } @@ -434,4 +436,4 @@ class CompilerBaselineRunner extends RunnerBase { } } } -} \ No newline at end of file +} diff --git a/src/harness/fourslashRunner.ts b/src/harness/fourslashRunner.ts index d11c5e639e5..9287f7361a5 100644 --- a/src/harness/fourslashRunner.ts +++ b/src/harness/fourslashRunner.ts @@ -2,7 +2,7 @@ /// /// -const enum FourSlashTestType { +const enum FourSlashTestType { Native, Shims, Server @@ -35,70 +35,72 @@ class FourSlashRunner extends RunnerBase { this.tests = this.enumerateFiles(this.basePath, /\.ts/i, { recursive: false }); } + describe('Fourslash tests', () => { this.tests.forEach((fn: string) => { - describe(fn, () => { - fn = ts.normalizeSlashes(fn); - var justName = fn.replace(/^.*[\\\/]/, ''); + describe(fn, () => { + fn = ts.normalizeSlashes(fn); + var justName = fn.replace(/^.*[\\\/]/, ''); - // Convert to relative path - var testIndex = fn.indexOf('tests/'); - if (testIndex >= 0) fn = fn.substr(testIndex); + // Convert to relative path + var testIndex = fn.indexOf('tests/'); + if (testIndex >= 0) fn = fn.substr(testIndex); - if (justName && !justName.match(/fourslash\.ts$/i) && !justName.match(/\.d\.ts$/i)) { - it(this.testSuiteName + ' test ' + justName + ' runs correctly',() => { - FourSlash.runFourSlashTest(this.basePath, this.testType, fn); - }); - } + if (justName && !justName.match(/fourslash\.ts$/i) && !justName.match(/\.d\.ts$/i)) { + it(this.testSuiteName + ' test ' + justName + ' runs correctly',() => { + FourSlash.runFourSlashTest(this.basePath, this.testType, fn); + }); + } + }); }); - }); - describe('Generate Tao XML', () => { - var invalidReasons: any = {}; - FourSlash.xmlData.forEach(xml => { - if (xml.invalidReason !== null) { - invalidReasons[xml.invalidReason] = (invalidReasons[xml.invalidReason] || 0) + 1; + describe('Generate Tao XML', () => { + var invalidReasons: any = {}; + FourSlash.xmlData.forEach(xml => { + if (xml.invalidReason !== null) { + invalidReasons[xml.invalidReason] = (invalidReasons[xml.invalidReason] || 0) + 1; + } + }); + var invalidReport: { reason: string; count: number }[] = []; + for (var reason in invalidReasons) { + if (invalidReasons.hasOwnProperty(reason)) { + invalidReport.push({ reason: reason, count: invalidReasons[reason] }); + } } - }); - var invalidReport: { reason: string; count: number }[] = []; - for (var reason in invalidReasons) { - if (invalidReasons.hasOwnProperty(reason)) { - invalidReport.push({ reason: reason, count: invalidReasons[reason] }); - } - } - invalidReport.sort((lhs, rhs) => lhs.count > rhs.count ? -1 : lhs.count === rhs.count ? 0 : 1); + invalidReport.sort((lhs, rhs) => lhs.count > rhs.count ? -1 : lhs.count === rhs.count ? 0 : 1); - var lines: string[] = []; - lines.push(''); + lines.push(''); + lines.push(' '); + lines.push(' '); + lines.push(' '); + lines.push(' '); + FourSlash.xmlData.forEach(xml => { + if (xml.invalidReason !== null) { + lines.push(''); + } else { + lines.push(' '); + xml.actions.forEach(action => { + lines.push(' ' + action); + }); + lines.push(' '); + } + }); + lines.push(' '); + lines.push(' '); + lines.push(' '); + lines.push(' '); + lines.push(' '); + lines.push(' '); + lines.push(' '); + lines.push(' '); + lines.push(''); + Harness.IO.writeFile('built/local/fourslash.xml', lines.join('\r\n')); }); - lines.push('-->'); - lines.push(''); - lines.push(' '); - lines.push(' '); - lines.push(' '); - lines.push(' '); - FourSlash.xmlData.forEach(xml => { - if (xml.invalidReason !== null) { - lines.push(''); - } else { - lines.push(' '); - xml.actions.forEach(action => { - lines.push(' ' + action); - }); - lines.push(' '); - } - }); - lines.push(' '); - lines.push(' '); - lines.push(' '); - lines.push(' '); - lines.push(' '); - lines.push(' '); - lines.push(' '); - lines.push(' '); - lines.push(''); - Harness.IO.writeFile('built/local/fourslash.xml', lines.join('\r\n')); }); } } @@ -108,4 +110,4 @@ class GeneratedFourslashRunner extends FourSlashRunner { super(testType); this.basePath += '/generated/'; } -} \ No newline at end of file +} diff --git a/src/harness/projectsRunner.ts b/src/harness/projectsRunner.ts index 5eb0016ff8d..01dc52308ff 100644 --- a/src/harness/projectsRunner.ts +++ b/src/harness/projectsRunner.ts @@ -89,7 +89,7 @@ class ProjectRunner extends RunnerBase { } // When test case output goes to tests/baselines/local/projectOutput/testCaseName/moduleKind/ - // We have these two separate locations because when comparing baselines the baseline verifier will delete the existing file + // We have these two separate locations because when comparing baselines the baseline verifier will delete the existing file // so even if it was created by compiler in that location, the file will be deleted by verified before we can read it // so lets keep these two locations separate function getProjectOutputFolder(fileName: string, moduleKind: ts.ModuleKind) { @@ -194,7 +194,7 @@ class ProjectRunner extends RunnerBase { }; } } - + function batchCompilerProjectTestCase(moduleKind: ts.ModuleKind): BatchCompileProjectTestCaseResult{ var nonSubfolderDiskFiles = 0; @@ -230,7 +230,7 @@ class ProjectRunner extends RunnerBase { var diskRelativeName = ts.getRelativePathToDirectoryOrUrl(testCase.projectRoot, diskFileName, getCurrentDirectory(), Harness.Compiler.getCanonicalFileName, /*isAbsolutePathAnUrl*/ false); if (ts.isRootedDiskPath(diskRelativeName) || diskRelativeName.substr(0, 3) === "../") { - // If the generated output file resides in the parent folder or is rooted path, + // If the generated output file resides in the parent folder or is rooted path, // we need to instead create files that can live in the project reference folder // but make sure extension of these files matches with the fileName the compiler asked to write diskRelativeName = "diskFile" + nonSubfolderDiskFiles++ + @@ -330,108 +330,110 @@ class ProjectRunner extends RunnerBase { var name = 'Compiling project for ' + testCase.scenario + ': testcase ' + testCaseFileName; - describe(name, () => { - function verifyCompilerResults(moduleKind: ts.ModuleKind) { - function getCompilerResolutionInfo() { - var resolutionInfo: ProjectRunnerTestCaseResolutionInfo = { - scenario: testCase.scenario, - projectRoot: testCase.projectRoot, - inputFiles: testCase.inputFiles, - out: testCase.out, - outDir: testCase.outDir, - sourceMap: testCase.sourceMap, - mapRoot: testCase.mapRoot, - resolveMapRoot: testCase.resolveMapRoot, - sourceRoot: testCase.sourceRoot, - resolveSourceRoot: testCase.resolveSourceRoot, - declaration: testCase.declaration, - baselineCheck: testCase.baselineCheck, - runTest: testCase.runTest, - bug: testCase.bug, - rootDir: testCase.rootDir, - resolvedInputFiles: ts.map(compilerResult.program.getSourceFiles(), inputFile => inputFile.fileName), - emittedFiles: ts.map(compilerResult.outputFiles, outputFile => outputFile.emittedFileName) - }; + describe('Projects tests', () => { + describe(name, () => { + function verifyCompilerResults(moduleKind: ts.ModuleKind) { + function getCompilerResolutionInfo() { + var resolutionInfo: ProjectRunnerTestCaseResolutionInfo = { + scenario: testCase.scenario, + projectRoot: testCase.projectRoot, + inputFiles: testCase.inputFiles, + out: testCase.out, + outDir: testCase.outDir, + sourceMap: testCase.sourceMap, + mapRoot: testCase.mapRoot, + resolveMapRoot: testCase.resolveMapRoot, + sourceRoot: testCase.sourceRoot, + resolveSourceRoot: testCase.resolveSourceRoot, + declaration: testCase.declaration, + baselineCheck: testCase.baselineCheck, + runTest: testCase.runTest, + bug: testCase.bug, + rootDir: testCase.rootDir, + resolvedInputFiles: ts.map(compilerResult.program.getSourceFiles(), inputFile => inputFile.fileName), + emittedFiles: ts.map(compilerResult.outputFiles, outputFile => outputFile.emittedFileName) + }; - return resolutionInfo; - } + return resolutionInfo; + } - var compilerResult: BatchCompileProjectTestCaseResult; + var compilerResult: BatchCompileProjectTestCaseResult; - it(name + ": " + moduleNameToString(moduleKind) , () => { - // Compile using node - compilerResult = batchCompilerProjectTestCase(moduleKind); - }); - - it('Resolution information of (' + moduleNameToString(moduleKind) + '): ' + testCaseFileName, () => { - Harness.Baseline.runBaseline('Resolution information of (' + moduleNameToString(compilerResult.moduleKind) + '): ' + testCaseFileName, getBaselineFolder(compilerResult.moduleKind) + testCaseJustName + '.json', () => { - return JSON.stringify(getCompilerResolutionInfo(), undefined, " "); + it(name + ": " + moduleNameToString(moduleKind) , () => { + // Compile using node + compilerResult = batchCompilerProjectTestCase(moduleKind); }); - }); - - it('Errors for (' + moduleNameToString(moduleKind) + '): ' + testCaseFileName, () => { - if (compilerResult.errors.length) { - Harness.Baseline.runBaseline('Errors for (' + moduleNameToString(compilerResult.moduleKind) + '): ' + testCaseFileName, getBaselineFolder(compilerResult.moduleKind) + testCaseJustName + '.errors.txt', () => { - return getErrorsBaseline(compilerResult); + it('Resolution information of (' + moduleNameToString(moduleKind) + '): ' + testCaseFileName, () => { + Harness.Baseline.runBaseline('Resolution information of (' + moduleNameToString(compilerResult.moduleKind) + '): ' + testCaseFileName, getBaselineFolder(compilerResult.moduleKind) + testCaseJustName + '.json', () => { + return JSON.stringify(getCompilerResolutionInfo(), undefined, " "); }); - } - }); + }); - it('Baseline of emitted result (' + moduleNameToString(moduleKind) + '): ' + testCaseFileName, () => { - if (testCase.baselineCheck) { - ts.forEach(compilerResult.outputFiles, outputFile => { - - Harness.Baseline.runBaseline('Baseline of emitted result (' + moduleNameToString(compilerResult.moduleKind) + '): ' + testCaseFileName, getBaselineFolder(compilerResult.moduleKind) + outputFile.fileName, () => { - try { - return ts.sys.readFile(getProjectOutputFolder(outputFile.fileName, compilerResult.moduleKind)); - } - catch (e) { - return undefined; - } - }); - }); - } - }); - - - it('SourceMapRecord for (' + moduleNameToString(moduleKind) + '): ' + testCaseFileName, () => { - if (compilerResult.sourceMapData) { - Harness.Baseline.runBaseline('SourceMapRecord for (' + moduleNameToString(compilerResult.moduleKind) + '): ' + testCaseFileName, getBaselineFolder(compilerResult.moduleKind) + testCaseJustName + '.sourcemap.txt', () => { - return Harness.SourceMapRecoder.getSourceMapRecord(compilerResult.sourceMapData, compilerResult.program, - ts.filter(compilerResult.outputFiles, outputFile => Harness.Compiler.isJS(outputFile.emittedFileName))); - }); - } - }); - - // Verify that all the generated .d.ts files compile - - it('Errors in generated Dts files for (' + moduleNameToString(moduleKind) + '): ' + testCaseFileName, () => { - if (!compilerResult.errors.length && testCase.declaration) { - var dTsCompileResult = compileCompileDTsFiles(compilerResult); - if (dTsCompileResult.errors.length) { - Harness.Baseline.runBaseline('Errors in generated Dts files for (' + moduleNameToString(compilerResult.moduleKind) + '): ' + testCaseFileName, getBaselineFolder(compilerResult.moduleKind) + testCaseJustName + '.dts.errors.txt', () => { - return getErrorsBaseline(dTsCompileResult); + it('Errors for (' + moduleNameToString(moduleKind) + '): ' + testCaseFileName, () => { + if (compilerResult.errors.length) { + Harness.Baseline.runBaseline('Errors for (' + moduleNameToString(compilerResult.moduleKind) + '): ' + testCaseFileName, getBaselineFolder(compilerResult.moduleKind) + testCaseJustName + '.errors.txt', () => { + return getErrorsBaseline(compilerResult); }); } - } - }); + }); + + + it('Baseline of emitted result (' + moduleNameToString(moduleKind) + '): ' + testCaseFileName, () => { + if (testCase.baselineCheck) { + ts.forEach(compilerResult.outputFiles, outputFile => { + + Harness.Baseline.runBaseline('Baseline of emitted result (' + moduleNameToString(compilerResult.moduleKind) + '): ' + testCaseFileName, getBaselineFolder(compilerResult.moduleKind) + outputFile.fileName, () => { + try { + return ts.sys.readFile(getProjectOutputFolder(outputFile.fileName, compilerResult.moduleKind)); + } + catch (e) { + return undefined; + } + }); + }); + } + }); + + + it('SourceMapRecord for (' + moduleNameToString(moduleKind) + '): ' + testCaseFileName, () => { + if (compilerResult.sourceMapData) { + Harness.Baseline.runBaseline('SourceMapRecord for (' + moduleNameToString(compilerResult.moduleKind) + '): ' + testCaseFileName, getBaselineFolder(compilerResult.moduleKind) + testCaseJustName + '.sourcemap.txt', () => { + return Harness.SourceMapRecoder.getSourceMapRecord(compilerResult.sourceMapData, compilerResult.program, + ts.filter(compilerResult.outputFiles, outputFile => Harness.Compiler.isJS(outputFile.emittedFileName))); + }); + } + }); + + // Verify that all the generated .d.ts files compile + + it('Errors in generated Dts files for (' + moduleNameToString(moduleKind) + '): ' + testCaseFileName, () => { + if (!compilerResult.errors.length && testCase.declaration) { + var dTsCompileResult = compileCompileDTsFiles(compilerResult); + if (dTsCompileResult.errors.length) { + Harness.Baseline.runBaseline('Errors in generated Dts files for (' + moduleNameToString(compilerResult.moduleKind) + '): ' + testCaseFileName, getBaselineFolder(compilerResult.moduleKind) + testCaseJustName + '.dts.errors.txt', () => { + return getErrorsBaseline(dTsCompileResult); + }); + } + } + }); + after(() => { + compilerResult = undefined; + }); + } + + verifyCompilerResults(ts.ModuleKind.CommonJS); + verifyCompilerResults(ts.ModuleKind.AMD); + after(() => { - compilerResult = undefined; + // Mocha holds onto the closure environment of the describe callback even after the test is done. + // Therefore we have to clean out large objects after the test is done. + testCase = undefined; + testFileText = undefined; + testCaseJustName = undefined; }); - } - - verifyCompilerResults(ts.ModuleKind.CommonJS); - verifyCompilerResults(ts.ModuleKind.AMD); - - after(() => { - // Mocha holds onto the closure environment of the describe callback even after the test is done. - // Therefore we have to clean out large objects after the test is done. - testCase = undefined; - testFileText = undefined; - testCaseJustName = undefined; }); }); } -} \ No newline at end of file +} From 4627f9c69ba79c7ace9dd0c706ed865df4f997dd Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Fri, 10 Jul 2015 11:42:22 -0700 Subject: [PATCH 08/30] Updated Error Message --- src/compiler/checker.ts | 2 +- src/compiler/diagnosticInformationMap.generated.ts | 2 +- src/compiler/diagnosticMessages.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e1826901399..feb76446e1a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4881,7 +4881,7 @@ namespace ts { if(sourceReturnDecl && sourceReturnDecl.flags & NodeFlags.Abstract && (!targetReturnDecl || !(targetReturnDecl.flags & NodeFlags.Abstract))) { if(reportErrors) { - reportError(Diagnostics.Constructor_objects_of_abstract_type_cannot_be_assigned_to_constructor_objects_of_non_abstract_type); + reportError(Diagnostics.Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type); } return Ternary.False; } diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index fbac2f44fb5..a0a95d47c8c 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -407,7 +407,7 @@ namespace ts { Classes_containing_abstract_methods_must_be_marked_abstract: { code: 2514, category: DiagnosticCategory.Error, key: "Classes containing abstract methods must be marked abstract." }, Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2: { code: 2515, category: DiagnosticCategory.Error, key: "Non-abstract class '{0}' does not implement inherited abstract member '{1}' from class '{2}'." }, All_declarations_of_an_abstract_method_must_be_consecutive: { code: 2516, category: DiagnosticCategory.Error, key: "All declarations of an abstract method must be consecutive." }, - Constructor_objects_of_abstract_type_cannot_be_assigned_to_constructor_objects_of_non_abstract_type: { code: 2517, category: DiagnosticCategory.Error, key: "Constructor objects of abstract type cannot be assigned to constructor objects of non-abstract type." }, + Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type: { code: 2517, category: DiagnosticCategory.Error, key: "Cannot assign an abstract constructor type to a non-abstract constructor type." }, Only_an_ambient_class_can_be_merged_with_an_interface: { code: 2518, category: DiagnosticCategory.Error, key: "Only an ambient class can be merged with an interface." }, Duplicate_identifier_0_Compiler_uses_declaration_1_to_support_async_functions: { code: 2520, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'. Compiler uses declaration '{1}' to support async functions." }, Expression_resolves_to_variable_declaration_0_that_compiler_uses_to_support_async_functions: { code: 2521, category: DiagnosticCategory.Error, key: "Expression resolves to variable declaration '{0}' that compiler uses to support async functions." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 4c9fbe2d49c..acf4e74ae9f 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1617,7 +1617,7 @@ "category": "Error", "code": 2516 }, - "Constructor objects of abstract type cannot be assigned to constructor objects of non-abstract type.": { + "Cannot assign an abstract constructor type to a non-abstract constructor type.": { "category": "Error", "code":2517 }, From 84326e6ef62541a0750465c859fa6339fa303171 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Fri, 10 Jul 2015 11:47:56 -0700 Subject: [PATCH 09/30] Updated Baselines --- .../classAbstractClinterfaceAssignability.errors.txt | 4 ++-- .../reference/classAbstractInstantiations2.errors.txt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/baselines/reference/classAbstractClinterfaceAssignability.errors.txt b/tests/baselines/reference/classAbstractClinterfaceAssignability.errors.txt index 17d08981d3e..d9462f28a22 100644 --- a/tests/baselines/reference/classAbstractClinterfaceAssignability.errors.txt +++ b/tests/baselines/reference/classAbstractClinterfaceAssignability.errors.txt @@ -1,5 +1,5 @@ tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractClinterfaceAssignability.ts(23,1): error TS2322: Type 'typeof A' is not assignable to type 'IConstructor'. - Constructor objects of abstract type cannot be assigned to constructor objects of non-abstract type. + Cannot assign an abstract constructor type to a non-abstract constructor type. ==== tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractClinterfaceAssignability.ts (1 errors) ==== @@ -28,4 +28,4 @@ tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbst AAA = A; ~~~ !!! error TS2322: Type 'typeof A' is not assignable to type 'IConstructor'. -!!! error TS2322: Constructor objects of abstract type cannot be assigned to constructor objects of non-abstract type. \ No newline at end of file +!!! error TS2322: Cannot assign an abstract constructor type to a non-abstract constructor type. \ No newline at end of file diff --git a/tests/baselines/reference/classAbstractInstantiations2.errors.txt b/tests/baselines/reference/classAbstractInstantiations2.errors.txt index 43dfb9e009f..077f87c5050 100644 --- a/tests/baselines/reference/classAbstractInstantiations2.errors.txt +++ b/tests/baselines/reference/classAbstractInstantiations2.errors.txt @@ -1,6 +1,6 @@ tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations2.ts(10,1): error TS2511: Cannot create an instance of the abstract class 'B'. tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations2.ts(13,5): error TS2322: Type 'typeof B' is not assignable to type 'typeof A'. - Constructor objects of abstract type cannot be assigned to constructor objects of non-abstract type. + Cannot assign an abstract constructor type to a non-abstract constructor type. tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations2.ts(17,5): error TS2511: Cannot create an instance of the abstract class 'B'. tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations2.ts(21,1): error TS2511: Cannot create an instance of the abstract class 'B'. tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations2.ts(26,7): error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'bar' from class 'B'. @@ -27,7 +27,7 @@ tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbst var AA: typeof A = BB; // error, AA is not of abstract type. ~~ !!! error TS2322: Type 'typeof B' is not assignable to type 'typeof A'. -!!! error TS2322: Constructor objects of abstract type cannot be assigned to constructor objects of non-abstract type. +!!! error TS2322: Cannot assign an abstract constructor type to a non-abstract constructor type. new AA; function constructB(Factory : typeof B) { From dc854158ab50efe69609b2f24c119219872ca71b Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Fri, 10 Jul 2015 11:48:09 -0700 Subject: [PATCH 10/30] Made check more readable --- src/compiler/checker.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index feb76446e1a..58f858e4d6d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4875,17 +4875,19 @@ namespace ts { let targetReturnType = getReturnTypeOfSignature(target); if (targetReturnType === voidType) return result; let sourceReturnType = getReturnTypeOfSignature(source); - - let targetReturnDecl = targetReturnType.symbol && getDeclarationOfKind(targetReturnType.symbol, SyntaxKind.ClassDeclaration); + let sourceReturnDecl = sourceReturnType.symbol && getDeclarationOfKind(sourceReturnType.symbol, SyntaxKind.ClassDeclaration); - - if(sourceReturnDecl && sourceReturnDecl.flags & NodeFlags.Abstract && (!targetReturnDecl || !(targetReturnDecl.flags & NodeFlags.Abstract))) { - if(reportErrors) { + let targetReturnDecl = targetReturnType.symbol && getDeclarationOfKind(targetReturnType.symbol, SyntaxKind.ClassDeclaration); + let sourceIsAbstract = sourceReturnDecl && sourceReturnDecl.flags & NodeFlags.Abstract; + let targetIsAbstract = targetReturnDecl && targetReturnDecl.flags & NodeFlags.Abstract; + + if (sourceIsAbstract && !targetIsAbstract) { + if (reportErrors) { reportError(Diagnostics.Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type); } return Ternary.False; } - + return result & isRelatedTo(sourceReturnType, targetReturnType, reportErrors); } From 4842501ecb6dddea0c84ed7101da28f3768524fc Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Fri, 10 Jul 2015 13:44:59 -0700 Subject: [PATCH 11/30] Move assignability test outside inner loop --- src/compiler/checker.ts | 42 ++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 58f858e4d6d..dd944b51fe5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4766,9 +4766,37 @@ namespace ts { outer: for (let t of targetSignatures) { if (!t.hasStringLiterals || target.flags & TypeFlags.FromSignature) { let localErrors = reportErrors; + let checkedAbstractAssignability = false; for (let s of sourceSignatures) { if (!s.hasStringLiterals || source.flags & TypeFlags.FromSignature) { - let related = signatureRelatedTo(s, t, localErrors); + let related = Ternary.True; + + // Because the "abstractness" of a class is the same across all construct signatures + // (internally we are checking the corresponding declaration), it is enough to perform + // the check and report an error once over all pairs of source and target construct signatures. + if (!checkedAbstractAssignability) { + checkedAbstractAssignability = true; + + let sourceErasedSignature = getErasedSignature(s); + let targetErasedSignature = getErasedSignature(t); + + let sourceReturnType = sourceErasedSignature && getReturnTypeOfSignature(sourceErasedSignature); + let targetReturnType = targetErasedSignature && getReturnTypeOfSignature(targetErasedSignature); + + let sourceReturnDecl = sourceReturnType && sourceReturnType.symbol && getDeclarationOfKind(sourceReturnType.symbol, SyntaxKind.ClassDeclaration); + let targetReturnDecl = targetReturnType && targetReturnType.symbol && getDeclarationOfKind(targetReturnType.symbol, SyntaxKind.ClassDeclaration); + let sourceIsAbstract = sourceReturnDecl && sourceReturnDecl.flags & NodeFlags.Abstract; + let targetIsAbstract = targetReturnDecl && targetReturnDecl.flags & NodeFlags.Abstract; + + if (sourceIsAbstract && !targetIsAbstract) { + if (reportErrors) { + reportError(Diagnostics.Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type); + } + related = Ternary.False; + } + } + + related &= signatureRelatedTo(s, t, localErrors); if (related) { result &= related; errorInfo = saveErrorInfo; @@ -4876,18 +4904,6 @@ namespace ts { if (targetReturnType === voidType) return result; let sourceReturnType = getReturnTypeOfSignature(source); - let sourceReturnDecl = sourceReturnType.symbol && getDeclarationOfKind(sourceReturnType.symbol, SyntaxKind.ClassDeclaration); - let targetReturnDecl = targetReturnType.symbol && getDeclarationOfKind(targetReturnType.symbol, SyntaxKind.ClassDeclaration); - let sourceIsAbstract = sourceReturnDecl && sourceReturnDecl.flags & NodeFlags.Abstract; - let targetIsAbstract = targetReturnDecl && targetReturnDecl.flags & NodeFlags.Abstract; - - if (sourceIsAbstract && !targetIsAbstract) { - if (reportErrors) { - reportError(Diagnostics.Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type); - } - return Ternary.False; - } - return result & isRelatedTo(sourceReturnType, targetReturnType, reportErrors); } From e6cf92066452e63eb1df2abdffea9daae1276b02 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Fri, 10 Jul 2015 13:47:50 -0700 Subject: [PATCH 12/30] separated tests for readability --- .../classAbstractConstructorAssignability.ts | 14 +++++++++++ .../classAbstractExtends.ts | 16 +++++++++++++ .../classAbstractFactoryFunction.ts | 17 ++++++++++++++ .../classAbstractInstantiations1.ts | 4 ++++ .../classAbstractMethodInNonAbstractClass.ts | 7 ++++++ .../classAbstractOverrideWithAbstract.ts | 23 +++++++++++++++++++ 6 files changed, 81 insertions(+) create mode 100644 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractConstructorAssignability.ts create mode 100644 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractExtends.ts create mode 100644 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractFactoryFunction.ts create mode 100644 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMethodInNonAbstractClass.ts create mode 100644 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractOverrideWithAbstract.ts diff --git a/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractConstructorAssignability.ts b/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractConstructorAssignability.ts new file mode 100644 index 00000000000..ecef21cc12a --- /dev/null +++ b/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractConstructorAssignability.ts @@ -0,0 +1,14 @@ + +class A {} + +abstract class B extends A {} + +class C extends B {} + +var AA : typeof A = B; +var BB : typeof B = A; +var CC : typeof C = B; + +new AA; +new BB; +new CC; \ No newline at end of file diff --git a/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractExtends.ts b/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractExtends.ts new file mode 100644 index 00000000000..0aa57b75835 --- /dev/null +++ b/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractExtends.ts @@ -0,0 +1,16 @@ + +class A { + foo() {} +} + +abstract class B extends A { + abstract bar(); +} + +class C extends B { } + +abstract class D extends B {} + +class E extends B { + bar() {} +} \ No newline at end of file diff --git a/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractFactoryFunction.ts b/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractFactoryFunction.ts new file mode 100644 index 00000000000..73d33a34e12 --- /dev/null +++ b/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractFactoryFunction.ts @@ -0,0 +1,17 @@ + +class A {} +abstract class B extends A {} + +function NewA(Factory: typeof A) { + return new A; +} + +function NewB(Factory: typeof B) { + return new B; +} + +NewA(A); +NewA(B); + +NewB(A); +NewB(B); \ No newline at end of file diff --git a/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations1.ts b/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations1.ts index 4daf27b53e4..c805a993a68 100644 --- a/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations1.ts +++ b/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations1.ts @@ -1,4 +1,8 @@ +// +// Calling new with (non)abstract classes. +// + abstract class A {} class B extends A {} diff --git a/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMethodInNonAbstractClass.ts b/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMethodInNonAbstractClass.ts new file mode 100644 index 00000000000..98a2091bc0c --- /dev/null +++ b/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMethodInNonAbstractClass.ts @@ -0,0 +1,7 @@ +class A { + abstract foo(); +} + +class B { + abstract foo() {} +} \ No newline at end of file diff --git a/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractOverrideWithAbstract.ts b/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractOverrideWithAbstract.ts new file mode 100644 index 00000000000..7e02dbd4d98 --- /dev/null +++ b/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractOverrideWithAbstract.ts @@ -0,0 +1,23 @@ +class A { + foo() {} +} + +abstract class B extends A { + abstract foo(); +} + +abstract class AA { + foo() {} + abstract bar(); +} + +abstract class BB extends AA { + abstract foo(); + bar () {} +} + +class CC extends BB {} // error + +class DD extends BB { + foo() {} +} \ No newline at end of file From 35d2592a510adc8781d3db816cbd71750fb8085e Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Fri, 10 Jul 2015 13:51:16 -0700 Subject: [PATCH 13/30] Updated Baselines --- ...bstractConstructorAssignability.errors.txt | 30 ++++++++ .../classAbstractConstructorAssignability.js | 47 ++++++++++++ .../reference/classAbstractExtends.errors.txt | 22 ++++++ .../reference/classAbstractExtends.js | 59 +++++++++++++++ .../classAbstractFactoryFunction.errors.txt | 28 +++++++ .../reference/classAbstractFactoryFunction.js | 47 ++++++++++++ .../classAbstractInstantiations1.errors.txt | 10 ++- .../reference/classAbstractInstantiations1.js | 7 ++ ...bstractMethodInNonAbstractClass.errors.txt | 19 +++++ .../classAbstractMethodInNonAbstractClass.js | 21 ++++++ ...assAbstractOverrideWithAbstract.errors.txt | 29 ++++++++ .../classAbstractOverrideWithAbstract.js | 73 +++++++++++++++++++ 12 files changed, 389 insertions(+), 3 deletions(-) create mode 100644 tests/baselines/reference/classAbstractConstructorAssignability.errors.txt create mode 100644 tests/baselines/reference/classAbstractConstructorAssignability.js create mode 100644 tests/baselines/reference/classAbstractExtends.errors.txt create mode 100644 tests/baselines/reference/classAbstractExtends.js create mode 100644 tests/baselines/reference/classAbstractFactoryFunction.errors.txt create mode 100644 tests/baselines/reference/classAbstractFactoryFunction.js create mode 100644 tests/baselines/reference/classAbstractMethodInNonAbstractClass.errors.txt create mode 100644 tests/baselines/reference/classAbstractMethodInNonAbstractClass.js create mode 100644 tests/baselines/reference/classAbstractOverrideWithAbstract.errors.txt create mode 100644 tests/baselines/reference/classAbstractOverrideWithAbstract.js diff --git a/tests/baselines/reference/classAbstractConstructorAssignability.errors.txt b/tests/baselines/reference/classAbstractConstructorAssignability.errors.txt new file mode 100644 index 00000000000..a3e9e077914 --- /dev/null +++ b/tests/baselines/reference/classAbstractConstructorAssignability.errors.txt @@ -0,0 +1,30 @@ +tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractConstructorAssignability.ts(8,5): error TS2322: Type 'typeof B' is not assignable to type 'typeof A'. + Cannot assign an abstract constructor type to a non-abstract constructor type. +tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractConstructorAssignability.ts(10,5): error TS2322: Type 'typeof B' is not assignable to type 'typeof C'. + Cannot assign an abstract constructor type to a non-abstract constructor type. +tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractConstructorAssignability.ts(13,1): error TS2511: Cannot create an instance of the abstract class 'B'. + + +==== tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractConstructorAssignability.ts (3 errors) ==== + + class A {} + + abstract class B extends A {} + + class C extends B {} + + var AA : typeof A = B; + ~~ +!!! error TS2322: Type 'typeof B' is not assignable to type 'typeof A'. +!!! error TS2322: Cannot assign an abstract constructor type to a non-abstract constructor type. + var BB : typeof B = A; + var CC : typeof C = B; + ~~ +!!! error TS2322: Type 'typeof B' is not assignable to type 'typeof C'. +!!! error TS2322: Cannot assign an abstract constructor type to a non-abstract constructor type. + + new AA; + new BB; + ~~~~~~ +!!! error TS2511: Cannot create an instance of the abstract class 'B'. + new CC; \ No newline at end of file diff --git a/tests/baselines/reference/classAbstractConstructorAssignability.js b/tests/baselines/reference/classAbstractConstructorAssignability.js new file mode 100644 index 00000000000..04357a44554 --- /dev/null +++ b/tests/baselines/reference/classAbstractConstructorAssignability.js @@ -0,0 +1,47 @@ +//// [classAbstractConstructorAssignability.ts] + +class A {} + +abstract class B extends A {} + +class C extends B {} + +var AA : typeof A = B; +var BB : typeof B = A; +var CC : typeof C = B; + +new AA; +new BB; +new CC; + +//// [classAbstractConstructorAssignability.js] +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +var A = (function () { + function A() { + } + return A; +})(); +var B = (function (_super) { + __extends(B, _super); + function B() { + _super.apply(this, arguments); + } + return B; +})(A); +var C = (function (_super) { + __extends(C, _super); + function C() { + _super.apply(this, arguments); + } + return C; +})(B); +var AA = B; +var BB = A; +var CC = B; +new AA; +new BB; +new CC; diff --git a/tests/baselines/reference/classAbstractExtends.errors.txt b/tests/baselines/reference/classAbstractExtends.errors.txt new file mode 100644 index 00000000000..550067cd0e1 --- /dev/null +++ b/tests/baselines/reference/classAbstractExtends.errors.txt @@ -0,0 +1,22 @@ +tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractExtends.ts(10,7): error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'bar' from class 'B'. + + +==== tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractExtends.ts (1 errors) ==== + + class A { + foo() {} + } + + abstract class B extends A { + abstract bar(); + } + + class C extends B { } + ~ +!!! error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'bar' from class 'B'. + + abstract class D extends B {} + + class E extends B { + bar() {} + } \ No newline at end of file diff --git a/tests/baselines/reference/classAbstractExtends.js b/tests/baselines/reference/classAbstractExtends.js new file mode 100644 index 00000000000..58e49de2c77 --- /dev/null +++ b/tests/baselines/reference/classAbstractExtends.js @@ -0,0 +1,59 @@ +//// [classAbstractExtends.ts] + +class A { + foo() {} +} + +abstract class B extends A { + abstract bar(); +} + +class C extends B { } + +abstract class D extends B {} + +class E extends B { + bar() {} +} + +//// [classAbstractExtends.js] +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +var A = (function () { + function A() { + } + A.prototype.foo = function () { }; + return A; +})(); +var B = (function (_super) { + __extends(B, _super); + function B() { + _super.apply(this, arguments); + } + return B; +})(A); +var C = (function (_super) { + __extends(C, _super); + function C() { + _super.apply(this, arguments); + } + return C; +})(B); +var D = (function (_super) { + __extends(D, _super); + function D() { + _super.apply(this, arguments); + } + return D; +})(B); +var E = (function (_super) { + __extends(E, _super); + function E() { + _super.apply(this, arguments); + } + E.prototype.bar = function () { }; + return E; +})(B); diff --git a/tests/baselines/reference/classAbstractFactoryFunction.errors.txt b/tests/baselines/reference/classAbstractFactoryFunction.errors.txt new file mode 100644 index 00000000000..f1b43adae59 --- /dev/null +++ b/tests/baselines/reference/classAbstractFactoryFunction.errors.txt @@ -0,0 +1,28 @@ +tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractFactoryFunction.ts(10,12): error TS2511: Cannot create an instance of the abstract class 'B'. +tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractFactoryFunction.ts(14,6): error TS2345: Argument of type 'typeof B' is not assignable to parameter of type 'typeof A'. + Cannot assign an abstract constructor type to a non-abstract constructor type. + + +==== tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractFactoryFunction.ts (2 errors) ==== + + class A {} + abstract class B extends A {} + + function NewA(Factory: typeof A) { + return new A; + } + + function NewB(Factory: typeof B) { + return new B; + ~~~~~ +!!! error TS2511: Cannot create an instance of the abstract class 'B'. + } + + NewA(A); + NewA(B); + ~ +!!! error TS2345: Argument of type 'typeof B' is not assignable to parameter of type 'typeof A'. +!!! error TS2345: Cannot assign an abstract constructor type to a non-abstract constructor type. + + NewB(A); + NewB(B); \ No newline at end of file diff --git a/tests/baselines/reference/classAbstractFactoryFunction.js b/tests/baselines/reference/classAbstractFactoryFunction.js new file mode 100644 index 00000000000..b1d89ba385d --- /dev/null +++ b/tests/baselines/reference/classAbstractFactoryFunction.js @@ -0,0 +1,47 @@ +//// [classAbstractFactoryFunction.ts] + +class A {} +abstract class B extends A {} + +function NewA(Factory: typeof A) { + return new A; +} + +function NewB(Factory: typeof B) { + return new B; +} + +NewA(A); +NewA(B); + +NewB(A); +NewB(B); + +//// [classAbstractFactoryFunction.js] +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +var A = (function () { + function A() { + } + return A; +})(); +var B = (function (_super) { + __extends(B, _super); + function B() { + _super.apply(this, arguments); + } + return B; +})(A); +function NewA(Factory) { + return new A; +} +function NewB(Factory) { + return new B; +} +NewA(A); +NewA(B); +NewB(A); +NewB(B); diff --git a/tests/baselines/reference/classAbstractInstantiations1.errors.txt b/tests/baselines/reference/classAbstractInstantiations1.errors.txt index 6171ef2efab..24a969fc6b8 100644 --- a/tests/baselines/reference/classAbstractInstantiations1.errors.txt +++ b/tests/baselines/reference/classAbstractInstantiations1.errors.txt @@ -1,10 +1,14 @@ -tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations1.ts(8,1): error TS2511: Cannot create an instance of the abstract class 'A'. -tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations1.ts(9,1): error TS2511: Cannot create an instance of the abstract class 'A'. -tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations1.ts(11,1): error TS2511: Cannot create an instance of the abstract class 'C'. +tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations1.ts(12,1): error TS2511: Cannot create an instance of the abstract class 'A'. +tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations1.ts(13,1): error TS2511: Cannot create an instance of the abstract class 'A'. +tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations1.ts(15,1): error TS2511: Cannot create an instance of the abstract class 'C'. ==== tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations1.ts (3 errors) ==== + // + // Calling new with (non)abstract classes. + // + abstract class A {} class B extends A {} diff --git a/tests/baselines/reference/classAbstractInstantiations1.js b/tests/baselines/reference/classAbstractInstantiations1.js index f3a0eecada9..689a78f1a06 100644 --- a/tests/baselines/reference/classAbstractInstantiations1.js +++ b/tests/baselines/reference/classAbstractInstantiations1.js @@ -1,5 +1,9 @@ //// [classAbstractInstantiations1.ts] +// +// Calling new with (non)abstract classes. +// + abstract class A {} class B extends A {} @@ -21,6 +25,9 @@ c = new B; //// [classAbstractInstantiations1.js] +// +// Calling new with (non)abstract classes. +// var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } diff --git a/tests/baselines/reference/classAbstractMethodInNonAbstractClass.errors.txt b/tests/baselines/reference/classAbstractMethodInNonAbstractClass.errors.txt new file mode 100644 index 00000000000..d6f9b7540d4 --- /dev/null +++ b/tests/baselines/reference/classAbstractMethodInNonAbstractClass.errors.txt @@ -0,0 +1,19 @@ +tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMethodInNonAbstractClass.ts(2,5): error TS1244: Abstract methods can only appear within an abstract class. +tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMethodInNonAbstractClass.ts(6,5): error TS1244: Abstract methods can only appear within an abstract class. +tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMethodInNonAbstractClass.ts(6,5): error TS1245: Method 'foo' cannot have an implementation because it is marked abstract. + + +==== tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMethodInNonAbstractClass.ts (3 errors) ==== + class A { + abstract foo(); + ~~~~~~~~ +!!! error TS1244: Abstract methods can only appear within an abstract class. + } + + class B { + abstract foo() {} + ~~~~~~~~ +!!! error TS1244: Abstract methods can only appear within an abstract class. + ~~~~~~~~~~~~~~~~~ +!!! error TS1245: Method 'foo' cannot have an implementation because it is marked abstract. + } \ No newline at end of file diff --git a/tests/baselines/reference/classAbstractMethodInNonAbstractClass.js b/tests/baselines/reference/classAbstractMethodInNonAbstractClass.js new file mode 100644 index 00000000000..6a38440cf41 --- /dev/null +++ b/tests/baselines/reference/classAbstractMethodInNonAbstractClass.js @@ -0,0 +1,21 @@ +//// [classAbstractMethodInNonAbstractClass.ts] +class A { + abstract foo(); +} + +class B { + abstract foo() {} +} + +//// [classAbstractMethodInNonAbstractClass.js] +var A = (function () { + function A() { + } + return A; +})(); +var B = (function () { + function B() { + } + B.prototype.foo = function () { }; + return B; +})(); diff --git a/tests/baselines/reference/classAbstractOverrideWithAbstract.errors.txt b/tests/baselines/reference/classAbstractOverrideWithAbstract.errors.txt new file mode 100644 index 00000000000..d9d073a07e0 --- /dev/null +++ b/tests/baselines/reference/classAbstractOverrideWithAbstract.errors.txt @@ -0,0 +1,29 @@ +tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractOverrideWithAbstract.ts(19,7): error TS2515: Non-abstract class 'CC' does not implement inherited abstract member 'foo' from class 'BB'. + + +==== tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractOverrideWithAbstract.ts (1 errors) ==== + class A { + foo() {} + } + + abstract class B extends A { + abstract foo(); + } + + abstract class AA { + foo() {} + abstract bar(); + } + + abstract class BB extends AA { + abstract foo(); + bar () {} + } + + class CC extends BB {} // error + ~~ +!!! error TS2515: Non-abstract class 'CC' does not implement inherited abstract member 'foo' from class 'BB'. + + class DD extends BB { + foo() {} + } \ No newline at end of file diff --git a/tests/baselines/reference/classAbstractOverrideWithAbstract.js b/tests/baselines/reference/classAbstractOverrideWithAbstract.js new file mode 100644 index 00000000000..fb03192f35e --- /dev/null +++ b/tests/baselines/reference/classAbstractOverrideWithAbstract.js @@ -0,0 +1,73 @@ +//// [classAbstractOverrideWithAbstract.ts] +class A { + foo() {} +} + +abstract class B extends A { + abstract foo(); +} + +abstract class AA { + foo() {} + abstract bar(); +} + +abstract class BB extends AA { + abstract foo(); + bar () {} +} + +class CC extends BB {} // error + +class DD extends BB { + foo() {} +} + +//// [classAbstractOverrideWithAbstract.js] +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +var A = (function () { + function A() { + } + A.prototype.foo = function () { }; + return A; +})(); +var B = (function (_super) { + __extends(B, _super); + function B() { + _super.apply(this, arguments); + } + return B; +})(A); +var AA = (function () { + function AA() { + } + AA.prototype.foo = function () { }; + return AA; +})(); +var BB = (function (_super) { + __extends(BB, _super); + function BB() { + _super.apply(this, arguments); + } + BB.prototype.bar = function () { }; + return BB; +})(AA); +var CC = (function (_super) { + __extends(CC, _super); + function CC() { + _super.apply(this, arguments); + } + return CC; +})(BB); // error +var DD = (function (_super) { + __extends(DD, _super); + function DD() { + _super.apply(this, arguments); + } + DD.prototype.foo = function () { }; + return DD; +})(BB); From 99d640f0f0bafd029ff09d56a19766babd7d57f1 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Fri, 10 Jul 2015 17:53:55 -0700 Subject: [PATCH 14/30] Actually move check outside the loop --- src/compiler/checker.ts | 51 +++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index dd944b51fe5..cdaf268fdf3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4763,40 +4763,35 @@ namespace ts { let targetSignatures = getSignaturesOfType(target, kind); let result = Ternary.True; let saveErrorInfo = errorInfo; + + // Because the "abstractness" of a class is the same across all construct signatures + // (internally we are checking the corresponding declaration), it is enough to perform + // the check and report an error once over all pairs of source and target construct signatures. + let sourceErasedSignature = getErasedSignature(s); + let targetErasedSignature = getErasedSignature(t); + + let sourceReturnType = sourceErasedSignature && getReturnTypeOfSignature(sourceErasedSignature); + let targetReturnType = targetErasedSignature && getReturnTypeOfSignature(targetErasedSignature); + + let sourceReturnDecl = sourceReturnType && sourceReturnType.symbol && getDeclarationOfKind(sourceReturnType.symbol, SyntaxKind.ClassDeclaration); + let targetReturnDecl = targetReturnType && targetReturnType.symbol && getDeclarationOfKind(targetReturnType.symbol, SyntaxKind.ClassDeclaration); + let sourceIsAbstract = sourceReturnDecl && sourceReturnDecl.flags & NodeFlags.Abstract; + let targetIsAbstract = targetReturnDecl && targetReturnDecl.flags & NodeFlags.Abstract; + + if (sourceIsAbstract && !targetIsAbstract) { + if (reportErrors) { + reportError(Diagnostics.Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type); + } + result = Ternary.False; + } + outer: for (let t of targetSignatures) { if (!t.hasStringLiterals || target.flags & TypeFlags.FromSignature) { let localErrors = reportErrors; let checkedAbstractAssignability = false; for (let s of sourceSignatures) { if (!s.hasStringLiterals || source.flags & TypeFlags.FromSignature) { - let related = Ternary.True; - - // Because the "abstractness" of a class is the same across all construct signatures - // (internally we are checking the corresponding declaration), it is enough to perform - // the check and report an error once over all pairs of source and target construct signatures. - if (!checkedAbstractAssignability) { - checkedAbstractAssignability = true; - - let sourceErasedSignature = getErasedSignature(s); - let targetErasedSignature = getErasedSignature(t); - - let sourceReturnType = sourceErasedSignature && getReturnTypeOfSignature(sourceErasedSignature); - let targetReturnType = targetErasedSignature && getReturnTypeOfSignature(targetErasedSignature); - - let sourceReturnDecl = sourceReturnType && sourceReturnType.symbol && getDeclarationOfKind(sourceReturnType.symbol, SyntaxKind.ClassDeclaration); - let targetReturnDecl = targetReturnType && targetReturnType.symbol && getDeclarationOfKind(targetReturnType.symbol, SyntaxKind.ClassDeclaration); - let sourceIsAbstract = sourceReturnDecl && sourceReturnDecl.flags & NodeFlags.Abstract; - let targetIsAbstract = targetReturnDecl && targetReturnDecl.flags & NodeFlags.Abstract; - - if (sourceIsAbstract && !targetIsAbstract) { - if (reportErrors) { - reportError(Diagnostics.Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type); - } - related = Ternary.False; - } - } - - related &= signatureRelatedTo(s, t, localErrors); + let related = signatureRelatedTo(s, t, localErrors); if (related) { result &= related; errorInfo = saveErrorInfo; From 2f15958d32fa51d46f87dc155892770d27abb0fe Mon Sep 17 00:00:00 2001 From: Dan Quirk Date: Fri, 10 Jul 2015 18:08:19 -0700 Subject: [PATCH 15/30] Use new mocha-fivemat-progress-reporter by default instead of dot reporter --- Jakefile.js | 2 +- package.json | 3 ++- src/harness/compilerRunner.ts | 12 +++++++----- src/harness/fourslashRunner.ts | 2 +- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Jakefile.js b/Jakefile.js index 517f5e862d5..1c6dfa25e7b 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -562,7 +562,7 @@ task("runtests", ["tests", builtLocalDirectory], function() { colors = process.env.colors || process.env.color colors = colors ? ' --no-colors ' : ' --colors '; tests = tests ? ' -g ' + tests : ''; - reporter = process.env.reporter || process.env.r || 'dot'; + reporter = process.env.reporter || process.env.r || 'mocha-fivemat-progress-reporter'; // timeout normally isn't necessary but Travis-CI has been timing out on compiler baselines occasionally // default timeout is 2sec which really should be enough, but maybe we just need a small amount longer var cmd = host + " -R " + reporter + tests + colors + ' -t ' + testTimeout + ' ' + run; diff --git a/package.json b/package.json index d6a8f538b78..9349efbd0ac 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,8 @@ "mocha": "latest", "chai": "latest", "browserify": "latest", - "istanbul": "latest" + "istanbul": "latest", + "mocha-fivemat-progress-reporter": "latest" }, "scripts": { "test": "jake runtests" diff --git a/src/harness/compilerRunner.ts b/src/harness/compilerRunner.ts index 1c8dccc6173..39d4b053956 100644 --- a/src/harness/compilerRunner.ts +++ b/src/harness/compilerRunner.ts @@ -10,6 +10,7 @@ const enum CompilerTestType { class CompilerBaselineRunner extends RunnerBase { private basePath = 'tests/cases'; + private testSuiteName: string; private errors: boolean; private emit: boolean; private decl: boolean; @@ -24,16 +25,17 @@ class CompilerBaselineRunner extends RunnerBase { this.decl = true; this.output = true; if (testType === CompilerTestType.Conformance) { - this.basePath += '/conformance'; + this.testSuiteName = 'conformance'; } else if (testType === CompilerTestType.Regressions) { - this.basePath += '/compiler'; + this.testSuiteName = 'compiler'; } else if (testType === CompilerTestType.Test262) { - this.basePath += '/test262'; + this.testSuiteName = 'test262'; } else { - this.basePath += '/compiler'; // default to this for historical reasons + this.testSuiteName = 'compiler'; // default to this for historical reasons } + this.basePath += '/' + this.testSuiteName; } public checkTestCodeOutput(fileName: string) { @@ -384,7 +386,7 @@ class CompilerBaselineRunner extends RunnerBase { } public initializeTests() { - describe('Compiler tests', () => { + describe(this.testSuiteName + ' tests', () => { describe("Setup compiler for compiler baselines", () => { var harnessCompiler = Harness.Compiler.getCompiler(); this.parseOptions(); diff --git a/src/harness/fourslashRunner.ts b/src/harness/fourslashRunner.ts index 9287f7361a5..37d55974612 100644 --- a/src/harness/fourslashRunner.ts +++ b/src/harness/fourslashRunner.ts @@ -35,7 +35,7 @@ class FourSlashRunner extends RunnerBase { this.tests = this.enumerateFiles(this.basePath, /\.ts/i, { recursive: false }); } - describe('Fourslash tests', () => { + describe(this.testSuiteName + ' tests', () => { this.tests.forEach((fn: string) => { describe(fn, () => { fn = ts.normalizeSlashes(fn); From 59be264be521e154c4a97fa1d5365083c1f00c19 Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Fri, 10 Jul 2015 18:16:51 -0700 Subject: [PATCH 16/30] Take the apparent type of the source in type argument inference --- src/compiler/checker.ts | 47 ++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index dd5e42e0f4c..ae44585fc5b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5508,30 +5508,33 @@ namespace ts { inferFromTypes(sourceType, target); } } - else if (source.flags & TypeFlags.ObjectType && (target.flags & (TypeFlags.Reference | TypeFlags.Tuple) || - (target.flags & TypeFlags.Anonymous) && target.symbol && target.symbol.flags & (SymbolFlags.Method | SymbolFlags.TypeLiteral | SymbolFlags.Class))) { - // If source is an object type, and target is a type reference, a tuple type, the type of a method, or a type literal, infer from members - if (isInProcess(source, target)) { - return; - } - if (isDeeplyNestedGeneric(source, sourceStack, depth) && isDeeplyNestedGeneric(target, targetStack, depth)) { - return; - } + else { + source = getApparentType(source); + if (source.flags & TypeFlags.ObjectType && (target.flags & (TypeFlags.Reference | TypeFlags.Tuple) || + (target.flags & TypeFlags.Anonymous) && target.symbol && target.symbol.flags & (SymbolFlags.Method | SymbolFlags.TypeLiteral | SymbolFlags.Class))) { + // If source is an object type, and target is a type reference, a tuple type, the type of a method, or a type literal, infer from members + if (isInProcess(source, target)) { + return; + } + if (isDeeplyNestedGeneric(source, sourceStack, depth) && isDeeplyNestedGeneric(target, targetStack, depth)) { + return; + } - if (depth === 0) { - sourceStack = []; - targetStack = []; + if (depth === 0) { + sourceStack = []; + targetStack = []; + } + sourceStack[depth] = source; + targetStack[depth] = target; + depth++; + inferFromProperties(source, target); + inferFromSignatures(source, target, SignatureKind.Call); + inferFromSignatures(source, target, SignatureKind.Construct); + inferFromIndexTypes(source, target, IndexKind.String, IndexKind.String); + inferFromIndexTypes(source, target, IndexKind.Number, IndexKind.Number); + inferFromIndexTypes(source, target, IndexKind.String, IndexKind.Number); + depth--; } - sourceStack[depth] = source; - targetStack[depth] = target; - depth++; - inferFromProperties(source, target); - inferFromSignatures(source, target, SignatureKind.Call); - inferFromSignatures(source, target, SignatureKind.Construct); - inferFromIndexTypes(source, target, IndexKind.String, IndexKind.String); - inferFromIndexTypes(source, target, IndexKind.Number, IndexKind.Number); - inferFromIndexTypes(source, target, IndexKind.String, IndexKind.Number); - depth--; } } From 72ef479ddd98731f3423f2acfd0db83103317148 Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Fri, 10 Jul 2015 18:16:59 -0700 Subject: [PATCH 17/30] Add tests --- .../typeArgumentInferenceApparentType1.js | 12 ++++++++ ...typeArgumentInferenceApparentType1.symbols | 16 +++++++++++ .../typeArgumentInferenceApparentType1.types | 18 ++++++++++++ .../typeArgumentInferenceApparentType2.js | 17 +++++++++++ ...typeArgumentInferenceApparentType2.symbols | 27 ++++++++++++++++++ .../typeArgumentInferenceApparentType2.types | 28 +++++++++++++++++++ .../typeArgumentInferenceApparentType1.ts | 6 ++++ .../typeArgumentInferenceApparentType2.ts | 8 ++++++ 8 files changed, 132 insertions(+) create mode 100644 tests/baselines/reference/typeArgumentInferenceApparentType1.js create mode 100644 tests/baselines/reference/typeArgumentInferenceApparentType1.symbols create mode 100644 tests/baselines/reference/typeArgumentInferenceApparentType1.types create mode 100644 tests/baselines/reference/typeArgumentInferenceApparentType2.js create mode 100644 tests/baselines/reference/typeArgumentInferenceApparentType2.symbols create mode 100644 tests/baselines/reference/typeArgumentInferenceApparentType2.types create mode 100644 tests/cases/compiler/typeArgumentInferenceApparentType1.ts create mode 100644 tests/cases/compiler/typeArgumentInferenceApparentType2.ts diff --git a/tests/baselines/reference/typeArgumentInferenceApparentType1.js b/tests/baselines/reference/typeArgumentInferenceApparentType1.js new file mode 100644 index 00000000000..7a4f1ea19f5 --- /dev/null +++ b/tests/baselines/reference/typeArgumentInferenceApparentType1.js @@ -0,0 +1,12 @@ +//// [typeArgumentInferenceApparentType1.ts] +function method(iterable: Iterable): T { + return; +} + +var res: string = method("test"); + +//// [typeArgumentInferenceApparentType1.js] +function method(iterable) { + return; +} +var res = method("test"); diff --git a/tests/baselines/reference/typeArgumentInferenceApparentType1.symbols b/tests/baselines/reference/typeArgumentInferenceApparentType1.symbols new file mode 100644 index 00000000000..abcb8fdfc68 --- /dev/null +++ b/tests/baselines/reference/typeArgumentInferenceApparentType1.symbols @@ -0,0 +1,16 @@ +=== tests/cases/compiler/typeArgumentInferenceApparentType1.ts === +function method(iterable: Iterable): T { +>method : Symbol(method, Decl(typeArgumentInferenceApparentType1.ts, 0, 0)) +>T : Symbol(T, Decl(typeArgumentInferenceApparentType1.ts, 0, 16)) +>iterable : Symbol(iterable, Decl(typeArgumentInferenceApparentType1.ts, 0, 19)) +>Iterable : Symbol(Iterable, Decl(lib.d.ts, 1681, 1)) +>T : Symbol(T, Decl(typeArgumentInferenceApparentType1.ts, 0, 16)) +>T : Symbol(T, Decl(typeArgumentInferenceApparentType1.ts, 0, 16)) + + return; +} + +var res: string = method("test"); +>res : Symbol(res, Decl(typeArgumentInferenceApparentType1.ts, 4, 3)) +>method : Symbol(method, Decl(typeArgumentInferenceApparentType1.ts, 0, 0)) + diff --git a/tests/baselines/reference/typeArgumentInferenceApparentType1.types b/tests/baselines/reference/typeArgumentInferenceApparentType1.types new file mode 100644 index 00000000000..29fd1aeca18 --- /dev/null +++ b/tests/baselines/reference/typeArgumentInferenceApparentType1.types @@ -0,0 +1,18 @@ +=== tests/cases/compiler/typeArgumentInferenceApparentType1.ts === +function method(iterable: Iterable): T { +>method : (iterable: Iterable) => T +>T : T +>iterable : Iterable +>Iterable : Iterable +>T : T +>T : T + + return; +} + +var res: string = method("test"); +>res : string +>method("test") : string +>method : (iterable: Iterable) => T +>"test" : string + diff --git a/tests/baselines/reference/typeArgumentInferenceApparentType2.js b/tests/baselines/reference/typeArgumentInferenceApparentType2.js new file mode 100644 index 00000000000..cf9f3bca00e --- /dev/null +++ b/tests/baselines/reference/typeArgumentInferenceApparentType2.js @@ -0,0 +1,17 @@ +//// [typeArgumentInferenceApparentType2.ts] +function method(iterable: Iterable): T { + function inner>() { + var u: U; + var res: T = method(u); + } + return; +} + +//// [typeArgumentInferenceApparentType2.js] +function method(iterable) { + function inner() { + var u; + var res = method(u); + } + return; +} diff --git a/tests/baselines/reference/typeArgumentInferenceApparentType2.symbols b/tests/baselines/reference/typeArgumentInferenceApparentType2.symbols new file mode 100644 index 00000000000..86cf8e7cdcd --- /dev/null +++ b/tests/baselines/reference/typeArgumentInferenceApparentType2.symbols @@ -0,0 +1,27 @@ +=== tests/cases/compiler/typeArgumentInferenceApparentType2.ts === +function method(iterable: Iterable): T { +>method : Symbol(method, Decl(typeArgumentInferenceApparentType2.ts, 0, 0)) +>T : Symbol(T, Decl(typeArgumentInferenceApparentType2.ts, 0, 16)) +>iterable : Symbol(iterable, Decl(typeArgumentInferenceApparentType2.ts, 0, 19)) +>Iterable : Symbol(Iterable, Decl(lib.d.ts, 1681, 1)) +>T : Symbol(T, Decl(typeArgumentInferenceApparentType2.ts, 0, 16)) +>T : Symbol(T, Decl(typeArgumentInferenceApparentType2.ts, 0, 16)) + + function inner>() { +>inner : Symbol(inner, Decl(typeArgumentInferenceApparentType2.ts, 0, 46)) +>U : Symbol(U, Decl(typeArgumentInferenceApparentType2.ts, 1, 19)) +>Iterable : Symbol(Iterable, Decl(lib.d.ts, 1681, 1)) +>T : Symbol(T, Decl(typeArgumentInferenceApparentType2.ts, 0, 16)) + + var u: U; +>u : Symbol(u, Decl(typeArgumentInferenceApparentType2.ts, 2, 11)) +>U : Symbol(U, Decl(typeArgumentInferenceApparentType2.ts, 1, 19)) + + var res: T = method(u); +>res : Symbol(res, Decl(typeArgumentInferenceApparentType2.ts, 3, 11)) +>T : Symbol(T, Decl(typeArgumentInferenceApparentType2.ts, 0, 16)) +>method : Symbol(method, Decl(typeArgumentInferenceApparentType2.ts, 0, 0)) +>u : Symbol(u, Decl(typeArgumentInferenceApparentType2.ts, 2, 11)) + } + return; +} diff --git a/tests/baselines/reference/typeArgumentInferenceApparentType2.types b/tests/baselines/reference/typeArgumentInferenceApparentType2.types new file mode 100644 index 00000000000..6a0e6ae6454 --- /dev/null +++ b/tests/baselines/reference/typeArgumentInferenceApparentType2.types @@ -0,0 +1,28 @@ +=== tests/cases/compiler/typeArgumentInferenceApparentType2.ts === +function method(iterable: Iterable): T { +>method : (iterable: Iterable) => T +>T : T +>iterable : Iterable +>Iterable : Iterable +>T : T +>T : T + + function inner>() { +>inner : >() => void +>U : U +>Iterable : Iterable +>T : T + + var u: U; +>u : U +>U : U + + var res: T = method(u); +>res : T +>T : T +>method(u) : T +>method : (iterable: Iterable) => T +>u : U + } + return; +} diff --git a/tests/cases/compiler/typeArgumentInferenceApparentType1.ts b/tests/cases/compiler/typeArgumentInferenceApparentType1.ts new file mode 100644 index 00000000000..4cc4a0dd4e5 --- /dev/null +++ b/tests/cases/compiler/typeArgumentInferenceApparentType1.ts @@ -0,0 +1,6 @@ +//@target: ES6 +function method(iterable: Iterable): T { + return; +} + +var res: string = method("test"); \ No newline at end of file diff --git a/tests/cases/compiler/typeArgumentInferenceApparentType2.ts b/tests/cases/compiler/typeArgumentInferenceApparentType2.ts new file mode 100644 index 00000000000..88ae4df8c4c --- /dev/null +++ b/tests/cases/compiler/typeArgumentInferenceApparentType2.ts @@ -0,0 +1,8 @@ +//@target: ES6 +function method(iterable: Iterable): T { + function inner>() { + var u: U; + var res: T = method(u); + } + return; +} \ No newline at end of file From 50f254b2d26fc24761d58617d65638ce60f1bf1f Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Fri, 10 Jul 2015 18:38:04 -0700 Subject: [PATCH 18/30] Fixed Testing --- src/compiler/checker.ts | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cdaf268fdf3..2bef37ad52c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4763,26 +4763,32 @@ namespace ts { let targetSignatures = getSignaturesOfType(target, kind); let result = Ternary.True; let saveErrorInfo = errorInfo; - + // Because the "abstractness" of a class is the same across all construct signatures // (internally we are checking the corresponding declaration), it is enough to perform // the check and report an error once over all pairs of source and target construct signatures. - let sourceErasedSignature = getErasedSignature(s); - let targetErasedSignature = getErasedSignature(t); + let sourceSig = sourceSignatures[0]; + // Note that in an extends-clause, targetSignatures is stripped, so the check never proceeds. + let targetSig = targetSignatures[0]; - let sourceReturnType = sourceErasedSignature && getReturnTypeOfSignature(sourceErasedSignature); - let targetReturnType = targetErasedSignature && getReturnTypeOfSignature(targetErasedSignature); + if (sourceSig && targetSig) { + let sourceErasedSignature = getErasedSignature(sourceSig); + let targetErasedSignature = getErasedSignature(targetSig); - let sourceReturnDecl = sourceReturnType && sourceReturnType.symbol && getDeclarationOfKind(sourceReturnType.symbol, SyntaxKind.ClassDeclaration); - let targetReturnDecl = targetReturnType && targetReturnType.symbol && getDeclarationOfKind(targetReturnType.symbol, SyntaxKind.ClassDeclaration); - let sourceIsAbstract = sourceReturnDecl && sourceReturnDecl.flags & NodeFlags.Abstract; - let targetIsAbstract = targetReturnDecl && targetReturnDecl.flags & NodeFlags.Abstract; + let sourceReturnType = sourceErasedSignature && getReturnTypeOfSignature(sourceErasedSignature); + let targetReturnType = targetErasedSignature && getReturnTypeOfSignature(targetErasedSignature); - if (sourceIsAbstract && !targetIsAbstract) { - if (reportErrors) { - reportError(Diagnostics.Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type); + let sourceReturnDecl = sourceReturnType && sourceReturnType.symbol && getDeclarationOfKind(sourceReturnType.symbol, SyntaxKind.ClassDeclaration); + let targetReturnDecl = targetReturnType && targetReturnType.symbol && getDeclarationOfKind(targetReturnType.symbol, SyntaxKind.ClassDeclaration); + let sourceIsAbstract = sourceReturnDecl && sourceReturnDecl.flags & NodeFlags.Abstract; + let targetIsAbstract = targetReturnDecl && targetReturnDecl.flags & NodeFlags.Abstract; + + if (sourceIsAbstract && !targetIsAbstract) { + if (reportErrors) { + reportError(Diagnostics.Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type); + } + return Ternary.False; } - result = Ternary.False; } outer: for (let t of targetSignatures) { From 6dcc9fcf655e30b65cd4a88974d766926b0fda4c Mon Sep 17 00:00:00 2001 From: Dick van den Brink Date: Mon, 13 Jul 2015 22:13:11 +0200 Subject: [PATCH 19/30] Don't fall through to the modifier check for get/set keywords --- src/services/services.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/services/services.ts b/src/services/services.ts index 10e38f98613..c85c10dc411 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -4546,6 +4546,7 @@ namespace ts { if (hasKind(node.parent, SyntaxKind.GetAccessor) || hasKind(node.parent, SyntaxKind.SetAccessor)) { return getGetAndSetOccurrences(node.parent); } + break; default: if (isModifier(node.kind) && node.parent && (isDeclaration(node.parent) || node.parent.kind === SyntaxKind.VariableStatement)) { From b33a35b1224a8a377007f4081d0408771d2081f7 Mon Sep 17 00:00:00 2001 From: Dick van den Brink Date: Mon, 13 Jul 2015 23:38:10 +0200 Subject: [PATCH 20/30] Highlight abstract keywords on classes and members --- src/services/services.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/services/services.ts b/src/services/services.ts index 10e38f98613..64f9a6bc14d 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -4694,6 +4694,10 @@ namespace ts { if (!(container.kind === SyntaxKind.ModuleBlock || container.kind === SyntaxKind.SourceFile)) { return undefined; } + } else if (modifier === SyntaxKind.AbstractKeyword) { + if (!(container.kind === SyntaxKind.ClassDeclaration || declaration.kind === SyntaxKind.ClassDeclaration)) { + return undefined; + } } else { // unsupported modifier @@ -4707,7 +4711,13 @@ namespace ts { switch (container.kind) { case SyntaxKind.ModuleBlock: case SyntaxKind.SourceFile: - nodes = (container).statements; + // Container is either a class declaration or the declaration is a classDeclaration + if (modifierFlag & NodeFlags.Abstract) { + nodes = ((declaration).members).concat(declaration); + } + else { + nodes = (container).statements; + } break; case SyntaxKind.Constructor: nodes = ((container).parameters).concat( @@ -4727,6 +4737,9 @@ namespace ts { nodes = nodes.concat(constructor.parameters); } } + else if (modifierFlag & NodeFlags.Abstract) { + nodes = nodes.concat(container); + } break; default: Debug.fail("Invalid container kind.") @@ -4754,6 +4767,8 @@ namespace ts { return NodeFlags.Export; case SyntaxKind.DeclareKeyword: return NodeFlags.Ambient; + case SyntaxKind.AbstractKeyword: + return NodeFlags.Abstract; default: Debug.fail(); } From 758abffd19c67d6f47e1b652415d9ed15403e556 Mon Sep 17 00:00:00 2001 From: Dick van den Brink Date: Tue, 14 Jul 2015 00:02:20 +0200 Subject: [PATCH 21/30] Added test for occurrences on abstract keyword --- .../cases/fourslash/getOccurrencesAbstract.ts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/cases/fourslash/getOccurrencesAbstract.ts diff --git a/tests/cases/fourslash/getOccurrencesAbstract.ts b/tests/cases/fourslash/getOccurrencesAbstract.ts new file mode 100644 index 00000000000..47252dd6f3b --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesAbstract.ts @@ -0,0 +1,20 @@ +/// + +////[|abstract|] class Animal { +//// [|abstract|] walk(): void; +//// [|abstract|] makeSound(): void; +////} +////// Abstract class below should not get highlighted +////abstract class Foo { +//// abstract foo(): void; +//// abstract bar(): void; +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + verify.occurrencesAtPositionCount(test.ranges().length); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); From fc47329ed2f12c55ee62345639fc1985d420697b Mon Sep 17 00:00:00 2001 From: Dick van den Brink Date: Tue, 14 Jul 2015 00:43:16 +0200 Subject: [PATCH 22/30] PR feedback for abstract keyword occurrences --- src/services/services.ts | 3 ++- tests/cases/fourslash/getOccurrencesAbstract.ts | 14 ++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 64f9a6bc14d..0d4099b9b47 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -4694,7 +4694,8 @@ namespace ts { if (!(container.kind === SyntaxKind.ModuleBlock || container.kind === SyntaxKind.SourceFile)) { return undefined; } - } else if (modifier === SyntaxKind.AbstractKeyword) { + } + else if (modifier === SyntaxKind.AbstractKeyword) { if (!(container.kind === SyntaxKind.ClassDeclaration || declaration.kind === SyntaxKind.ClassDeclaration)) { return undefined; } diff --git a/tests/cases/fourslash/getOccurrencesAbstract.ts b/tests/cases/fourslash/getOccurrencesAbstract.ts index 47252dd6f3b..8746cf1b489 100644 --- a/tests/cases/fourslash/getOccurrencesAbstract.ts +++ b/tests/cases/fourslash/getOccurrencesAbstract.ts @@ -10,11 +10,13 @@ //// abstract bar(): void; ////} -test.ranges().forEach(r => { - goTo.position(r.start); - verify.occurrencesAtPositionCount(test.ranges().length); +const ranges = test.ranges(); - test.ranges().forEach(range => { +for(let r of ranges) { + goTo.position(r.start); + verify.occurrencesAtPositionCount(ranges.length); + + for(let range of ranges) { verify.occurrencesAtPositionContains(range, false); - }); -}); + } +} From 2718539588b425fe743bd40adaa7c22527c2eda2 Mon Sep 17 00:00:00 2001 From: Dick van den Brink Date: Tue, 14 Jul 2015 01:39:39 +0200 Subject: [PATCH 23/30] Added more test cases for highlighting abstract keyword --- ...bstract.ts => getOccurrencesAbstract01.ts} | 6 ++-- .../fourslash/getOccurrencesAbstract02.ts | 29 +++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) rename tests/cases/fourslash/{getOccurrencesAbstract.ts => getOccurrencesAbstract01.ts} (74%) create mode 100644 tests/cases/fourslash/getOccurrencesAbstract02.ts diff --git a/tests/cases/fourslash/getOccurrencesAbstract.ts b/tests/cases/fourslash/getOccurrencesAbstract01.ts similarity index 74% rename from tests/cases/fourslash/getOccurrencesAbstract.ts rename to tests/cases/fourslash/getOccurrencesAbstract01.ts index 8746cf1b489..3e48ba4841a 100644 --- a/tests/cases/fourslash/getOccurrencesAbstract.ts +++ b/tests/cases/fourslash/getOccurrencesAbstract01.ts @@ -1,6 +1,8 @@ /// ////[|abstract|] class Animal { +//// [|abstract|] prop1; // Does not compile +//// [|abstract|] abstract(); //// [|abstract|] walk(): void; //// [|abstract|] makeSound(): void; ////} @@ -12,11 +14,11 @@ const ranges = test.ranges(); -for(let r of ranges) { +for (let r of ranges) { goTo.position(r.start); verify.occurrencesAtPositionCount(ranges.length); - for(let range of ranges) { + for (let range of ranges) { verify.occurrencesAtPositionContains(range, false); } } diff --git a/tests/cases/fourslash/getOccurrencesAbstract02.ts b/tests/cases/fourslash/getOccurrencesAbstract02.ts new file mode 100644 index 00000000000..8daafdbdc8e --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesAbstract02.ts @@ -0,0 +1,29 @@ +/// + +////// Not valid TS (abstract methods can only appear in abstract classes) +////class Animal { +//// [|abstract|] walk(): void; +//// [|abstract|] makeSound(): void; +////} +////// abstract cannot appear here, won't get highlighted +////let c = /*1*/abstract class Foo { +//// /*2*/abstract foo(): void; +//// abstract bar(): void; +////} + +const ranges = test.ranges(); + +for (let r of ranges) { + goTo.position(r.start); + verify.occurrencesAtPositionCount(ranges.length); + + for (let range of ranges) { + verify.occurrencesAtPositionContains(range, false); + } +} + +goTo.marker("1"); +verify.occurrencesAtPositionCount(0); + +goTo.marker("2"); +verify.occurrencesAtPositionCount(2); From 96c1b9c3585fd204681772f32e8ce7bb36eff882 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 13 Jul 2015 16:44:07 -0700 Subject: [PATCH 24/30] Classify Identifiers as 'Identifier', not 'Text'. --- src/services/services.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/services.ts b/src/services/services.ts index 10e38f98613..0a20cabd1c9 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -6574,7 +6574,7 @@ namespace ts { } } - return ClassificationType.text; + return ClassificationType.identifier; } } From 9c7d1211a7fddf9f3f9ac0484037024d0671634a Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 13 Jul 2015 16:57:11 -0700 Subject: [PATCH 25/30] Update tests. --- .../syntacticClassificationWithErrors.ts | 4 ++-- .../fourslash/syntacticClassifications1.ts | 4 ++-- ...syntacticClassificationsConflictMarkers1.ts | 4 ++-- ...syntacticClassificationsConflictMarkers2.ts | 2 +- .../syntacticClassificationsDocComment1.ts | 2 +- .../syntacticClassificationsDocComment2.ts | 4 ++-- .../syntacticClassificationsDocComment3.ts | 2 +- .../syntacticClassificationsForOfKeyword.ts | 4 ++-- .../syntacticClassificationsForOfKeyword2.ts | 4 ++-- .../syntacticClassificationsForOfKeyword3.ts | 6 +++--- ...acticClassificationsFunctionWithComments.ts | 4 ++-- .../syntacticClassificationsObjectLiteral.ts | 18 +++++++++--------- .../syntacticClassificationsTemplates1.ts | 8 ++++---- .../syntacticClassificationsTemplates2.ts | 2 +- 14 files changed, 34 insertions(+), 34 deletions(-) diff --git a/tests/cases/fourslash/syntacticClassificationWithErrors.ts b/tests/cases/fourslash/syntacticClassificationWithErrors.ts index b4572d3e620..166a22a1a51 100644 --- a/tests/cases/fourslash/syntacticClassificationWithErrors.ts +++ b/tests/cases/fourslash/syntacticClassificationWithErrors.ts @@ -8,7 +8,7 @@ let c = classification verify.syntacticClassificationsAre( c.keyword("class"), c.className("A"), c.punctuation("{"), - c.text("a"), c.punctuation(":"), + c.identifier("a"), c.punctuation(":"), c.punctuation("}"), - c.text("c"), c.operator("=") + c.identifier("c"), c.operator("=") ); \ No newline at end of file diff --git a/tests/cases/fourslash/syntacticClassifications1.ts b/tests/cases/fourslash/syntacticClassifications1.ts index 88f655683a3..1dbe2944b8a 100644 --- a/tests/cases/fourslash/syntacticClassifications1.ts +++ b/tests/cases/fourslash/syntacticClassifications1.ts @@ -22,8 +22,8 @@ var c = classification; verify.syntacticClassificationsAre( c.comment("// comment"), c.keyword("module"), c.moduleName("M"), c.punctuation("{"), - c.keyword("var"), c.text("v"), c.operator("="), c.numericLiteral("0"), c.operator("+"), c.numericLiteral("1"), c.punctuation(";"), - c.keyword("var"), c.text("s"), c.operator("="), c.stringLiteral('"string"'), c.punctuation(";"), + c.keyword("var"), c.identifier("v"), c.operator("="), c.numericLiteral("0"), c.operator("+"), c.numericLiteral("1"), c.punctuation(";"), + c.keyword("var"), c.identifier("s"), c.operator("="), c.stringLiteral('"string"'), c.punctuation(";"), c.keyword("class"), c.className("C"), c.punctuation("<"), c.typeParameterName("T"), c.punctuation(">"), c.punctuation("{"), c.punctuation("}"), c.keyword("enum"), c.enumName("E"), c.punctuation("{"), diff --git a/tests/cases/fourslash/syntacticClassificationsConflictMarkers1.ts b/tests/cases/fourslash/syntacticClassificationsConflictMarkers1.ts index 7f26038c33e..99db7443a4c 100644 --- a/tests/cases/fourslash/syntacticClassificationsConflictMarkers1.ts +++ b/tests/cases/fourslash/syntacticClassificationsConflictMarkers1.ts @@ -12,8 +12,8 @@ var c = classification; verify.syntacticClassificationsAre( c.keyword("class"), c.className("C"), c.punctuation("{"), c.comment("<<<<<<< HEAD"), - c.text("v"), c.operator("="), c.numericLiteral("1"), c.punctuation(";"), + c.identifier("v"), c.operator("="), c.numericLiteral("1"), c.punctuation(";"), c.comment("======="), - c.text("v"), c.punctuation("="), c.numericLiteral("2"), c.punctuation(";"), + c.identifier("v"), c.punctuation("="), c.numericLiteral("2"), c.punctuation(";"), c.comment(">>>>>>> Branch - a"), c.punctuation("}")); \ No newline at end of file diff --git a/tests/cases/fourslash/syntacticClassificationsConflictMarkers2.ts b/tests/cases/fourslash/syntacticClassificationsConflictMarkers2.ts index 92ede0d104b..18363c0389e 100644 --- a/tests/cases/fourslash/syntacticClassificationsConflictMarkers2.ts +++ b/tests/cases/fourslash/syntacticClassificationsConflictMarkers2.ts @@ -11,5 +11,5 @@ verify.syntacticClassificationsAre( c.comment("<<<<<<< HEAD"), c.keyword("class"), c.className("C"), c.punctuation("{"), c.punctuation("}"), c.comment("======="), - c.keyword("class"), c.text("D"), c.punctuation("{"), c.punctuation("}"), + c.keyword("class"), c.identifier("D"), c.punctuation("{"), c.punctuation("}"), c.comment(">>>>>>> Branch - a")); \ No newline at end of file diff --git a/tests/cases/fourslash/syntacticClassificationsDocComment1.ts b/tests/cases/fourslash/syntacticClassificationsDocComment1.ts index fe812b4c780..1ea3bf9684a 100644 --- a/tests/cases/fourslash/syntacticClassificationsDocComment1.ts +++ b/tests/cases/fourslash/syntacticClassificationsDocComment1.ts @@ -13,5 +13,5 @@ verify.syntacticClassificationsAre( c.punctuation("}"), c.comment(" */"), c.keyword("var"), - c.text("v"), + c.identifier("v"), c.punctuation(";")); diff --git a/tests/cases/fourslash/syntacticClassificationsDocComment2.ts b/tests/cases/fourslash/syntacticClassificationsDocComment2.ts index 201251dde6d..38dca4edcf2 100644 --- a/tests/cases/fourslash/syntacticClassificationsDocComment2.ts +++ b/tests/cases/fourslash/syntacticClassificationsDocComment2.ts @@ -15,12 +15,12 @@ verify.syntacticClassificationsAre( c.punctuation("{"), c.keyword("function"), c.punctuation("("), - c.text("x"), + c.identifier("x"), c.punctuation(")"), c.punctuation(":"), c.keyword("string"), c.punctuation("}"), c.comment(" */"), c.keyword("var"), - c.text("v"), + c.identifier("v"), c.punctuation(";")); diff --git a/tests/cases/fourslash/syntacticClassificationsDocComment3.ts b/tests/cases/fourslash/syntacticClassificationsDocComment3.ts index 6aca8cc415f..d7996fbbc54 100644 --- a/tests/cases/fourslash/syntacticClassificationsDocComment3.ts +++ b/tests/cases/fourslash/syntacticClassificationsDocComment3.ts @@ -15,5 +15,5 @@ verify.syntacticClassificationsAre( c.keyword("number"), c.comment(" /* } */"), c.keyword("var"), - c.text("v"), + c.identifier("v"), c.punctuation(";")); diff --git a/tests/cases/fourslash/syntacticClassificationsForOfKeyword.ts b/tests/cases/fourslash/syntacticClassificationsForOfKeyword.ts index a7a8c704ce6..22d7aa8ba94 100644 --- a/tests/cases/fourslash/syntacticClassificationsForOfKeyword.ts +++ b/tests/cases/fourslash/syntacticClassificationsForOfKeyword.ts @@ -7,9 +7,9 @@ verify.syntacticClassificationsAre( c.keyword("for"), c.punctuation("("), c.keyword("var"), - c.text("of"), + c.identifier("of"), c.keyword("of"), - c.text("of"), + c.identifier("of"), c.punctuation(")"), c.punctuation("{"), c.punctuation("}") diff --git a/tests/cases/fourslash/syntacticClassificationsForOfKeyword2.ts b/tests/cases/fourslash/syntacticClassificationsForOfKeyword2.ts index 30cfaea51e0..190663caa99 100644 --- a/tests/cases/fourslash/syntacticClassificationsForOfKeyword2.ts +++ b/tests/cases/fourslash/syntacticClassificationsForOfKeyword2.ts @@ -7,9 +7,9 @@ verify.syntacticClassificationsAre( c.keyword("for"), c.punctuation("("), c.keyword("var"), - c.text("of"), + c.identifier("of"), c.keyword("in"), - c.text("of"), + c.identifier("of"), c.punctuation(")"), c.punctuation("{"), c.punctuation("}") diff --git a/tests/cases/fourslash/syntacticClassificationsForOfKeyword3.ts b/tests/cases/fourslash/syntacticClassificationsForOfKeyword3.ts index 3af4733f3b2..ef96c99fed4 100644 --- a/tests/cases/fourslash/syntacticClassificationsForOfKeyword3.ts +++ b/tests/cases/fourslash/syntacticClassificationsForOfKeyword3.ts @@ -7,11 +7,11 @@ verify.syntacticClassificationsAre( c.keyword("for"), c.punctuation("("), c.keyword("var"), - c.text("of"), + c.identifier("of"), c.punctuation(";"), - c.text("of"), + c.identifier("of"), c.punctuation(";"), - c.text("of"), + c.identifier("of"), c.punctuation(")"), c.punctuation("{"), c.punctuation("}") diff --git a/tests/cases/fourslash/syntacticClassificationsFunctionWithComments.ts b/tests/cases/fourslash/syntacticClassificationsFunctionWithComments.ts index f7e5b7355a7..05a5aaa173e 100644 --- a/tests/cases/fourslash/syntacticClassificationsFunctionWithComments.ts +++ b/tests/cases/fourslash/syntacticClassificationsFunctionWithComments.ts @@ -19,7 +19,7 @@ var firstCommentText = var c = classification; verify.syntacticClassificationsAre( c.comment(firstCommentText), - c.keyword("function"), c.text("myFunction"), c.punctuation("("), c.comment("/* x */"), c.parameterName("x"), c.punctuation(":"), c.keyword("any"), c.punctuation(")"), c.punctuation("{"), - c.keyword("var"), c.text("y"), c.operator("="), c.text("x"), c.operator("?"), c.text("x"), c.operator("++"), c.operator(":"), c.operator("++"), c.text("x"), c.punctuation(";"), + c.keyword("function"), c.identifier("myFunction"), c.punctuation("("), c.comment("/* x */"), c.parameterName("x"), c.punctuation(":"), c.keyword("any"), c.punctuation(")"), c.punctuation("{"), + c.keyword("var"), c.identifier("y"), c.operator("="), c.identifier("x"), c.operator("?"), c.identifier("x"), c.operator("++"), c.operator(":"), c.operator("++"), c.identifier("x"), c.punctuation(";"), c.punctuation("}"), c.comment("// end of file")); \ No newline at end of file diff --git a/tests/cases/fourslash/syntacticClassificationsObjectLiteral.ts b/tests/cases/fourslash/syntacticClassificationsObjectLiteral.ts index 59642468ce9..c5bab5181a3 100644 --- a/tests/cases/fourslash/syntacticClassificationsObjectLiteral.ts +++ b/tests/cases/fourslash/syntacticClassificationsObjectLiteral.ts @@ -13,13 +13,13 @@ var c = classification; verify.syntacticClassificationsAre( - c.keyword("var"), c.text("v"), c.operator("="), c.numericLiteral("10e0"), c.punctuation(";"), - c.keyword("var"), c.text("x"), c.operator("="), c.punctuation("{"), - c.text("p1"), c.punctuation(":"), c.numericLiteral("1"), c.punctuation(","), - c.text("p2"), c.punctuation(":"), c.numericLiteral("2"), c.punctuation(","), - c.text("any"), c.punctuation(":"), c.numericLiteral("3"), c.punctuation(","), - c.text("function"), c.punctuation(":"), c.numericLiteral("4"), c.punctuation(","), - c.text("var"), c.punctuation(":"), c.numericLiteral("5"), c.punctuation(","), - c.text("void"), c.punctuation(":"), c.keyword("void"), c.numericLiteral("0"), c.punctuation(","), - c.text("v"), c.punctuation(":"), c.text("v"), c.operator("+="), c.text("v"), c.punctuation(","), + c.keyword("var"), c.identifier("v"), c.operator("="), c.numericLiteral("10e0"), c.punctuation(";"), + c.keyword("var"), c.identifier("x"), c.operator("="), c.punctuation("{"), + c.identifier("p1"), c.punctuation(":"), c.numericLiteral("1"), c.punctuation(","), + c.identifier("p2"), c.punctuation(":"), c.numericLiteral("2"), c.punctuation(","), + c.identifier("any"), c.punctuation(":"), c.numericLiteral("3"), c.punctuation(","), + c.identifier("function"), c.punctuation(":"), c.numericLiteral("4"), c.punctuation(","), + c.identifier("var"), c.punctuation(":"), c.numericLiteral("5"), c.punctuation(","), + c.identifier("void"), c.punctuation(":"), c.keyword("void"), c.numericLiteral("0"), c.punctuation(","), + c.identifier("v"), c.punctuation(":"), c.identifier("v"), c.operator("+="), c.identifier("v"), c.punctuation(","), c.punctuation("}"), c.punctuation(";")); \ No newline at end of file diff --git a/tests/cases/fourslash/syntacticClassificationsTemplates1.ts b/tests/cases/fourslash/syntacticClassificationsTemplates1.ts index 8ee48fb8a11..6c27aab3f40 100644 --- a/tests/cases/fourslash/syntacticClassificationsTemplates1.ts +++ b/tests/cases/fourslash/syntacticClassificationsTemplates1.ts @@ -8,8 +8,8 @@ var c = classification; verify.syntacticClassificationsAre( - c.keyword("var"), c.text("v"), c.operator("="), c.numericLiteral("10e0"), c.punctuation(";"), - c.keyword("var"), c.text("x"), c.operator("="), c.punctuation("{"), - c.text("p1"), c.punctuation(":"), c.stringLiteral("`hello world`"), c.punctuation(","), - c.text("p2"), c.punctuation(":"), c.stringLiteral("`goodbye ${"), c.numericLiteral("0"), c.stringLiteral("} cruel ${"), c.numericLiteral("0"), c.stringLiteral("} world`"), c.punctuation(","), + c.keyword("var"), c.identifier("v"), c.operator("="), c.numericLiteral("10e0"), c.punctuation(";"), + c.keyword("var"), c.identifier("x"), c.operator("="), c.punctuation("{"), + c.identifier("p1"), c.punctuation(":"), c.stringLiteral("`hello world`"), c.punctuation(","), + c.identifier("p2"), c.punctuation(":"), c.stringLiteral("`goodbye ${"), c.numericLiteral("0"), c.stringLiteral("} cruel ${"), c.numericLiteral("0"), c.stringLiteral("} world`"), c.punctuation(","), c.punctuation("}"), c.punctuation(";")); \ No newline at end of file diff --git a/tests/cases/fourslash/syntacticClassificationsTemplates2.ts b/tests/cases/fourslash/syntacticClassificationsTemplates2.ts index 913dc039012..25bb64e78ba 100644 --- a/tests/cases/fourslash/syntacticClassificationsTemplates2.ts +++ b/tests/cases/fourslash/syntacticClassificationsTemplates2.ts @@ -6,6 +6,6 @@ var c = classification; verify.syntacticClassificationsAre( - c.keyword("var"), c.text("tiredOfCanonicalExamples"), c.operator("="), + c.keyword("var"), c.identifier("tiredOfCanonicalExamples"), c.operator("="), c.stringLiteral("`goodbye \"${"), c.stringLiteral("`hello world`"), c.stringLiteral("}\" \nand ${"), c.stringLiteral("`good${"), c.stringLiteral("\" \""), c.stringLiteral("}riddance`"), c.stringLiteral("}`"), c.punctuation(";")); \ No newline at end of file From 785097445e7cf141f3d0f42a2322adba6b3d8bbb Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 13 Jul 2015 17:02:55 -0700 Subject: [PATCH 26/30] Update shim tests. --- tests/cases/fourslash/shims/getSyntacticClassifications.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cases/fourslash/shims/getSyntacticClassifications.ts b/tests/cases/fourslash/shims/getSyntacticClassifications.ts index 88f655683a3..1dbe2944b8a 100644 --- a/tests/cases/fourslash/shims/getSyntacticClassifications.ts +++ b/tests/cases/fourslash/shims/getSyntacticClassifications.ts @@ -22,8 +22,8 @@ var c = classification; verify.syntacticClassificationsAre( c.comment("// comment"), c.keyword("module"), c.moduleName("M"), c.punctuation("{"), - c.keyword("var"), c.text("v"), c.operator("="), c.numericLiteral("0"), c.operator("+"), c.numericLiteral("1"), c.punctuation(";"), - c.keyword("var"), c.text("s"), c.operator("="), c.stringLiteral('"string"'), c.punctuation(";"), + c.keyword("var"), c.identifier("v"), c.operator("="), c.numericLiteral("0"), c.operator("+"), c.numericLiteral("1"), c.punctuation(";"), + c.keyword("var"), c.identifier("s"), c.operator("="), c.stringLiteral('"string"'), c.punctuation(";"), c.keyword("class"), c.className("C"), c.punctuation("<"), c.typeParameterName("T"), c.punctuation(">"), c.punctuation("{"), c.punctuation("}"), c.keyword("enum"), c.enumName("E"), c.punctuation("{"), From dfa108f4ec5e2074fe3ef0a26471fa52a5581d1e Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Tue, 14 Jul 2015 11:17:07 -0700 Subject: [PATCH 27/30] Allow tuples to be widened --- src/compiler/checker.ts | 60 +++++++++++++------ .../diagnosticInformationMap.generated.ts | 1 + src/compiler/diagnosticMessages.json | 8 +++ 3 files changed, 50 insertions(+), 19 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index da45c08ab44..5209f02847e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5299,7 +5299,7 @@ namespace ts { * Check if a Type was written as a tuple type literal. * Prefer using isTupleLikeType() unless the use of `elementTypes` is required. */ - function isTupleType(type: Type): boolean { + function isTupleType(type: Type): type is TupleType { return (type.flags & TypeFlags.Tuple) && !!(type).elementTypes; } @@ -5341,37 +5341,53 @@ namespace ts { if (isArrayType(type)) { return createArrayType(getWidenedType((type).typeArguments[0])); } + if (isTupleType(type)) { + return createTupleType(map(type.elementTypes, getWidenedType)); + } } return type; } - function reportWideningErrorsInType(type: Type): boolean { + function reportWideningErrorsInType(type: Type, expression: Expression): boolean { + let errorReported = false; if (type.flags & TypeFlags.Union) { - let errorReported = false; - forEach((type).types, t => { - if (reportWideningErrorsInType(t)) { + for (let t of (type).types) { + if (reportWideningErrorsInType(t, expression)) { errorReported = true; } - }); - return errorReported; + } } if (isArrayType(type)) { - return reportWideningErrorsInType((type).typeArguments[0]); + return reportWideningErrorsInType((type).typeArguments[0], expression); + } + if (isTupleType(type)) { + let { elementTypes } = type; + for (let i = 0; i < elementTypes.length; i++) { + let t = elementTypes[i]; + if (t.flags & TypeFlags.ContainsUndefinedOrNull) { + if (reportWideningErrorsInType(t, expression)) { + errorReported = true; + } + else if (expression.kind === SyntaxKind.ArrayLiteralExpression) { + let element = (expression).elements[i]; + error(element, Diagnostics.Array_element_at_index_0_implicitly_has_an_1_type, i, typeToString(getWidenedType(t))); + errorReported = true; + } + } + } } if (type.flags & TypeFlags.ObjectLiteral) { - let errorReported = false; - forEach(getPropertiesOfObjectType(type), p => { + for (let p of getPropertiesOfObjectType(type)) { let t = getTypeOfSymbol(p); if (t.flags & TypeFlags.ContainsUndefinedOrNull) { - if (!reportWideningErrorsInType(t)) { + if (!reportWideningErrorsInType(t, expression)) { error(p.valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, p.name, typeToString(getWidenedType(t))); } errorReported = true; } - }); - return errorReported; + } } - return false; + return errorReported; } function reportImplicitAnyError(declaration: Declaration, type: Type) { @@ -5409,7 +5425,7 @@ namespace ts { function reportErrorsFromWidening(declaration: Declaration, type: Type) { if (produceDiagnostics && compilerOptions.noImplicitAny && type.flags & TypeFlags.ContainsUndefinedOrNull) { // Report implicit any error within type if possible, otherwise report error on declaration - if (!reportWideningErrorsInType(type)) { + if (!reportWideningErrorsInType(type, declaration.kind === SyntaxKind.VariableDeclaration && (declaration).initializer)) { reportImplicitAnyError(declaration, type); } } @@ -6785,6 +6801,7 @@ namespace ts { let hasSpreadElement = false; let elementTypes: Type[] = []; let inDestructuringPattern = isAssignmentTarget(node); + let typeFlags: TypeFlags; for (let e of elements) { if (inDestructuringPattern && e.kind === SyntaxKind.SpreadElementExpression) { // Given the following situation: @@ -6804,21 +6821,23 @@ namespace ts { (languageVersion >= ScriptTarget.ES6 ? getElementTypeOfIterable(restArrayType, /*errorNode*/ undefined) : undefined); if (restElementType) { elementTypes.push(restElementType); + typeFlags |= restElementType.flags; } } else { let type = checkExpression(e, contextualMapper); elementTypes.push(type); + typeFlags |= type.flags; } hasSpreadElement = hasSpreadElement || e.kind === SyntaxKind.SpreadElementExpression; } if (!hasSpreadElement) { let contextualType = getContextualType(node); if (contextualType && contextualTypeIsTupleLikeType(contextualType) || inDestructuringPattern) { - return createTupleType(elementTypes); + return addTypeFlags(createTupleType(elementTypes), typeFlags & TypeFlags.RequiresWidening); } } - return createArrayType(getUnionType(elementTypes)); + return addTypeFlags(createArrayType(getUnionType(elementTypes)), typeFlags & TypeFlags.RequiresWidening); } function isNumericName(name: DeclarationName): boolean { @@ -6934,8 +6953,7 @@ namespace ts { let stringIndexType = getIndexType(IndexKind.String); let numberIndexType = getIndexType(IndexKind.Number); let result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexType, numberIndexType); - result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | (typeFlags & TypeFlags.ContainsUndefinedOrNull); - return result; + return addTypeFlags(result, TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | (typeFlags & TypeFlags.ContainsUndefinedOrNull)); function getIndexType(kind: IndexKind) { if (contextualType && contextualTypeHasIndexSignature(contextualType, kind)) { @@ -6961,6 +6979,10 @@ namespace ts { } } + function addTypeFlags(type: Type, flags: TypeFlags): Type { + type.flags |= flags; + return type; + } function checkJsxSelfClosingElement(node: JsxSelfClosingElement) { checkJsxOpeningLikeElement(node); diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index a0a95d47c8c..ce28cbbc387 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -589,6 +589,7 @@ namespace ts { Function_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions: { code: 7024, category: DiagnosticCategory.Error, key: "Function implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions." }, Generator_implicitly_has_type_0_because_it_does_not_yield_any_values_Consider_supplying_a_return_type: { code: 7025, category: DiagnosticCategory.Error, key: "Generator implicitly has type '{0}' because it does not yield any values. Consider supplying a return type." }, JSX_element_implicitly_has_type_any_because_no_interface_JSX_0_exists: { code: 7026, category: DiagnosticCategory.Error, key: "JSX element implicitly has type 'any' because no interface 'JSX.{0}' exists" }, + Array_element_at_index_0_implicitly_has_an_1_type: { code: 7027, category: DiagnosticCategory.Error, key: "Array element at index {0} implicitly has an '{1}' type." }, You_cannot_rename_this_element: { code: 8000, category: DiagnosticCategory.Error, key: "You cannot rename this element." }, You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library: { code: 8001, category: DiagnosticCategory.Error, key: "You cannot rename elements that are defined in the standard TypeScript library." }, import_can_only_be_used_in_a_ts_file: { code: 8002, category: DiagnosticCategory.Error, key: "'import ... =' can only be used in a .ts file." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index acf4e74ae9f..65e3bab9ec5 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2347,6 +2347,14 @@ "category": "Error", "code": 7026 }, + "JSX element implicitly has type 'any' because no interface 'JSX.{0}' exists": { + "category": "Error", + "code": 7026 + }, + "Array element at index {0} implicitly has an '{1}' type.": { + "category": "Error", + "code": 7027 + }, "You cannot rename this element.": { From 6954cd2fd72b872c7317cad6e04e34f81f252565 Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Tue, 14 Jul 2015 11:49:50 -0700 Subject: [PATCH 28/30] Add new tests --- tests/cases/conformance/types/tuple/wideningTuples1.ts | 5 +++++ tests/cases/conformance/types/tuple/wideningTuples2.ts | 6 ++++++ tests/cases/conformance/types/tuple/wideningTuples3.ts | 4 ++++ tests/cases/conformance/types/tuple/wideningTuples4.ts | 4 ++++ tests/cases/conformance/types/tuple/wideningTuples5.ts | 2 ++ tests/cases/conformance/types/tuple/wideningTuples6.ts | 3 +++ tests/cases/conformance/types/tuple/wideningTuples7.ts | 5 +++++ 7 files changed, 29 insertions(+) create mode 100644 tests/cases/conformance/types/tuple/wideningTuples1.ts create mode 100644 tests/cases/conformance/types/tuple/wideningTuples2.ts create mode 100644 tests/cases/conformance/types/tuple/wideningTuples3.ts create mode 100644 tests/cases/conformance/types/tuple/wideningTuples4.ts create mode 100644 tests/cases/conformance/types/tuple/wideningTuples5.ts create mode 100644 tests/cases/conformance/types/tuple/wideningTuples6.ts create mode 100644 tests/cases/conformance/types/tuple/wideningTuples7.ts diff --git a/tests/cases/conformance/types/tuple/wideningTuples1.ts b/tests/cases/conformance/types/tuple/wideningTuples1.ts new file mode 100644 index 00000000000..f4885435dcf --- /dev/null +++ b/tests/cases/conformance/types/tuple/wideningTuples1.ts @@ -0,0 +1,5 @@ +//@noImplicitAny: true +declare function foo(x: T): T; + +var y = foo([undefined]); +y = [""]; \ No newline at end of file diff --git a/tests/cases/conformance/types/tuple/wideningTuples2.ts b/tests/cases/conformance/types/tuple/wideningTuples2.ts new file mode 100644 index 00000000000..d8bf1248546 --- /dev/null +++ b/tests/cases/conformance/types/tuple/wideningTuples2.ts @@ -0,0 +1,6 @@ +//@noImplicitAny: true +var foo: () => [any] = function bar() { + let intermediate = bar(); + intermediate = [""]; + return [undefined]; +}; \ No newline at end of file diff --git a/tests/cases/conformance/types/tuple/wideningTuples3.ts b/tests/cases/conformance/types/tuple/wideningTuples3.ts new file mode 100644 index 00000000000..a6837be2a0f --- /dev/null +++ b/tests/cases/conformance/types/tuple/wideningTuples3.ts @@ -0,0 +1,4 @@ +//@noImplicitAny: true +var a: [any]; + +var b = a = [undefined, null]; \ No newline at end of file diff --git a/tests/cases/conformance/types/tuple/wideningTuples4.ts b/tests/cases/conformance/types/tuple/wideningTuples4.ts new file mode 100644 index 00000000000..550ba07f600 --- /dev/null +++ b/tests/cases/conformance/types/tuple/wideningTuples4.ts @@ -0,0 +1,4 @@ +var a: [any]; + +var b = a = [undefined, null]; +b = ["", ""]; \ No newline at end of file diff --git a/tests/cases/conformance/types/tuple/wideningTuples5.ts b/tests/cases/conformance/types/tuple/wideningTuples5.ts new file mode 100644 index 00000000000..36434c6eafe --- /dev/null +++ b/tests/cases/conformance/types/tuple/wideningTuples5.ts @@ -0,0 +1,2 @@ +//@noImplicitAny: true +var [a, b] = [undefined, null]; \ No newline at end of file diff --git a/tests/cases/conformance/types/tuple/wideningTuples6.ts b/tests/cases/conformance/types/tuple/wideningTuples6.ts new file mode 100644 index 00000000000..cac228ecb4d --- /dev/null +++ b/tests/cases/conformance/types/tuple/wideningTuples6.ts @@ -0,0 +1,3 @@ +var [a, b] = [undefined, null]; +a = ""; +b = ""; \ No newline at end of file diff --git a/tests/cases/conformance/types/tuple/wideningTuples7.ts b/tests/cases/conformance/types/tuple/wideningTuples7.ts new file mode 100644 index 00000000000..1a4d212d362 --- /dev/null +++ b/tests/cases/conformance/types/tuple/wideningTuples7.ts @@ -0,0 +1,5 @@ +//@noImplicitAny: true +var foo = function bar() { + let intermediate: [string]; + return intermediate = [undefined]; +}; \ No newline at end of file From 6f94314774c0a2788904caf6966296dea2e7382c Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Tue, 14 Jul 2015 11:50:00 -0700 Subject: [PATCH 29/30] Accept baselines --- ...cturingParameterDeclaration1ES5.errors.txt | 20 +---------------- tests/baselines/reference/wideningTuples1.js | 9 ++++++++ .../reference/wideningTuples1.symbols | 16 ++++++++++++++ .../baselines/reference/wideningTuples1.types | 21 ++++++++++++++++++ tests/baselines/reference/wideningTuples2.js | 13 +++++++++++ .../reference/wideningTuples2.symbols | 16 ++++++++++++++ .../baselines/reference/wideningTuples2.types | 22 +++++++++++++++++++ .../reference/wideningTuples3.errors.txt | 9 ++++++++ tests/baselines/reference/wideningTuples3.js | 8 +++++++ tests/baselines/reference/wideningTuples4.js | 10 +++++++++ .../reference/wideningTuples4.symbols | 12 ++++++++++ .../baselines/reference/wideningTuples4.types | 19 ++++++++++++++++ .../reference/wideningTuples5.errors.txt | 10 +++++++++ tests/baselines/reference/wideningTuples5.js | 5 +++++ tests/baselines/reference/wideningTuples6.js | 9 ++++++++ .../reference/wideningTuples6.symbols | 12 ++++++++++ .../baselines/reference/wideningTuples6.types | 18 +++++++++++++++ .../reference/wideningTuples7.errors.txt | 10 +++++++++ tests/baselines/reference/wideningTuples7.js | 11 ++++++++++ 19 files changed, 231 insertions(+), 19 deletions(-) create mode 100644 tests/baselines/reference/wideningTuples1.js create mode 100644 tests/baselines/reference/wideningTuples1.symbols create mode 100644 tests/baselines/reference/wideningTuples1.types create mode 100644 tests/baselines/reference/wideningTuples2.js create mode 100644 tests/baselines/reference/wideningTuples2.symbols create mode 100644 tests/baselines/reference/wideningTuples2.types create mode 100644 tests/baselines/reference/wideningTuples3.errors.txt create mode 100644 tests/baselines/reference/wideningTuples3.js create mode 100644 tests/baselines/reference/wideningTuples4.js create mode 100644 tests/baselines/reference/wideningTuples4.symbols create mode 100644 tests/baselines/reference/wideningTuples4.types create mode 100644 tests/baselines/reference/wideningTuples5.errors.txt create mode 100644 tests/baselines/reference/wideningTuples5.js create mode 100644 tests/baselines/reference/wideningTuples6.js create mode 100644 tests/baselines/reference/wideningTuples6.symbols create mode 100644 tests/baselines/reference/wideningTuples6.types create mode 100644 tests/baselines/reference/wideningTuples7.errors.txt create mode 100644 tests/baselines/reference/wideningTuples7.js diff --git a/tests/baselines/reference/destructuringParameterDeclaration1ES5.errors.txt b/tests/baselines/reference/destructuringParameterDeclaration1ES5.errors.txt index 269d2b5640d..8e51c2b6111 100644 --- a/tests/baselines/reference/destructuringParameterDeclaration1ES5.errors.txt +++ b/tests/baselines/reference/destructuringParameterDeclaration1ES5.errors.txt @@ -1,16 +1,8 @@ -tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration1ES5.ts(32,4): error TS2345: Argument of type '[string, number, number]' is not assignable to parameter of type '[undefined, null, undefined]'. - Types of property '0' are incompatible. - Type 'string' is not assignable to type 'undefined'. -tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration1ES5.ts(33,4): error TS2345: Argument of type '[[string], number, [[boolean, boolean]]]' is not assignable to parameter of type '[[undefined], undefined, [[undefined, undefined]]]'. - Types of property '0' are incompatible. - Type '[string]' is not assignable to type '[undefined]'. - Types of property '0' are incompatible. - Type 'string' is not assignable to type 'undefined'. tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration1ES5.ts(62,10): error TS2393: Duplicate function implementation. tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration1ES5.ts(63,10): error TS2393: Duplicate function implementation. -==== tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration1ES5.ts (4 errors) ==== +==== tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration1ES5.ts (2 errors) ==== // A parameter declaration may specify either an identifier or a binding pattern. // The identifiers specified in parameter declarations and binding patterns // in a parameter list must be unique within that parameter list. @@ -43,17 +35,7 @@ tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration1ES5. b2("string", { x: 200, y: "string" }); b2("string", { x: 200, y: true }); b6(["string", 1, 2]); // Shouldn't be an error - ~~~~~~~~~~~~~~~~ -!!! error TS2345: Argument of type '[string, number, number]' is not assignable to parameter of type '[undefined, null, undefined]'. -!!! error TS2345: Types of property '0' are incompatible. -!!! error TS2345: Type 'string' is not assignable to type 'undefined'. b7([["string"], 1, [[true, false]]]); // Shouldn't be an error - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2345: Argument of type '[[string], number, [[boolean, boolean]]]' is not assignable to parameter of type '[[undefined], undefined, [[undefined, undefined]]]'. -!!! error TS2345: Types of property '0' are incompatible. -!!! error TS2345: Type '[string]' is not assignable to type '[undefined]'. -!!! error TS2345: Types of property '0' are incompatible. -!!! error TS2345: Type 'string' is not assignable to type 'undefined'. // If the declaration specifies a binding pattern, the parameter type is the implied type of that binding pattern (section 5.1.3) diff --git a/tests/baselines/reference/wideningTuples1.js b/tests/baselines/reference/wideningTuples1.js new file mode 100644 index 00000000000..ed39a735bfe --- /dev/null +++ b/tests/baselines/reference/wideningTuples1.js @@ -0,0 +1,9 @@ +//// [wideningTuples1.ts] +declare function foo(x: T): T; + +var y = foo([undefined]); +y = [""]; + +//// [wideningTuples1.js] +var y = foo([undefined]); +y = [""]; diff --git a/tests/baselines/reference/wideningTuples1.symbols b/tests/baselines/reference/wideningTuples1.symbols new file mode 100644 index 00000000000..819510b7319 --- /dev/null +++ b/tests/baselines/reference/wideningTuples1.symbols @@ -0,0 +1,16 @@ +=== tests/cases/conformance/types/tuple/wideningTuples1.ts === +declare function foo(x: T): T; +>foo : Symbol(foo, Decl(wideningTuples1.ts, 0, 0)) +>T : Symbol(T, Decl(wideningTuples1.ts, 0, 21)) +>x : Symbol(x, Decl(wideningTuples1.ts, 0, 38)) +>T : Symbol(T, Decl(wideningTuples1.ts, 0, 21)) +>T : Symbol(T, Decl(wideningTuples1.ts, 0, 21)) + +var y = foo([undefined]); +>y : Symbol(y, Decl(wideningTuples1.ts, 2, 3)) +>foo : Symbol(foo, Decl(wideningTuples1.ts, 0, 0)) +>undefined : Symbol(undefined) + +y = [""]; +>y : Symbol(y, Decl(wideningTuples1.ts, 2, 3)) + diff --git a/tests/baselines/reference/wideningTuples1.types b/tests/baselines/reference/wideningTuples1.types new file mode 100644 index 00000000000..1fdd4a6cb53 --- /dev/null +++ b/tests/baselines/reference/wideningTuples1.types @@ -0,0 +1,21 @@ +=== tests/cases/conformance/types/tuple/wideningTuples1.ts === +declare function foo(x: T): T; +>foo : (x: T) => T +>T : T +>x : T +>T : T +>T : T + +var y = foo([undefined]); +>y : [any] +>foo([undefined]) : [any] +>foo : (x: T) => T +>[undefined] : [undefined] +>undefined : undefined + +y = [""]; +>y = [""] : [string] +>y : [any] +>[""] : [string] +>"" : string + diff --git a/tests/baselines/reference/wideningTuples2.js b/tests/baselines/reference/wideningTuples2.js new file mode 100644 index 00000000000..fa74e089961 --- /dev/null +++ b/tests/baselines/reference/wideningTuples2.js @@ -0,0 +1,13 @@ +//// [wideningTuples2.ts] +var foo: () => [any] = function bar() { + let intermediate = bar(); + intermediate = [""]; + return [undefined]; +}; + +//// [wideningTuples2.js] +var foo = function bar() { + var intermediate = bar(); + intermediate = [""]; + return [undefined]; +}; diff --git a/tests/baselines/reference/wideningTuples2.symbols b/tests/baselines/reference/wideningTuples2.symbols new file mode 100644 index 00000000000..74186045e90 --- /dev/null +++ b/tests/baselines/reference/wideningTuples2.symbols @@ -0,0 +1,16 @@ +=== tests/cases/conformance/types/tuple/wideningTuples2.ts === +var foo: () => [any] = function bar() { +>foo : Symbol(foo, Decl(wideningTuples2.ts, 0, 3)) +>bar : Symbol(bar, Decl(wideningTuples2.ts, 0, 22)) + + let intermediate = bar(); +>intermediate : Symbol(intermediate, Decl(wideningTuples2.ts, 1, 7)) +>bar : Symbol(bar, Decl(wideningTuples2.ts, 0, 22)) + + intermediate = [""]; +>intermediate : Symbol(intermediate, Decl(wideningTuples2.ts, 1, 7)) + + return [undefined]; +>undefined : Symbol(undefined) + +}; diff --git a/tests/baselines/reference/wideningTuples2.types b/tests/baselines/reference/wideningTuples2.types new file mode 100644 index 00000000000..c07166c53f0 --- /dev/null +++ b/tests/baselines/reference/wideningTuples2.types @@ -0,0 +1,22 @@ +=== tests/cases/conformance/types/tuple/wideningTuples2.ts === +var foo: () => [any] = function bar() { +>foo : () => [any] +>function bar() { let intermediate = bar(); intermediate = [""]; return [undefined];} : () => [any] +>bar : () => [any] + + let intermediate = bar(); +>intermediate : [any] +>bar() : [any] +>bar : () => [any] + + intermediate = [""]; +>intermediate = [""] : [string] +>intermediate : [any] +>[""] : [string] +>"" : string + + return [undefined]; +>[undefined] : [undefined] +>undefined : undefined + +}; diff --git a/tests/baselines/reference/wideningTuples3.errors.txt b/tests/baselines/reference/wideningTuples3.errors.txt new file mode 100644 index 00000000000..43c7e349a0c --- /dev/null +++ b/tests/baselines/reference/wideningTuples3.errors.txt @@ -0,0 +1,9 @@ +tests/cases/conformance/types/tuple/wideningTuples3.ts(3,5): error TS7005: Variable 'b' implicitly has an '[any, any]' type. + + +==== tests/cases/conformance/types/tuple/wideningTuples3.ts (1 errors) ==== + var a: [any]; + + var b = a = [undefined, null]; + ~ +!!! error TS7005: Variable 'b' implicitly has an '[any, any]' type. \ No newline at end of file diff --git a/tests/baselines/reference/wideningTuples3.js b/tests/baselines/reference/wideningTuples3.js new file mode 100644 index 00000000000..dfeaae745d4 --- /dev/null +++ b/tests/baselines/reference/wideningTuples3.js @@ -0,0 +1,8 @@ +//// [wideningTuples3.ts] +var a: [any]; + +var b = a = [undefined, null]; + +//// [wideningTuples3.js] +var a; +var b = a = [undefined, null]; diff --git a/tests/baselines/reference/wideningTuples4.js b/tests/baselines/reference/wideningTuples4.js new file mode 100644 index 00000000000..b4d16a3058b --- /dev/null +++ b/tests/baselines/reference/wideningTuples4.js @@ -0,0 +1,10 @@ +//// [wideningTuples4.ts] +var a: [any]; + +var b = a = [undefined, null]; +b = ["", ""]; + +//// [wideningTuples4.js] +var a; +var b = a = [undefined, null]; +b = ["", ""]; diff --git a/tests/baselines/reference/wideningTuples4.symbols b/tests/baselines/reference/wideningTuples4.symbols new file mode 100644 index 00000000000..95e7cc3cff8 --- /dev/null +++ b/tests/baselines/reference/wideningTuples4.symbols @@ -0,0 +1,12 @@ +=== tests/cases/conformance/types/tuple/wideningTuples4.ts === +var a: [any]; +>a : Symbol(a, Decl(wideningTuples4.ts, 0, 3)) + +var b = a = [undefined, null]; +>b : Symbol(b, Decl(wideningTuples4.ts, 2, 3)) +>a : Symbol(a, Decl(wideningTuples4.ts, 0, 3)) +>undefined : Symbol(undefined) + +b = ["", ""]; +>b : Symbol(b, Decl(wideningTuples4.ts, 2, 3)) + diff --git a/tests/baselines/reference/wideningTuples4.types b/tests/baselines/reference/wideningTuples4.types new file mode 100644 index 00000000000..6d101dd1e01 --- /dev/null +++ b/tests/baselines/reference/wideningTuples4.types @@ -0,0 +1,19 @@ +=== tests/cases/conformance/types/tuple/wideningTuples4.ts === +var a: [any]; +>a : [any] + +var b = a = [undefined, null]; +>b : [any, any] +>a = [undefined, null] : [undefined, null] +>a : [any] +>[undefined, null] : [undefined, null] +>undefined : undefined +>null : null + +b = ["", ""]; +>b = ["", ""] : [string, string] +>b : [any, any] +>["", ""] : [string, string] +>"" : string +>"" : string + diff --git a/tests/baselines/reference/wideningTuples5.errors.txt b/tests/baselines/reference/wideningTuples5.errors.txt new file mode 100644 index 00000000000..bfd72079f55 --- /dev/null +++ b/tests/baselines/reference/wideningTuples5.errors.txt @@ -0,0 +1,10 @@ +tests/cases/conformance/types/tuple/wideningTuples5.ts(1,6): error TS7005: Variable 'a' implicitly has an 'any' type. +tests/cases/conformance/types/tuple/wideningTuples5.ts(1,9): error TS7005: Variable 'b' implicitly has an 'any' type. + + +==== tests/cases/conformance/types/tuple/wideningTuples5.ts (2 errors) ==== + var [a, b] = [undefined, null]; + ~ +!!! error TS7005: Variable 'a' implicitly has an 'any' type. + ~ +!!! error TS7005: Variable 'b' implicitly has an 'any' type. \ No newline at end of file diff --git a/tests/baselines/reference/wideningTuples5.js b/tests/baselines/reference/wideningTuples5.js new file mode 100644 index 00000000000..5763fb3340f --- /dev/null +++ b/tests/baselines/reference/wideningTuples5.js @@ -0,0 +1,5 @@ +//// [wideningTuples5.ts] +var [a, b] = [undefined, null]; + +//// [wideningTuples5.js] +var _a = [undefined, null], a = _a[0], b = _a[1]; diff --git a/tests/baselines/reference/wideningTuples6.js b/tests/baselines/reference/wideningTuples6.js new file mode 100644 index 00000000000..b1d5e8ec0bd --- /dev/null +++ b/tests/baselines/reference/wideningTuples6.js @@ -0,0 +1,9 @@ +//// [wideningTuples6.ts] +var [a, b] = [undefined, null]; +a = ""; +b = ""; + +//// [wideningTuples6.js] +var _a = [undefined, null], a = _a[0], b = _a[1]; +a = ""; +b = ""; diff --git a/tests/baselines/reference/wideningTuples6.symbols b/tests/baselines/reference/wideningTuples6.symbols new file mode 100644 index 00000000000..88de6a7b9b7 --- /dev/null +++ b/tests/baselines/reference/wideningTuples6.symbols @@ -0,0 +1,12 @@ +=== tests/cases/conformance/types/tuple/wideningTuples6.ts === +var [a, b] = [undefined, null]; +>a : Symbol(a, Decl(wideningTuples6.ts, 0, 5)) +>b : Symbol(b, Decl(wideningTuples6.ts, 0, 7)) +>undefined : Symbol(undefined) + +a = ""; +>a : Symbol(a, Decl(wideningTuples6.ts, 0, 5)) + +b = ""; +>b : Symbol(b, Decl(wideningTuples6.ts, 0, 7)) + diff --git a/tests/baselines/reference/wideningTuples6.types b/tests/baselines/reference/wideningTuples6.types new file mode 100644 index 00000000000..d75c0b49e9e --- /dev/null +++ b/tests/baselines/reference/wideningTuples6.types @@ -0,0 +1,18 @@ +=== tests/cases/conformance/types/tuple/wideningTuples6.ts === +var [a, b] = [undefined, null]; +>a : any +>b : any +>[undefined, null] : [undefined, null] +>undefined : undefined +>null : null + +a = ""; +>a = "" : string +>a : any +>"" : string + +b = ""; +>b = "" : string +>b : any +>"" : string + diff --git a/tests/baselines/reference/wideningTuples7.errors.txt b/tests/baselines/reference/wideningTuples7.errors.txt new file mode 100644 index 00000000000..25fd1f58e64 --- /dev/null +++ b/tests/baselines/reference/wideningTuples7.errors.txt @@ -0,0 +1,10 @@ +tests/cases/conformance/types/tuple/wideningTuples7.ts(1,20): error TS7010: 'bar', which lacks return-type annotation, implicitly has an '[any]' return type. + + +==== tests/cases/conformance/types/tuple/wideningTuples7.ts (1 errors) ==== + var foo = function bar() { + ~~~ +!!! error TS7010: 'bar', which lacks return-type annotation, implicitly has an '[any]' return type. + let intermediate: [string]; + return intermediate = [undefined]; + }; \ No newline at end of file diff --git a/tests/baselines/reference/wideningTuples7.js b/tests/baselines/reference/wideningTuples7.js new file mode 100644 index 00000000000..4d94a1909ad --- /dev/null +++ b/tests/baselines/reference/wideningTuples7.js @@ -0,0 +1,11 @@ +//// [wideningTuples7.ts] +var foo = function bar() { + let intermediate: [string]; + return intermediate = [undefined]; +}; + +//// [wideningTuples7.js] +var foo = function bar() { + var intermediate; + return intermediate = [undefined]; +}; From 6fc08ea3e62baee65235abcb23c7572b8c61140d Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Tue, 14 Jul 2015 13:44:40 -0700 Subject: [PATCH 30/30] Clean up and address CR feedback --- src/compiler/checker.ts | 55 +++++++++---------- .../diagnosticInformationMap.generated.ts | 1 - src/compiler/diagnosticMessages.json | 8 --- 3 files changed, 25 insertions(+), 39 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5209f02847e..20e0af5e873 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3943,7 +3943,7 @@ namespace ts { let id = getTypeListId(elementTypes); let type = tupleTypes[id]; if (!type) { - type = tupleTypes[id] = createObjectType(TypeFlags.Tuple); + type = tupleTypes[id] = createObjectType(TypeFlags.Tuple | getWideningFlagsOfTypes(elementTypes)); type.elementTypes = elementTypes; } return type; @@ -5300,7 +5300,7 @@ namespace ts { * Prefer using isTupleLikeType() unless the use of `elementTypes` is required. */ function isTupleType(type: Type): type is TupleType { - return (type.flags & TypeFlags.Tuple) && !!(type).elementTypes; + return !!(type.flags & TypeFlags.Tuple); } function getWidenedTypeOfObjectLiteral(type: Type): Type { @@ -5348,31 +5348,33 @@ namespace ts { return type; } - function reportWideningErrorsInType(type: Type, expression: Expression): boolean { + /** + * Reports implicit any errors that occur as a result of widening 'null' and 'undefined' + * to 'any'. A call to reportWideningErrorsInType is normally accompanied by a call to + * getWidenedType. But in some cases getWidenedType is called without reporting errors + * (type argument inference is an example). + * + * The return value indicates whether an error was in fact reported. The particular circumstances + * are on a best effort basis. Currently, if the null or undefined that causes widening is inside + * an object literal property (arbitrarily deeply), this function reports an error. If no error is + * reported, reportImplicitAnyError is a suitable fallback to report a general error. + */ + function reportWideningErrorsInType(type: Type): boolean { let errorReported = false; if (type.flags & TypeFlags.Union) { for (let t of (type).types) { - if (reportWideningErrorsInType(t, expression)) { + if (reportWideningErrorsInType(t)) { errorReported = true; } } } if (isArrayType(type)) { - return reportWideningErrorsInType((type).typeArguments[0], expression); + return reportWideningErrorsInType((type).typeArguments[0]); } if (isTupleType(type)) { - let { elementTypes } = type; - for (let i = 0; i < elementTypes.length; i++) { - let t = elementTypes[i]; - if (t.flags & TypeFlags.ContainsUndefinedOrNull) { - if (reportWideningErrorsInType(t, expression)) { - errorReported = true; - } - else if (expression.kind === SyntaxKind.ArrayLiteralExpression) { - let element = (expression).elements[i]; - error(element, Diagnostics.Array_element_at_index_0_implicitly_has_an_1_type, i, typeToString(getWidenedType(t))); - errorReported = true; - } + for (let t of type.elementTypes) { + if (reportWideningErrorsInType(t)) { + errorReported = true; } } } @@ -5380,7 +5382,7 @@ namespace ts { for (let p of getPropertiesOfObjectType(type)) { let t = getTypeOfSymbol(p); if (t.flags & TypeFlags.ContainsUndefinedOrNull) { - if (!reportWideningErrorsInType(t, expression)) { + if (!reportWideningErrorsInType(t)) { error(p.valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, p.name, typeToString(getWidenedType(t))); } errorReported = true; @@ -5425,7 +5427,7 @@ namespace ts { function reportErrorsFromWidening(declaration: Declaration, type: Type) { if (produceDiagnostics && compilerOptions.noImplicitAny && type.flags & TypeFlags.ContainsUndefinedOrNull) { // Report implicit any error within type if possible, otherwise report error on declaration - if (!reportWideningErrorsInType(type, declaration.kind === SyntaxKind.VariableDeclaration && (declaration).initializer)) { + if (!reportWideningErrorsInType(type)) { reportImplicitAnyError(declaration, type); } } @@ -6801,7 +6803,6 @@ namespace ts { let hasSpreadElement = false; let elementTypes: Type[] = []; let inDestructuringPattern = isAssignmentTarget(node); - let typeFlags: TypeFlags; for (let e of elements) { if (inDestructuringPattern && e.kind === SyntaxKind.SpreadElementExpression) { // Given the following situation: @@ -6821,23 +6822,21 @@ namespace ts { (languageVersion >= ScriptTarget.ES6 ? getElementTypeOfIterable(restArrayType, /*errorNode*/ undefined) : undefined); if (restElementType) { elementTypes.push(restElementType); - typeFlags |= restElementType.flags; } } else { let type = checkExpression(e, contextualMapper); elementTypes.push(type); - typeFlags |= type.flags; } hasSpreadElement = hasSpreadElement || e.kind === SyntaxKind.SpreadElementExpression; } if (!hasSpreadElement) { let contextualType = getContextualType(node); if (contextualType && contextualTypeIsTupleLikeType(contextualType) || inDestructuringPattern) { - return addTypeFlags(createTupleType(elementTypes), typeFlags & TypeFlags.RequiresWidening); + return createTupleType(elementTypes); } } - return addTypeFlags(createArrayType(getUnionType(elementTypes)), typeFlags & TypeFlags.RequiresWidening); + return createArrayType(getUnionType(elementTypes)); } function isNumericName(name: DeclarationName): boolean { @@ -6953,7 +6952,8 @@ namespace ts { let stringIndexType = getIndexType(IndexKind.String); let numberIndexType = getIndexType(IndexKind.Number); let result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexType, numberIndexType); - return addTypeFlags(result, TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | (typeFlags & TypeFlags.ContainsUndefinedOrNull)); + result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | (typeFlags & TypeFlags.ContainsUndefinedOrNull); + return result; function getIndexType(kind: IndexKind) { if (contextualType && contextualTypeHasIndexSignature(contextualType, kind)) { @@ -6979,11 +6979,6 @@ namespace ts { } } - function addTypeFlags(type: Type, flags: TypeFlags): Type { - type.flags |= flags; - return type; - } - function checkJsxSelfClosingElement(node: JsxSelfClosingElement) { checkJsxOpeningLikeElement(node); return jsxElementType || anyType; diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index ce28cbbc387..a0a95d47c8c 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -589,7 +589,6 @@ namespace ts { Function_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions: { code: 7024, category: DiagnosticCategory.Error, key: "Function implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions." }, Generator_implicitly_has_type_0_because_it_does_not_yield_any_values_Consider_supplying_a_return_type: { code: 7025, category: DiagnosticCategory.Error, key: "Generator implicitly has type '{0}' because it does not yield any values. Consider supplying a return type." }, JSX_element_implicitly_has_type_any_because_no_interface_JSX_0_exists: { code: 7026, category: DiagnosticCategory.Error, key: "JSX element implicitly has type 'any' because no interface 'JSX.{0}' exists" }, - Array_element_at_index_0_implicitly_has_an_1_type: { code: 7027, category: DiagnosticCategory.Error, key: "Array element at index {0} implicitly has an '{1}' type." }, You_cannot_rename_this_element: { code: 8000, category: DiagnosticCategory.Error, key: "You cannot rename this element." }, You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library: { code: 8001, category: DiagnosticCategory.Error, key: "You cannot rename elements that are defined in the standard TypeScript library." }, import_can_only_be_used_in_a_ts_file: { code: 8002, category: DiagnosticCategory.Error, key: "'import ... =' can only be used in a .ts file." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 65e3bab9ec5..acf4e74ae9f 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2347,14 +2347,6 @@ "category": "Error", "code": 7026 }, - "JSX element implicitly has type 'any' because no interface 'JSX.{0}' exists": { - "category": "Error", - "code": 7026 - }, - "Array element at index {0} implicitly has an '{1}' type.": { - "category": "Error", - "code": 7027 - }, "You cannot rename this element.": {