From 70d2938f4fe210616c7320b2afadd73da55943f7 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 16 May 2015 11:38:28 -0700 Subject: [PATCH 001/107] Support "exclude" property in tsconfig.json --- src/compiler/commandLineParser.ts | 15 +++++----- src/compiler/sys.ts | 46 +++++++++++++++++++++---------- src/compiler/types.ts | 2 +- 3 files changed, 40 insertions(+), 23 deletions(-) diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 7a589fe61cb..1de9188aed7 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -343,7 +343,7 @@ module ts { return { options: getCompilerOptions(), - fileNames: getFiles(), + fileNames: getFileNames(), errors }; @@ -389,23 +389,24 @@ module ts { return options; } - function getFiles(): string[] { - var files: string[] = []; + function getFileNames(): string[] { + var fileNames: string[] = []; if (hasProperty(json, "files")) { if (json["files"] instanceof Array) { - var files = map(json["files"], s => combinePaths(basePath, s)); + fileNames = map(json["files"], s => combinePaths(basePath, s)); } } else { - var sysFiles = host.readDirectory(basePath, ".ts"); + var exclude = json["exclude"] instanceof Array ? map(json["exclude"], normalizeSlashes) : undefined; + var sysFiles = host.readDirectory(basePath, ".ts", exclude); for (var i = 0; i < sysFiles.length; i++) { var name = sysFiles[i]; if (!fileExtensionIs(name, ".d.ts") || !contains(sysFiles, name.substr(0, name.length - 5) + ".ts")) { - files.push(name); + fileNames.push(name); } } } - return files; + return fileNames; } } } diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index f9daf52c5f2..8f246540c61 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -15,7 +15,7 @@ module ts { createDirectory(path: string): void; getExecutingFilePath(): string; getCurrentDirectory(): string; - readDirectory(path: string, extension?: string): string[]; + readDirectory(path: string, extension?: string, exclude?: string[]): string[]; getMemoryUsage?(): number; exit(exitCode?: number): void; } @@ -109,7 +109,11 @@ module ts { } } - function getNames(collection: any): string[] { + function getCanonicalPath(path: string): string { + return path.toLowerCase(); + } + + function getNames(collection: any): string[]{ var result: string[] = []; for (var e = new Enumerator(collection); !e.atEnd(); e.moveNext()) { result.push(e.item().Name); @@ -117,21 +121,26 @@ module ts { return result.sort(); } - function readDirectory(path: string, extension?: string): string[] { + function readDirectory(path: string, extension?: string, exclude?: string[]): string[] { var result: string[] = []; + exclude = map(exclude, s => getCanonicalPath(combinePaths(path, s))); visitDirectory(path); return result; function visitDirectory(path: string) { var folder = fso.GetFolder(path || "."); var files = getNames(folder.files); - for (let name of files) { - if (!extension || fileExtensionIs(name, extension)) { - result.push(combinePaths(path, name)); + for (let current of files) { + let name = combinePaths(path, current); + if ((!extension || fileExtensionIs(name, extension)) && !contains(exclude, getCanonicalPath(name))) { + result.push(name); } } var subfolders = getNames(folder.subfolders); for (let current of subfolders) { - visitDirectory(combinePaths(path, current)); + let name = combinePaths(path, current); + if (!contains(exclude, getCanonicalPath(name))) { + visitDirectory(name); + } } } } @@ -222,8 +231,13 @@ module ts { _fs.writeFileSync(fileName, data, "utf8"); } - function readDirectory(path: string, extension?: string): string[] { + function getCanonicalPath(path: string): string { + return useCaseSensitiveFileNames ? path.toLowerCase() : path; + } + + function readDirectory(path: string, extension?: string, exclude?: string[]): string[] { var result: string[] = []; + exclude = map(exclude, s => getCanonicalPath(combinePaths(path, s))); visitDirectory(path); return result; function visitDirectory(path: string) { @@ -231,14 +245,16 @@ module ts { var directories: string[] = []; for (let current of files) { var name = combinePaths(path, current); - var stat = _fs.lstatSync(name); - if (stat.isFile()) { - if (!extension || fileExtensionIs(name, extension)) { - result.push(name); + if (!contains(exclude, getCanonicalPath(name))) { + var stat = _fs.lstatSync(name); + if (stat.isFile()) { + if (!extension || fileExtensionIs(name, extension)) { + result.push(name); + } + } + else if (stat.isDirectory()) { + directories.push(name); } - } - else if (stat.isDirectory()) { - directories.push(name); } } for (let current of directories) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 86e680ca8b0..831cc26eedf 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1035,7 +1035,7 @@ module ts { } export interface ParseConfigHost { - readDirectory(rootDir: string, extension: string): string[]; + readDirectory(rootDir: string, extension: string, exclude: string[]): string[]; } export interface WriteFileCallback { From e7eef830e13509baa479eabe0e75aaa4992927c1 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 26 May 2015 20:18:13 -0700 Subject: [PATCH 002/107] Fix #3245: ensure transpile diagnostics only include syntactic and compiler options diagnostics --- Jakefile.js | 3 +- src/compiler/program.ts | 15 ++++---- src/compiler/types.ts | 1 + src/compiler/utilities.ts | 15 ++++++++ src/services/services.ts | 17 +++++++-- tests/cases/unittests/transpile.ts | 59 ++++++++++++++++++++++++++++++ 6 files changed, 98 insertions(+), 12 deletions(-) create mode 100644 tests/cases/unittests/transpile.ts diff --git a/Jakefile.js b/Jakefile.js index cb53b479502..f27e61062f0 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -128,7 +128,8 @@ var harnessSources = [ "services/preProcessFile.ts", "services/patternMatcher.ts", "versionCache.ts", - "convertToBase64.ts" + "convertToBase64.ts", + "transpile.ts" ].map(function (f) { return path.join(unittestsDirectory, f); })).concat([ diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 32503de2566..4cccc881d40 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -10,9 +10,6 @@ module ts { /** The version of the TypeScript compiler release */ export const version = "1.5.3"; - const carriageReturnLineFeed = "\r\n"; - const lineFeed = "\n"; - export function findConfigFile(searchPath: string): string { var fileName = "tsconfig.json"; while (true) { @@ -94,10 +91,7 @@ module ts { } } - let newLine = - options.newLine === NewLineKind.CarriageReturnLineFeed ? carriageReturnLineFeed : - options.newLine === NewLineKind.LineFeed ? lineFeed : - sys.newLine; + const newLine = getNewLineCharacter(options); return { getSourceFile, @@ -175,6 +169,7 @@ module ts { getGlobalDiagnostics, getSemanticDiagnostics, getDeclarationDiagnostics, + getCompilerOptionsDiagnostics, getTypeChecker, getDiagnosticsProducingTypeChecker, getCommonSourceDirectory: () => commonSourceDirectory, @@ -291,6 +286,12 @@ module ts { } } + function getCompilerOptionsDiagnostics(): Diagnostic[]{ + let allDiagnostics: Diagnostic[] = []; + addRange(allDiagnostics, diagnostics.getGlobalDiagnostics()); + return sortAndDeduplicateDiagnostics(allDiagnostics); + } + function getGlobalDiagnostics(): Diagnostic[] { let typeChecker = getDiagnosticsProducingTypeChecker(); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index a6fa89846bb..7eec44eb2f2 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1064,6 +1064,7 @@ module ts { getGlobalDiagnostics(): Diagnostic[]; getSemanticDiagnostics(sourceFile?: SourceFile): Diagnostic[]; getDeclarationDiagnostics(sourceFile?: SourceFile): Diagnostic[]; + /* @internal */ getCompilerOptionsDiagnostics(): Diagnostic[]; /** * Gets a type checker that can be used to semantically analyze source fils in the program. diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 3ded0a7cfd9..3bb459ff99e 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1774,6 +1774,21 @@ module ts { return result; } + + const carriageReturnLineFeed = "\r\n"; + const lineFeed = "\n"; + export function getNewLineCharacter(options: CompilerOptions): string { + if (options.newLine === NewLineKind.CarriageReturnLineFeed) { + return carriageReturnLineFeed; + } + else if (options.newLine === NewLineKind.LineFeed) { + return lineFeed; + } + else if (sys) { + return sys.newLine + } + return carriageReturnLineFeed; + } } module ts { diff --git a/src/services/services.ts b/src/services/services.ts index d5ba024cee5..ff1e627a241 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1772,15 +1772,24 @@ module ts { // Filename can be non-ts file. options.allowNonTsExtensions = true; + // We are not returning a lib file when asked, so pass this flag to + // avoid reporting a file not found error + options.noLib = true; + + // Similar to the library, we are not returning any refrenced files + options.noResolve = true; + // Parse - var inputFileName = fileName || "module.ts"; - var sourceFile = createSourceFile(inputFileName, input, options.target); + let inputFileName = fileName || "module.ts"; + let sourceFile = createSourceFile(inputFileName, input, options.target); // Store syntactic diagnostics if (diagnostics && sourceFile.parseDiagnostics) { diagnostics.push(...sourceFile.parseDiagnostics); } + let newLine = getNewLineCharacter(options); + // Output let outputText: string; @@ -1795,13 +1804,13 @@ module ts { useCaseSensitiveFileNames: () => false, getCanonicalFileName: fileName => fileName, getCurrentDirectory: () => "", - getNewLine: () => (sys && sys.newLine) || "\r\n" + getNewLine: () => newLine }; var program = createProgram([inputFileName], options, compilerHost); if (diagnostics) { - diagnostics.push(...program.getGlobalDiagnostics()); + diagnostics.push(...program.getCompilerOptionsDiagnostics()); } // Emit diff --git a/tests/cases/unittests/transpile.ts b/tests/cases/unittests/transpile.ts new file mode 100644 index 00000000000..32caad8d05c --- /dev/null +++ b/tests/cases/unittests/transpile.ts @@ -0,0 +1,59 @@ +/// + +module ts { + describe("Transpile", () => { + + function runTest(input: string, compilerOptions: ts.CompilerOptions = {}, expectedOutput?: string, expectedDiagnosticCodes: number[] = []): void { + let diagnostics: Diagnostic[] = []; + let result = transpile(input, compilerOptions, "file.ts", diagnostics); + + assert.equal(diagnostics.length, expectedDiagnosticCodes.length); + for (let diagnostic of diagnostics) { + assert.isTrue(expectedDiagnosticCodes.indexOf(diagnostic.code) >= 0, `Found an unexpected diagnostic: ${ diagnostic.code }`); + } + + if (expectedOutput !== undefined) { + assert.equal(result, expectedOutput); + } + } + + it("Generates correct compilerOptions diagnostics", () => { + // Expecting 5047: "Option 'isolatedModules' can only be used when either option'--module' is provided or option 'target' is 'ES6' or higher." + runTest(`var x = 0;`, {}, /*expectedOutput*/ undefined, [5047]); + }); + + it("Generates no diagnostics with valid inputs", () => { + // No errors + runTest(`var x = 0;`, { module: ModuleKind.CommonJS }, /*expectedOutput*/ undefined, []); + }); + + it("Generates no diagnostics for missing file references", () => { + runTest(`/// +var x = 0;`, + { module: ModuleKind.CommonJS }, /*expectedOutput*/ undefined, []); + }); + + it("Generates no diagnostics for missing module imports", () => { + runTest(`import {a} from "module2";`, + { module: ModuleKind.CommonJS }, /*expectedOutput*/ undefined, []); + }); + + it("Generates expected syntactic diagnostics", () => { + runTest(`a b`, + { module: ModuleKind.CommonJS }, /*expectedOutput*/ undefined, [1005]); /// 1005: ';' Expected + }); + + it("Does not generate semantic diagnostics", () => { + runTest(`var x: string = 0;`, + { module: ModuleKind.CommonJS }, /*expectedOutput*/ undefined, []); + }); + + it("Generates module output", () => { + runTest(`var x = 0;`, { module: ModuleKind.AMD }, `define(["require", "exports"], function (require, exports) {\r\n var x = 0;\r\n});\r\n`); + }); + + it("Uses correct newLine character", () => { + runTest(`var x = 0;`, { module: ModuleKind.CommonJS, newLine: NewLineKind.LineFeed }, `var x = 0;\n`); + }); + }); +} From 2cbe14e1312296cdb1c8abfa0b81c6fb6932701e Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 27 May 2015 10:20:01 -0700 Subject: [PATCH 003/107] Respond to code review comments --- src/compiler/program.ts | 2 +- src/services/services.ts | 9 ++++++--- tests/cases/unittests/transpile.ts | 6 +++--- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 4cccc881d40..1db32b95954 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -286,7 +286,7 @@ module ts { } } - function getCompilerOptionsDiagnostics(): Diagnostic[]{ + function getCompilerOptionsDiagnostics(): Diagnostic[] { let allDiagnostics: Diagnostic[] = []; addRange(allDiagnostics, diagnostics.getGlobalDiagnostics()); return sortAndDeduplicateDiagnostics(allDiagnostics); diff --git a/src/services/services.ts b/src/services/services.ts index ff1e627a241..58155f2a691 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1763,6 +1763,8 @@ module ts { * Extra compiler options that will unconditionally be used bu this function are: * - isolatedModules = true * - allowNonTsExtensions = true + * - noLib = true + * - noResolve = true */ export function transpile(input: string, compilerOptions?: CompilerOptions, fileName?: string, diagnostics?: Diagnostic[]): string { let options = compilerOptions ? clone(compilerOptions) : getDefaultCompilerOptions(); @@ -1772,11 +1774,12 @@ module ts { // Filename can be non-ts file. options.allowNonTsExtensions = true; - // We are not returning a lib file when asked, so pass this flag to - // avoid reporting a file not found error + // We are not returning a sourceFile for lib file when asked by the program, + // so pass --noLib to avoid reporting a file not found error. options.noLib = true; - // Similar to the library, we are not returning any refrenced files + // We are not doing a full typecheck, we are not resolving the whole context, + // so pass --noResolve to avoid reporting missing file errors. options.noResolve = true; // Parse diff --git a/tests/cases/unittests/transpile.ts b/tests/cases/unittests/transpile.ts index 32caad8d05c..eca136649f2 100644 --- a/tests/cases/unittests/transpile.ts +++ b/tests/cases/unittests/transpile.ts @@ -7,10 +7,10 @@ module ts { let diagnostics: Diagnostic[] = []; let result = transpile(input, compilerOptions, "file.ts", diagnostics); - assert.equal(diagnostics.length, expectedDiagnosticCodes.length); - for (let diagnostic of diagnostics) { - assert.isTrue(expectedDiagnosticCodes.indexOf(diagnostic.code) >= 0, `Found an unexpected diagnostic: ${ diagnostic.code }`); + for (let i = 0; i < expectedDiagnosticCodes.length; i++) { + assert.equal(expectedDiagnosticCodes[i], diagnostics[i] && diagnostics[i].code, `Could not find expeced diagnostic.`); } + assert.equal(diagnostics.length, expectedDiagnosticCodes.length, "Resuting diagnostics count does not match expected"); if (expectedOutput !== undefined) { assert.equal(result, expectedOutput); From 456eedf43295e90bcb5cedeb4e84c66efc96aceb Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 27 May 2015 14:56:30 -0700 Subject: [PATCH 004/107] Added tests. --- ...lassExpressionWithResolutionOfNamespaceOfSameName01.ts | 8 ++++++++ ...tionDeclarationWithResolutionOfTypeNamedArguments01.ts | 6 ++++++ ...functionDeclarationWithResolutionOfTypeOfSameName01.ts | 6 ++++++ ...ctionExpressionWithResolutionOfTypeNamedArguments01.ts | 6 ++++++ .../functionExpressionWithResolutionOfTypeOfSameName01.ts | 6 ++++++ 5 files changed, 32 insertions(+) create mode 100644 tests/cases/compiler/classExpressionWithResolutionOfNamespaceOfSameName01.ts create mode 100644 tests/cases/compiler/functionDeclarationWithResolutionOfTypeNamedArguments01.ts create mode 100644 tests/cases/compiler/functionDeclarationWithResolutionOfTypeOfSameName01.ts create mode 100644 tests/cases/compiler/functionExpressionWithResolutionOfTypeNamedArguments01.ts create mode 100644 tests/cases/compiler/functionExpressionWithResolutionOfTypeOfSameName01.ts diff --git a/tests/cases/compiler/classExpressionWithResolutionOfNamespaceOfSameName01.ts b/tests/cases/compiler/classExpressionWithResolutionOfNamespaceOfSameName01.ts new file mode 100644 index 00000000000..ce44c2bca43 --- /dev/null +++ b/tests/cases/compiler/classExpressionWithResolutionOfNamespaceOfSameName01.ts @@ -0,0 +1,8 @@ +namespace C { + export interface type { + } +} + +var x = class C { + prop: C.type; +} \ No newline at end of file diff --git a/tests/cases/compiler/functionDeclarationWithResolutionOfTypeNamedArguments01.ts b/tests/cases/compiler/functionDeclarationWithResolutionOfTypeNamedArguments01.ts new file mode 100644 index 00000000000..b9ceeb4740b --- /dev/null +++ b/tests/cases/compiler/functionDeclarationWithResolutionOfTypeNamedArguments01.ts @@ -0,0 +1,6 @@ +interface arguments { +} + +function f() { + arguments; +} \ No newline at end of file diff --git a/tests/cases/compiler/functionDeclarationWithResolutionOfTypeOfSameName01.ts b/tests/cases/compiler/functionDeclarationWithResolutionOfTypeOfSameName01.ts new file mode 100644 index 00000000000..9dc0bf86943 --- /dev/null +++ b/tests/cases/compiler/functionDeclarationWithResolutionOfTypeOfSameName01.ts @@ -0,0 +1,6 @@ +interface f { +} + +function f() { + f; +} \ No newline at end of file diff --git a/tests/cases/compiler/functionExpressionWithResolutionOfTypeNamedArguments01.ts b/tests/cases/compiler/functionExpressionWithResolutionOfTypeNamedArguments01.ts new file mode 100644 index 00000000000..c1b99ee8f0e --- /dev/null +++ b/tests/cases/compiler/functionExpressionWithResolutionOfTypeNamedArguments01.ts @@ -0,0 +1,6 @@ +interface arguments { +} + +var x = function f() { + arguments; +} \ No newline at end of file diff --git a/tests/cases/compiler/functionExpressionWithResolutionOfTypeOfSameName01.ts b/tests/cases/compiler/functionExpressionWithResolutionOfTypeOfSameName01.ts new file mode 100644 index 00000000000..de4d0e3bb90 --- /dev/null +++ b/tests/cases/compiler/functionExpressionWithResolutionOfTypeOfSameName01.ts @@ -0,0 +1,6 @@ +interface f { +} + +var x = function f() { + f; +} \ No newline at end of file From ac152ed19d548dd418ddd15e563671e13f3f8504 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 27 May 2015 15:03:54 -0700 Subject: [PATCH 005/107] Accepted baselines for the only test that was expected to pass. --- ...onDeclarationWithResolutionOfTypeOfSameName01.js | 12 ++++++++++++ ...larationWithResolutionOfTypeOfSameName01.symbols | 12 ++++++++++++ ...eclarationWithResolutionOfTypeOfSameName01.types | 13 +++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 tests/baselines/reference/functionDeclarationWithResolutionOfTypeOfSameName01.js create mode 100644 tests/baselines/reference/functionDeclarationWithResolutionOfTypeOfSameName01.symbols create mode 100644 tests/baselines/reference/functionDeclarationWithResolutionOfTypeOfSameName01.types diff --git a/tests/baselines/reference/functionDeclarationWithResolutionOfTypeOfSameName01.js b/tests/baselines/reference/functionDeclarationWithResolutionOfTypeOfSameName01.js new file mode 100644 index 00000000000..6f5bb2cacf9 --- /dev/null +++ b/tests/baselines/reference/functionDeclarationWithResolutionOfTypeOfSameName01.js @@ -0,0 +1,12 @@ +//// [functionDeclarationWithResolutionOfTypeOfSameName01.ts] +interface f { +} + +function f() { + f; +} + +//// [functionDeclarationWithResolutionOfTypeOfSameName01.js] +function f() { + f; +} diff --git a/tests/baselines/reference/functionDeclarationWithResolutionOfTypeOfSameName01.symbols b/tests/baselines/reference/functionDeclarationWithResolutionOfTypeOfSameName01.symbols new file mode 100644 index 00000000000..aa51fad0538 --- /dev/null +++ b/tests/baselines/reference/functionDeclarationWithResolutionOfTypeOfSameName01.symbols @@ -0,0 +1,12 @@ +=== tests/cases/compiler/functionDeclarationWithResolutionOfTypeOfSameName01.ts === +interface f { +>f : Symbol(f, Decl(functionDeclarationWithResolutionOfTypeOfSameName01.ts, 0, 0), Decl(functionDeclarationWithResolutionOfTypeOfSameName01.ts, 1, 1)) +} + +function f() { +>f : Symbol(f, Decl(functionDeclarationWithResolutionOfTypeOfSameName01.ts, 0, 0), Decl(functionDeclarationWithResolutionOfTypeOfSameName01.ts, 1, 1)) + + f; +>f : Symbol(f, Decl(functionDeclarationWithResolutionOfTypeOfSameName01.ts, 0, 0), Decl(functionDeclarationWithResolutionOfTypeOfSameName01.ts, 1, 1)) +>f : Symbol(f, Decl(functionDeclarationWithResolutionOfTypeOfSameName01.ts, 0, 0), Decl(functionDeclarationWithResolutionOfTypeOfSameName01.ts, 1, 1)) +} diff --git a/tests/baselines/reference/functionDeclarationWithResolutionOfTypeOfSameName01.types b/tests/baselines/reference/functionDeclarationWithResolutionOfTypeOfSameName01.types new file mode 100644 index 00000000000..1067b8989c8 --- /dev/null +++ b/tests/baselines/reference/functionDeclarationWithResolutionOfTypeOfSameName01.types @@ -0,0 +1,13 @@ +=== tests/cases/compiler/functionDeclarationWithResolutionOfTypeOfSameName01.ts === +interface f { +>f : f +} + +function f() { +>f : () => void + + f; +>f : f +>f : f +>f : () => void +} From 4088bc099c797ada14b0b2606d1e8d758324a413 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 27 May 2015 15:04:34 -0700 Subject: [PATCH 006/107] Only resolve 'arguments' and function/class expression names if the meaning permits it. --- src/compiler/checker.ts | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d409d1ea2fa..8a833123dcb 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -422,27 +422,33 @@ module ts { case SyntaxKind.SetAccessor: case SyntaxKind.FunctionDeclaration: case SyntaxKind.ArrowFunction: - if (name === "arguments") { - result = argumentsSymbol; - break loop; + if (meaning & SymbolFlags.Value) { + if (name === "arguments") { + result = argumentsSymbol; + break loop; + } } break; case SyntaxKind.FunctionExpression: - if (name === "arguments") { - result = argumentsSymbol; - break loop; - } - let functionName = (location).name; - if (functionName && name === functionName.text) { - result = location.symbol; - break loop; + if (meaning & SymbolFlags.Value) { + if (name === "arguments") { + result = argumentsSymbol; + break loop; + } + let functionName = (location).name; + if (functionName && name === functionName.text) { + result = location.symbol; + break loop; + } } break; case SyntaxKind.ClassExpression: - let className = (location).name; - if (className && name === className.text) { - result = location.symbol; - break loop; + if (meaning & (SymbolFlags.Value | SymbolFlags.Type)) { + let className = (location).name; + if (className && name === className.text) { + result = location.symbol; + break loop; + } } break; case SyntaxKind.Decorator: From 644dbf230fabd7bb85c5bd0bc359083b88bd8600 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 27 May 2015 16:03:04 -0700 Subject: [PATCH 007/107] Don't use 'Value' or 'Type' as they have overlap. Instead test for the precice meaning. --- src/compiler/checker.ts | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8a833123dcb..991e83150a3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -422,19 +422,18 @@ module ts { case SyntaxKind.SetAccessor: case SyntaxKind.FunctionDeclaration: case SyntaxKind.ArrowFunction: - if (meaning & SymbolFlags.Value) { - if (name === "arguments") { - result = argumentsSymbol; - break loop; - } + if (meaning & SymbolFlags.Variable && name === "arguments") { + result = argumentsSymbol; + break loop; } break; case SyntaxKind.FunctionExpression: - if (meaning & SymbolFlags.Value) { - if (name === "arguments") { - result = argumentsSymbol; - break loop; - } + if (meaning & SymbolFlags.Variable && name === "arguments") { + result = argumentsSymbol; + break loop; + } + + if (meaning & SymbolFlags.Function) { let functionName = (location).name; if (functionName && name === functionName.text) { result = location.symbol; @@ -443,7 +442,7 @@ module ts { } break; case SyntaxKind.ClassExpression: - if (meaning & (SymbolFlags.Value | SymbolFlags.Type)) { + if (meaning & SymbolFlags.Class) { let className = (location).name; if (className && name === className.text) { result = location.symbol; From 636347d86b7537c708b0478545dde85b2bd7eb6e Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 27 May 2015 16:03:27 -0700 Subject: [PATCH 008/107] Accepted baselines. --- ...hResolutionOfNamespaceOfSameName01.errors.txt | 14 ++++++++++++++ ...ssionWithResolutionOfNamespaceOfSameName01.js | 16 ++++++++++++++++ ...rationWithResolutionOfTypeNamedArguments01.js | 12 ++++++++++++ ...nWithResolutionOfTypeNamedArguments01.symbols | 12 ++++++++++++ ...ionWithResolutionOfTypeNamedArguments01.types | 13 +++++++++++++ ...essionWithResolutionOfTypeNamedArguments01.js | 12 ++++++++++++ ...nWithResolutionOfTypeNamedArguments01.symbols | 13 +++++++++++++ ...ionWithResolutionOfTypeNamedArguments01.types | 15 +++++++++++++++ ...ExpressionWithResolutionOfTypeOfSameName01.js | 12 ++++++++++++ ...ssionWithResolutionOfTypeOfSameName01.symbols | 13 +++++++++++++ ...ressionWithResolutionOfTypeOfSameName01.types | 15 +++++++++++++++ 11 files changed, 147 insertions(+) create mode 100644 tests/baselines/reference/classExpressionWithResolutionOfNamespaceOfSameName01.errors.txt create mode 100644 tests/baselines/reference/classExpressionWithResolutionOfNamespaceOfSameName01.js create mode 100644 tests/baselines/reference/functionDeclarationWithResolutionOfTypeNamedArguments01.js create mode 100644 tests/baselines/reference/functionDeclarationWithResolutionOfTypeNamedArguments01.symbols create mode 100644 tests/baselines/reference/functionDeclarationWithResolutionOfTypeNamedArguments01.types create mode 100644 tests/baselines/reference/functionExpressionWithResolutionOfTypeNamedArguments01.js create mode 100644 tests/baselines/reference/functionExpressionWithResolutionOfTypeNamedArguments01.symbols create mode 100644 tests/baselines/reference/functionExpressionWithResolutionOfTypeNamedArguments01.types create mode 100644 tests/baselines/reference/functionExpressionWithResolutionOfTypeOfSameName01.js create mode 100644 tests/baselines/reference/functionExpressionWithResolutionOfTypeOfSameName01.symbols create mode 100644 tests/baselines/reference/functionExpressionWithResolutionOfTypeOfSameName01.types diff --git a/tests/baselines/reference/classExpressionWithResolutionOfNamespaceOfSameName01.errors.txt b/tests/baselines/reference/classExpressionWithResolutionOfNamespaceOfSameName01.errors.txt new file mode 100644 index 00000000000..8edc1d8f74b --- /dev/null +++ b/tests/baselines/reference/classExpressionWithResolutionOfNamespaceOfSameName01.errors.txt @@ -0,0 +1,14 @@ +tests/cases/compiler/classExpressionWithResolutionOfNamespaceOfSameName01.ts(6,15): error TS9003: 'class' expressions are not currently supported. + + +==== tests/cases/compiler/classExpressionWithResolutionOfNamespaceOfSameName01.ts (1 errors) ==== + namespace C { + export interface type { + } + } + + var x = class C { + ~ +!!! error TS9003: 'class' expressions are not currently supported. + prop: C.type; + } \ No newline at end of file diff --git a/tests/baselines/reference/classExpressionWithResolutionOfNamespaceOfSameName01.js b/tests/baselines/reference/classExpressionWithResolutionOfNamespaceOfSameName01.js new file mode 100644 index 00000000000..7c9f25cdfe6 --- /dev/null +++ b/tests/baselines/reference/classExpressionWithResolutionOfNamespaceOfSameName01.js @@ -0,0 +1,16 @@ +//// [classExpressionWithResolutionOfNamespaceOfSameName01.ts] +namespace C { + export interface type { + } +} + +var x = class C { + prop: C.type; +} + +//// [classExpressionWithResolutionOfNamespaceOfSameName01.js] +var x = (function () { + function C() { + } + return C; +})(); diff --git a/tests/baselines/reference/functionDeclarationWithResolutionOfTypeNamedArguments01.js b/tests/baselines/reference/functionDeclarationWithResolutionOfTypeNamedArguments01.js new file mode 100644 index 00000000000..3659f3fd9f9 --- /dev/null +++ b/tests/baselines/reference/functionDeclarationWithResolutionOfTypeNamedArguments01.js @@ -0,0 +1,12 @@ +//// [functionDeclarationWithResolutionOfTypeNamedArguments01.ts] +interface arguments { +} + +function f() { + arguments; +} + +//// [functionDeclarationWithResolutionOfTypeNamedArguments01.js] +function f() { + arguments; +} diff --git a/tests/baselines/reference/functionDeclarationWithResolutionOfTypeNamedArguments01.symbols b/tests/baselines/reference/functionDeclarationWithResolutionOfTypeNamedArguments01.symbols new file mode 100644 index 00000000000..8a36f146001 --- /dev/null +++ b/tests/baselines/reference/functionDeclarationWithResolutionOfTypeNamedArguments01.symbols @@ -0,0 +1,12 @@ +=== tests/cases/compiler/functionDeclarationWithResolutionOfTypeNamedArguments01.ts === +interface arguments { +>arguments : Symbol(arguments, Decl(functionDeclarationWithResolutionOfTypeNamedArguments01.ts, 0, 0)) +} + +function f() { +>f : Symbol(f, Decl(functionDeclarationWithResolutionOfTypeNamedArguments01.ts, 1, 1)) + + arguments; +>arguments : Symbol(arguments, Decl(functionDeclarationWithResolutionOfTypeNamedArguments01.ts, 0, 0)) +>arguments : Symbol(arguments) +} diff --git a/tests/baselines/reference/functionDeclarationWithResolutionOfTypeNamedArguments01.types b/tests/baselines/reference/functionDeclarationWithResolutionOfTypeNamedArguments01.types new file mode 100644 index 00000000000..72dbbf8ec69 --- /dev/null +++ b/tests/baselines/reference/functionDeclarationWithResolutionOfTypeNamedArguments01.types @@ -0,0 +1,13 @@ +=== tests/cases/compiler/functionDeclarationWithResolutionOfTypeNamedArguments01.ts === +interface arguments { +>arguments : arguments +} + +function f() { +>f : () => void + + arguments; +>arguments : arguments +>arguments : arguments +>arguments : IArguments +} diff --git a/tests/baselines/reference/functionExpressionWithResolutionOfTypeNamedArguments01.js b/tests/baselines/reference/functionExpressionWithResolutionOfTypeNamedArguments01.js new file mode 100644 index 00000000000..43b38f2dd39 --- /dev/null +++ b/tests/baselines/reference/functionExpressionWithResolutionOfTypeNamedArguments01.js @@ -0,0 +1,12 @@ +//// [functionExpressionWithResolutionOfTypeNamedArguments01.ts] +interface arguments { +} + +var x = function f() { + arguments; +} + +//// [functionExpressionWithResolutionOfTypeNamedArguments01.js] +var x = function f() { + arguments; +}; diff --git a/tests/baselines/reference/functionExpressionWithResolutionOfTypeNamedArguments01.symbols b/tests/baselines/reference/functionExpressionWithResolutionOfTypeNamedArguments01.symbols new file mode 100644 index 00000000000..d2455fd0106 --- /dev/null +++ b/tests/baselines/reference/functionExpressionWithResolutionOfTypeNamedArguments01.symbols @@ -0,0 +1,13 @@ +=== tests/cases/compiler/functionExpressionWithResolutionOfTypeNamedArguments01.ts === +interface arguments { +>arguments : Symbol(arguments, Decl(functionExpressionWithResolutionOfTypeNamedArguments01.ts, 0, 0)) +} + +var x = function f() { +>x : Symbol(x, Decl(functionExpressionWithResolutionOfTypeNamedArguments01.ts, 3, 3)) +>f : Symbol(f, Decl(functionExpressionWithResolutionOfTypeNamedArguments01.ts, 3, 7)) + + arguments; +>arguments : Symbol(arguments, Decl(functionExpressionWithResolutionOfTypeNamedArguments01.ts, 0, 0)) +>arguments : Symbol(arguments) +} diff --git a/tests/baselines/reference/functionExpressionWithResolutionOfTypeNamedArguments01.types b/tests/baselines/reference/functionExpressionWithResolutionOfTypeNamedArguments01.types new file mode 100644 index 00000000000..1a65010a4f6 --- /dev/null +++ b/tests/baselines/reference/functionExpressionWithResolutionOfTypeNamedArguments01.types @@ -0,0 +1,15 @@ +=== tests/cases/compiler/functionExpressionWithResolutionOfTypeNamedArguments01.ts === +interface arguments { +>arguments : arguments +} + +var x = function f() { +>x : () => void +>function f() { arguments;} : () => void +>f : () => void + + arguments; +>arguments : arguments +>arguments : arguments +>arguments : IArguments +} diff --git a/tests/baselines/reference/functionExpressionWithResolutionOfTypeOfSameName01.js b/tests/baselines/reference/functionExpressionWithResolutionOfTypeOfSameName01.js new file mode 100644 index 00000000000..c9af7ab3297 --- /dev/null +++ b/tests/baselines/reference/functionExpressionWithResolutionOfTypeOfSameName01.js @@ -0,0 +1,12 @@ +//// [functionExpressionWithResolutionOfTypeOfSameName01.ts] +interface f { +} + +var x = function f() { + f; +} + +//// [functionExpressionWithResolutionOfTypeOfSameName01.js] +var x = function f() { + f; +}; diff --git a/tests/baselines/reference/functionExpressionWithResolutionOfTypeOfSameName01.symbols b/tests/baselines/reference/functionExpressionWithResolutionOfTypeOfSameName01.symbols new file mode 100644 index 00000000000..cd2248c6018 --- /dev/null +++ b/tests/baselines/reference/functionExpressionWithResolutionOfTypeOfSameName01.symbols @@ -0,0 +1,13 @@ +=== tests/cases/compiler/functionExpressionWithResolutionOfTypeOfSameName01.ts === +interface f { +>f : Symbol(f, Decl(functionExpressionWithResolutionOfTypeOfSameName01.ts, 0, 0)) +} + +var x = function f() { +>x : Symbol(x, Decl(functionExpressionWithResolutionOfTypeOfSameName01.ts, 3, 3)) +>f : Symbol(f, Decl(functionExpressionWithResolutionOfTypeOfSameName01.ts, 3, 7)) + + f; +>f : Symbol(f, Decl(functionExpressionWithResolutionOfTypeOfSameName01.ts, 0, 0)) +>f : Symbol(f, Decl(functionExpressionWithResolutionOfTypeOfSameName01.ts, 3, 7)) +} diff --git a/tests/baselines/reference/functionExpressionWithResolutionOfTypeOfSameName01.types b/tests/baselines/reference/functionExpressionWithResolutionOfTypeOfSameName01.types new file mode 100644 index 00000000000..08b51f35226 --- /dev/null +++ b/tests/baselines/reference/functionExpressionWithResolutionOfTypeOfSameName01.types @@ -0,0 +1,15 @@ +=== tests/cases/compiler/functionExpressionWithResolutionOfTypeOfSameName01.ts === +interface f { +>f : f +} + +var x = function f() { +>x : () => void +>function f() { f;} : () => void +>f : () => void + + f; +>f : f +>f : f +>f : () => void +} From db313061ee1ba80fc263829f14f65dc26f8dc766 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 27 May 2015 16:30:44 -0700 Subject: [PATCH 009/107] Added another test. --- .../functionExpressionWithResolutionOfTypeOfSameName02.ts | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tests/cases/compiler/functionExpressionWithResolutionOfTypeOfSameName02.ts diff --git a/tests/cases/compiler/functionExpressionWithResolutionOfTypeOfSameName02.ts b/tests/cases/compiler/functionExpressionWithResolutionOfTypeOfSameName02.ts new file mode 100644 index 00000000000..041195271fb --- /dev/null +++ b/tests/cases/compiler/functionExpressionWithResolutionOfTypeOfSameName02.ts @@ -0,0 +1,6 @@ +interface Foo { +} + +var x = function Foo() { + var x: Foo; +} \ No newline at end of file From acbff901da2b80b346ea1dcaae057ca854294265 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 27 May 2015 16:34:39 -0700 Subject: [PATCH 010/107] Accepted baselines. --- ...onExpressionWithResolutionOfTypeOfSameName02.js | 12 ++++++++++++ ...ressionWithResolutionOfTypeOfSameName02.symbols | 13 +++++++++++++ ...xpressionWithResolutionOfTypeOfSameName02.types | 14 ++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 tests/baselines/reference/functionExpressionWithResolutionOfTypeOfSameName02.js create mode 100644 tests/baselines/reference/functionExpressionWithResolutionOfTypeOfSameName02.symbols create mode 100644 tests/baselines/reference/functionExpressionWithResolutionOfTypeOfSameName02.types diff --git a/tests/baselines/reference/functionExpressionWithResolutionOfTypeOfSameName02.js b/tests/baselines/reference/functionExpressionWithResolutionOfTypeOfSameName02.js new file mode 100644 index 00000000000..ada96c63a56 --- /dev/null +++ b/tests/baselines/reference/functionExpressionWithResolutionOfTypeOfSameName02.js @@ -0,0 +1,12 @@ +//// [functionExpressionWithResolutionOfTypeOfSameName02.ts] +interface Foo { +} + +var x = function Foo() { + var x: Foo; +} + +//// [functionExpressionWithResolutionOfTypeOfSameName02.js] +var x = function Foo() { + var x; +}; diff --git a/tests/baselines/reference/functionExpressionWithResolutionOfTypeOfSameName02.symbols b/tests/baselines/reference/functionExpressionWithResolutionOfTypeOfSameName02.symbols new file mode 100644 index 00000000000..89b46c99b4e --- /dev/null +++ b/tests/baselines/reference/functionExpressionWithResolutionOfTypeOfSameName02.symbols @@ -0,0 +1,13 @@ +=== tests/cases/compiler/functionExpressionWithResolutionOfTypeOfSameName02.ts === +interface Foo { +>Foo : Symbol(Foo, Decl(functionExpressionWithResolutionOfTypeOfSameName02.ts, 0, 0)) +} + +var x = function Foo() { +>x : Symbol(x, Decl(functionExpressionWithResolutionOfTypeOfSameName02.ts, 3, 3)) +>Foo : Symbol(Foo, Decl(functionExpressionWithResolutionOfTypeOfSameName02.ts, 3, 7)) + + var x: Foo; +>x : Symbol(x, Decl(functionExpressionWithResolutionOfTypeOfSameName02.ts, 4, 7)) +>Foo : Symbol(Foo, Decl(functionExpressionWithResolutionOfTypeOfSameName02.ts, 0, 0)) +} diff --git a/tests/baselines/reference/functionExpressionWithResolutionOfTypeOfSameName02.types b/tests/baselines/reference/functionExpressionWithResolutionOfTypeOfSameName02.types new file mode 100644 index 00000000000..218276a95ea --- /dev/null +++ b/tests/baselines/reference/functionExpressionWithResolutionOfTypeOfSameName02.types @@ -0,0 +1,14 @@ +=== tests/cases/compiler/functionExpressionWithResolutionOfTypeOfSameName02.ts === +interface Foo { +>Foo : Foo +} + +var x = function Foo() { +>x : () => void +>function Foo() { var x: Foo;} : () => void +>Foo : () => void + + var x: Foo; +>x : Foo +>Foo : Foo +} From 413176b2a1a54babdd94d8baa51d996d62cee1a7 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 30 May 2015 16:37:03 -0700 Subject: [PATCH 011/107] Use symbols instead of types in infinite instantiation detection --- src/compiler/checker.ts | 123 +++++++++++++++++++++------------------- src/compiler/types.ts | 11 ++-- 2 files changed, 70 insertions(+), 64 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 76ec977491e..7c640598e69 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1472,7 +1472,7 @@ module ts { return appendParentTypeArgumentsAndSymbolName(symbol); } - function buildTypeDisplay(type: Type, writer: SymbolWriter, enclosingDeclaration?: Node, globalFlags?: TypeFormatFlags, typeStack?: Type[]) { + function buildTypeDisplay(type: Type, writer: SymbolWriter, enclosingDeclaration?: Node, globalFlags?: TypeFormatFlags, symbolStack?: Symbol[]) { let globalFlagsToPass = globalFlags & TypeFormatFlags.WriteOwnNameForAnyLike; return writeType(type, globalFlags); @@ -1557,49 +1557,54 @@ module ts { } function writeAnonymousType(type: ObjectType, flags: TypeFormatFlags) { - // Always use 'typeof T' for type of class, enum, and module objects - if (type.symbol && type.symbol.flags & (SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) { - writeTypeofSymbol(type, flags); - } - // Use 'typeof T' for types of functions and methods that circularly reference themselves - else if (shouldWriteTypeOfFunctionSymbol()) { - writeTypeofSymbol(type, flags); - } - else if (typeStack && contains(typeStack, type)) { - // If type is an anonymous type literal in a type alias declaration, use type alias name - let typeAlias = getTypeAliasForTypeLiteral(type); - if (typeAlias) { - // The specified symbol flags need to be reinterpreted as type flags - buildSymbolDisplay(typeAlias, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, flags); + let symbol = type.symbol; + if (symbol) { + // Always use 'typeof T' for type of class, enum, and module objects + if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) { + writeTypeofSymbol(type, flags); + } + else if (shouldWriteTypeOfFunctionSymbol()) { + writeTypeofSymbol(type, flags); + } + else if (contains(symbolStack, symbol)) { + // If type is an anonymous type literal in a type alias declaration, use type alias name + let typeAlias = getTypeAliasForTypeLiteral(type); + if (typeAlias) { + // The specified symbol flags need to be reinterpreted as type flags + buildSymbolDisplay(typeAlias, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, flags); + } + else { + // Recursive usage, use any + writeKeyword(writer, SyntaxKind.AnyKeyword); + } } else { - // Recursive usage, use any - writeKeyword(writer, SyntaxKind.AnyKeyword); + // Since instantiations of the same anonymous type have the same symbol, tracking symbols instead + // of types allows us to catch circular references to instantiations of the same anonymous type + if (!symbolStack) { + symbolStack = []; + } + symbolStack.push(symbol); + writeLiteralType(type, flags); + symbolStack.pop(); } } else { - if (!typeStack) { - typeStack = []; - } - typeStack.push(type); + // Anonymous types with no symbol are never circular writeLiteralType(type, flags); - typeStack.pop(); } function shouldWriteTypeOfFunctionSymbol() { - if (type.symbol) { - let isStaticMethodSymbol = !!(type.symbol.flags & SymbolFlags.Method && // typeof static method - ts.forEach(type.symbol.declarations, declaration => declaration.flags & NodeFlags.Static)); - let isNonLocalFunctionSymbol = !!(type.symbol.flags & SymbolFlags.Function) && - (type.symbol.parent || // is exported function symbol - ts.forEach(type.symbol.declarations, declaration => - declaration.parent.kind === SyntaxKind.SourceFile || declaration.parent.kind === SyntaxKind.ModuleBlock)); - - if (isStaticMethodSymbol || isNonLocalFunctionSymbol) { - // typeof is allowed only for static/non local functions - return !!(flags & TypeFormatFlags.UseTypeOfFunction) || // use typeof if format flags specify it - (typeStack && contains(typeStack, type)); // it is type of the symbol uses itself recursively - } + let isStaticMethodSymbol = !!(symbol.flags & SymbolFlags.Method && // typeof static method + forEach(symbol.declarations, declaration => declaration.flags & NodeFlags.Static)); + let isNonLocalFunctionSymbol = !!(symbol.flags & SymbolFlags.Function) && + (symbol.parent || // is exported function symbol + forEach(symbol.declarations, declaration => + declaration.parent.kind === SyntaxKind.SourceFile || declaration.parent.kind === SyntaxKind.ModuleBlock)); + if (isStaticMethodSymbol || isNonLocalFunctionSymbol) { + // typeof is allowed only for static/non local functions + return !!(flags & TypeFormatFlags.UseTypeOfFunction) || // use typeof if format flags specify it + (contains(symbolStack, symbol)); // it is type of the symbol uses itself recursively } } } @@ -1634,7 +1639,7 @@ module ts { if (flags & TypeFormatFlags.InElementType) { writePunctuation(writer, SyntaxKind.OpenParenToken); } - buildSignatureDisplay(resolved.callSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | TypeFormatFlags.WriteArrowStyleSignature, typeStack); + buildSignatureDisplay(resolved.callSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | TypeFormatFlags.WriteArrowStyleSignature, symbolStack); if (flags & TypeFormatFlags.InElementType) { writePunctuation(writer, SyntaxKind.CloseParenToken); } @@ -1646,7 +1651,7 @@ module ts { } writeKeyword(writer, SyntaxKind.NewKeyword); writeSpace(writer); - buildSignatureDisplay(resolved.constructSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | TypeFormatFlags.WriteArrowStyleSignature, typeStack); + buildSignatureDisplay(resolved.constructSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | TypeFormatFlags.WriteArrowStyleSignature, symbolStack); if (flags & TypeFormatFlags.InElementType) { writePunctuation(writer, SyntaxKind.CloseParenToken); } @@ -1658,7 +1663,7 @@ module ts { writer.writeLine(); writer.increaseIndent(); for (let signature of resolved.callSignatures) { - buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, typeStack); + buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, symbolStack); writePunctuation(writer, SyntaxKind.SemicolonToken); writer.writeLine(); } @@ -1666,7 +1671,7 @@ module ts { writeKeyword(writer, SyntaxKind.NewKeyword); writeSpace(writer); - buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, typeStack); + buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, symbolStack); writePunctuation(writer, SyntaxKind.SemicolonToken); writer.writeLine(); } @@ -1707,7 +1712,7 @@ module ts { if (p.flags & SymbolFlags.Optional) { writePunctuation(writer, SyntaxKind.QuestionToken); } - buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, typeStack); + buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, symbolStack); writePunctuation(writer, SyntaxKind.SemicolonToken); writer.writeLine(); } @@ -1736,18 +1741,18 @@ module ts { } } - function buildTypeParameterDisplay(tp: TypeParameter, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) { + function buildTypeParameterDisplay(tp: TypeParameter, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) { appendSymbolNameOnly(tp.symbol, writer); let constraint = getConstraintOfTypeParameter(tp); if (constraint) { writeSpace(writer); writeKeyword(writer, SyntaxKind.ExtendsKeyword); writeSpace(writer); - buildTypeDisplay(constraint, writer, enclosingDeclaration, flags, typeStack); + buildTypeDisplay(constraint, writer, enclosingDeclaration, flags, symbolStack); } } - function buildParameterDisplay(p: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) { + function buildParameterDisplay(p: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) { if (hasDotDotDotToken(p.valueDeclaration)) { writePunctuation(writer, SyntaxKind.DotDotDotToken); } @@ -1758,10 +1763,10 @@ module ts { writePunctuation(writer, SyntaxKind.ColonToken); writeSpace(writer); - buildTypeDisplay(getTypeOfSymbol(p), writer, enclosingDeclaration, flags, typeStack); + buildTypeDisplay(getTypeOfSymbol(p), writer, enclosingDeclaration, flags, symbolStack); } - function buildDisplayForTypeParametersAndDelimiters(typeParameters: TypeParameter[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) { + function buildDisplayForTypeParametersAndDelimiters(typeParameters: TypeParameter[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) { if (typeParameters && typeParameters.length) { writePunctuation(writer, SyntaxKind.LessThanToken); for (let i = 0; i < typeParameters.length; i++) { @@ -1769,13 +1774,13 @@ module ts { writePunctuation(writer, SyntaxKind.CommaToken); writeSpace(writer); } - buildTypeParameterDisplay(typeParameters[i], writer, enclosingDeclaration, flags, typeStack); + buildTypeParameterDisplay(typeParameters[i], writer, enclosingDeclaration, flags, symbolStack); } writePunctuation(writer, SyntaxKind.GreaterThanToken); } } - function buildDisplayForTypeArgumentsAndDelimiters(typeParameters: TypeParameter[], mapper: TypeMapper, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) { + function buildDisplayForTypeArgumentsAndDelimiters(typeParameters: TypeParameter[], mapper: TypeMapper, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) { if (typeParameters && typeParameters.length) { writePunctuation(writer, SyntaxKind.LessThanToken); for (let i = 0; i < typeParameters.length; i++) { @@ -1789,19 +1794,19 @@ module ts { } } - function buildDisplayForParametersAndDelimiters(parameters: Symbol[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) { + function buildDisplayForParametersAndDelimiters(parameters: Symbol[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) { writePunctuation(writer, SyntaxKind.OpenParenToken); for (let i = 0; i < parameters.length; i++) { if (i > 0) { writePunctuation(writer, SyntaxKind.CommaToken); writeSpace(writer); } - buildParameterDisplay(parameters[i], writer, enclosingDeclaration, flags, typeStack); + buildParameterDisplay(parameters[i], writer, enclosingDeclaration, flags, symbolStack); } writePunctuation(writer, SyntaxKind.CloseParenToken); } - function buildReturnTypeDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) { + function buildReturnTypeDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) { if (flags & TypeFormatFlags.WriteArrowStyleSignature) { writeSpace(writer); writePunctuation(writer, SyntaxKind.EqualsGreaterThanToken); @@ -1810,21 +1815,21 @@ module ts { writePunctuation(writer, SyntaxKind.ColonToken); } writeSpace(writer); - buildTypeDisplay(getReturnTypeOfSignature(signature), writer, enclosingDeclaration, flags, typeStack); + buildTypeDisplay(getReturnTypeOfSignature(signature), writer, enclosingDeclaration, flags, symbolStack); } - function buildSignatureDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) { + function buildSignatureDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) { if (signature.target && (flags & TypeFormatFlags.WriteTypeArgumentsOfSignature)) { // Instantiated signature, write type arguments instead // This is achieved by passing in the mapper separately buildDisplayForTypeArgumentsAndDelimiters(signature.target.typeParameters, signature.mapper, writer, enclosingDeclaration); } else { - buildDisplayForTypeParametersAndDelimiters(signature.typeParameters, writer, enclosingDeclaration, flags, typeStack); + buildDisplayForTypeParametersAndDelimiters(signature.typeParameters, writer, enclosingDeclaration, flags, symbolStack); } - buildDisplayForParametersAndDelimiters(signature.parameters, writer, enclosingDeclaration, flags, typeStack); - buildReturnTypeDisplay(signature, writer, enclosingDeclaration, flags, typeStack); + buildDisplayForParametersAndDelimiters(signature.parameters, writer, enclosingDeclaration, flags, symbolStack); + buildReturnTypeDisplay(signature, writer, enclosingDeclaration, flags, symbolStack); } return _displayBuilder || (_displayBuilder = { @@ -3889,7 +3894,7 @@ module ts { mapper.mappings = {}; } // Instantiate the given type using the given mapper and cache the result - let result = createObjectType(TypeFlags.Anonymous, type.symbol); + let result = createObjectType(TypeFlags.Anonymous | TypeFlags.Instantiated, type.symbol); result.properties = instantiateList(getPropertiesOfObjectType(type), mapper, instantiateSymbol); result.members = createSymbolTable(result.properties); result.callSignatures = instantiateList(getSignaturesOfType(type, SignatureKind.Call), mapper, instantiateSignature); @@ -4313,12 +4318,12 @@ module ts { // Effectively, we will generate a false positive when two types are structurally equal to at least 10 levels, but unequal at // some level beyond that. function isDeeplyNestedGeneric(type: ObjectType, stack: ObjectType[]): boolean { - if (type.flags & TypeFlags.Reference && depth >= 10) { - let target = (type).target; + if (type.flags & (TypeFlags.Reference | TypeFlags.Instantiated) && depth >= 10) { + let symbol = type.symbol; let count = 0; for (let i = 0; i < depth; i++) { let t = stack[i]; - if (t.flags & TypeFlags.Reference && (t).target === target) { + if (t.flags & (TypeFlags.Reference | TypeFlags.Instantiated) && t.symbol === symbol) { count++; if (count >= 10) return true; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 3d52d096b03..a6ab19d4296 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1582,14 +1582,15 @@ module ts { Tuple = 0x00002000, // Tuple Union = 0x00004000, // Union Anonymous = 0x00008000, // Anonymous + Instantiated = 0x00010000, // Instantiated anonymous type /* @internal */ - FromSignature = 0x00010000, // Created for signature assignment check - ObjectLiteral = 0x00020000, // Originates in an object literal + FromSignature = 0x00020000, // Created for signature assignment check + ObjectLiteral = 0x00040000, // Originates in an object literal /* @internal */ - ContainsUndefinedOrNull = 0x00040000, // Type is or contains Undefined or Null type + ContainsUndefinedOrNull = 0x00080000, // Type is or contains Undefined or Null type /* @internal */ - ContainsObjectLiteral = 0x00080000, // Type is or contains object literal type - ESSymbol = 0x00100000, // Type of symbol primitive introduced in ES6 + ContainsObjectLiteral = 0x00100000, // Type is or contains object literal type + ESSymbol = 0x00200000, // Type of symbol primitive introduced in ES6 /* @internal */ Intrinsic = Any | String | Number | Boolean | ESSymbol | Void | Undefined | Null, From 46e0ba82cec8e97e1e0be137e94d1d2fcef31381 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 30 May 2015 17:25:44 -0700 Subject: [PATCH 012/107] Remove old (and insufficient) instantiation caching --- src/compiler/checker.ts | 14 +------------- src/compiler/types.ts | 1 - 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7c640598e69..c180d8425f2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3882,18 +3882,7 @@ module ts { } function instantiateAnonymousType(type: ObjectType, mapper: TypeMapper): ObjectType { - // If this type has already been instantiated using this mapper, returned the cached result. This guards against - // infinite instantiations of cyclic types, e.g. "var x: { a: T, b: typeof x };" - if (mapper.mappings) { - let cached = mapper.mappings[type.id]; - if (cached) { - return cached; - } - } - else { - mapper.mappings = {}; - } - // Instantiate the given type using the given mapper and cache the result + // Mark the anonymous type as instantiated such that our infinite instantiation detection logic can recognize it let result = createObjectType(TypeFlags.Anonymous | TypeFlags.Instantiated, type.symbol); result.properties = instantiateList(getPropertiesOfObjectType(type), mapper, instantiateSymbol); result.members = createSymbolTable(result.properties); @@ -3903,7 +3892,6 @@ module ts { let numberIndexType = getIndexTypeOfType(type, IndexKind.Number); if (stringIndexType) result.stringIndexType = instantiateType(stringIndexType, mapper); if (numberIndexType) result.numberIndexType = instantiateType(numberIndexType, mapper); - mapper.mappings[type.id] = result; return result; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index a6ab19d4296..2d1175df080 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1730,7 +1730,6 @@ module ts { /* @internal */ export interface TypeMapper { (t: TypeParameter): Type; - mappings?: Map; // Type mapping cache } /* @internal */ From e336e3ad0aa6e983d380dcd9bbd107b157a5bfba Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 30 May 2015 18:09:13 -0700 Subject: [PATCH 013/107] Adding regression test --- .../cyclicGenericTypeInstantiation.js | 37 ++++++++++++ .../cyclicGenericTypeInstantiation.symbols | 55 +++++++++++++++++ .../cyclicGenericTypeInstantiation.types | 60 +++++++++++++++++++ .../cyclicGenericTypeInstantiation.ts | 20 +++++++ 4 files changed, 172 insertions(+) create mode 100644 tests/baselines/reference/cyclicGenericTypeInstantiation.js create mode 100644 tests/baselines/reference/cyclicGenericTypeInstantiation.symbols create mode 100644 tests/baselines/reference/cyclicGenericTypeInstantiation.types create mode 100644 tests/cases/compiler/cyclicGenericTypeInstantiation.ts diff --git a/tests/baselines/reference/cyclicGenericTypeInstantiation.js b/tests/baselines/reference/cyclicGenericTypeInstantiation.js new file mode 100644 index 00000000000..10f52e10d89 --- /dev/null +++ b/tests/baselines/reference/cyclicGenericTypeInstantiation.js @@ -0,0 +1,37 @@ +//// [cyclicGenericTypeInstantiation.ts] +function foo() { + var z = foo(); + var y: { + y2: typeof z + }; + return y; +} + + +function bar() { + var z = bar(); + var y: { + y2: typeof z; + } + return y; +} + +var a = foo(); +var b = bar(); +a = b; + + +//// [cyclicGenericTypeInstantiation.js] +function foo() { + var z = foo(); + var y; + return y; +} +function bar() { + var z = bar(); + var y; + return y; +} +var a = foo(); +var b = bar(); +a = b; diff --git a/tests/baselines/reference/cyclicGenericTypeInstantiation.symbols b/tests/baselines/reference/cyclicGenericTypeInstantiation.symbols new file mode 100644 index 00000000000..a6566b86839 --- /dev/null +++ b/tests/baselines/reference/cyclicGenericTypeInstantiation.symbols @@ -0,0 +1,55 @@ +=== tests/cases/compiler/cyclicGenericTypeInstantiation.ts === +function foo() { +>foo : Symbol(foo, Decl(cyclicGenericTypeInstantiation.ts, 0, 0)) +>T : Symbol(T, Decl(cyclicGenericTypeInstantiation.ts, 0, 13)) + + var z = foo(); +>z : Symbol(z, Decl(cyclicGenericTypeInstantiation.ts, 1, 7)) +>foo : Symbol(foo, Decl(cyclicGenericTypeInstantiation.ts, 0, 0)) +>y : Symbol(y, Decl(cyclicGenericTypeInstantiation.ts, 2, 7)) + + var y: { +>y : Symbol(y, Decl(cyclicGenericTypeInstantiation.ts, 2, 7)) + + y2: typeof z +>y2 : Symbol(y2, Decl(cyclicGenericTypeInstantiation.ts, 2, 12)) +>z : Symbol(z, Decl(cyclicGenericTypeInstantiation.ts, 1, 7)) + + }; + return y; +>y : Symbol(y, Decl(cyclicGenericTypeInstantiation.ts, 2, 7)) +} + + +function bar() { +>bar : Symbol(bar, Decl(cyclicGenericTypeInstantiation.ts, 6, 1)) +>T : Symbol(T, Decl(cyclicGenericTypeInstantiation.ts, 9, 13)) + + var z = bar(); +>z : Symbol(z, Decl(cyclicGenericTypeInstantiation.ts, 10, 7)) +>bar : Symbol(bar, Decl(cyclicGenericTypeInstantiation.ts, 6, 1)) +>y : Symbol(y, Decl(cyclicGenericTypeInstantiation.ts, 11, 7)) + + var y: { +>y : Symbol(y, Decl(cyclicGenericTypeInstantiation.ts, 11, 7)) + + y2: typeof z; +>y2 : Symbol(y2, Decl(cyclicGenericTypeInstantiation.ts, 11, 12)) +>z : Symbol(z, Decl(cyclicGenericTypeInstantiation.ts, 10, 7)) + } + return y; +>y : Symbol(y, Decl(cyclicGenericTypeInstantiation.ts, 11, 7)) +} + +var a = foo(); +>a : Symbol(a, Decl(cyclicGenericTypeInstantiation.ts, 17, 3)) +>foo : Symbol(foo, Decl(cyclicGenericTypeInstantiation.ts, 0, 0)) + +var b = bar(); +>b : Symbol(b, Decl(cyclicGenericTypeInstantiation.ts, 18, 3)) +>bar : Symbol(bar, Decl(cyclicGenericTypeInstantiation.ts, 6, 1)) + +a = b; +>a : Symbol(a, Decl(cyclicGenericTypeInstantiation.ts, 17, 3)) +>b : Symbol(b, Decl(cyclicGenericTypeInstantiation.ts, 18, 3)) + diff --git a/tests/baselines/reference/cyclicGenericTypeInstantiation.types b/tests/baselines/reference/cyclicGenericTypeInstantiation.types new file mode 100644 index 00000000000..69b0955b22f --- /dev/null +++ b/tests/baselines/reference/cyclicGenericTypeInstantiation.types @@ -0,0 +1,60 @@ +=== tests/cases/compiler/cyclicGenericTypeInstantiation.ts === +function foo() { +>foo : () => { y2: any; } +>T : T + + var z = foo(); +>z : { y2: any; } +>foo() : { y2: any; } +>foo : () => { y2: any; } +>y : { y2: any; } + + var y: { +>y : { y2: any; } + + y2: typeof z +>y2 : { y2: any; } +>z : { y2: any; } + + }; + return y; +>y : { y2: any; } +} + + +function bar() { +>bar : () => { y2: any; } +>T : T + + var z = bar(); +>z : { y2: any; } +>bar() : { y2: any; } +>bar : () => { y2: any; } +>y : { y2: any; } + + var y: { +>y : { y2: any; } + + y2: typeof z; +>y2 : { y2: any; } +>z : { y2: any; } + } + return y; +>y : { y2: any; } +} + +var a = foo(); +>a : { y2: any; } +>foo() : { y2: any; } +>foo : () => { y2: any; } + +var b = bar(); +>b : { y2: any; } +>bar() : { y2: any; } +>bar : () => { y2: any; } + +a = b; +>a = b : { y2: any; } +>a : { y2: any; } +>b : { y2: any; } + diff --git a/tests/cases/compiler/cyclicGenericTypeInstantiation.ts b/tests/cases/compiler/cyclicGenericTypeInstantiation.ts new file mode 100644 index 00000000000..070cc44a63a --- /dev/null +++ b/tests/cases/compiler/cyclicGenericTypeInstantiation.ts @@ -0,0 +1,20 @@ +function foo() { + var z = foo(); + var y: { + y2: typeof z + }; + return y; +} + + +function bar() { + var z = bar(); + var y: { + y2: typeof z; + } + return y; +} + +var a = foo(); +var b = bar(); +a = b; From 8b7caedbec33bc442b98764ba981903a8da97993 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 2 Jun 2015 10:45:50 -0700 Subject: [PATCH 014/107] Remove EmitResolver.getExpressionNameSubstitution Add EmitResolver.getReferencedExportContainer Add EmitResolver.getReferencedImportDeclaration Clean up getGeneratedNameForNode in emitter.ts Switch isNotExpressionIdentifier to isExpressionIdentifier in emitter.ts Revise emitExpressionIdentifier in emitter.ts --- src/compiler/checker.ts | 110 ++++++++------------ src/compiler/emitter.ts | 216 +++++++++++++++++++++------------------- src/compiler/types.ts | 3 +- 3 files changed, 155 insertions(+), 174 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 759b235ad0a..6257031afbd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11784,76 +11784,39 @@ module ts { // Emitter support - function isExternalModuleSymbol(symbol: Symbol): boolean { - return symbol.flags & SymbolFlags.ValueModule && symbol.declarations.length === 1 && symbol.declarations[0].kind === SyntaxKind.SourceFile; - } - - function getAliasNameSubstitution(symbol: Symbol, getGeneratedNameForNode: (node: Node) => string): string { - // If this is es6 or higher, just use the name of the export - // no need to qualify it. - if (languageVersion >= ScriptTarget.ES6) { - return undefined; - } - - let node = getDeclarationOfAliasSymbol(symbol); - if (node) { - if (node.kind === SyntaxKind.ImportClause) { - let defaultKeyword: string; - - if (languageVersion === ScriptTarget.ES3) { - defaultKeyword = "[\"default\"]"; - } else { - defaultKeyword = ".default"; - } - return getGeneratedNameForNode(node.parent) + defaultKeyword; - } - if (node.kind === SyntaxKind.ImportSpecifier) { - let moduleName = getGeneratedNameForNode(node.parent.parent.parent); - let propertyName = (node).propertyName || (node).name; - return moduleName + "." + unescapeIdentifier(propertyName.text); - } - } - } - - function getExportNameSubstitution(symbol: Symbol, location: Node, getGeneratedNameForNode: (Node: Node) => string): string { - if (isExternalModuleSymbol(symbol.parent)) { - // 1. If this is es6 or higher, just use the name of the export - // no need to qualify it. - // 2. export mechanism for System modules is different from CJS\AMD - // and it does not need qualifications for exports - if (languageVersion >= ScriptTarget.ES6 || compilerOptions.module === ModuleKind.System) { - return undefined; - } - return "exports." + unescapeIdentifier(symbol.name); - } - let node = location; - let containerSymbol = getParentOfSymbol(symbol); - while (node) { - if ((node.kind === SyntaxKind.ModuleDeclaration || node.kind === SyntaxKind.EnumDeclaration) && getSymbolOfNode(node) === containerSymbol) { - return getGeneratedNameForNode(node) + "." + unescapeIdentifier(symbol.name); - } - node = node.parent; - } - } - - function getExpressionNameSubstitution(node: Identifier, getGeneratedNameForNode: (Node: Node) => string): string { - let symbol = getNodeLinks(node).resolvedSymbol || (isDeclarationName(node) ? getSymbolOfNode(node.parent) : undefined); + // When resolved as an expression identifier, if the given node references an exported entity, return the declaration + // node of the exported entity's container. Otherwise, return undefined. + function getReferencedExportContainer(node: Identifier): SourceFile | ModuleDeclaration | EnumDeclaration { + let symbol = getReferencedValueSymbol(node); if (symbol) { - // Whan an identifier resolves to a parented symbol, it references an exported entity from - // another declaration of the same internal module. - if (symbol.parent) { - return getExportNameSubstitution(symbol, node.parent, getGeneratedNameForNode); + if (symbol.flags & SymbolFlags.ExportValue) { + let exportSymbol = getMergedSymbol(symbol.exportSymbol); + if (!(exportSymbol.flags & SymbolFlags.ExportHasLocal)) { + symbol = exportSymbol; + } } - // If we reference an exported entity within the same module declaration, then whether - // we prefix depends on the kind of entity. SymbolFlags.ExportHasLocal encompasses all the - // kinds that we do NOT prefix. - let exportSymbol = getExportSymbolOfValueSymbolIfExported(symbol); - if (symbol !== exportSymbol && !(exportSymbol.flags & SymbolFlags.ExportHasLocal)) { - return getExportNameSubstitution(exportSymbol, node.parent, getGeneratedNameForNode); + let parentSymbol = getParentOfSymbol(symbol); + if (parentSymbol) { + if (parentSymbol.flags & SymbolFlags.ValueModule && parentSymbol.valueDeclaration.kind === SyntaxKind.SourceFile) { + return parentSymbol.valueDeclaration; + } + for (let n = node.parent; n; n = n.parent) { + if ((n.kind === SyntaxKind.ModuleDeclaration || n.kind === SyntaxKind.EnumDeclaration) && getSymbolOfNode(n) === parentSymbol) { + return n; + } + } } - // Named imports from ES6 import declarations are rewritten - if (symbol.flags & SymbolFlags.Alias) { - return getAliasNameSubstitution(symbol, getGeneratedNameForNode); + } + } + + // When resolved as an expression identifier, if the given node references a default import or a named import, return + // the declaration node of that import. Otherwise, return undefined. + function getReferencedImportDeclaration(node: Identifier): ImportClause | ImportSpecifier { + let symbol = getReferencedValueSymbol(node); + if (symbol && symbol.flags & SymbolFlags.Alias) { + let declaration = getDeclarationOfAliasSymbol(symbol); + if (declaration.kind === SyntaxKind.ImportClause || declaration.kind === SyntaxKind.ImportSpecifier) { + return declaration; } } } @@ -12182,12 +12145,15 @@ module ts { return !!resolveName(location, name, SymbolFlags.Value, /*nodeNotFoundMessage*/ undefined, /*nameArg*/ undefined); } + function getReferencedValueSymbol(reference: Identifier): Symbol { + return getNodeLinks(reference).resolvedSymbol || + resolveName(reference, reference.text, SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias, + /*nodeNotFoundMessage*/ undefined, /*nameArg*/ undefined); + } + function getReferencedValueDeclaration(reference: Identifier): Declaration { Debug.assert(!nodeIsSynthesized(reference)); - let symbol = - getNodeLinks(reference).resolvedSymbol || - resolveName(reference, reference.text, SymbolFlags.Value | SymbolFlags.Alias, /*nodeNotFoundMessage*/ undefined, /*nameArg*/ undefined); - + let symbol = getReferencedValueSymbol(reference); return symbol && getExportSymbolOfValueSymbolIfExported(symbol).valueDeclaration; } @@ -12233,6 +12199,8 @@ module ts { function createResolver(): EmitResolver { return { getExpressionNameSubstitution, + getReferencedExportContainer, + getReferencedImportDeclaration, isValueAliasDeclaration, hasGlobalName, isReferencedAliasDeclaration, diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 32ebeaec08f..2414c88a7a9 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -249,81 +249,42 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { } } - function assignGeneratedName(node: Node, name: string) { - nodeToGeneratedName[getNodeId(node)] = unescapeIdentifier(name); - } - - function generateNameForFunctionOrClassDeclaration(node: Declaration) { - if (!node.name) { - assignGeneratedName(node, makeUniqueName("default")); - } - } - function generateNameForModuleOrEnum(node: ModuleDeclaration | EnumDeclaration) { - if (node.name.kind === SyntaxKind.Identifier) { - let name = node.name.text; - // Use module/enum name itself if it is unique, otherwise make a unique variation - assignGeneratedName(node, isUniqueLocalName(name, node) ? name : makeUniqueName(name)); - } + let name = node.name.text; + // Use module/enum name itself if it is unique, otherwise make a unique variation + return isUniqueLocalName(name, node) ? name : makeUniqueName(name); } function generateNameForImportOrExportDeclaration(node: ImportDeclaration | ExportDeclaration) { let expr = getExternalModuleName(node); let baseName = expr.kind === SyntaxKind.StringLiteral ? escapeIdentifier(makeIdentifierFromModuleName((expr).text)) : "module"; - assignGeneratedName(node, makeUniqueName(baseName)); + return makeUniqueName(baseName); } - function generateNameForImportDeclaration(node: ImportDeclaration) { - if (node.importClause) { - generateNameForImportOrExportDeclaration(node); - } - } - - function generateNameForExportDeclaration(node: ExportDeclaration) { - if (node.moduleSpecifier) { - generateNameForImportOrExportDeclaration(node); - } - } - - function generateNameForExportAssignment(node: ExportAssignment) { - if (node.expression && node.expression.kind !== SyntaxKind.Identifier) { - assignGeneratedName(node, makeUniqueName("default")); - } + function generateNameForExportDefault() { + return makeUniqueName("default"); } function generateNameForNode(node: Node) { switch (node.kind) { + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.EnumDeclaration: + return generateNameForModuleOrEnum(node); + case SyntaxKind.ImportDeclaration: + case SyntaxKind.ExportDeclaration: + return generateNameForImportOrExportDeclaration(node); case SyntaxKind.FunctionDeclaration: case SyntaxKind.ClassDeclaration: case SyntaxKind.ClassExpression: - generateNameForFunctionOrClassDeclaration(node); - break; - case SyntaxKind.ModuleDeclaration: - generateNameForModuleOrEnum(node); - generateNameForNode((node).body); - break; - case SyntaxKind.EnumDeclaration: - generateNameForModuleOrEnum(node); - break; - case SyntaxKind.ImportDeclaration: - generateNameForImportDeclaration(node); - break; - case SyntaxKind.ExportDeclaration: - generateNameForExportDeclaration(node); - break; case SyntaxKind.ExportAssignment: - generateNameForExportAssignment(node); - break; + return generateNameForExportDefault(); } } function getGeneratedNameForNode(node: Node) { - let nodeId = getNodeId(node); - if (!nodeToGeneratedName[nodeId]) { - generateNameForNode(node); - } - return nodeToGeneratedName[nodeId]; + let id = getNodeId(node); + return nodeToGeneratedName[id] || (nodeToGeneratedName[id] = unescapeIdentifier(generateNameForNode(node))); } function initializeEmitterWithSourceMaps() { @@ -1201,51 +1162,96 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { } } - function isNotExpressionIdentifier(node: Identifier) { + function isExpressionIdentifier(node: Node): boolean { let parent = node.parent; switch (parent.kind) { - case SyntaxKind.Parameter: - case SyntaxKind.VariableDeclaration: - case SyntaxKind.BindingElement: - case SyntaxKind.PropertyDeclaration: - case SyntaxKind.PropertySignature: - case SyntaxKind.PropertyAssignment: - case SyntaxKind.ShorthandPropertyAssignment: - case SyntaxKind.EnumMember: - case SyntaxKind.MethodDeclaration: - case SyntaxKind.MethodSignature: - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - case SyntaxKind.FunctionExpression: - case SyntaxKind.ClassDeclaration: - case SyntaxKind.InterfaceDeclaration: - case SyntaxKind.EnumDeclaration: - case SyntaxKind.ModuleDeclaration: - case SyntaxKind.ImportEqualsDeclaration: - case SyntaxKind.ImportClause: - case SyntaxKind.NamespaceImport: - return (parent).name === node; - case SyntaxKind.ImportSpecifier: - case SyntaxKind.ExportSpecifier: - return (parent).name === node || (parent).propertyName === node; - case SyntaxKind.BreakStatement: - case SyntaxKind.ContinueStatement: + case SyntaxKind.ArrayLiteralExpression: + case SyntaxKind.BinaryExpression: + case SyntaxKind.CallExpression: + case SyntaxKind.CaseClause: + case SyntaxKind.ComputedPropertyName: + case SyntaxKind.ConditionalExpression: + case SyntaxKind.Decorator: + case SyntaxKind.DeleteExpression: + case SyntaxKind.DoStatement: + case SyntaxKind.ElementAccessExpression: case SyntaxKind.ExportAssignment: - return false; - case SyntaxKind.LabeledStatement: - return (node.parent).label === node; + case SyntaxKind.ExpressionStatement: + case SyntaxKind.ExpressionWithTypeArguments: + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + case SyntaxKind.IfStatement: + case SyntaxKind.NewExpression: + case SyntaxKind.ParenthesizedExpression: + case SyntaxKind.PostfixUnaryExpression: + case SyntaxKind.PrefixUnaryExpression: + case SyntaxKind.ReturnStatement: + case SyntaxKind.SpreadElementExpression: + case SyntaxKind.SwitchStatement: + case SyntaxKind.TaggedTemplateExpression: + case SyntaxKind.TemplateSpan: + case SyntaxKind.ThrowStatement: + case SyntaxKind.TypeAssertionExpression: + case SyntaxKind.TypeOfExpression: + case SyntaxKind.VoidExpression: + case SyntaxKind.WhileStatement: + case SyntaxKind.WithStatement: + case SyntaxKind.YieldExpression: + return true; + case SyntaxKind.BindingElement: + case SyntaxKind.EnumMember: + case SyntaxKind.Parameter: + case SyntaxKind.PropertyAssignment: + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.VariableDeclaration: + return (parent).initializer === node; + case SyntaxKind.PropertyAccessExpression: + return (parent).expression === node; + case SyntaxKind.ArrowFunction: + case SyntaxKind.FunctionExpression: + return (parent).body === node; + case SyntaxKind.ImportEqualsDeclaration: + return (parent).moduleReference === node; + case SyntaxKind.QualifiedName: + return (parent).left === node; } + return false; } function emitExpressionIdentifier(node: Identifier) { - let substitution = resolver.getExpressionNameSubstitution(node, getGeneratedNameForNode); - if (substitution) { - write(substitution); + let container = resolver.getReferencedExportContainer(node); + if (container) { + if (container.kind === SyntaxKind.SourceFile) { + // Identifier references module export + if (languageVersion < ScriptTarget.ES6 && compilerOptions.module !== ModuleKind.System) { + write("exports."); + } + } + else { + // Identifier references namespace export + write(getGeneratedNameForNode(container)); + write("."); + } } - else { - writeTextOfNode(currentSourceFile, node); + else if (languageVersion < ScriptTarget.ES6) { + let declaration = resolver.getReferencedImportDeclaration(node); + if (declaration) { + if (declaration.kind === SyntaxKind.ImportClause) { + // Identifier references default import + write(getGeneratedNameForNode(declaration.parent)); + write(languageVersion === ScriptTarget.ES3 ? '["default"]' : ".default"); + } + else { + // Identifier references named import + write(getGeneratedNameForNode(declaration.parent.parent.parent)); + write("."); + writeTextOfNode(currentSourceFile, (declaration).propertyName || (declaration).name); + } + return; + } } + writeTextOfNode(currentSourceFile, node); } function getGeneratedNameForIdentifier(node: Identifier): string { @@ -1272,7 +1278,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { if (!node.parent) { write(node.text); } - else if (!isNotExpressionIdentifier(node)) { + else if (isExpressionIdentifier(node)) { emitExpressionIdentifier(node); } else { @@ -1709,12 +1715,15 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { emitExpressionIdentifier(node.name); } } - else if (resolver.getExpressionNameSubstitution(node.name, getGeneratedNameForNode)) { - // Emit identifier as an identifier - write(": "); - // Even though this is stored as identifier treat it as an expression - // Short-hand, { x }, is equivalent of normal form { x: x } - emitExpressionIdentifier(node.name); + else { + let container = resolver.getReferencedExportContainer(node.name); + if (container && container.kind !== SyntaxKind.SourceFile) { + // Emit identifier as an identifier + write(": "); + // Even though this is stored as identifier treat it as an expression + // Short-hand, { x }, is equivalent of normal form { x: x } + emitExpressionIdentifier(node.name); + } } } @@ -4983,13 +4992,16 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { } } - function getLocalNameForExternalImport(importNode: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration): string { - let namespaceDeclaration = getNamespaceDeclarationNode(importNode); - if (namespaceDeclaration && !isDefaultImport(importNode)) { + function getLocalNameForExternalImport(node: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration): string { + let namespaceDeclaration = getNamespaceDeclarationNode(node); + if (namespaceDeclaration && !isDefaultImport(node)) { return getSourceTextOfNodeFromSourceFile(currentSourceFile, namespaceDeclaration.name); } - else { - return getGeneratedNameForNode(importNode); + if (node.kind === SyntaxKind.ImportDeclaration && (node).importClause) { + return getGeneratedNameForNode(node); + } + if (node.kind === SyntaxKind.ExportDeclaration && (node).moduleSpecifier) { + return getGeneratedNameForNode(node); } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 14e53ee8f72..e64d6afad8e 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1396,7 +1396,8 @@ module ts { /* @internal */ export interface EmitResolver { hasGlobalName(name: string): boolean; - getExpressionNameSubstitution(node: Identifier, getGeneratedNameForNode: (node: Node) => string): string; + getReferencedExportContainer(node: Identifier): SourceFile | ModuleDeclaration | EnumDeclaration; + getReferencedImportDeclaration(node: Identifier): ImportClause | ImportSpecifier; isValueAliasDeclaration(node: Node): boolean; isReferencedAliasDeclaration(node: Node, checkChildren?: boolean): boolean; isTopLevelValueImportEqualsWithEntityName(node: ImportEqualsDeclaration): boolean; From e93b7a75ce38177c57ee0df1684fdc94d01f418e Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 2 Jun 2015 14:59:46 -0700 Subject: [PATCH 015/107] Added tests. --- .../asiPreventsParsingAsAmbientExternalModule01.ts | 8 ++++++++ .../asiPreventsParsingAsAmbientExternalModule02.ts | 10 ++++++++++ .../asiPreventsParsingAsNamespace01.ts | 7 +++++++ .../asiPreventsParsingAsNamespace02.ts | 7 +++++++ .../asiPreventsParsingAsNamespace03.ts | 9 +++++++++ .../typeAliases/asiPreventsParsingAsTypeAlias01.ts | 7 +++++++ .../typeAliases/asiPreventsParsingAsTypeAlias02.ts | 9 +++++++++ 7 files changed, 57 insertions(+) create mode 100644 tests/cases/conformance/externalModules/asiPreventsParsingAsAmbientExternalModule01.ts create mode 100644 tests/cases/conformance/externalModules/asiPreventsParsingAsAmbientExternalModule02.ts create mode 100644 tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace01.ts create mode 100644 tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace02.ts create mode 100644 tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace03.ts create mode 100644 tests/cases/conformance/types/typeAliases/asiPreventsParsingAsTypeAlias01.ts create mode 100644 tests/cases/conformance/types/typeAliases/asiPreventsParsingAsTypeAlias02.ts diff --git a/tests/cases/conformance/externalModules/asiPreventsParsingAsAmbientExternalModule01.ts b/tests/cases/conformance/externalModules/asiPreventsParsingAsAmbientExternalModule01.ts new file mode 100644 index 00000000000..73dcd821f65 --- /dev/null +++ b/tests/cases/conformance/externalModules/asiPreventsParsingAsAmbientExternalModule01.ts @@ -0,0 +1,8 @@ + +var declare: number; +var module: string; + +declare // this is the identifier 'declare' +module // this is the identifier 'module' +"my external module" // this is just a string +{ } // this is a block body \ No newline at end of file diff --git a/tests/cases/conformance/externalModules/asiPreventsParsingAsAmbientExternalModule02.ts b/tests/cases/conformance/externalModules/asiPreventsParsingAsAmbientExternalModule02.ts new file mode 100644 index 00000000000..ba0b2d48d62 --- /dev/null +++ b/tests/cases/conformance/externalModules/asiPreventsParsingAsAmbientExternalModule02.ts @@ -0,0 +1,10 @@ + +var declare: number; +var module: string; + +module container { + declare // this is the identifier 'declare' + module // this is the identifier 'module' + "my external module" // this is just a string + { } // this is a block body +} \ No newline at end of file diff --git a/tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace01.ts b/tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace01.ts new file mode 100644 index 00000000000..f3bced2be48 --- /dev/null +++ b/tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace01.ts @@ -0,0 +1,7 @@ + +var namespace: number; +var n: string; + +namespace // this is the identifier 'namespace' +n // this is the identifier 'n' +{ } // this is a block body \ No newline at end of file diff --git a/tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace02.ts b/tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace02.ts new file mode 100644 index 00000000000..63004ef3b62 --- /dev/null +++ b/tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace02.ts @@ -0,0 +1,7 @@ + +var module: number; +var m: string; + +module // this is the identifier 'namespace' +m // this is the identifier 'm' +{ } // this is a block body \ No newline at end of file diff --git a/tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace03.ts b/tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace03.ts new file mode 100644 index 00000000000..de560b7fff4 --- /dev/null +++ b/tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace03.ts @@ -0,0 +1,9 @@ + +var namespace: number; +var n: string; + +namespace container { + namespace // this is the identifier 'namespace' + n // this is the identifier 'n' + { } // this is a block body +} \ No newline at end of file diff --git a/tests/cases/conformance/types/typeAliases/asiPreventsParsingAsTypeAlias01.ts b/tests/cases/conformance/types/typeAliases/asiPreventsParsingAsTypeAlias01.ts new file mode 100644 index 00000000000..8c4bc6e5420 --- /dev/null +++ b/tests/cases/conformance/types/typeAliases/asiPreventsParsingAsTypeAlias01.ts @@ -0,0 +1,7 @@ + +var type; +var string; +var Foo; + +type +Foo = string; \ No newline at end of file diff --git a/tests/cases/conformance/types/typeAliases/asiPreventsParsingAsTypeAlias02.ts b/tests/cases/conformance/types/typeAliases/asiPreventsParsingAsTypeAlias02.ts new file mode 100644 index 00000000000..9357dbbfe09 --- /dev/null +++ b/tests/cases/conformance/types/typeAliases/asiPreventsParsingAsTypeAlias02.ts @@ -0,0 +1,9 @@ + +var type; +var string; +var Foo; + +namespace container { + type + Foo = string; +} \ No newline at end of file From 448e8bf0c7d5adae72cfb0e12bfdae1e2a01bc4d Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 2 Jun 2015 15:47:23 -0700 Subject: [PATCH 016/107] Added baselines. --- ...PreventsParsingAsAmbientExternalModule01.js | 13 +++++++++++++ ...ntsParsingAsAmbientExternalModule01.symbols | 12 ++++++++++++ ...ventsParsingAsAmbientExternalModule01.types | 12 ++++++++++++ ...ParsingAsAmbientExternalModule02.errors.txt | 16 ++++++++++++++++ ...PreventsParsingAsAmbientExternalModule02.js | 15 +++++++++++++++ .../asiPreventsParsingAsNamespace01.js | 12 ++++++++++++ .../asiPreventsParsingAsNamespace01.symbols | 13 +++++++++++++ .../asiPreventsParsingAsNamespace01.types | 13 +++++++++++++ .../asiPreventsParsingAsNamespace02.js | 12 ++++++++++++ .../asiPreventsParsingAsNamespace02.symbols | 13 +++++++++++++ .../asiPreventsParsingAsNamespace02.types | 13 +++++++++++++ .../asiPreventsParsingAsNamespace03.js | 14 ++++++++++++++ .../asiPreventsParsingAsNamespace03.symbols | 17 +++++++++++++++++ .../asiPreventsParsingAsNamespace03.types | 17 +++++++++++++++++ .../asiPreventsParsingAsTypeAlias01.js | 13 +++++++++++++ .../asiPreventsParsingAsTypeAlias01.symbols | 15 +++++++++++++++ .../asiPreventsParsingAsTypeAlias01.types | 15 +++++++++++++++ .../asiPreventsParsingAsTypeAlias02.js | 15 +++++++++++++++ .../asiPreventsParsingAsTypeAlias02.symbols | 18 ++++++++++++++++++ .../asiPreventsParsingAsTypeAlias02.types | 18 ++++++++++++++++++ 20 files changed, 286 insertions(+) create mode 100644 tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule01.js create mode 100644 tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule01.symbols create mode 100644 tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule01.types create mode 100644 tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule02.errors.txt create mode 100644 tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule02.js create mode 100644 tests/baselines/reference/asiPreventsParsingAsNamespace01.js create mode 100644 tests/baselines/reference/asiPreventsParsingAsNamespace01.symbols create mode 100644 tests/baselines/reference/asiPreventsParsingAsNamespace01.types create mode 100644 tests/baselines/reference/asiPreventsParsingAsNamespace02.js create mode 100644 tests/baselines/reference/asiPreventsParsingAsNamespace02.symbols create mode 100644 tests/baselines/reference/asiPreventsParsingAsNamespace02.types create mode 100644 tests/baselines/reference/asiPreventsParsingAsNamespace03.js create mode 100644 tests/baselines/reference/asiPreventsParsingAsNamespace03.symbols create mode 100644 tests/baselines/reference/asiPreventsParsingAsNamespace03.types create mode 100644 tests/baselines/reference/asiPreventsParsingAsTypeAlias01.js create mode 100644 tests/baselines/reference/asiPreventsParsingAsTypeAlias01.symbols create mode 100644 tests/baselines/reference/asiPreventsParsingAsTypeAlias01.types create mode 100644 tests/baselines/reference/asiPreventsParsingAsTypeAlias02.js create mode 100644 tests/baselines/reference/asiPreventsParsingAsTypeAlias02.symbols create mode 100644 tests/baselines/reference/asiPreventsParsingAsTypeAlias02.types diff --git a/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule01.js b/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule01.js new file mode 100644 index 00000000000..efd82f27d1f --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule01.js @@ -0,0 +1,13 @@ +//// [asiPreventsParsingAsAmbientExternalModule01.ts] + +var declare: number; +var module: string; + +declare // this is the identifier 'declare' +module // this is the identifier 'module' +"my external module" // this is just a string +{ } // this is a block body + +//// [asiPreventsParsingAsAmbientExternalModule01.js] +var declare; +var module; diff --git a/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule01.symbols b/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule01.symbols new file mode 100644 index 00000000000..87eb8daf7e2 --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule01.symbols @@ -0,0 +1,12 @@ +=== tests/cases/conformance/externalModules/asiPreventsParsingAsAmbientExternalModule01.ts === + +var declare: number; +>declare : Symbol(declare, Decl(asiPreventsParsingAsAmbientExternalModule01.ts, 1, 3)) + +var module: string; +>module : Symbol(module, Decl(asiPreventsParsingAsAmbientExternalModule01.ts, 2, 3)) + +declare // this is the identifier 'declare' +module // this is the identifier 'module' +"my external module" // this is just a string +{ } // this is a block body diff --git a/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule01.types b/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule01.types new file mode 100644 index 00000000000..94a2cc8d6a1 --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule01.types @@ -0,0 +1,12 @@ +=== tests/cases/conformance/externalModules/asiPreventsParsingAsAmbientExternalModule01.ts === + +var declare: number; +>declare : number + +var module: string; +>module : string + +declare // this is the identifier 'declare' +module // this is the identifier 'module' +"my external module" // this is just a string +{ } // this is a block body diff --git a/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule02.errors.txt b/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule02.errors.txt new file mode 100644 index 00000000000..3064b137a19 --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule02.errors.txt @@ -0,0 +1,16 @@ +tests/cases/conformance/externalModules/asiPreventsParsingAsAmbientExternalModule02.ts(8,5): error TS2435: Ambient modules cannot be nested in other modules. + + +==== tests/cases/conformance/externalModules/asiPreventsParsingAsAmbientExternalModule02.ts (1 errors) ==== + + var declare: number; + var module: string; + + module container { + declare // this is the identifier 'declare' + module // this is the identifier 'module' + "my external module" // this is just a string + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS2435: Ambient modules cannot be nested in other modules. + { } // this is a block body + } \ No newline at end of file diff --git a/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule02.js b/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule02.js new file mode 100644 index 00000000000..444b4b392c9 --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule02.js @@ -0,0 +1,15 @@ +//// [asiPreventsParsingAsAmbientExternalModule02.ts] + +var declare: number; +var module: string; + +module container { + declare // this is the identifier 'declare' + module // this is the identifier 'module' + "my external module" // this is just a string + { } // this is a block body +} + +//// [asiPreventsParsingAsAmbientExternalModule02.js] +var declare; +var module; diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace01.js b/tests/baselines/reference/asiPreventsParsingAsNamespace01.js new file mode 100644 index 00000000000..eed9769da69 --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace01.js @@ -0,0 +1,12 @@ +//// [asiPreventsParsingAsNamespace01.ts] + +var namespace: number; +var n: string; + +namespace // this is the identifier 'namespace' +n // this is the identifier 'n' +{ } // this is a block body + +//// [asiPreventsParsingAsNamespace01.js] +var namespace; +var n; diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace01.symbols b/tests/baselines/reference/asiPreventsParsingAsNamespace01.symbols new file mode 100644 index 00000000000..a2494904bed --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace01.symbols @@ -0,0 +1,13 @@ +=== tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace01.ts === + +var namespace: number; +>namespace : Symbol(namespace, Decl(asiPreventsParsingAsNamespace01.ts, 1, 3)) + +var n: string; +>n : Symbol(n, Decl(asiPreventsParsingAsNamespace01.ts, 2, 3), Decl(asiPreventsParsingAsNamespace01.ts, 2, 14)) + +namespace // this is the identifier 'namespace' +n // this is the identifier 'n' +>n : Symbol(n, Decl(asiPreventsParsingAsNamespace01.ts, 2, 3), Decl(asiPreventsParsingAsNamespace01.ts, 2, 14)) + +{ } // this is a block body diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace01.types b/tests/baselines/reference/asiPreventsParsingAsNamespace01.types new file mode 100644 index 00000000000..87044c58066 --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace01.types @@ -0,0 +1,13 @@ +=== tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace01.ts === + +var namespace: number; +>namespace : number + +var n: string; +>n : string + +namespace // this is the identifier 'namespace' +n // this is the identifier 'n' +>n : string + +{ } // this is a block body diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace02.js b/tests/baselines/reference/asiPreventsParsingAsNamespace02.js new file mode 100644 index 00000000000..de2bdfa8a9e --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace02.js @@ -0,0 +1,12 @@ +//// [asiPreventsParsingAsNamespace02.ts] + +var module: number; +var m: string; + +module // this is the identifier 'namespace' +m // this is the identifier 'm' +{ } // this is a block body + +//// [asiPreventsParsingAsNamespace02.js] +var module; +var m; diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace02.symbols b/tests/baselines/reference/asiPreventsParsingAsNamespace02.symbols new file mode 100644 index 00000000000..70024a8de62 --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace02.symbols @@ -0,0 +1,13 @@ +=== tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace02.ts === + +var module: number; +>module : Symbol(module, Decl(asiPreventsParsingAsNamespace02.ts, 1, 3)) + +var m: string; +>m : Symbol(m, Decl(asiPreventsParsingAsNamespace02.ts, 2, 3), Decl(asiPreventsParsingAsNamespace02.ts, 2, 14)) + +module // this is the identifier 'namespace' +m // this is the identifier 'm' +>m : Symbol(m, Decl(asiPreventsParsingAsNamespace02.ts, 2, 3), Decl(asiPreventsParsingAsNamespace02.ts, 2, 14)) + +{ } // this is a block body diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace02.types b/tests/baselines/reference/asiPreventsParsingAsNamespace02.types new file mode 100644 index 00000000000..8f6dec87a00 --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace02.types @@ -0,0 +1,13 @@ +=== tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace02.ts === + +var module: number; +>module : number + +var m: string; +>m : string + +module // this is the identifier 'namespace' +m // this is the identifier 'm' +>m : string + +{ } // this is a block body diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace03.js b/tests/baselines/reference/asiPreventsParsingAsNamespace03.js new file mode 100644 index 00000000000..6d8b8970977 --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace03.js @@ -0,0 +1,14 @@ +//// [asiPreventsParsingAsNamespace03.ts] + +var namespace: number; +var n: string; + +namespace container { + namespace // this is the identifier 'namespace' + n // this is the identifier 'n' + { } // this is a block body +} + +//// [asiPreventsParsingAsNamespace03.js] +var namespace; +var n; diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace03.symbols b/tests/baselines/reference/asiPreventsParsingAsNamespace03.symbols new file mode 100644 index 00000000000..8dfa30c17a4 --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace03.symbols @@ -0,0 +1,17 @@ +=== tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace03.ts === + +var namespace: number; +>namespace : Symbol(namespace, Decl(asiPreventsParsingAsNamespace03.ts, 1, 3)) + +var n: string; +>n : Symbol(n, Decl(asiPreventsParsingAsNamespace03.ts, 2, 3)) + +namespace container { +>container : Symbol(container, Decl(asiPreventsParsingAsNamespace03.ts, 2, 14)) + + namespace // this is the identifier 'namespace' + n // this is the identifier 'n' +>n : Symbol(n, Decl(asiPreventsParsingAsNamespace03.ts, 4, 21)) + + { } // this is a block body +} diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace03.types b/tests/baselines/reference/asiPreventsParsingAsNamespace03.types new file mode 100644 index 00000000000..37423757159 --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace03.types @@ -0,0 +1,17 @@ +=== tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace03.ts === + +var namespace: number; +>namespace : number + +var n: string; +>n : string + +namespace container { +>container : any + + namespace // this is the identifier 'namespace' + n // this is the identifier 'n' +>n : any + + { } // this is a block body +} diff --git a/tests/baselines/reference/asiPreventsParsingAsTypeAlias01.js b/tests/baselines/reference/asiPreventsParsingAsTypeAlias01.js new file mode 100644 index 00000000000..33e3895fab4 --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsTypeAlias01.js @@ -0,0 +1,13 @@ +//// [asiPreventsParsingAsTypeAlias01.ts] + +var type; +var string; +var Foo; + +type +Foo = string; + +//// [asiPreventsParsingAsTypeAlias01.js] +var type; +var string; +var Foo; diff --git a/tests/baselines/reference/asiPreventsParsingAsTypeAlias01.symbols b/tests/baselines/reference/asiPreventsParsingAsTypeAlias01.symbols new file mode 100644 index 00000000000..d11c9ff5c13 --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsTypeAlias01.symbols @@ -0,0 +1,15 @@ +=== tests/cases/conformance/types/typeAliases/asiPreventsParsingAsTypeAlias01.ts === + +var type; +>type : Symbol(type, Decl(asiPreventsParsingAsTypeAlias01.ts, 1, 3)) + +var string; +>string : Symbol(string, Decl(asiPreventsParsingAsTypeAlias01.ts, 2, 3)) + +var Foo; +>Foo : Symbol(Foo, Decl(asiPreventsParsingAsTypeAlias01.ts, 3, 3), Decl(asiPreventsParsingAsTypeAlias01.ts, 3, 8)) + +type +Foo = string; +>Foo : Symbol(Foo, Decl(asiPreventsParsingAsTypeAlias01.ts, 3, 3), Decl(asiPreventsParsingAsTypeAlias01.ts, 3, 8)) + diff --git a/tests/baselines/reference/asiPreventsParsingAsTypeAlias01.types b/tests/baselines/reference/asiPreventsParsingAsTypeAlias01.types new file mode 100644 index 00000000000..d112022afa4 --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsTypeAlias01.types @@ -0,0 +1,15 @@ +=== tests/cases/conformance/types/typeAliases/asiPreventsParsingAsTypeAlias01.ts === + +var type; +>type : any + +var string; +>string : any + +var Foo; +>Foo : any + +type +Foo = string; +>Foo : string + diff --git a/tests/baselines/reference/asiPreventsParsingAsTypeAlias02.js b/tests/baselines/reference/asiPreventsParsingAsTypeAlias02.js new file mode 100644 index 00000000000..4a8298b2bdf --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsTypeAlias02.js @@ -0,0 +1,15 @@ +//// [asiPreventsParsingAsTypeAlias02.ts] + +var type; +var string; +var Foo; + +namespace container { + type + Foo = string; +} + +//// [asiPreventsParsingAsTypeAlias02.js] +var type; +var string; +var Foo; diff --git a/tests/baselines/reference/asiPreventsParsingAsTypeAlias02.symbols b/tests/baselines/reference/asiPreventsParsingAsTypeAlias02.symbols new file mode 100644 index 00000000000..0da88560109 --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsTypeAlias02.symbols @@ -0,0 +1,18 @@ +=== tests/cases/conformance/types/typeAliases/asiPreventsParsingAsTypeAlias02.ts === + +var type; +>type : Symbol(type, Decl(asiPreventsParsingAsTypeAlias02.ts, 1, 3)) + +var string; +>string : Symbol(string, Decl(asiPreventsParsingAsTypeAlias02.ts, 2, 3)) + +var Foo; +>Foo : Symbol(Foo, Decl(asiPreventsParsingAsTypeAlias02.ts, 3, 3)) + +namespace container { +>container : Symbol(container, Decl(asiPreventsParsingAsTypeAlias02.ts, 3, 8)) + + type + Foo = string; +>Foo : Symbol(Foo, Decl(asiPreventsParsingAsTypeAlias02.ts, 5, 21)) +} diff --git a/tests/baselines/reference/asiPreventsParsingAsTypeAlias02.types b/tests/baselines/reference/asiPreventsParsingAsTypeAlias02.types new file mode 100644 index 00000000000..4af0721ec24 --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsTypeAlias02.types @@ -0,0 +1,18 @@ +=== tests/cases/conformance/types/typeAliases/asiPreventsParsingAsTypeAlias02.ts === + +var type; +>type : any + +var string; +>string : any + +var Foo; +>Foo : any + +namespace container { +>container : any + + type + Foo = string; +>Foo : string +} From a10cd1e8226d97c904b35dffcd5d7890f4cbb062 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 2 Jun 2015 15:48:59 -0700 Subject: [PATCH 017/107] Update LKG --- bin/tsc.js | 24 ++++++++++++++---------- bin/tsserver.js | 24 ++++++++++++++---------- bin/typescript.js | 24 ++++++++++++++---------- bin/typescriptServices.js | 24 ++++++++++++++---------- 4 files changed, 56 insertions(+), 40 deletions(-) diff --git a/bin/tsc.js b/bin/tsc.js index 8c1542d6c7b..01d312f2083 100644 --- a/bin/tsc.js +++ b/bin/tsc.js @@ -8892,27 +8892,31 @@ var ts; case 138: case 201: case 164: - if (name === "arguments") { + if (meaning & 3 && name === "arguments") { result = argumentsSymbol; break loop; } break; case 163: - if (name === "arguments") { + if (meaning & 3 && name === "arguments") { result = argumentsSymbol; break loop; } - var functionName = location.name; - if (functionName && name === functionName.text) { - result = location.symbol; - break loop; + if (meaning & 16) { + var functionName = location.name; + if (functionName && name === functionName.text) { + result = location.symbol; + break loop; + } } break; case 175: - var className = location.name; - if (className && name === className.text) { - result = location.symbol; - break loop; + if (meaning & 32) { + var className = location.name; + if (className && name === className.text) { + result = location.symbol; + break loop; + } } break; case 131: diff --git a/bin/tsserver.js b/bin/tsserver.js index 4f175eee95b..6cdb8f9560c 100644 --- a/bin/tsserver.js +++ b/bin/tsserver.js @@ -9282,27 +9282,31 @@ var ts; case 138: case 201: case 164: - if (name === "arguments") { + if (meaning & 3 && name === "arguments") { result = argumentsSymbol; break loop; } break; case 163: - if (name === "arguments") { + if (meaning & 3 && name === "arguments") { result = argumentsSymbol; break loop; } - var functionName = location.name; - if (functionName && name === functionName.text) { - result = location.symbol; - break loop; + if (meaning & 16) { + var functionName = location.name; + if (functionName && name === functionName.text) { + result = location.symbol; + break loop; + } } break; case 175: - var className = location.name; - if (className && name === className.text) { - result = location.symbol; - break loop; + if (meaning & 32) { + var className = location.name; + if (className && name === className.text) { + result = location.symbol; + break loop; + } } break; case 131: diff --git a/bin/typescript.js b/bin/typescript.js index a60814cc7fd..dbede84a76e 100644 --- a/bin/typescript.js +++ b/bin/typescript.js @@ -11147,27 +11147,31 @@ var ts; case 138 /* SetAccessor */: case 201 /* FunctionDeclaration */: case 164 /* ArrowFunction */: - if (name === "arguments") { + if (meaning & 3 /* Variable */ && name === "arguments") { result = argumentsSymbol; break loop; } break; case 163 /* FunctionExpression */: - if (name === "arguments") { + if (meaning & 3 /* Variable */ && name === "arguments") { result = argumentsSymbol; break loop; } - var functionName = location.name; - if (functionName && name === functionName.text) { - result = location.symbol; - break loop; + if (meaning & 16 /* Function */) { + var functionName = location.name; + if (functionName && name === functionName.text) { + result = location.symbol; + break loop; + } } break; case 175 /* ClassExpression */: - var className = location.name; - if (className && name === className.text) { - result = location.symbol; - break loop; + if (meaning & 32 /* Class */) { + var className = location.name; + if (className && name === className.text) { + result = location.symbol; + break loop; + } } break; case 131 /* Decorator */: diff --git a/bin/typescriptServices.js b/bin/typescriptServices.js index a60814cc7fd..dbede84a76e 100644 --- a/bin/typescriptServices.js +++ b/bin/typescriptServices.js @@ -11147,27 +11147,31 @@ var ts; case 138 /* SetAccessor */: case 201 /* FunctionDeclaration */: case 164 /* ArrowFunction */: - if (name === "arguments") { + if (meaning & 3 /* Variable */ && name === "arguments") { result = argumentsSymbol; break loop; } break; case 163 /* FunctionExpression */: - if (name === "arguments") { + if (meaning & 3 /* Variable */ && name === "arguments") { result = argumentsSymbol; break loop; } - var functionName = location.name; - if (functionName && name === functionName.text) { - result = location.symbol; - break loop; + if (meaning & 16 /* Function */) { + var functionName = location.name; + if (functionName && name === functionName.text) { + result = location.symbol; + break loop; + } } break; case 175 /* ClassExpression */: - var className = location.name; - if (className && name === className.text) { - result = location.symbol; - break loop; + if (meaning & 32 /* Class */) { + var className = location.name; + if (className && name === className.text) { + result = location.symbol; + break loop; + } } break; case 131 /* Decorator */: From 77306a3ea6192c7eb56cd57371001ddcb156c71f Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 2 Jun 2015 17:08:51 -0700 Subject: [PATCH 018/107] Added more tests. --- .../asiPreventsParsingAsNamespace04.ts | 3 +++ .../asiPreventsParsingAsNamespace05.ts | 10 ++++++++++ 2 files changed, 13 insertions(+) create mode 100644 tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace04.ts create mode 100644 tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace05.ts diff --git a/tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace04.ts b/tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace04.ts new file mode 100644 index 00000000000..03021576ea5 --- /dev/null +++ b/tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace04.ts @@ -0,0 +1,3 @@ + +let module = 10; +module in {} \ No newline at end of file diff --git a/tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace05.ts b/tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace05.ts new file mode 100644 index 00000000000..a821dbc363c --- /dev/null +++ b/tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace05.ts @@ -0,0 +1,10 @@ + +let namespace = 10; +namespace a.b { + export let c = 20; +} + +namespace +a.b.c +{ +} \ No newline at end of file From 70f74ad640a2f029b3df749273e58bcaa216b4f0 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 2 Jun 2015 17:31:20 -0700 Subject: [PATCH 019/107] Accepted more baselines. --- .../asiPreventsParsingAsNamespace04.errors.txt | 9 +++++++++ .../reference/asiPreventsParsingAsNamespace04.js | 8 ++++++++ .../reference/asiPreventsParsingAsNamespace05.js | 11 +++++++++++ .../asiPreventsParsingAsNamespace05.symbols | 12 ++++++++++++ .../reference/asiPreventsParsingAsNamespace05.types | 13 +++++++++++++ 5 files changed, 53 insertions(+) create mode 100644 tests/baselines/reference/asiPreventsParsingAsNamespace04.errors.txt create mode 100644 tests/baselines/reference/asiPreventsParsingAsNamespace04.js create mode 100644 tests/baselines/reference/asiPreventsParsingAsNamespace05.js create mode 100644 tests/baselines/reference/asiPreventsParsingAsNamespace05.symbols create mode 100644 tests/baselines/reference/asiPreventsParsingAsNamespace05.types diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace04.errors.txt b/tests/baselines/reference/asiPreventsParsingAsNamespace04.errors.txt new file mode 100644 index 00000000000..d0a6be446aa --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace04.errors.txt @@ -0,0 +1,9 @@ +tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace04.ts(3,8): error TS1003: Identifier expected. + + +==== tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace04.ts (1 errors) ==== + + let module = 10; + module in {} + ~~ +!!! error TS1003: Identifier expected. \ No newline at end of file diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace04.js b/tests/baselines/reference/asiPreventsParsingAsNamespace04.js new file mode 100644 index 00000000000..bcd8975d46d --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace04.js @@ -0,0 +1,8 @@ +//// [asiPreventsParsingAsNamespace04.ts] + +let module = 10; +module in {} + +//// [asiPreventsParsingAsNamespace04.js] +var module = 10; + in {}; diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace05.js b/tests/baselines/reference/asiPreventsParsingAsNamespace05.js new file mode 100644 index 00000000000..0a525179d2d --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace05.js @@ -0,0 +1,11 @@ +//// [asiPreventsParsingAsNamespace05.ts] + +let namespace = 10; + +namespace +a.b.c +{ +} + +//// [asiPreventsParsingAsNamespace05.js] +var namespace = 10; diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace05.symbols b/tests/baselines/reference/asiPreventsParsingAsNamespace05.symbols new file mode 100644 index 00000000000..65125806b61 --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace05.symbols @@ -0,0 +1,12 @@ +=== tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace05.ts === + +let namespace = 10; +>namespace : Symbol(namespace, Decl(asiPreventsParsingAsNamespace05.ts, 1, 3)) + +namespace +a.b.c +>a : Symbol(a, Decl(asiPreventsParsingAsNamespace05.ts, 1, 19)) +>b : Symbol(b, Decl(asiPreventsParsingAsNamespace05.ts, 4, 2)) +>c : Symbol(c, Decl(asiPreventsParsingAsNamespace05.ts, 4, 4)) +{ +} diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace05.types b/tests/baselines/reference/asiPreventsParsingAsNamespace05.types new file mode 100644 index 00000000000..f17ad1f2a1e --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace05.types @@ -0,0 +1,13 @@ +=== tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace05.ts === + +let namespace = 10; +>namespace : number +>10 : number + +namespace +a.b.c +>a : any +>b : any +>c : any +{ +} From 6902b050ca9cb94ba494d0900ad48a0780850ef4 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 2 Jun 2015 18:04:05 -0700 Subject: [PATCH 020/107] Respond to code review comments --- tests/cases/unittests/transpile.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/cases/unittests/transpile.ts b/tests/cases/unittests/transpile.ts index eca136649f2..c906c03a9e0 100644 --- a/tests/cases/unittests/transpile.ts +++ b/tests/cases/unittests/transpile.ts @@ -19,33 +19,33 @@ module ts { it("Generates correct compilerOptions diagnostics", () => { // Expecting 5047: "Option 'isolatedModules' can only be used when either option'--module' is provided or option 'target' is 'ES6' or higher." - runTest(`var x = 0;`, {}, /*expectedOutput*/ undefined, [5047]); + runTest(`var x = 0;`, {}, /*expectedOutput*/ undefined, /*expectedDiagnosticCodes*/ [5047]); }); it("Generates no diagnostics with valid inputs", () => { // No errors - runTest(`var x = 0;`, { module: ModuleKind.CommonJS }, /*expectedOutput*/ undefined, []); + runTest(`var x = 0;`, { module: ModuleKind.CommonJS }, /*expectedOutput*/ undefined, /*expectedDiagnosticCodes*/ []); }); it("Generates no diagnostics for missing file references", () => { runTest(`/// var x = 0;`, - { module: ModuleKind.CommonJS }, /*expectedOutput*/ undefined, []); + { module: ModuleKind.CommonJS }, /*expectedOutput*/ undefined, /*expectedDiagnosticCodes*/ []); }); it("Generates no diagnostics for missing module imports", () => { runTest(`import {a} from "module2";`, - { module: ModuleKind.CommonJS }, /*expectedOutput*/ undefined, []); + { module: ModuleKind.CommonJS }, /*expectedOutput*/ undefined, /*expectedDiagnosticCodes*/ []); }); it("Generates expected syntactic diagnostics", () => { runTest(`a b`, - { module: ModuleKind.CommonJS }, /*expectedOutput*/ undefined, [1005]); /// 1005: ';' Expected + { module: ModuleKind.CommonJS }, /*expectedOutput*/ undefined, /*expectedDiagnosticCodes*/ [1005]); /// 1005: ';' Expected }); it("Does not generate semantic diagnostics", () => { runTest(`var x: string = 0;`, - { module: ModuleKind.CommonJS }, /*expectedOutput*/ undefined, []); + { module: ModuleKind.CommonJS }, /*expectedOutput*/ undefined, /*expectedDiagnosticCodes*/ []); }); it("Generates module output", () => { @@ -53,7 +53,7 @@ var x = 0;`, }); it("Uses correct newLine character", () => { - runTest(`var x = 0;`, { module: ModuleKind.CommonJS, newLine: NewLineKind.LineFeed }, `var x = 0;\n`); + runTest(`var x = 0;`, { module: ModuleKind.CommonJS, newLine: NewLineKind.LineFeed }, `var x = 0;\n`, /*expectedDiagnosticCodes*/ []); }); }); } From 8b62a326d4fbf06c69777984256f2b8df48d1709 Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Tue, 2 Jun 2015 19:22:03 -0700 Subject: [PATCH 021/107] Dom lib file bug fix Fix #3344; removed duplicated overloads for ``createEvent`` and some minor fixes. --- src/lib/dom.generated.d.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/lib/dom.generated.d.ts b/src/lib/dom.generated.d.ts index 5a4151c0c1c..d9daefa1aeb 100644 --- a/src/lib/dom.generated.d.ts +++ b/src/lib/dom.generated.d.ts @@ -7677,10 +7677,10 @@ declare var MediaQueryList: { interface MediaSource extends EventTarget { activeSourceBuffers: SourceBufferList; duration: number; - readyState: string; + readyState: number; sourceBuffers: SourceBufferList; addSourceBuffer(type: string): SourceBuffer; - endOfStream(error?: string): void; + endOfStream(error?: number): void; removeSourceBuffer(sourceBuffer: SourceBuffer): void; } @@ -8409,7 +8409,7 @@ declare var PopStateEvent: { interface Position { coords: Coordinates; - timestamp: Date; + timestamp: number; } declare var Position: { @@ -11090,6 +11090,7 @@ interface WebGLRenderingContext { stencilMaskSeparate(face: number, mask: number): void; stencilOp(fail: number, zfail: number, zpass: number): void; stencilOpSeparate(face: number, fail: number, zfail: number, zpass: number): void; + texImage2D(target: number, level: number, internalformat: number, width: number, height: number, border: number, format: number, type: number, pixels: ArrayBufferView): void; texImage2D(target: number, level: number, internalformat: number, format: number, type: number, pixels: ImageData): void; texParameterf(target: number, pname: number, param: number): void; texParameteri(target: number, pname: number, param: number): void; @@ -12332,12 +12333,14 @@ interface DocumentEvent { createEvent(eventInterface:"AriaRequestEvent"): AriaRequestEvent; createEvent(eventInterface:"AudioProcessingEvent"): AudioProcessingEvent; createEvent(eventInterface:"BeforeUnloadEvent"): BeforeUnloadEvent; + createEvent(eventInterface:"ClipboardEvent"): ClipboardEvent; createEvent(eventInterface:"CloseEvent"): CloseEvent; createEvent(eventInterface:"CommandEvent"): CommandEvent; createEvent(eventInterface:"CompositionEvent"): CompositionEvent; - createEvent(eventInterface: "CustomEvent"): CustomEvent; + createEvent(eventInterface:"CustomEvent"): CustomEvent; createEvent(eventInterface:"DeviceMotionEvent"): DeviceMotionEvent; createEvent(eventInterface:"DeviceOrientationEvent"): DeviceOrientationEvent; + createEvent(eventInterface:"DocumentEvent"): DocumentEvent; createEvent(eventInterface:"DragEvent"): DragEvent; createEvent(eventInterface:"ErrorEvent"): ErrorEvent; createEvent(eventInterface:"Event"): Event; @@ -12358,8 +12361,6 @@ interface DocumentEvent { createEvent(eventInterface:"MouseEvent"): MouseEvent; createEvent(eventInterface:"MouseEvents"): MouseEvent; createEvent(eventInterface:"MouseWheelEvent"): MouseWheelEvent; - createEvent(eventInterface:"MSGestureEvent"): MSGestureEvent; - createEvent(eventInterface:"MSPointerEvent"): MSPointerEvent; createEvent(eventInterface:"MutationEvent"): MutationEvent; createEvent(eventInterface:"MutationEvents"): MutationEvent; createEvent(eventInterface:"NavigationCompletedEvent"): NavigationCompletedEvent; @@ -12971,4 +12972,4 @@ declare function addEventListener(type: "unload", listener: (ev: Event) => any, declare function addEventListener(type: "volumechange", listener: (ev: Event) => any, useCapture?: boolean): void; declare function addEventListener(type: "waiting", listener: (ev: Event) => any, useCapture?: boolean): void; declare function addEventListener(type: "wheel", listener: (ev: WheelEvent) => any, useCapture?: boolean): void; -declare function addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; \ No newline at end of file +declare function addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; From 9515947092941127079a06a8d3d6bac245898835 Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Tue, 2 Jun 2015 12:49:07 +0800 Subject: [PATCH 022/107] Adds custom type guard --- src/compiler/checker.ts | 162 ++++++++++++++++-- .../diagnosticInformationMap.generated.ts | 5 + src/compiler/diagnosticMessages.json | 21 +++ src/compiler/parser.ts | 20 ++- src/compiler/scanner.ts | 1 + src/compiler/types.ts | 19 +- 6 files changed, 210 insertions(+), 18 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fad7293412e..a09a2736aac 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -97,8 +97,8 @@ module ts { let anyFunctionType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); let noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); - let anySignature = createSignature(undefined, undefined, emptyArray, anyType, 0, false, false); - let unknownSignature = createSignature(undefined, undefined, emptyArray, unknownType, 0, false, false); + let anySignature = createSignature(undefined, undefined, emptyArray, anyType, undefined, 0, false, false); + let unknownSignature = createSignature(undefined, undefined, emptyArray, unknownType, undefined, 0, false, false); let globals: SymbolTable = {}; @@ -2772,7 +2772,7 @@ module ts { function resolveDeclaredMembers(type: InterfaceType): InterfaceTypeWithDeclaredMembers { if (!(type).declaredProperties) { - var symbol = type.symbol; + let symbol = type.symbol; (type).declaredProperties = getNamedMembers(symbol.members); (type).declaredCallSignatures = getSignaturesOfSymbol(symbol.members["__call"]); (type).declaredConstructSignatures = getSignaturesOfSymbol(symbol.members["__new"]); @@ -2782,7 +2782,7 @@ module ts { return type; } - function resolveClassOrInterfaceMembers(type: InterfaceType): void { + function resolveClassOrInterfaceMembers(type: InterfaceType) { let target = resolveDeclaredMembers(type); let members = target.symbol.members; let callSignatures = target.declaredCallSignatures; @@ -2823,12 +2823,13 @@ module ts { } function createSignature(declaration: SignatureDeclaration, typeParameters: TypeParameter[], parameters: Symbol[], - resolvedReturnType: Type, minArgumentCount: number, hasRestParameter: boolean, hasStringLiterals: boolean): Signature { + resolvedReturnType: Type, typePredicate: TypePredicate, minArgumentCount: number, hasRestParameter: boolean, hasStringLiterals: boolean): Signature { let sig = new Signature(checker); sig.declaration = declaration; sig.typeParameters = typeParameters; sig.parameters = parameters; sig.resolvedReturnType = resolvedReturnType; + sig.typePredicate = typePredicate; sig.minArgumentCount = minArgumentCount; sig.hasRestParameter = hasRestParameter; sig.hasStringLiterals = hasStringLiterals; @@ -2836,7 +2837,7 @@ module ts { } function cloneSignature(sig: Signature): Signature { - return createSignature(sig.declaration, sig.typeParameters, sig.parameters, sig.resolvedReturnType, + return createSignature(sig.declaration, sig.typeParameters, sig.parameters, sig.resolvedReturnType, sig.typePredicate, sig.minArgumentCount, sig.hasRestParameter, sig.hasStringLiterals); } @@ -2853,7 +2854,7 @@ module ts { return signature; }); } - return [createSignature(undefined, classType.localTypeParameters, emptyArray, classType, 0, false, false)]; + return [createSignature(undefined, classType.localTypeParameters, emptyArray, classType, undefined, 0, false, false)]; } function createTupleTypeMemberSymbols(memberTypes: Type[]): SymbolTable { @@ -3229,7 +3230,24 @@ module ts { } let returnType: Type; - if (classType) { + let typePredicate: TypePredicate; + if (declaration.typePredicate) { + returnType = booleanType; + let typePredicateNode = declaration.typePredicate; + let links = getNodeLinks(typePredicateNode); + if (links.typePredicateParameterIndex === undefined) { + links.typePredicateParameterIndex = getTypePredicateParameterIndex(declaration.parameters, typePredicateNode.parameterName); + } + if (!links.typeFromTypePredicate) { + links.typeFromTypePredicate = getTypeFromTypeNode(declaration.typePredicate.type); + } + typePredicate = { + parameterName: typePredicateNode.parameterName ? typePredicateNode.parameterName.text : undefined, + parameterIndex: typePredicateNode.parameterName ? links.typePredicateParameterIndex : undefined, + type: links.typeFromTypePredicate + }; + } + else if (classType) { returnType = classType; } else if (declaration.type) { @@ -3248,8 +3266,8 @@ module ts { } } - links.resolvedSignature = createSignature(declaration, typeParameters, parameters, returnType, - minArgumentCount, hasRestParameter(declaration), hasStringLiterals); + links.resolvedSignature = createSignature(declaration, typeParameters, parameters, returnType, typePredicate, + minArgumentCount, hasRestParameters(declaration), hasStringLiterals); } return links.resolvedSignature; } @@ -3962,9 +3980,13 @@ module ts { freshTypeParameters = instantiateList(signature.typeParameters, mapper, instantiateTypeParameter); mapper = combineTypeMappers(createTypeMapper(signature.typeParameters, freshTypeParameters), mapper); } + if (signature.typePredicate) { + signature.typePredicate.type = instantiateType(signature.typePredicate.type, mapper); + } let result = createSignature(signature.declaration, freshTypeParameters, instantiateList(signature.parameters, mapper, instantiateSymbol), signature.resolvedReturnType ? instantiateType(signature.resolvedReturnType, mapper) : undefined, + signature.typePredicate, signature.minArgumentCount, signature.hasRestParameter, signature.hasStringLiterals); result.target = signature; result.mapper = mapper; @@ -4632,6 +4654,43 @@ module ts { } result &= related; } + + if (source.typePredicate && target.typePredicate) { + if (source.typePredicate.parameterIndex !== target.typePredicate.parameterIndex || + source.typePredicate.type.symbol !== target.typePredicate.type.symbol) { + + if (reportErrors) { + let sourceParamText = source.typePredicate.parameterName; + let targetParamText = target.typePredicate.parameterName; + let sourceTypeText = typeToString(source.typePredicate.type); + let targetTypeText = typeToString(target.typePredicate.type); + + if (source.typePredicate.parameterIndex !== target.typePredicate.parameterIndex) { + reportError(Diagnostics.Parameter_index_from_0_does_not_match_the_parameter_index_from_1, + sourceParamText, + targetParamText); + } + if (source.typePredicate.type.symbol !== target.typePredicate.type.symbol) { + reportError(Diagnostics.Type_0_is_not_assignable_to_type_1, + sourceTypeText, + targetTypeText); + } + + reportError(Diagnostics.Type_guard_annotation_0_is_not_assignable_to_1, + `${sourceParamText} is ${sourceTypeText}`, + `${targetParamText} is ${targetTypeText}`); + } + + return Ternary.False; + } + } + else if (!source.typePredicate && target.typePredicate) { + if (reportErrors) { + reportError(Diagnostics.A_non_type_guard_function_is_not_assignable_to_a_type_guard_function); + } + return Ternary.False; + } + let t = getReturnTypeOfSignature(target); if (t === voidType) return result; let s = getReturnTypeOfSignature(source); @@ -5164,6 +5223,13 @@ module ts { function inferFromSignature(source: Signature, target: Signature) { forEachMatchingParameterType(source, target, inferFromTypes); + if (source.typePredicate && + target.typePredicate && + target.typePredicate.parameterIndex === source.typePredicate.parameterIndex) { + + inferFromTypes(source.typePredicate.type, target.typePredicate.type); + return; + } inferFromTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target)); } @@ -5545,7 +5611,7 @@ module ts { let targetType: Type; let prototypeProperty = getPropertyOfType(rightType, "prototype"); if (prototypeProperty) { - // Target type is type of the protoype property + // Target type is type of the prototype property let prototypePropertyType = getTypeOfSymbol(prototypeProperty); if (prototypePropertyType !== anyType) { targetType = prototypePropertyType; @@ -5561,7 +5627,6 @@ module ts { else if (rightType.flags & TypeFlags.Anonymous) { constructSignatures = getSignaturesOfType(rightType, SignatureKind.Construct); } - if (constructSignatures && constructSignatures.length) { targetType = getUnionType(map(constructSignatures, signature => getReturnTypeOfSignature(getErasedSignature(signature)))); } @@ -5581,10 +5646,38 @@ module ts { return type; } + function narrowTypeByTypePredicate(type: Type, expr: CallExpression, assumeTrue: boolean): Type { + if (type.flags & TypeFlags.Any) { + return type; + } + let signature = getResolvedSignature(expr); + if (!assumeTrue) { + if (type.flags & TypeFlags.Union && signature.typePredicate) { + return getUnionType(filter((type).types, t => !isTypeSubtypeOf(t, signature.typePredicate.type))); + } + return type; + } + if (signature.typePredicate) { + if (expr.arguments && expr.arguments[signature.typePredicate.parameterIndex]) { + if (getSymbolAtLocation(expr.arguments[signature.typePredicate.parameterIndex]) === symbol) { + if (isTypeSubtypeOf(signature.typePredicate.type, type)) { + return signature.typePredicate.type; + } + if (type.flags & TypeFlags.Union) { + return getUnionType(filter((type).types, t => isTypeSubtypeOf(t, signature.typePredicate.type))); + } + } + } + } + return type; + } + // Narrow the given type based on the given expression having the assumed boolean value. The returned type // will be a subtype or the same type as the argument. function narrowType(type: Type, expr: Expression, assumeTrue: boolean): Type { switch (expr.kind) { + case SyntaxKind.CallExpression: + return narrowTypeByTypePredicate(type, expr, assumeTrue); case SyntaxKind.ParenthesizedExpression: return narrowType(type, (expr).expression, assumeTrue); case SyntaxKind.BinaryExpression: @@ -8486,6 +8579,20 @@ module ts { node.kind === SyntaxKind.FunctionExpression; } + function getTypePredicateParameterIndex(parameterList: NodeArray, parameter: Identifier): number { + let index = -1; + if (parameterList) { + for (let i = 0; i < parameterList.length; i++) { + let param = parameterList[i]; + if (param.name.kind === SyntaxKind.Identifier && + (param.name).text === parameter.text) { + + return i; + } + } + } + } + function checkSignatureDeclaration(node: SignatureDeclaration) { // Grammar checking if (node.kind === SyntaxKind.IndexSignature) { @@ -8506,6 +8613,27 @@ module ts { checkSourceElement(node.type); } + if (node.typePredicate) { + let links = getNodeLinks(node.typePredicate); + if (links.typePredicateParameterIndex === undefined) { + links.typePredicateParameterIndex = getTypePredicateParameterIndex(node.parameters, node.typePredicate.parameterName); + } + if (!links.typeFromTypePredicate) { + links.typeFromTypePredicate = getTypeFromTypeNode(node.typePredicate.type); + } + if (links.typePredicateParameterIndex >= 0) { + checkTypeAssignableTo( + links.typeFromTypePredicate, + getTypeAtLocation(node.parameters[links.typePredicateParameterIndex]), + node.typePredicate.type); + } + else if(node.typePredicate.parameterName) { + error(node.typePredicate.parameterName, + Diagnostics.Cannot_find_parameter_0, + node.typePredicate.parameterName.text); + } + } + if (produceDiagnostics) { checkCollisionWithArgumentsInGeneratedCode(node); if (compilerOptions.noImplicitAny && !node.type) { @@ -10065,9 +10193,6 @@ module ts { if (node.expression) { let func = getContainingFunction(node); if (func) { - let returnType = getReturnTypeOfSignature(getSignatureFromDeclaration(func)); - let exprType = checkExpressionCached(node.expression); - if (func.asteriskToken) { // A generator does not need its return expressions checked against its return type. // Instead, the yield expressions are checked against the element type. @@ -10076,6 +10201,13 @@ module ts { return; } + let signature = getSignatureFromDeclaration(func); + let exprType = checkExpressionCached(node.expression); + if (signature.typePredicate && exprType !== booleanType) { + error(node.expression, Diagnostics.A_type_guard_function_can_only_return_a_boolean); + } + let returnType = getReturnTypeOfSignature(signature); + if (func.kind === SyntaxKind.SetAccessor) { error(node.expression, Diagnostics.Setters_cannot_return_a_value); } diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 8ccc9d890e2..5a87f67ddd3 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -179,6 +179,11 @@ module ts { Generators_are_not_allowed_in_an_ambient_context: { code: 1221, category: DiagnosticCategory.Error, key: "Generators are not allowed in an ambient context." }, An_overload_signature_cannot_be_declared_as_a_generator: { code: 1222, category: DiagnosticCategory.Error, key: "An overload signature cannot be declared as a generator." }, _0_tag_already_specified: { code: 1223, category: DiagnosticCategory.Error, key: "'{0}' tag already specified." }, + A_non_type_guard_function_is_not_assignable_to_a_type_guard_function: { code: 1224, category: DiagnosticCategory.Error, key: "A non-type guard function is not assignable to a type guard function." }, + A_type_guard_function_can_only_return_a_boolean: { code: 1225, category: DiagnosticCategory.Error, key: "A type-guard function can only return a boolean." }, + Cannot_find_parameter_0: { code: 1226, category: DiagnosticCategory.Error, key: "Cannot find parameter '{0}'." }, + Type_guard_annotation_0_is_not_assignable_to_1: { code: 1227, category: DiagnosticCategory.Error, key: "Type-guard annotation '{0}' is not assignable to '{1}'." }, + Parameter_index_from_0_does_not_match_the_parameter_index_from_1: { code: 1228, category: DiagnosticCategory.Error, key: "Parameter index from '{0}' does not match the parameter index from '{1}'." }, Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." }, Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." }, Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index fb246955f73..0053b071438 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -703,6 +703,27 @@ "category": "Error", "code": 1223 }, + "A non-type guard function is not assignable to a type guard function.": { + "category": "Error", + "code": 1224 + }, + "A type-guard function can only return a boolean.": { + "category": "Error", + "code": 1225 + }, + "Cannot find parameter '{0}'.": { + "category": "Error", + "code": 1226 + }, + "Type-guard annotation '{0}' is not assignable to '{1}'.": { + "category": "Error", + "code": 1227 + }, + "Parameter index from '{0}' does not match the parameter index from '{1}'.": { + "category": "Error", + "code": 1228 + }, + "Duplicate identifier '{0}'.": { "category": "Error", diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 80c70a250fb..ac4517a0b79 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -81,7 +81,8 @@ module ts { visitNodes(cbNodes, node.modifiers) || visitNodes(cbNodes, (node).typeParameters) || visitNodes(cbNodes, (node).parameters) || - visitNode(cbNode, (node).type); + visitNode(cbNode, (node).type) || + visitNode(cbNode, (node).typePredicate); case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: case SyntaxKind.Constructor: @@ -98,11 +99,15 @@ module ts { visitNodes(cbNodes, (node).typeParameters) || visitNodes(cbNodes, (node).parameters) || visitNode(cbNode, (node).type) || + visitNode(cbNode, (node).typePredicate) || visitNode(cbNode, (node).equalsGreaterThanToken) || visitNode(cbNode, (node).body); case SyntaxKind.TypeReference: return visitNode(cbNode, (node).typeName) || visitNodes(cbNodes, (node).typeArguments); + case SyntaxKind.TypePredicate: + return visitNode(cbNode, (node).parameterName) || + visitNode(cbNode, (node).type); case SyntaxKind.TypeQuery: return visitNode(cbNode, (node).exprName); case SyntaxKind.TypeLiteral: @@ -763,7 +768,7 @@ module ts { return (contextFlags & ParserContextFlags.Decorator) !== 0; } - function parseErrorAtCurrentToken(message: DiagnosticMessage, arg0?: any): void { + function parseErrorAtCurrentToken(message: DiagnosticMessage, arg0?: any) { let start = scanner.getTokenPos(); let length = scanner.getTextPos() - start; @@ -2025,6 +2030,17 @@ module ts { else if (parseOptional(returnToken)) { signature.type = parseType(); } + if (token === SyntaxKind.IsKeyword) { + let node = createNode(SyntaxKind.TypePredicate); + node.pos = signature.type.pos; + node.parameterName = (signature.type).typeName; + + nextToken(); + + node.type = parseType(); + signature.type = undefined; + signature.typePredicate = finishNode(node); + } } // Note: after careful analysis of the grammar, it does not appear to be possible to diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 89ac837ab24..d7e65dff81c 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -72,6 +72,7 @@ module ts { "in": SyntaxKind.InKeyword, "instanceof": SyntaxKind.InstanceOfKeyword, "interface": SyntaxKind.InterfaceKeyword, + "is": SyntaxKind.IsKeyword, "let": SyntaxKind.LetKeyword, "module": SyntaxKind.ModuleKeyword, "namespace": SyntaxKind.NamespaceKeyword, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 0fcf0e1f67a..acf71db16c7 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -137,6 +137,7 @@ module ts { ConstructorKeyword, DeclareKeyword, GetKeyword, + IsKeyword, ModuleKeyword, NamespaceKeyword, RequireKeyword, @@ -169,6 +170,7 @@ module ts { ConstructSignature, IndexSignature, // Type + TypePredicate, TypeReference, FunctionType, ConstructorType, @@ -462,6 +464,7 @@ module ts { typeParameters?: NodeArray; parameters: NodeArray; type?: TypeNode; + typePredicate?: TypePredicateNode; } // SyntaxKind.VariableDeclaration @@ -605,6 +608,11 @@ module ts { typeName: EntityName; typeArguments?: NodeArray; } + + export interface TypePredicateNode extends TypeNode { + parameterName?: Identifier; + type: TypeNode; + } export interface TypeQueryNode extends TypeNode { exprName: EntityName; @@ -1376,6 +1384,12 @@ module ts { NotAccessible, CannotBeNamed } + + export interface TypePredicate { + parameterName: string; + parameterIndex?: number; + type: Type; + } /* @internal */ export type AnyImportSyntax = ImportDeclaration | ImportEqualsDeclaration; @@ -1563,6 +1577,8 @@ module ts { assignmentChecks?: Map; // Cache of assignment checks hasReportedStatementInAmbientContext?: boolean; // Cache boolean if we report statements in ambient context importOnRightSide?: Symbol; // for import declarations - import that appear on the right side + typePredicateParameterIndex?: number; // Index of type predicate parameter + typeFromTypePredicate?: Type; // Type from TypePredicate } export const enum TypeFlags { @@ -1588,7 +1604,7 @@ module ts { /* @internal */ ContainsUndefinedOrNull = 0x00040000, // Type is or contains Undefined or Null type /* @internal */ - ContainsObjectLiteral = 0x00080000, // Type is or contains object literal type + ContainsObjectLiteral = 0x00080000, // Type is or contains object literal type ESSymbol = 0x00100000, // Type of symbol primitive introduced in ES6 /* @internal */ @@ -1703,6 +1719,7 @@ module ts { declaration: SignatureDeclaration; // Originating declaration typeParameters: TypeParameter[]; // Type parameters (undefined if non-generic) parameters: Symbol[]; // Parameters + typePredicate?: TypePredicate; // Type predicate /* @internal */ resolvedReturnType: Type; // Resolved return type /* @internal */ From 284b9db268ebc85445e3e2131e98ce68f7e6e4dc Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Tue, 2 Jun 2015 12:49:23 +0800 Subject: [PATCH 023/107] Fixes old tests --- tests/baselines/reference/APISample_linter.js | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/baselines/reference/APISample_linter.js b/tests/baselines/reference/APISample_linter.js index cd2df23ffbf..9b2675535f2 100644 --- a/tests/baselines/reference/APISample_linter.js +++ b/tests/baselines/reference/APISample_linter.js @@ -75,26 +75,26 @@ function delint(sourceFile) { delintNode(sourceFile); function delintNode(node) { switch (node.kind) { - case 187 /* ForStatement */: - case 188 /* ForInStatement */: - case 186 /* WhileStatement */: - case 185 /* DoStatement */: - if (node.statement.kind !== 180 /* Block */) { + case 189 /* ForStatement */: + case 190 /* ForInStatement */: + case 188 /* WhileStatement */: + case 187 /* DoStatement */: + if (node.statement.kind !== 182 /* Block */) { report(node, "A looping statement's contents should be wrapped in a block body."); } break; - case 184 /* IfStatement */: + case 186 /* IfStatement */: var ifStatement = node; - if (ifStatement.thenStatement.kind !== 180 /* Block */) { + if (ifStatement.thenStatement.kind !== 182 /* Block */) { report(ifStatement.thenStatement, "An if statement's contents should be wrapped in a block body."); } if (ifStatement.elseStatement && - ifStatement.elseStatement.kind !== 180 /* Block */ && - ifStatement.elseStatement.kind !== 184 /* IfStatement */) { + ifStatement.elseStatement.kind !== 182 /* Block */ && + ifStatement.elseStatement.kind !== 186 /* IfStatement */) { report(ifStatement.elseStatement, "An else statement's contents should be wrapped in a block body."); } break; - case 170 /* BinaryExpression */: + case 172 /* BinaryExpression */: var op = node.operatorToken.kind; if (op === 28 /* EqualsEqualsToken */ || op == 29 /* ExclamationEqualsToken */) { report(node, "Use '===' and '!=='."); From f8e2b99b6c0cb94add93d3ac5948130d0e5959fa Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Tue, 2 Jun 2015 12:49:36 +0800 Subject: [PATCH 024/107] Adds tests --- .../baselines/reference/typeGuardFunction.js | 105 ++++++++++ .../reference/typeGuardFunction.symbols | 144 ++++++++++++++ .../reference/typeGuardFunction.types | 159 +++++++++++++++ .../typeGuardFunctionErrors.errors.txt | 174 ++++++++++++++++ .../reference/typeGuardFunctionErrors.js | 173 ++++++++++++++++ .../reference/typeGuardFunctionGenerics.js | 69 +++++++ .../typeGuardFunctionGenerics.symbols | 125 ++++++++++++ .../reference/typeGuardFunctionGenerics.types | 138 +++++++++++++ .../reference/typeGuardOfFormIsType.js | 85 ++++++++ .../reference/typeGuardOfFormIsType.symbols | 128 ++++++++++++ .../reference/typeGuardOfFormIsType.types | 157 +++++++++++++++ .../typeGuardOfFormIsTypeOnInterfaces.js | 74 +++++++ .../typeGuardOfFormIsTypeOnInterfaces.symbols | 159 +++++++++++++++ .../typeGuardOfFormIsTypeOnInterfaces.types | 188 ++++++++++++++++++ .../typeGuards/typeGuardFunction.ts | 56 ++++++ .../typeGuards/typeGuardFunctionErrors.ts | 92 +++++++++ .../typeGuards/typeGuardFunctionGenerics.ts | 33 +++ .../typeGuards/typeGuardOfFormIsType.ts | 37 ++++ .../typeGuardOfFormIsTypeOnInterfaces.ts | 46 +++++ 19 files changed, 2142 insertions(+) create mode 100644 tests/baselines/reference/typeGuardFunction.js create mode 100644 tests/baselines/reference/typeGuardFunction.symbols create mode 100644 tests/baselines/reference/typeGuardFunction.types create mode 100644 tests/baselines/reference/typeGuardFunctionErrors.errors.txt create mode 100644 tests/baselines/reference/typeGuardFunctionErrors.js create mode 100644 tests/baselines/reference/typeGuardFunctionGenerics.js create mode 100644 tests/baselines/reference/typeGuardFunctionGenerics.symbols create mode 100644 tests/baselines/reference/typeGuardFunctionGenerics.types create mode 100644 tests/baselines/reference/typeGuardOfFormIsType.js create mode 100644 tests/baselines/reference/typeGuardOfFormIsType.symbols create mode 100644 tests/baselines/reference/typeGuardOfFormIsType.types create mode 100644 tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.js create mode 100644 tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.symbols create mode 100644 tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.types create mode 100644 tests/cases/conformance/expressions/typeGuards/typeGuardFunction.ts create mode 100644 tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts create mode 100644 tests/cases/conformance/expressions/typeGuards/typeGuardFunctionGenerics.ts create mode 100644 tests/cases/conformance/expressions/typeGuards/typeGuardOfFormIsType.ts create mode 100644 tests/cases/conformance/expressions/typeGuards/typeGuardOfFormIsTypeOnInterfaces.ts diff --git a/tests/baselines/reference/typeGuardFunction.js b/tests/baselines/reference/typeGuardFunction.js new file mode 100644 index 00000000000..d6b64c09d4d --- /dev/null +++ b/tests/baselines/reference/typeGuardFunction.js @@ -0,0 +1,105 @@ +//// [typeGuardFunction.ts] + +class A { + propA: number; +} + +class B { + propB: number; +} + +class C extends A { + propC: number; +} + +declare function isA(p1: any): p1 is A; +declare function isB(p1: any): p1 is B; +declare function isC(p1: any): p1 is C; + +declare function retC(): C; + +var a: A; +var b: B; + +// Basic. +if (isC(a)) { + a.propC; +} + +// Sub type. +var subType: C; +if(isA(subType)) { + subType.propC; +} + +// Union type. +var union: A | B; +if(isA(union)) { + union.propA; +} + +// The parameter index and argument index for the type guard target is matching. +// The type predicate type is assignable to the parameter type. +declare function isC_multipleParams(p1, p2): p1 is C; +if (isC_multipleParams(a, 0)) { + a.propC; +} + +// Evaluations are asssignable to boolean. +declare function acceptingBoolean(a: boolean); +acceptingBoolean(isA(a)); + +// Type predicates with different parameter name. +declare function acceptingTypeGuardFunction(p1: (item) => item is A); +acceptingTypeGuardFunction(isA); + +let union2: C | B; +let union3: boolean | B = isA(union2) || union2; + +//// [typeGuardFunction.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; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var A = (function () { + function A() { + } + return A; +})(); +var B = (function () { + function B() { + } + return B; +})(); +var C = (function (_super) { + __extends(C, _super); + function C() { + _super.apply(this, arguments); + } + return C; +})(A); +var a; +var b; +// Basic. +if (isC(a)) { + a.propC; +} +// Sub type. +var subType; +if (isA(subType)) { + subType.propC; +} +// Union type. +var union; +if (isA(union)) { + union.propA; +} +if (isC_multipleParams(a, 0)) { + a.propC; +} +acceptingBoolean(isA(a)); +acceptingTypeGuardFunction(isA); +var union2; +var union3 = isA(union2) || union2; diff --git a/tests/baselines/reference/typeGuardFunction.symbols b/tests/baselines/reference/typeGuardFunction.symbols new file mode 100644 index 00000000000..f9180d56b0b --- /dev/null +++ b/tests/baselines/reference/typeGuardFunction.symbols @@ -0,0 +1,144 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardFunction.ts === + +class A { +>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0)) + + propA: number; +>propA : Symbol(propA, Decl(typeGuardFunction.ts, 1, 9)) +} + +class B { +>B : Symbol(B, Decl(typeGuardFunction.ts, 3, 1)) + + propB: number; +>propB : Symbol(propB, Decl(typeGuardFunction.ts, 5, 9)) +} + +class C extends A { +>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1)) +>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0)) + + propC: number; +>propC : Symbol(propC, Decl(typeGuardFunction.ts, 9, 19)) +} + +declare function isA(p1: any): p1 is A; +>isA : Symbol(isA, Decl(typeGuardFunction.ts, 11, 1)) +>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 13, 21)) +>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0)) + +declare function isB(p1: any): p1 is B; +>isB : Symbol(isB, Decl(typeGuardFunction.ts, 13, 39)) +>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 14, 21)) +>B : Symbol(B, Decl(typeGuardFunction.ts, 3, 1)) + +declare function isC(p1: any): p1 is C; +>isC : Symbol(isC, Decl(typeGuardFunction.ts, 14, 39)) +>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 15, 21)) +>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1)) + +declare function retC(): C; +>retC : Symbol(retC, Decl(typeGuardFunction.ts, 15, 39)) +>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1)) + +var a: A; +>a : Symbol(a, Decl(typeGuardFunction.ts, 19, 3)) +>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0)) + +var b: B; +>b : Symbol(b, Decl(typeGuardFunction.ts, 20, 3)) +>B : Symbol(B, Decl(typeGuardFunction.ts, 3, 1)) + +// Basic. +if (isC(a)) { +>isC : Symbol(isC, Decl(typeGuardFunction.ts, 14, 39)) +>a : Symbol(a, Decl(typeGuardFunction.ts, 19, 3)) + + a.propC; +>a.propC : Symbol(C.propC, Decl(typeGuardFunction.ts, 9, 19)) +>a : Symbol(a, Decl(typeGuardFunction.ts, 19, 3)) +>propC : Symbol(C.propC, Decl(typeGuardFunction.ts, 9, 19)) +} + +// Sub type. +var subType: C; +>subType : Symbol(subType, Decl(typeGuardFunction.ts, 28, 3)) +>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1)) + +if(isA(subType)) { +>isA : Symbol(isA, Decl(typeGuardFunction.ts, 11, 1)) +>subType : Symbol(subType, Decl(typeGuardFunction.ts, 28, 3)) + + subType.propC; +>subType.propC : Symbol(C.propC, Decl(typeGuardFunction.ts, 9, 19)) +>subType : Symbol(subType, Decl(typeGuardFunction.ts, 28, 3)) +>propC : Symbol(C.propC, Decl(typeGuardFunction.ts, 9, 19)) +} + +// Union type. +var union: A | B; +>union : Symbol(union, Decl(typeGuardFunction.ts, 34, 3)) +>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0)) +>B : Symbol(B, Decl(typeGuardFunction.ts, 3, 1)) + +if(isA(union)) { +>isA : Symbol(isA, Decl(typeGuardFunction.ts, 11, 1)) +>union : Symbol(union, Decl(typeGuardFunction.ts, 34, 3)) + + union.propA; +>union.propA : Symbol(A.propA, Decl(typeGuardFunction.ts, 1, 9)) +>union : Symbol(union, Decl(typeGuardFunction.ts, 34, 3)) +>propA : Symbol(A.propA, Decl(typeGuardFunction.ts, 1, 9)) +} + +// The parameter index and argument index for the type guard target is matching. +// The type predicate type is assignable to the parameter type. +declare function isC_multipleParams(p1, p2): p1 is C; +>isC_multipleParams : Symbol(isC_multipleParams, Decl(typeGuardFunction.ts, 37, 1)) +>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 41, 36)) +>p2 : Symbol(p2, Decl(typeGuardFunction.ts, 41, 39)) +>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1)) + +if (isC_multipleParams(a, 0)) { +>isC_multipleParams : Symbol(isC_multipleParams, Decl(typeGuardFunction.ts, 37, 1)) +>a : Symbol(a, Decl(typeGuardFunction.ts, 19, 3)) + + a.propC; +>a.propC : Symbol(C.propC, Decl(typeGuardFunction.ts, 9, 19)) +>a : Symbol(a, Decl(typeGuardFunction.ts, 19, 3)) +>propC : Symbol(C.propC, Decl(typeGuardFunction.ts, 9, 19)) +} + +// Evaluations are asssignable to boolean. +declare function acceptingBoolean(a: boolean); +>acceptingBoolean : Symbol(acceptingBoolean, Decl(typeGuardFunction.ts, 44, 1)) +>a : Symbol(a, Decl(typeGuardFunction.ts, 47, 34)) + +acceptingBoolean(isA(a)); +>acceptingBoolean : Symbol(acceptingBoolean, Decl(typeGuardFunction.ts, 44, 1)) +>isA : Symbol(isA, Decl(typeGuardFunction.ts, 11, 1)) +>a : Symbol(a, Decl(typeGuardFunction.ts, 19, 3)) + +// Type predicates with different parameter name. +declare function acceptingTypeGuardFunction(p1: (item) => item is A); +>acceptingTypeGuardFunction : Symbol(acceptingTypeGuardFunction, Decl(typeGuardFunction.ts, 48, 25)) +>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 51, 44)) +>item : Symbol(item, Decl(typeGuardFunction.ts, 51, 49)) +>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0)) + +acceptingTypeGuardFunction(isA); +>acceptingTypeGuardFunction : Symbol(acceptingTypeGuardFunction, Decl(typeGuardFunction.ts, 48, 25)) +>isA : Symbol(isA, Decl(typeGuardFunction.ts, 11, 1)) + +let union2: C | B; +>union2 : Symbol(union2, Decl(typeGuardFunction.ts, 54, 3)) +>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1)) +>B : Symbol(B, Decl(typeGuardFunction.ts, 3, 1)) + +let union3: boolean | B = isA(union2) || union2; +>union3 : Symbol(union3, Decl(typeGuardFunction.ts, 55, 3)) +>B : Symbol(B, Decl(typeGuardFunction.ts, 3, 1)) +>isA : Symbol(isA, Decl(typeGuardFunction.ts, 11, 1)) +>union2 : Symbol(union2, Decl(typeGuardFunction.ts, 54, 3)) +>union2 : Symbol(union2, Decl(typeGuardFunction.ts, 54, 3)) + diff --git a/tests/baselines/reference/typeGuardFunction.types b/tests/baselines/reference/typeGuardFunction.types new file mode 100644 index 00000000000..2b3d1c40c8e --- /dev/null +++ b/tests/baselines/reference/typeGuardFunction.types @@ -0,0 +1,159 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardFunction.ts === + +class A { +>A : A + + propA: number; +>propA : number +} + +class B { +>B : B + + propB: number; +>propB : number +} + +class C extends A { +>C : C +>A : A + + propC: number; +>propC : number +} + +declare function isA(p1: any): p1 is A; +>isA : (p1: any) => boolean +>p1 : any +>p1 : any +>A : A + +declare function isB(p1: any): p1 is B; +>isB : (p1: any) => boolean +>p1 : any +>p1 : any +>B : B + +declare function isC(p1: any): p1 is C; +>isC : (p1: any) => boolean +>p1 : any +>p1 : any +>C : C + +declare function retC(): C; +>retC : () => C +>C : C + +var a: A; +>a : A +>A : A + +var b: B; +>b : B +>B : B + +// Basic. +if (isC(a)) { +>isC(a) : boolean +>isC : (p1: any) => boolean +>a : A + + a.propC; +>a.propC : number +>a : C +>propC : number +} + +// Sub type. +var subType: C; +>subType : C +>C : C + +if(isA(subType)) { +>isA(subType) : boolean +>isA : (p1: any) => boolean +>subType : C + + subType.propC; +>subType.propC : number +>subType : C +>propC : number +} + +// Union type. +var union: A | B; +>union : A | B +>A : A +>B : B + +if(isA(union)) { +>isA(union) : boolean +>isA : (p1: any) => boolean +>union : A | B + + union.propA; +>union.propA : number +>union : A +>propA : number +} + +// The parameter index and argument index for the type guard target is matching. +// The type predicate type is assignable to the parameter type. +declare function isC_multipleParams(p1, p2): p1 is C; +>isC_multipleParams : (p1: any, p2: any) => boolean +>p1 : any +>p2 : any +>p1 : any +>C : C + +if (isC_multipleParams(a, 0)) { +>isC_multipleParams(a, 0) : boolean +>isC_multipleParams : (p1: any, p2: any) => boolean +>a : A +>0 : number + + a.propC; +>a.propC : number +>a : C +>propC : number +} + +// Evaluations are asssignable to boolean. +declare function acceptingBoolean(a: boolean); +>acceptingBoolean : (a: boolean) => any +>a : boolean + +acceptingBoolean(isA(a)); +>acceptingBoolean(isA(a)) : any +>acceptingBoolean : (a: boolean) => any +>isA(a) : boolean +>isA : (p1: any) => boolean +>a : A + +// Type predicates with different parameter name. +declare function acceptingTypeGuardFunction(p1: (item) => item is A); +>acceptingTypeGuardFunction : (p1: (item: any) => boolean) => any +>p1 : (item: any) => boolean +>item : any +>item : any +>A : A + +acceptingTypeGuardFunction(isA); +>acceptingTypeGuardFunction(isA) : any +>acceptingTypeGuardFunction : (p1: (item: any) => boolean) => any +>isA : (p1: any) => boolean + +let union2: C | B; +>union2 : B | C +>C : C +>B : B + +let union3: boolean | B = isA(union2) || union2; +>union3 : boolean | B +>B : B +>isA(union2) || union2 : boolean | B +>isA(union2) : boolean +>isA : (p1: any) => boolean +>union2 : B | C +>union2 : B + diff --git a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt new file mode 100644 index 00000000000..8b5ed551dff --- /dev/null +++ b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt @@ -0,0 +1,174 @@ +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(15,12): error TS1225: A type-guard function can only return a boolean. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,55): error TS2304: Cannot find name 'x'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,57): error TS1144: '{' or ';' expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,57): error TS2304: Cannot find name 'is'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,60): error TS1005: ';' expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,62): error TS1005: ';' expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(22,33): error TS2304: Cannot find name 'x'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(26,10): error TS2391: Function implementation is missing or not immediately following the declaration. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(27,5): error TS1131: Property or signature expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(28,1): error TS1128: Declaration or statement expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(30,38): error TS1226: Cannot find parameter 'x'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(34,51): error TS2322: Type 'B' is not assignable to type 'A'. + Property 'propA' is missing in type 'B'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(38,56): error TS2322: Type 'number' is not assignable to type 'string'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(42,56): error TS2322: Type 'T[]' is not assignable to type 'string'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(56,7): error TS2339: Property 'propB' does not exist on type 'A'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(61,7): error TS2339: Property 'propB' does not exist on type 'A'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(66,7): error TS2339: Property 'propB' does not exist on type 'A'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(71,46): error TS2345: Argument of type '(p1: any) => boolean' is not assignable to parameter of type '(p1: any) => boolean'. + Type-guard annotation 'p1 is C' is not assignable to 'p1 is B'. + Type 'C' is not assignable to type 'B'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(75,1): error TS2322: Type '(p1: any, p2: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. + A non-type guard function is not assignable to a type guard function. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(81,1): error TS2322: Type '(p1: any, p2: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. + Type-guard annotation 'p2 is A' is not assignable to 'p1 is A'. + Parameter index from 'p2' does not match the parameter index from 'p1'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(87,1): error TS2322: Type '(p1: any, p2: any, p3: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,56): error TS1226: Cannot find parameter 'p1'. + + +==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts (22 errors) ==== + + class A { + propA: number; + } + + class B { + propB: number; + } + + class C extends A { + propC: number; + } + + function hasANonBooleanReturnStatement(x): x is A { + return ''; + ~~ +!!! error TS1225: A type-guard function can only return a boolean. + } + + function hasTypeGuardTypeInsideTypeGuardType(x): x is x is A { + ~ +!!! error TS2304: Cannot find name 'x'. + ~~ +!!! error TS1144: '{' or ';' expected. + ~~ +!!! error TS2304: Cannot find name 'is'. + ~ +!!! error TS1005: ';' expected. + ~ +!!! error TS1005: ';' expected. + return true; + } + + function hasMissingIsKeyword(): x { + ~ +!!! error TS2304: Cannot find name 'x'. + return true; + } + + function hasMissingTypeInTypeGuardType(x): x is { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2391: Function implementation is missing or not immediately following the declaration. + return true; + ~~~~~~ +!!! error TS1131: Property or signature expected. + } + ~ +!!! error TS1128: Declaration or statement expected. + + function hasNonMatchingParameter(y): x is A { + ~ +!!! error TS1226: Cannot find parameter 'x'. + return true; + } + + function hasNonMatchingParameterType1(x: A): x is B { + ~ +!!! error TS2322: Type 'B' is not assignable to type 'A'. +!!! error TS2322: Property 'propA' is missing in type 'B'. + return true; + } + + function hasNonMatchingParameterType2(x: string): x is number { + ~~~~~~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. + return true; + } + + function hasNonMathcingGenericType(a: string): a is T[] { + ~~~ +!!! error TS2322: Type 'T[]' is not assignable to type 'string'. + return true; + } + + let a: A; + let b: B; + + declare function isB(p1): p1 is B; + declare function isC(p1): p1 is C; + declare function funA(p1: any, p2: any): p1 is B; + declare function hasNoTypeGuard(x); + + // Passed argument is not the same as the one being guarded. + if (isB(b)) { + a.propB; + ~~~~~ +!!! error TS2339: Property 'propB' does not exist on type 'A'. + } + + // Parameter index and argument index for the type guard target is not matching. + if (funA(0, a)) { + a.propB; // Error + ~~~~~ +!!! error TS2339: Property 'propB' does not exist on type 'A'. + } + + // No type guard in if statement + if (hasNoTypeGuard(a)) { + a.propB; + ~~~~~ +!!! error TS2339: Property 'propB' does not exist on type 'A'. + } + + // Type predicate type is not assignable + declare function acceptingDifferentSignatureTypeGuardFunction(p1: (p1) => p1 is B); + acceptingDifferentSignatureTypeGuardFunction(isC); + ~~~ +!!! error TS2345: Argument of type '(p1: any) => boolean' is not assignable to parameter of type '(p1: any) => boolean'. +!!! error TS2345: Type-guard annotation 'p1 is C' is not assignable to 'p1 is B'. +!!! error TS2345: Type 'C' is not assignable to type 'B'. + + // Boolean not assignable to type guard + var assign1: (p1, p2) => p1 is A; + assign1 = function(p1, p2): boolean { + ~~~~~~~ +!!! error TS2322: Type '(p1: any, p2: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. +!!! error TS2322: A non-type guard function is not assignable to a type guard function. + return true; + }; + + // Must have matching parameter index + var assign2: (p1, p2) => p1 is A; + assign2 = function(p1, p2): p2 is A { + ~~~~~~~ +!!! error TS2322: Type '(p1: any, p2: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. +!!! error TS2322: Type-guard annotation 'p2 is A' is not assignable to 'p1 is A'. +!!! error TS2322: Parameter index from 'p2' does not match the parameter index from 'p1'. + return true; + }; + + // No matching signature + var assign3: (p1, p2) => p1 is A; + assign3 = function(p1, p2, p3): p1 is A { + ~~~~~~~ +!!! error TS2322: Type '(p1: any, p2: any, p3: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. + return true; + }; + + // Type guard paramater referring to a binding pattern + declare function destructureParameter({ p1, p2, p3 }): p1 is A; + ~~ +!!! error TS1226: Cannot find parameter 'p1'. + \ No newline at end of file diff --git a/tests/baselines/reference/typeGuardFunctionErrors.js b/tests/baselines/reference/typeGuardFunctionErrors.js new file mode 100644 index 00000000000..cc65fc00cba --- /dev/null +++ b/tests/baselines/reference/typeGuardFunctionErrors.js @@ -0,0 +1,173 @@ +//// [typeGuardFunctionErrors.ts] + +class A { + propA: number; +} + +class B { + propB: number; +} + +class C extends A { + propC: number; +} + +function hasANonBooleanReturnStatement(x): x is A { + return ''; +} + +function hasTypeGuardTypeInsideTypeGuardType(x): x is x is A { + return true; +} + +function hasMissingIsKeyword(): x { + return true; +} + +function hasMissingTypeInTypeGuardType(x): x is { + return true; +} + +function hasNonMatchingParameter(y): x is A { + return true; +} + +function hasNonMatchingParameterType1(x: A): x is B { + return true; +} + +function hasNonMatchingParameterType2(x: string): x is number { + return true; +} + +function hasNonMathcingGenericType(a: string): a is T[] { + return true; +} + +let a: A; +let b: B; + +declare function isB(p1): p1 is B; +declare function isC(p1): p1 is C; +declare function funA(p1: any, p2: any): p1 is B; +declare function hasNoTypeGuard(x); + +// Passed argument is not the same as the one being guarded. +if (isB(b)) { + a.propB; +} + +// Parameter index and argument index for the type guard target is not matching. +if (funA(0, a)) { + a.propB; // Error +} + +// No type guard in if statement +if (hasNoTypeGuard(a)) { + a.propB; +} + +// Type predicate type is not assignable +declare function acceptingDifferentSignatureTypeGuardFunction(p1: (p1) => p1 is B); +acceptingDifferentSignatureTypeGuardFunction(isC); + +// Boolean not assignable to type guard +var assign1: (p1, p2) => p1 is A; +assign1 = function(p1, p2): boolean { + return true; +}; + +// Must have matching parameter index +var assign2: (p1, p2) => p1 is A; +assign2 = function(p1, p2): p2 is A { + return true; +}; + +// No matching signature +var assign3: (p1, p2) => p1 is A; +assign3 = function(p1, p2, p3): p1 is A { + return true; +}; + +// Type guard paramater referring to a binding pattern +declare function destructureParameter({ p1, p2, p3 }): p1 is A; + + +//// [typeGuardFunctionErrors.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; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var A = (function () { + function A() { + } + return A; +})(); +var B = (function () { + function B() { + } + return B; +})(); +var C = (function (_super) { + __extends(C, _super); + function C() { + _super.apply(this, arguments); + } + return C; +})(A); +function hasANonBooleanReturnStatement(x) { + return ''; +} +is; +A; +{ + return true; +} +function hasMissingIsKeyword() { + return true; +} +return true; +function hasNonMatchingParameter(y) { + return true; +} +function hasNonMatchingParameterType1(x) { + return true; +} +function hasNonMatchingParameterType2(x) { + return true; +} +function hasNonMathcingGenericType(a) { + return true; +} +var a; +var b; +// Passed argument is not the same as the one being guarded. +if (isB(b)) { + a.propB; +} +// Parameter index and argument index for the type guard target is not matching. +if (funA(0, a)) { + a.propB; // Error +} +// No type guard in if statement +if (hasNoTypeGuard(a)) { + a.propB; +} +acceptingDifferentSignatureTypeGuardFunction(isC); +// Boolean not assignable to type guard +var assign1; +assign1 = function (p1, p2) { + return true; +}; +// Must have matching parameter index +var assign2; +assign2 = function (p1, p2) { + return true; +}; +// No matching signature +var assign3; +assign3 = function (p1, p2, p3) { + return true; +}; diff --git a/tests/baselines/reference/typeGuardFunctionGenerics.js b/tests/baselines/reference/typeGuardFunctionGenerics.js new file mode 100644 index 00000000000..6704225a0d0 --- /dev/null +++ b/tests/baselines/reference/typeGuardFunctionGenerics.js @@ -0,0 +1,69 @@ +//// [typeGuardFunctionGenerics.ts] + +class A { + propA: number; +} + +class B { + propB: number; +} + +class C extends A { + propC: number; +} + +declare function isB(p1): p1 is B; +declare function isC(p1): p1 is C; +declare function retC(x): C; + +declare function funA(p1: (p1) => T): T; +declare function funB(p1: (p1) => T, p2: any): p2 is T; +declare function funC(p1: (p1) => p1 is T): T; +declare function funD(p1: (p1) => p1 is T, p2: any): p2 is T; +declare function funE(p1: (p1) => p1 is T, p2: U): T; + +let a: A; +let test1: boolean = funA(isB); +if (funB(retC, a)) { + a.propC; +} +let test2: B = funC(isB); +if (funD(isC, a)) { + a.propC; +} +let test3: B = funE(isB, 1); + +//// [typeGuardFunctionGenerics.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; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var A = (function () { + function A() { + } + return A; +})(); +var B = (function () { + function B() { + } + return B; +})(); +var C = (function (_super) { + __extends(C, _super); + function C() { + _super.apply(this, arguments); + } + return C; +})(A); +var a; +var test1 = funA(isB); +if (funB(retC, a)) { + a.propC; +} +var test2 = funC(isB); +if (funD(isC, a)) { + a.propC; +} +var test3 = funE(isB, 1); diff --git a/tests/baselines/reference/typeGuardFunctionGenerics.symbols b/tests/baselines/reference/typeGuardFunctionGenerics.symbols new file mode 100644 index 00000000000..0ad8fab2fdb --- /dev/null +++ b/tests/baselines/reference/typeGuardFunctionGenerics.symbols @@ -0,0 +1,125 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionGenerics.ts === + +class A { +>A : Symbol(A, Decl(typeGuardFunctionGenerics.ts, 0, 0)) + + propA: number; +>propA : Symbol(propA, Decl(typeGuardFunctionGenerics.ts, 1, 9)) +} + +class B { +>B : Symbol(B, Decl(typeGuardFunctionGenerics.ts, 3, 1)) + + propB: number; +>propB : Symbol(propB, Decl(typeGuardFunctionGenerics.ts, 5, 9)) +} + +class C extends A { +>C : Symbol(C, Decl(typeGuardFunctionGenerics.ts, 7, 1)) +>A : Symbol(A, Decl(typeGuardFunctionGenerics.ts, 0, 0)) + + propC: number; +>propC : Symbol(propC, Decl(typeGuardFunctionGenerics.ts, 9, 19)) +} + +declare function isB(p1): p1 is B; +>isB : Symbol(isB, Decl(typeGuardFunctionGenerics.ts, 11, 1)) +>p1 : Symbol(p1, Decl(typeGuardFunctionGenerics.ts, 13, 21)) +>B : Symbol(B, Decl(typeGuardFunctionGenerics.ts, 3, 1)) + +declare function isC(p1): p1 is C; +>isC : Symbol(isC, Decl(typeGuardFunctionGenerics.ts, 13, 34)) +>p1 : Symbol(p1, Decl(typeGuardFunctionGenerics.ts, 14, 21)) +>C : Symbol(C, Decl(typeGuardFunctionGenerics.ts, 7, 1)) + +declare function retC(x): C; +>retC : Symbol(retC, Decl(typeGuardFunctionGenerics.ts, 14, 34)) +>x : Symbol(x, Decl(typeGuardFunctionGenerics.ts, 15, 22)) +>C : Symbol(C, Decl(typeGuardFunctionGenerics.ts, 7, 1)) + +declare function funA(p1: (p1) => T): T; +>funA : Symbol(funA, Decl(typeGuardFunctionGenerics.ts, 15, 28)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 17, 22)) +>p1 : Symbol(p1, Decl(typeGuardFunctionGenerics.ts, 17, 25)) +>p1 : Symbol(p1, Decl(typeGuardFunctionGenerics.ts, 17, 30)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 17, 22)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 17, 22)) + +declare function funB(p1: (p1) => T, p2: any): p2 is T; +>funB : Symbol(funB, Decl(typeGuardFunctionGenerics.ts, 17, 43)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 18, 22)) +>p1 : Symbol(p1, Decl(typeGuardFunctionGenerics.ts, 18, 25)) +>p1 : Symbol(p1, Decl(typeGuardFunctionGenerics.ts, 18, 30)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 18, 22)) +>p2 : Symbol(p2, Decl(typeGuardFunctionGenerics.ts, 18, 39)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 18, 22)) + +declare function funC(p1: (p1) => p1 is T): T; +>funC : Symbol(funC, Decl(typeGuardFunctionGenerics.ts, 18, 58)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 19, 22)) +>p1 : Symbol(p1, Decl(typeGuardFunctionGenerics.ts, 19, 25)) +>p1 : Symbol(p1, Decl(typeGuardFunctionGenerics.ts, 19, 30)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 19, 22)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 19, 22)) + +declare function funD(p1: (p1) => p1 is T, p2: any): p2 is T; +>funD : Symbol(funD, Decl(typeGuardFunctionGenerics.ts, 19, 49)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 20, 22)) +>p1 : Symbol(p1, Decl(typeGuardFunctionGenerics.ts, 20, 25)) +>p1 : Symbol(p1, Decl(typeGuardFunctionGenerics.ts, 20, 30)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 20, 22)) +>p2 : Symbol(p2, Decl(typeGuardFunctionGenerics.ts, 20, 45)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 20, 22)) + +declare function funE(p1: (p1) => p1 is T, p2: U): T; +>funE : Symbol(funE, Decl(typeGuardFunctionGenerics.ts, 20, 64)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 21, 22)) +>U : Symbol(U, Decl(typeGuardFunctionGenerics.ts, 21, 24)) +>p1 : Symbol(p1, Decl(typeGuardFunctionGenerics.ts, 21, 28)) +>p1 : Symbol(p1, Decl(typeGuardFunctionGenerics.ts, 21, 33)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 21, 22)) +>p2 : Symbol(p2, Decl(typeGuardFunctionGenerics.ts, 21, 48)) +>U : Symbol(U, Decl(typeGuardFunctionGenerics.ts, 21, 24)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 21, 22)) + +let a: A; +>a : Symbol(a, Decl(typeGuardFunctionGenerics.ts, 23, 3)) +>A : Symbol(A, Decl(typeGuardFunctionGenerics.ts, 0, 0)) + +let test1: boolean = funA(isB); +>test1 : Symbol(test1, Decl(typeGuardFunctionGenerics.ts, 24, 3)) +>funA : Symbol(funA, Decl(typeGuardFunctionGenerics.ts, 15, 28)) +>isB : Symbol(isB, Decl(typeGuardFunctionGenerics.ts, 11, 1)) + +if (funB(retC, a)) { +>funB : Symbol(funB, Decl(typeGuardFunctionGenerics.ts, 17, 43)) +>retC : Symbol(retC, Decl(typeGuardFunctionGenerics.ts, 14, 34)) +>a : Symbol(a, Decl(typeGuardFunctionGenerics.ts, 23, 3)) + + a.propC; +>a.propC : Symbol(C.propC, Decl(typeGuardFunctionGenerics.ts, 9, 19)) +>a : Symbol(a, Decl(typeGuardFunctionGenerics.ts, 23, 3)) +>propC : Symbol(C.propC, Decl(typeGuardFunctionGenerics.ts, 9, 19)) +} +let test2: B = funC(isB); +>test2 : Symbol(test2, Decl(typeGuardFunctionGenerics.ts, 28, 3)) +>B : Symbol(B, Decl(typeGuardFunctionGenerics.ts, 3, 1)) +>funC : Symbol(funC, Decl(typeGuardFunctionGenerics.ts, 18, 58)) +>isB : Symbol(isB, Decl(typeGuardFunctionGenerics.ts, 11, 1)) + +if (funD(isC, a)) { +>funD : Symbol(funD, Decl(typeGuardFunctionGenerics.ts, 19, 49)) +>isC : Symbol(isC, Decl(typeGuardFunctionGenerics.ts, 13, 34)) +>a : Symbol(a, Decl(typeGuardFunctionGenerics.ts, 23, 3)) + + a.propC; +>a.propC : Symbol(C.propC, Decl(typeGuardFunctionGenerics.ts, 9, 19)) +>a : Symbol(a, Decl(typeGuardFunctionGenerics.ts, 23, 3)) +>propC : Symbol(C.propC, Decl(typeGuardFunctionGenerics.ts, 9, 19)) +} +let test3: B = funE(isB, 1); +>test3 : Symbol(test3, Decl(typeGuardFunctionGenerics.ts, 32, 3)) +>B : Symbol(B, Decl(typeGuardFunctionGenerics.ts, 3, 1)) +>funE : Symbol(funE, Decl(typeGuardFunctionGenerics.ts, 20, 64)) +>isB : Symbol(isB, Decl(typeGuardFunctionGenerics.ts, 11, 1)) + diff --git a/tests/baselines/reference/typeGuardFunctionGenerics.types b/tests/baselines/reference/typeGuardFunctionGenerics.types new file mode 100644 index 00000000000..77162e55a40 --- /dev/null +++ b/tests/baselines/reference/typeGuardFunctionGenerics.types @@ -0,0 +1,138 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionGenerics.ts === + +class A { +>A : A + + propA: number; +>propA : number +} + +class B { +>B : B + + propB: number; +>propB : number +} + +class C extends A { +>C : C +>A : A + + propC: number; +>propC : number +} + +declare function isB(p1): p1 is B; +>isB : (p1: any) => boolean +>p1 : any +>p1 : any +>B : B + +declare function isC(p1): p1 is C; +>isC : (p1: any) => boolean +>p1 : any +>p1 : any +>C : C + +declare function retC(x): C; +>retC : (x: any) => C +>x : any +>C : C + +declare function funA(p1: (p1) => T): T; +>funA : (p1: (p1: any) => T) => T +>T : T +>p1 : (p1: any) => T +>p1 : any +>T : T +>T : T + +declare function funB(p1: (p1) => T, p2: any): p2 is T; +>funB : (p1: (p1: any) => T, p2: any) => boolean +>T : T +>p1 : (p1: any) => T +>p1 : any +>T : T +>p2 : any +>p2 : any +>T : T + +declare function funC(p1: (p1) => p1 is T): T; +>funC : (p1: (p1: any) => boolean) => T +>T : T +>p1 : (p1: any) => boolean +>p1 : any +>p1 : any +>T : T +>T : T + +declare function funD(p1: (p1) => p1 is T, p2: any): p2 is T; +>funD : (p1: (p1: any) => boolean, p2: any) => boolean +>T : T +>p1 : (p1: any) => boolean +>p1 : any +>p1 : any +>T : T +>p2 : any +>p2 : any +>T : T + +declare function funE(p1: (p1) => p1 is T, p2: U): T; +>funE : (p1: (p1: any) => boolean, p2: U) => T +>T : T +>U : U +>p1 : (p1: any) => boolean +>p1 : any +>p1 : any +>T : T +>p2 : U +>U : U +>T : T + +let a: A; +>a : A +>A : A + +let test1: boolean = funA(isB); +>test1 : boolean +>funA(isB) : boolean +>funA : (p1: (p1: any) => T) => T +>isB : (p1: any) => boolean + +if (funB(retC, a)) { +>funB(retC, a) : boolean +>funB : (p1: (p1: any) => T, p2: any) => boolean +>retC : (x: any) => C +>a : A + + a.propC; +>a.propC : number +>a : C +>propC : number +} +let test2: B = funC(isB); +>test2 : B +>B : B +>funC(isB) : B +>funC : (p1: (p1: any) => boolean) => T +>isB : (p1: any) => boolean + +if (funD(isC, a)) { +>funD(isC, a) : boolean +>funD : (p1: (p1: any) => boolean, p2: any) => boolean +>isC : (p1: any) => boolean +>a : A + + a.propC; +>a.propC : number +>a : C +>propC : number +} +let test3: B = funE(isB, 1); +>test3 : B +>B : B +>funE(isB, 1) : B +>funE : (p1: (p1: any) => boolean, p2: U) => T +>isB : (p1: any) => boolean +>1 : number + diff --git a/tests/baselines/reference/typeGuardOfFormIsType.js b/tests/baselines/reference/typeGuardOfFormIsType.js new file mode 100644 index 00000000000..65d99319d1e --- /dev/null +++ b/tests/baselines/reference/typeGuardOfFormIsType.js @@ -0,0 +1,85 @@ +//// [typeGuardOfFormIsType.ts] + +class C1 { + p1: string; +} +class C2 { + p2: number; +} +class D1 extends C1 { + p3: number; +} +var str: string; +var num: number; +var strOrNum: string | number; + +function isC1(x: any): x is C1 { + return true; +} + +function isC2(x: any): x is C2 { + return true; +} + +function isD1(x: any): x is D1 { + return true; +} + +var c1Orc2: C1 | C2; +str = isC1(c1Orc2) && c1Orc2.p1; // C1 +num = isC2(c1Orc2) && c1Orc2.p2; // C2 +str = isD1(c1Orc2) && c1Orc2.p1; // D1 +num = isD1(c1Orc2) && c1Orc2.p3; // D1 + +var c2Ord1: C2 | D1; +num = isC2(c2Ord1) && c2Ord1.p2; // C2 +num = isD1(c2Ord1) && c2Ord1.p3; // D1 +str = isD1(c2Ord1) && c2Ord1.p1; // D1 +var r2: C2 | D1 = isC1(c2Ord1) && c2Ord1; // C2 | D1 + +//// [typeGuardOfFormIsType.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; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var C1 = (function () { + function C1() { + } + return C1; +})(); +var C2 = (function () { + function C2() { + } + return C2; +})(); +var D1 = (function (_super) { + __extends(D1, _super); + function D1() { + _super.apply(this, arguments); + } + return D1; +})(C1); +var str; +var num; +var strOrNum; +function isC1(x) { + return true; +} +function isC2(x) { + return true; +} +function isD1(x) { + return true; +} +var c1Orc2; +str = isC1(c1Orc2) && c1Orc2.p1; // C1 +num = isC2(c1Orc2) && c1Orc2.p2; // C2 +str = isD1(c1Orc2) && c1Orc2.p1; // D1 +num = isD1(c1Orc2) && c1Orc2.p3; // D1 +var c2Ord1; +num = isC2(c2Ord1) && c2Ord1.p2; // C2 +num = isD1(c2Ord1) && c2Ord1.p3; // D1 +str = isD1(c2Ord1) && c2Ord1.p1; // D1 +var r2 = isC1(c2Ord1) && c2Ord1; // C2 | D1 diff --git a/tests/baselines/reference/typeGuardOfFormIsType.symbols b/tests/baselines/reference/typeGuardOfFormIsType.symbols new file mode 100644 index 00000000000..a7bd0f4c165 --- /dev/null +++ b/tests/baselines/reference/typeGuardOfFormIsType.symbols @@ -0,0 +1,128 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardOfFormIsType.ts === + +class C1 { +>C1 : Symbol(C1, Decl(typeGuardOfFormIsType.ts, 0, 0)) + + p1: string; +>p1 : Symbol(p1, Decl(typeGuardOfFormIsType.ts, 1, 10)) +} +class C2 { +>C2 : Symbol(C2, Decl(typeGuardOfFormIsType.ts, 3, 1)) + + p2: number; +>p2 : Symbol(p2, Decl(typeGuardOfFormIsType.ts, 4, 10)) +} +class D1 extends C1 { +>D1 : Symbol(D1, Decl(typeGuardOfFormIsType.ts, 6, 1)) +>C1 : Symbol(C1, Decl(typeGuardOfFormIsType.ts, 0, 0)) + + p3: number; +>p3 : Symbol(p3, Decl(typeGuardOfFormIsType.ts, 7, 21)) +} +var str: string; +>str : Symbol(str, Decl(typeGuardOfFormIsType.ts, 10, 3)) + +var num: number; +>num : Symbol(num, Decl(typeGuardOfFormIsType.ts, 11, 3)) + +var strOrNum: string | number; +>strOrNum : Symbol(strOrNum, Decl(typeGuardOfFormIsType.ts, 12, 3)) + +function isC1(x: any): x is C1 { +>isC1 : Symbol(isC1, Decl(typeGuardOfFormIsType.ts, 12, 30)) +>x : Symbol(x, Decl(typeGuardOfFormIsType.ts, 14, 14)) +>C1 : Symbol(C1, Decl(typeGuardOfFormIsType.ts, 0, 0)) + + return true; +} + +function isC2(x: any): x is C2 { +>isC2 : Symbol(isC2, Decl(typeGuardOfFormIsType.ts, 16, 1)) +>x : Symbol(x, Decl(typeGuardOfFormIsType.ts, 18, 14)) +>C2 : Symbol(C2, Decl(typeGuardOfFormIsType.ts, 3, 1)) + + return true; +} + +function isD1(x: any): x is D1 { +>isD1 : Symbol(isD1, Decl(typeGuardOfFormIsType.ts, 20, 1)) +>x : Symbol(x, Decl(typeGuardOfFormIsType.ts, 22, 14)) +>D1 : Symbol(D1, Decl(typeGuardOfFormIsType.ts, 6, 1)) + + return true; +} + +var c1Orc2: C1 | C2; +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsType.ts, 26, 3)) +>C1 : Symbol(C1, Decl(typeGuardOfFormIsType.ts, 0, 0)) +>C2 : Symbol(C2, Decl(typeGuardOfFormIsType.ts, 3, 1)) + +str = isC1(c1Orc2) && c1Orc2.p1; // C1 +>str : Symbol(str, Decl(typeGuardOfFormIsType.ts, 10, 3)) +>isC1 : Symbol(isC1, Decl(typeGuardOfFormIsType.ts, 12, 30)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsType.ts, 26, 3)) +>c1Orc2.p1 : Symbol(C1.p1, Decl(typeGuardOfFormIsType.ts, 1, 10)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsType.ts, 26, 3)) +>p1 : Symbol(C1.p1, Decl(typeGuardOfFormIsType.ts, 1, 10)) + +num = isC2(c1Orc2) && c1Orc2.p2; // C2 +>num : Symbol(num, Decl(typeGuardOfFormIsType.ts, 11, 3)) +>isC2 : Symbol(isC2, Decl(typeGuardOfFormIsType.ts, 16, 1)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsType.ts, 26, 3)) +>c1Orc2.p2 : Symbol(C2.p2, Decl(typeGuardOfFormIsType.ts, 4, 10)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsType.ts, 26, 3)) +>p2 : Symbol(C2.p2, Decl(typeGuardOfFormIsType.ts, 4, 10)) + +str = isD1(c1Orc2) && c1Orc2.p1; // D1 +>str : Symbol(str, Decl(typeGuardOfFormIsType.ts, 10, 3)) +>isD1 : Symbol(isD1, Decl(typeGuardOfFormIsType.ts, 20, 1)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsType.ts, 26, 3)) +>c1Orc2.p1 : Symbol(C1.p1, Decl(typeGuardOfFormIsType.ts, 1, 10)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsType.ts, 26, 3)) +>p1 : Symbol(C1.p1, Decl(typeGuardOfFormIsType.ts, 1, 10)) + +num = isD1(c1Orc2) && c1Orc2.p3; // D1 +>num : Symbol(num, Decl(typeGuardOfFormIsType.ts, 11, 3)) +>isD1 : Symbol(isD1, Decl(typeGuardOfFormIsType.ts, 20, 1)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsType.ts, 26, 3)) +>c1Orc2.p3 : Symbol(D1.p3, Decl(typeGuardOfFormIsType.ts, 7, 21)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsType.ts, 26, 3)) +>p3 : Symbol(D1.p3, Decl(typeGuardOfFormIsType.ts, 7, 21)) + +var c2Ord1: C2 | D1; +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsType.ts, 32, 3)) +>C2 : Symbol(C2, Decl(typeGuardOfFormIsType.ts, 3, 1)) +>D1 : Symbol(D1, Decl(typeGuardOfFormIsType.ts, 6, 1)) + +num = isC2(c2Ord1) && c2Ord1.p2; // C2 +>num : Symbol(num, Decl(typeGuardOfFormIsType.ts, 11, 3)) +>isC2 : Symbol(isC2, Decl(typeGuardOfFormIsType.ts, 16, 1)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsType.ts, 32, 3)) +>c2Ord1.p2 : Symbol(C2.p2, Decl(typeGuardOfFormIsType.ts, 4, 10)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsType.ts, 32, 3)) +>p2 : Symbol(C2.p2, Decl(typeGuardOfFormIsType.ts, 4, 10)) + +num = isD1(c2Ord1) && c2Ord1.p3; // D1 +>num : Symbol(num, Decl(typeGuardOfFormIsType.ts, 11, 3)) +>isD1 : Symbol(isD1, Decl(typeGuardOfFormIsType.ts, 20, 1)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsType.ts, 32, 3)) +>c2Ord1.p3 : Symbol(D1.p3, Decl(typeGuardOfFormIsType.ts, 7, 21)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsType.ts, 32, 3)) +>p3 : Symbol(D1.p3, Decl(typeGuardOfFormIsType.ts, 7, 21)) + +str = isD1(c2Ord1) && c2Ord1.p1; // D1 +>str : Symbol(str, Decl(typeGuardOfFormIsType.ts, 10, 3)) +>isD1 : Symbol(isD1, Decl(typeGuardOfFormIsType.ts, 20, 1)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsType.ts, 32, 3)) +>c2Ord1.p1 : Symbol(C1.p1, Decl(typeGuardOfFormIsType.ts, 1, 10)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsType.ts, 32, 3)) +>p1 : Symbol(C1.p1, Decl(typeGuardOfFormIsType.ts, 1, 10)) + +var r2: C2 | D1 = isC1(c2Ord1) && c2Ord1; // C2 | D1 +>r2 : Symbol(r2, Decl(typeGuardOfFormIsType.ts, 36, 3)) +>C2 : Symbol(C2, Decl(typeGuardOfFormIsType.ts, 3, 1)) +>D1 : Symbol(D1, Decl(typeGuardOfFormIsType.ts, 6, 1)) +>isC1 : Symbol(isC1, Decl(typeGuardOfFormIsType.ts, 12, 30)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsType.ts, 32, 3)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsType.ts, 32, 3)) + diff --git a/tests/baselines/reference/typeGuardOfFormIsType.types b/tests/baselines/reference/typeGuardOfFormIsType.types new file mode 100644 index 00000000000..b14e5e22910 --- /dev/null +++ b/tests/baselines/reference/typeGuardOfFormIsType.types @@ -0,0 +1,157 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardOfFormIsType.ts === + +class C1 { +>C1 : C1 + + p1: string; +>p1 : string +} +class C2 { +>C2 : C2 + + p2: number; +>p2 : number +} +class D1 extends C1 { +>D1 : D1 +>C1 : C1 + + p3: number; +>p3 : number +} +var str: string; +>str : string + +var num: number; +>num : number + +var strOrNum: string | number; +>strOrNum : string | number + +function isC1(x: any): x is C1 { +>isC1 : (x: any) => boolean +>x : any +>x : any +>C1 : C1 + + return true; +>true : boolean +} + +function isC2(x: any): x is C2 { +>isC2 : (x: any) => boolean +>x : any +>x : any +>C2 : C2 + + return true; +>true : boolean +} + +function isD1(x: any): x is D1 { +>isD1 : (x: any) => boolean +>x : any +>x : any +>D1 : D1 + + return true; +>true : boolean +} + +var c1Orc2: C1 | C2; +>c1Orc2 : C1 | C2 +>C1 : C1 +>C2 : C2 + +str = isC1(c1Orc2) && c1Orc2.p1; // C1 +>str = isC1(c1Orc2) && c1Orc2.p1 : string +>str : string +>isC1(c1Orc2) && c1Orc2.p1 : string +>isC1(c1Orc2) : boolean +>isC1 : (x: any) => boolean +>c1Orc2 : C1 | C2 +>c1Orc2.p1 : string +>c1Orc2 : C1 +>p1 : string + +num = isC2(c1Orc2) && c1Orc2.p2; // C2 +>num = isC2(c1Orc2) && c1Orc2.p2 : number +>num : number +>isC2(c1Orc2) && c1Orc2.p2 : number +>isC2(c1Orc2) : boolean +>isC2 : (x: any) => boolean +>c1Orc2 : C1 | C2 +>c1Orc2.p2 : number +>c1Orc2 : C2 +>p2 : number + +str = isD1(c1Orc2) && c1Orc2.p1; // D1 +>str = isD1(c1Orc2) && c1Orc2.p1 : string +>str : string +>isD1(c1Orc2) && c1Orc2.p1 : string +>isD1(c1Orc2) : boolean +>isD1 : (x: any) => boolean +>c1Orc2 : C1 | C2 +>c1Orc2.p1 : string +>c1Orc2 : D1 +>p1 : string + +num = isD1(c1Orc2) && c1Orc2.p3; // D1 +>num = isD1(c1Orc2) && c1Orc2.p3 : number +>num : number +>isD1(c1Orc2) && c1Orc2.p3 : number +>isD1(c1Orc2) : boolean +>isD1 : (x: any) => boolean +>c1Orc2 : C1 | C2 +>c1Orc2.p3 : number +>c1Orc2 : D1 +>p3 : number + +var c2Ord1: C2 | D1; +>c2Ord1 : C2 | D1 +>C2 : C2 +>D1 : D1 + +num = isC2(c2Ord1) && c2Ord1.p2; // C2 +>num = isC2(c2Ord1) && c2Ord1.p2 : number +>num : number +>isC2(c2Ord1) && c2Ord1.p2 : number +>isC2(c2Ord1) : boolean +>isC2 : (x: any) => boolean +>c2Ord1 : C2 | D1 +>c2Ord1.p2 : number +>c2Ord1 : C2 +>p2 : number + +num = isD1(c2Ord1) && c2Ord1.p3; // D1 +>num = isD1(c2Ord1) && c2Ord1.p3 : number +>num : number +>isD1(c2Ord1) && c2Ord1.p3 : number +>isD1(c2Ord1) : boolean +>isD1 : (x: any) => boolean +>c2Ord1 : C2 | D1 +>c2Ord1.p3 : number +>c2Ord1 : D1 +>p3 : number + +str = isD1(c2Ord1) && c2Ord1.p1; // D1 +>str = isD1(c2Ord1) && c2Ord1.p1 : string +>str : string +>isD1(c2Ord1) && c2Ord1.p1 : string +>isD1(c2Ord1) : boolean +>isD1 : (x: any) => boolean +>c2Ord1 : C2 | D1 +>c2Ord1.p1 : string +>c2Ord1 : D1 +>p1 : string + +var r2: C2 | D1 = isC1(c2Ord1) && c2Ord1; // C2 | D1 +>r2 : C2 | D1 +>C2 : C2 +>D1 : D1 +>isC1(c2Ord1) && c2Ord1 : D1 +>isC1(c2Ord1) : boolean +>isC1 : (x: any) => boolean +>c2Ord1 : C2 | D1 +>c2Ord1 : D1 + diff --git a/tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.js b/tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.js new file mode 100644 index 00000000000..d5faee96e8b --- /dev/null +++ b/tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.js @@ -0,0 +1,74 @@ +//// [typeGuardOfFormIsTypeOnInterfaces.ts] + +interface C1 { + (): C1; + prototype: C1; + p1: string; +} +interface C2 { + (): C2; + prototype: C2; + p2: number; +} +interface D1 extends C1 { + prototype: D1; + p3: number; +} +var str: string; +var num: number; +var strOrNum: string | number; + + +function isC1(x: any): x is C1 { + return true; +} + +function isC2(x: any): x is C2 { + return true; +} + +function isD1(x: any): x is D1 { + return true; +} + +var c1: C1; +var c2: C2; +var d1: D1; +var c1Orc2: C1 | C2; +str = isC1(c1Orc2) && c1Orc2.p1; // C1 +num = isC2(c1Orc2) && c1Orc2.p2; // C2 +str = isD1(c1Orc2) && c1Orc2.p1; // D1 +num = isD1(c1Orc2) && c1Orc2.p3; // D1 + +var c2Ord1: C2 | D1; +num = isC2(c2Ord1) && c2Ord1.p2; // C2 +num = isD1(c2Ord1) && c2Ord1.p3; // D1 +str = isD1(c2Ord1) && c2Ord1.p1; // D1 +var r2: C2 | D1 = isC1(c2Ord1) && c2Ord1; // C2 | D1 + +//// [typeGuardOfFormIsTypeOnInterfaces.js] +var str; +var num; +var strOrNum; +function isC1(x) { + return true; +} +function isC2(x) { + return true; +} +function isD1(x) { + return true; +} +var c1; +var c2; +var d1; +var c1Orc2; +str = isC1(c1Orc2) && c1Orc2.p1; // C1 +num = isC2(c1Orc2) && c1Orc2.p2; // C2 +str = isD1(c1Orc2) && c1Orc2.p1; // D1 +num = isD1(c1Orc2) && c1Orc2.p3; // D1 +var c2Ord1; +num = isC2(c2Ord1) && c2Ord1.p2; // C2 +num = isD1(c2Ord1) && c2Ord1.p3; // D1 +str = isD1(c2Ord1) && c2Ord1.p1; // D1 +var r2 = isC1(c2Ord1) && c2Ord1; // C2 | D1 diff --git a/tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.symbols b/tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.symbols new file mode 100644 index 00000000000..37249ef7659 --- /dev/null +++ b/tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.symbols @@ -0,0 +1,159 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardOfFormIsTypeOnInterfaces.ts === + +interface C1 { +>C1 : Symbol(C1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 0, 0)) + + (): C1; +>C1 : Symbol(C1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 0, 0)) + + prototype: C1; +>prototype : Symbol(prototype, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 2, 11)) +>C1 : Symbol(C1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 0, 0)) + + p1: string; +>p1 : Symbol(p1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 3, 18)) +} +interface C2 { +>C2 : Symbol(C2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 5, 1)) + + (): C2; +>C2 : Symbol(C2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 5, 1)) + + prototype: C2; +>prototype : Symbol(prototype, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 7, 11)) +>C2 : Symbol(C2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 5, 1)) + + p2: number; +>p2 : Symbol(p2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 8, 18)) +} +interface D1 extends C1 { +>D1 : Symbol(D1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 10, 1)) +>C1 : Symbol(C1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 0, 0)) + + prototype: D1; +>prototype : Symbol(prototype, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 11, 25)) +>D1 : Symbol(D1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 10, 1)) + + p3: number; +>p3 : Symbol(p3, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 12, 18)) +} +var str: string; +>str : Symbol(str, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 15, 3)) + +var num: number; +>num : Symbol(num, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 16, 3)) + +var strOrNum: string | number; +>strOrNum : Symbol(strOrNum, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 17, 3)) + + +function isC1(x: any): x is C1 { +>isC1 : Symbol(isC1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 17, 30)) +>x : Symbol(x, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 20, 14)) +>C1 : Symbol(C1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 0, 0)) + + return true; +} + +function isC2(x: any): x is C2 { +>isC2 : Symbol(isC2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 22, 1)) +>x : Symbol(x, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 24, 14)) +>C2 : Symbol(C2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 5, 1)) + + return true; +} + +function isD1(x: any): x is D1 { +>isD1 : Symbol(isD1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 26, 1)) +>x : Symbol(x, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 28, 14)) +>D1 : Symbol(D1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 10, 1)) + + return true; +} + +var c1: C1; +>c1 : Symbol(c1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 32, 3)) +>C1 : Symbol(C1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 0, 0)) + +var c2: C2; +>c2 : Symbol(c2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 33, 3)) +>C2 : Symbol(C2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 5, 1)) + +var d1: D1; +>d1 : Symbol(d1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 34, 3)) +>D1 : Symbol(D1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 10, 1)) + +var c1Orc2: C1 | C2; +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 35, 3)) +>C1 : Symbol(C1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 0, 0)) +>C2 : Symbol(C2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 5, 1)) + +str = isC1(c1Orc2) && c1Orc2.p1; // C1 +>str : Symbol(str, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 15, 3)) +>isC1 : Symbol(isC1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 17, 30)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 35, 3)) +>c1Orc2.p1 : Symbol(C1.p1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 3, 18)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 35, 3)) +>p1 : Symbol(C1.p1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 3, 18)) + +num = isC2(c1Orc2) && c1Orc2.p2; // C2 +>num : Symbol(num, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 16, 3)) +>isC2 : Symbol(isC2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 22, 1)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 35, 3)) +>c1Orc2.p2 : Symbol(C2.p2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 8, 18)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 35, 3)) +>p2 : Symbol(C2.p2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 8, 18)) + +str = isD1(c1Orc2) && c1Orc2.p1; // D1 +>str : Symbol(str, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 15, 3)) +>isD1 : Symbol(isD1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 26, 1)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 35, 3)) +>c1Orc2.p1 : Symbol(C1.p1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 3, 18)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 35, 3)) +>p1 : Symbol(C1.p1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 3, 18)) + +num = isD1(c1Orc2) && c1Orc2.p3; // D1 +>num : Symbol(num, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 16, 3)) +>isD1 : Symbol(isD1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 26, 1)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 35, 3)) +>c1Orc2.p3 : Symbol(D1.p3, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 12, 18)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 35, 3)) +>p3 : Symbol(D1.p3, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 12, 18)) + +var c2Ord1: C2 | D1; +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 41, 3)) +>C2 : Symbol(C2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 5, 1)) +>D1 : Symbol(D1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 10, 1)) + +num = isC2(c2Ord1) && c2Ord1.p2; // C2 +>num : Symbol(num, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 16, 3)) +>isC2 : Symbol(isC2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 22, 1)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 41, 3)) +>c2Ord1.p2 : Symbol(C2.p2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 8, 18)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 41, 3)) +>p2 : Symbol(C2.p2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 8, 18)) + +num = isD1(c2Ord1) && c2Ord1.p3; // D1 +>num : Symbol(num, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 16, 3)) +>isD1 : Symbol(isD1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 26, 1)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 41, 3)) +>c2Ord1.p3 : Symbol(D1.p3, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 12, 18)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 41, 3)) +>p3 : Symbol(D1.p3, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 12, 18)) + +str = isD1(c2Ord1) && c2Ord1.p1; // D1 +>str : Symbol(str, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 15, 3)) +>isD1 : Symbol(isD1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 26, 1)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 41, 3)) +>c2Ord1.p1 : Symbol(C1.p1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 3, 18)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 41, 3)) +>p1 : Symbol(C1.p1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 3, 18)) + +var r2: C2 | D1 = isC1(c2Ord1) && c2Ord1; // C2 | D1 +>r2 : Symbol(r2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 45, 3)) +>C2 : Symbol(C2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 5, 1)) +>D1 : Symbol(D1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 10, 1)) +>isC1 : Symbol(isC1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 17, 30)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 41, 3)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 41, 3)) + diff --git a/tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.types b/tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.types new file mode 100644 index 00000000000..3a659d71163 --- /dev/null +++ b/tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.types @@ -0,0 +1,188 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardOfFormIsTypeOnInterfaces.ts === + +interface C1 { +>C1 : C1 + + (): C1; +>C1 : C1 + + prototype: C1; +>prototype : C1 +>C1 : C1 + + p1: string; +>p1 : string +} +interface C2 { +>C2 : C2 + + (): C2; +>C2 : C2 + + prototype: C2; +>prototype : C2 +>C2 : C2 + + p2: number; +>p2 : number +} +interface D1 extends C1 { +>D1 : D1 +>C1 : C1 + + prototype: D1; +>prototype : D1 +>D1 : D1 + + p3: number; +>p3 : number +} +var str: string; +>str : string + +var num: number; +>num : number + +var strOrNum: string | number; +>strOrNum : string | number + + +function isC1(x: any): x is C1 { +>isC1 : (x: any) => boolean +>x : any +>x : any +>C1 : C1 + + return true; +>true : boolean +} + +function isC2(x: any): x is C2 { +>isC2 : (x: any) => boolean +>x : any +>x : any +>C2 : C2 + + return true; +>true : boolean +} + +function isD1(x: any): x is D1 { +>isD1 : (x: any) => boolean +>x : any +>x : any +>D1 : D1 + + return true; +>true : boolean +} + +var c1: C1; +>c1 : C1 +>C1 : C1 + +var c2: C2; +>c2 : C2 +>C2 : C2 + +var d1: D1; +>d1 : D1 +>D1 : D1 + +var c1Orc2: C1 | C2; +>c1Orc2 : C1 | C2 +>C1 : C1 +>C2 : C2 + +str = isC1(c1Orc2) && c1Orc2.p1; // C1 +>str = isC1(c1Orc2) && c1Orc2.p1 : string +>str : string +>isC1(c1Orc2) && c1Orc2.p1 : string +>isC1(c1Orc2) : boolean +>isC1 : (x: any) => boolean +>c1Orc2 : C1 | C2 +>c1Orc2.p1 : string +>c1Orc2 : C1 +>p1 : string + +num = isC2(c1Orc2) && c1Orc2.p2; // C2 +>num = isC2(c1Orc2) && c1Orc2.p2 : number +>num : number +>isC2(c1Orc2) && c1Orc2.p2 : number +>isC2(c1Orc2) : boolean +>isC2 : (x: any) => boolean +>c1Orc2 : C1 | C2 +>c1Orc2.p2 : number +>c1Orc2 : C2 +>p2 : number + +str = isD1(c1Orc2) && c1Orc2.p1; // D1 +>str = isD1(c1Orc2) && c1Orc2.p1 : string +>str : string +>isD1(c1Orc2) && c1Orc2.p1 : string +>isD1(c1Orc2) : boolean +>isD1 : (x: any) => boolean +>c1Orc2 : C1 | C2 +>c1Orc2.p1 : string +>c1Orc2 : D1 +>p1 : string + +num = isD1(c1Orc2) && c1Orc2.p3; // D1 +>num = isD1(c1Orc2) && c1Orc2.p3 : number +>num : number +>isD1(c1Orc2) && c1Orc2.p3 : number +>isD1(c1Orc2) : boolean +>isD1 : (x: any) => boolean +>c1Orc2 : C1 | C2 +>c1Orc2.p3 : number +>c1Orc2 : D1 +>p3 : number + +var c2Ord1: C2 | D1; +>c2Ord1 : C2 | D1 +>C2 : C2 +>D1 : D1 + +num = isC2(c2Ord1) && c2Ord1.p2; // C2 +>num = isC2(c2Ord1) && c2Ord1.p2 : number +>num : number +>isC2(c2Ord1) && c2Ord1.p2 : number +>isC2(c2Ord1) : boolean +>isC2 : (x: any) => boolean +>c2Ord1 : C2 | D1 +>c2Ord1.p2 : number +>c2Ord1 : C2 +>p2 : number + +num = isD1(c2Ord1) && c2Ord1.p3; // D1 +>num = isD1(c2Ord1) && c2Ord1.p3 : number +>num : number +>isD1(c2Ord1) && c2Ord1.p3 : number +>isD1(c2Ord1) : boolean +>isD1 : (x: any) => boolean +>c2Ord1 : C2 | D1 +>c2Ord1.p3 : number +>c2Ord1 : D1 +>p3 : number + +str = isD1(c2Ord1) && c2Ord1.p1; // D1 +>str = isD1(c2Ord1) && c2Ord1.p1 : string +>str : string +>isD1(c2Ord1) && c2Ord1.p1 : string +>isD1(c2Ord1) : boolean +>isD1 : (x: any) => boolean +>c2Ord1 : C2 | D1 +>c2Ord1.p1 : string +>c2Ord1 : D1 +>p1 : string + +var r2: C2 | D1 = isC1(c2Ord1) && c2Ord1; // C2 | D1 +>r2 : C2 | D1 +>C2 : C2 +>D1 : D1 +>isC1(c2Ord1) && c2Ord1 : D1 +>isC1(c2Ord1) : boolean +>isC1 : (x: any) => boolean +>c2Ord1 : C2 | D1 +>c2Ord1 : D1 + diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardFunction.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardFunction.ts new file mode 100644 index 00000000000..93cfd90ceb5 --- /dev/null +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardFunction.ts @@ -0,0 +1,56 @@ + +class A { + propA: number; +} + +class B { + propB: number; +} + +class C extends A { + propC: number; +} + +declare function isA(p1: any): p1 is A; +declare function isB(p1: any): p1 is B; +declare function isC(p1: any): p1 is C; + +declare function retC(): C; + +var a: A; +var b: B; + +// Basic. +if (isC(a)) { + a.propC; +} + +// Sub type. +var subType: C; +if(isA(subType)) { + subType.propC; +} + +// Union type. +var union: A | B; +if(isA(union)) { + union.propA; +} + +// The parameter index and argument index for the type guard target is matching. +// The type predicate type is assignable to the parameter type. +declare function isC_multipleParams(p1, p2): p1 is C; +if (isC_multipleParams(a, 0)) { + a.propC; +} + +// Evaluations are asssignable to boolean. +declare function acceptingBoolean(a: boolean); +acceptingBoolean(isA(a)); + +// Type predicates with different parameter name. +declare function acceptingTypeGuardFunction(p1: (item) => item is A); +acceptingTypeGuardFunction(isA); + +let union2: C | B; +let union3: boolean | B = isA(union2) || union2; \ No newline at end of file diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts new file mode 100644 index 00000000000..28a512aca6d --- /dev/null +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts @@ -0,0 +1,92 @@ + +class A { + propA: number; +} + +class B { + propB: number; +} + +class C extends A { + propC: number; +} + +function hasANonBooleanReturnStatement(x): x is A { + return ''; +} + +function hasTypeGuardTypeInsideTypeGuardType(x): x is x is A { + return true; +} + +function hasMissingIsKeyword(): x { + return true; +} + +function hasMissingTypeInTypeGuardType(x): x is { + return true; +} + +function hasNonMatchingParameter(y): x is A { + return true; +} + +function hasNonMatchingParameterType1(x: A): x is B { + return true; +} + +function hasNonMatchingParameterType2(x: string): x is number { + return true; +} + +function hasNonMathcingGenericType(a: string): a is T[] { + return true; +} + +let a: A; +let b: B; + +declare function isB(p1): p1 is B; +declare function isC(p1): p1 is C; +declare function funA(p1: any, p2: any): p1 is B; +declare function hasNoTypeGuard(x); + +// Passed argument is not the same as the one being guarded. +if (isB(b)) { + a.propB; +} + +// Parameter index and argument index for the type guard target is not matching. +if (funA(0, a)) { + a.propB; // Error +} + +// No type guard in if statement +if (hasNoTypeGuard(a)) { + a.propB; +} + +// Type predicate type is not assignable +declare function acceptingDifferentSignatureTypeGuardFunction(p1: (p1) => p1 is B); +acceptingDifferentSignatureTypeGuardFunction(isC); + +// Boolean not assignable to type guard +var assign1: (p1, p2) => p1 is A; +assign1 = function(p1, p2): boolean { + return true; +}; + +// Must have matching parameter index +var assign2: (p1, p2) => p1 is A; +assign2 = function(p1, p2): p2 is A { + return true; +}; + +// No matching signature +var assign3: (p1, p2) => p1 is A; +assign3 = function(p1, p2, p3): p1 is A { + return true; +}; + +// Type guard paramater referring to a binding pattern +declare function destructureParameter({ p1, p2, p3 }): p1 is A; diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionGenerics.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionGenerics.ts new file mode 100644 index 00000000000..d0e108b5735 --- /dev/null +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionGenerics.ts @@ -0,0 +1,33 @@ + +class A { + propA: number; +} + +class B { + propB: number; +} + +class C extends A { + propC: number; +} + +declare function isB(p1): p1 is B; +declare function isC(p1): p1 is C; +declare function retC(x): C; + +declare function funA(p1: (p1) => T): T; +declare function funB(p1: (p1) => T, p2: any): p2 is T; +declare function funC(p1: (p1) => p1 is T): T; +declare function funD(p1: (p1) => p1 is T, p2: any): p2 is T; +declare function funE(p1: (p1) => p1 is T, p2: U): T; + +let a: A; +let test1: boolean = funA(isB); +if (funB(retC, a)) { + a.propC; +} +let test2: B = funC(isB); +if (funD(isC, a)) { + a.propC; +} +let test3: B = funE(isB, 1); \ No newline at end of file diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormIsType.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormIsType.ts new file mode 100644 index 00000000000..9f5ca611ee9 --- /dev/null +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormIsType.ts @@ -0,0 +1,37 @@ + +class C1 { + p1: string; +} +class C2 { + p2: number; +} +class D1 extends C1 { + p3: number; +} +var str: string; +var num: number; +var strOrNum: string | number; + +function isC1(x: any): x is C1 { + return true; +} + +function isC2(x: any): x is C2 { + return true; +} + +function isD1(x: any): x is D1 { + return true; +} + +var c1Orc2: C1 | C2; +str = isC1(c1Orc2) && c1Orc2.p1; // C1 +num = isC2(c1Orc2) && c1Orc2.p2; // C2 +str = isD1(c1Orc2) && c1Orc2.p1; // D1 +num = isD1(c1Orc2) && c1Orc2.p3; // D1 + +var c2Ord1: C2 | D1; +num = isC2(c2Ord1) && c2Ord1.p2; // C2 +num = isD1(c2Ord1) && c2Ord1.p3; // D1 +str = isD1(c2Ord1) && c2Ord1.p1; // D1 +var r2: C2 | D1 = isC1(c2Ord1) && c2Ord1; // C2 | D1 \ No newline at end of file diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormIsTypeOnInterfaces.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormIsTypeOnInterfaces.ts new file mode 100644 index 00000000000..a199aeb1e68 --- /dev/null +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormIsTypeOnInterfaces.ts @@ -0,0 +1,46 @@ + +interface C1 { + (): C1; + prototype: C1; + p1: string; +} +interface C2 { + (): C2; + prototype: C2; + p2: number; +} +interface D1 extends C1 { + prototype: D1; + p3: number; +} +var str: string; +var num: number; +var strOrNum: string | number; + + +function isC1(x: any): x is C1 { + return true; +} + +function isC2(x: any): x is C2 { + return true; +} + +function isD1(x: any): x is D1 { + return true; +} + +var c1: C1; +var c2: C2; +var d1: D1; +var c1Orc2: C1 | C2; +str = isC1(c1Orc2) && c1Orc2.p1; // C1 +num = isC2(c1Orc2) && c1Orc2.p2; // C2 +str = isD1(c1Orc2) && c1Orc2.p1; // D1 +num = isD1(c1Orc2) && c1Orc2.p3; // D1 + +var c2Ord1: C2 | D1; +num = isC2(c2Ord1) && c2Ord1.p2; // C2 +num = isD1(c2Ord1) && c2Ord1.p3; // D1 +str = isD1(c2Ord1) && c2Ord1.p1; // D1 +var r2: C2 | D1 = isC1(c2Ord1) && c2Ord1; // C2 | D1 \ No newline at end of file From b7d1df68fb21703e529a2600bf42ad0ce3f6b9be Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Tue, 2 Jun 2015 23:25:21 +0800 Subject: [PATCH 025/107] Adds type guard methods --- src/compiler/checker.ts | 48 ++++-- .../diagnosticInformationMap.generated.ts | 1 + src/compiler/diagnosticMessages.json | 4 + src/compiler/parser.ts | 42 ++++-- .../reference/typeGuardMethods.errors.txt | 73 +++++++++ tests/baselines/reference/typeGuardMethods.js | 141 ++++++++++++++++++ .../typeGuards/typeGuardMethods.ts | 64 ++++++++ 7 files changed, 350 insertions(+), 23 deletions(-) create mode 100644 tests/baselines/reference/typeGuardMethods.errors.txt create mode 100644 tests/baselines/reference/typeGuardMethods.js create mode 100644 tests/cases/conformance/expressions/typeGuards/typeGuardMethods.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a09a2736aac..5a33748fb0b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5646,6 +5646,24 @@ module ts { return type; } + function shouldNarrowTypeByTypePredicate(signature: Signature, expr: CallExpression): boolean { + if (!signature.typePredicate) { + return false; + } + if (expr.arguments && + expr.arguments[signature.typePredicate.parameterIndex] && + getSymbolAtLocation(expr.arguments[signature.typePredicate.parameterIndex]) === symbol) { + + return true; + } + if (expr.expression.kind === SyntaxKind.PropertyAccessExpression && + getSymbolAtLocation((expr.expression).expression) === symbol) { + + return true; + } + return false; + } + function narrowTypeByTypePredicate(type: Type, expr: CallExpression, assumeTrue: boolean): Type { if (type.flags & TypeFlags.Any) { return type; @@ -5657,16 +5675,12 @@ module ts { } return type; } - if (signature.typePredicate) { - if (expr.arguments && expr.arguments[signature.typePredicate.parameterIndex]) { - if (getSymbolAtLocation(expr.arguments[signature.typePredicate.parameterIndex]) === symbol) { - if (isTypeSubtypeOf(signature.typePredicate.type, type)) { - return signature.typePredicate.type; - } - if (type.flags & TypeFlags.Union) { - return getUnionType(filter((type).types, t => isTypeSubtypeOf(t, signature.typePredicate.type))); - } - } + if (shouldNarrowTypeByTypePredicate(signature, expr)) { + if (isTypeSubtypeOf(signature.typePredicate.type, type)) { + return signature.typePredicate.type; + } + if (type.flags & TypeFlags.Union) { + return getUnionType(filter((type).types, t => isTypeSubtypeOf(t, signature.typePredicate.type))); } } return type; @@ -8622,8 +8636,7 @@ module ts { links.typeFromTypePredicate = getTypeFromTypeNode(node.typePredicate.type); } if (links.typePredicateParameterIndex >= 0) { - checkTypeAssignableTo( - links.typeFromTypePredicate, + checkTypeAssignableTo(links.typeFromTypePredicate, getTypeAtLocation(node.parameters[links.typePredicateParameterIndex]), node.typePredicate.type); } @@ -8632,6 +8645,17 @@ module ts { Diagnostics.Cannot_find_parameter_0, node.typePredicate.parameterName.text); } + else { + let typeOfClass = getTypeAtLocation(node.parent); + if (!isTypeSubtypeOf(links.typeFromTypePredicate, typeOfClass) && + !isTypeSubtypeOf(typeOfClass, links.typeFromTypePredicate)) { + + error(node.typePredicate, + Diagnostics.Type_0_and_type_1_are_disjoint_types, + typeToString(links.typeFromTypePredicate), + typeToString(typeOfClass)); + } + } } if (produceDiagnostics) { diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 5a87f67ddd3..aba138b9a1b 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -184,6 +184,7 @@ module ts { Cannot_find_parameter_0: { code: 1226, category: DiagnosticCategory.Error, key: "Cannot find parameter '{0}'." }, Type_guard_annotation_0_is_not_assignable_to_1: { code: 1227, category: DiagnosticCategory.Error, key: "Type-guard annotation '{0}' is not assignable to '{1}'." }, Parameter_index_from_0_does_not_match_the_parameter_index_from_1: { code: 1228, category: DiagnosticCategory.Error, key: "Parameter index from '{0}' does not match the parameter index from '{1}'." }, + Type_0_and_type_1_are_disjoint_types: { code: 1229, category: DiagnosticCategory.Error, key: "Type '{0}' and type '{1}' are disjoint types." }, Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." }, Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." }, Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 0053b071438..a94839fba7d 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -723,6 +723,10 @@ "category": "Error", "code": 1228 }, + "Type '{0}' and type '{1}' are disjoint types.": { + "category": "Error", + "code": 1229 + }, "Duplicate identifier '{0}'.": { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index ac4517a0b79..0f84ec20383 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2014,6 +2014,34 @@ module ts { return parseInitializer(/*inParameter*/ true); } + function parseTypePredicate(signature: SignatureDeclaration) { + let node = createNode(SyntaxKind.TypePredicate); + if (token !== SyntaxKind.ThisKeyword) { + node.pos = signature.type.pos; + node.parameterName = (signature.type).typeName; + signature.type = undefined; + } + else { + // Swallow `this` + nextToken(); + } + + // Swallow `is` + nextToken(); + + node.type = parseType(); + signature.typePredicate = finishNode(node); + } + + function parseTypePredicateOrReturnType(signature: SignatureDeclaration) { + if (token === SyntaxKind.ThisKeyword) { + parseTypePredicate(signature); + } + else { + signature.type = parseType(); + } + } + function fillSignature( returnToken: SyntaxKind, yieldAndGeneratorParameterContext: boolean, @@ -2025,21 +2053,13 @@ module ts { if (returnTokenRequired) { parseExpected(returnToken); - signature.type = parseType(); + parseTypePredicateOrReturnType(signature); } else if (parseOptional(returnToken)) { - signature.type = parseType(); + parseTypePredicateOrReturnType(signature); } if (token === SyntaxKind.IsKeyword) { - let node = createNode(SyntaxKind.TypePredicate); - node.pos = signature.type.pos; - node.parameterName = (signature.type).typeName; - - nextToken(); - - node.type = parseType(); - signature.type = undefined; - signature.typePredicate = finishNode(node); + parseTypePredicate(signature); } } diff --git a/tests/baselines/reference/typeGuardMethods.errors.txt b/tests/baselines/reference/typeGuardMethods.errors.txt new file mode 100644 index 00000000000..246f84ccc09 --- /dev/null +++ b/tests/baselines/reference/typeGuardMethods.errors.txt @@ -0,0 +1,73 @@ +tests/cases/conformance/expressions/typeGuards/typeGuardMethods.ts(14,12): error TS1229: Type 'A' and type 'B' are disjoint types. +tests/cases/conformance/expressions/typeGuards/typeGuardMethods.ts(17,12): error TS1229: Type 'C' and type 'B' are disjoint types. + + +==== tests/cases/conformance/expressions/typeGuards/typeGuardMethods.ts (2 errors) ==== + + class A { + propA: number; + isA(): this is A { + return true; + } + isC(): this is C { + return false; + } + } + + class B { + propB: number; + isA(): this is A { + ~~~~~~~~~ +!!! error TS1229: Type 'A' and type 'B' are disjoint types. + return false; + } + isC(): this is C { + ~~~~~~~~~ +!!! error TS1229: Type 'C' and type 'B' are disjoint types. + return false; + } + } + + class C extends A { + propC: number; + isA(): this is A { + return false; + } + isC(): this is C { + return true; + } + } + + class D extends C { + isA(): this is A { + return false; + } + isString(x: any): x is string { // with parameter declaration + return true; + } + } + + var a: A; + + // Basic. + if (a.isC()) { + a.propC; + } + + // Sub type. + var subType: C; + if(subType.isA()) { + subType.propC; + } + + // Union type. + var union: A | B; + if(union.isA()) { + union.propA; + } + + var b: any; + var d = new D; + if(d.isString(b)) { + b.length; + } \ No newline at end of file diff --git a/tests/baselines/reference/typeGuardMethods.js b/tests/baselines/reference/typeGuardMethods.js new file mode 100644 index 00000000000..dcc7eca43c9 --- /dev/null +++ b/tests/baselines/reference/typeGuardMethods.js @@ -0,0 +1,141 @@ +//// [typeGuardMethods.ts] + +class A { + propA: number; + isA(): this is A { + return true; + } + isC(): this is C { + return false; + } +} + +class B { + propB: number; + isA(): this is A { + return false; + } + isC(): this is C { + return false; + } +} + +class C extends A { + propC: number; + isA(): this is A { + return false; + } + isC(): this is C { + return true; + } +} + +class D extends C { + isA(): this is A { + return false; + } + isString(x: any): x is string { // with parameter declaration + return true; + } +} + +var a: A; + +// Basic. +if (a.isC()) { + a.propC; +} + +// Sub type. +var subType: C; +if(subType.isA()) { + subType.propC; +} + +// Union type. +var union: A | B; +if(union.isA()) { + union.propA; +} + +var b: any; +var d = new D; +if(d.isString(b)) { + b.length; +} + +//// [typeGuardMethods.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; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var A = (function () { + function A() { + } + A.prototype.isA = function () { + return true; + }; + A.prototype.isC = function () { + return false; + }; + return A; +})(); +var B = (function () { + function B() { + } + B.prototype.isA = function () { + return false; + }; + B.prototype.isC = function () { + return false; + }; + return B; +})(); +var C = (function (_super) { + __extends(C, _super); + function C() { + _super.apply(this, arguments); + } + C.prototype.isA = function () { + return false; + }; + C.prototype.isC = function () { + return true; + }; + return C; +})(A); +var D = (function (_super) { + __extends(D, _super); + function D() { + _super.apply(this, arguments); + } + D.prototype.isA = function () { + return false; + }; + D.prototype.isString = function (x) { + return true; + }; + return D; +})(C); +var a; +// Basic. +if (a.isC()) { + a.propC; +} +// Sub type. +var subType; +if (subType.isA()) { + subType.propC; +} +// Union type. +var union; +if (union.isA()) { + union.propA; +} +var b; +var d = new D; +if (d.isString(b)) { + b.length; +} diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardMethods.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardMethods.ts new file mode 100644 index 00000000000..80ae65a7ddb --- /dev/null +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardMethods.ts @@ -0,0 +1,64 @@ + +class A { + propA: number; + isA(): this is A { + return true; + } + isC(): this is C { + return false; + } +} + +class B { + propB: number; + isA(): this is A { + return false; + } + isC(): this is C { + return false; + } +} + +class C extends A { + propC: number; + isA(): this is A { + return false; + } + isC(): this is C { + return true; + } +} + +class D extends C { + isA(): this is A { + return false; + } + isString(x: any): x is string { // with parameter declaration + return true; + } +} + +var a: A; + +// Basic. +if (a.isC()) { + a.propC; +} + +// Sub type. +var subType: C; +if(subType.isA()) { + subType.propC; +} + +// Union type. +var union: A | B; +if(union.isA()) { + union.propA; +} + +var b: any; +var d = new D; +if(d.isString(b)) { + b.length; +} \ No newline at end of file From b0542342c38749367530d7b6d400b7824795286c Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Wed, 3 Jun 2015 15:29:06 +0800 Subject: [PATCH 026/107] Addresses PR feedback --- src/compiler/checker.ts | 100 ++++++++++-------- .../diagnosticInformationMap.generated.ts | 4 +- src/compiler/diagnosticMessages.json | 4 +- .../typeGuardFunctionErrors.errors.txt | 16 +-- 4 files changed, 66 insertions(+), 58 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5a33748fb0b..80477ea1841 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3231,7 +3231,10 @@ module ts { let returnType: Type; let typePredicate: TypePredicate; - if (declaration.typePredicate) { + if (classType) { + returnType = classType; + } + else if (declaration.typePredicate) { returnType = booleanType; let typePredicateNode = declaration.typePredicate; let links = getNodeLinks(typePredicateNode); @@ -3242,14 +3245,11 @@ module ts { links.typeFromTypePredicate = getTypeFromTypeNode(declaration.typePredicate.type); } typePredicate = { - parameterName: typePredicateNode.parameterName ? typePredicateNode.parameterName.text : undefined, - parameterIndex: typePredicateNode.parameterName ? links.typePredicateParameterIndex : undefined, - type: links.typeFromTypePredicate + parameterName: typePredicateNode.parameterName ? typePredicateNode.parameterName.text : undefined, + parameterIndex: typePredicateNode.parameterName ? links.typePredicateParameterIndex : undefined, + type: links.typeFromTypePredicate }; } - else if (classType) { - returnType = classType; - } else if (declaration.type) { returnType = getTypeFromTypeNode(declaration.type); } @@ -3976,17 +3976,22 @@ module ts { function instantiateSignature(signature: Signature, mapper: TypeMapper, eraseTypeParameters?: boolean): Signature { let freshTypeParameters: TypeParameter[]; + let freshTypePredicate: TypePredicate; if (signature.typeParameters && !eraseTypeParameters) { freshTypeParameters = instantiateList(signature.typeParameters, mapper, instantiateTypeParameter); mapper = combineTypeMappers(createTypeMapper(signature.typeParameters, freshTypeParameters), mapper); } if (signature.typePredicate) { - signature.typePredicate.type = instantiateType(signature.typePredicate.type, mapper); + freshTypePredicate = { + parameterName: signature.typePredicate.parameterName, + parameterIndex: signature.typePredicate.parameterIndex, + type: instantiateType(signature.typePredicate.type, mapper) + } } let result = createSignature(signature.declaration, freshTypeParameters, instantiateList(signature.parameters, mapper, instantiateSymbol), signature.resolvedReturnType ? instantiateType(signature.resolvedReturnType, mapper) : undefined, - signature.typePredicate, + freshTypePredicate, signature.minArgumentCount, signature.hasRestParameter, signature.hasStringLiterals); result.target = signature; result.mapper = mapper; @@ -4656,33 +4661,33 @@ module ts { } if (source.typePredicate && target.typePredicate) { - if (source.typePredicate.parameterIndex !== target.typePredicate.parameterIndex || - source.typePredicate.type.symbol !== target.typePredicate.type.symbol) { - + let hasDifferentParamaterIndex = source.typePredicate.parameterIndex !== target.typePredicate.parameterIndex; + let hasDifferentTypes = !isTypeIdenticalTo(source.typePredicate.type, target.typePredicate.type); + if (hasDifferentParamaterIndex || hasDifferentTypes) { if (reportErrors) { let sourceParamText = source.typePredicate.parameterName; let targetParamText = target.typePredicate.parameterName; let sourceTypeText = typeToString(source.typePredicate.type); let targetTypeText = typeToString(target.typePredicate.type); - if (source.typePredicate.parameterIndex !== target.typePredicate.parameterIndex) { - reportError(Diagnostics.Parameter_index_from_0_does_not_match_the_parameter_index_from_1, + if (hasDifferentParamaterIndex) { + reportError(Diagnostics.Parameter_0_is_not_in_the_same_position_as_parameter_1, sourceParamText, targetParamText); } - if (source.typePredicate.type.symbol !== target.typePredicate.type.symbol) { + if (hasDifferentTypes) { reportError(Diagnostics.Type_0_is_not_assignable_to_type_1, sourceTypeText, targetTypeText); } - reportError(Diagnostics.Type_guard_annotation_0_is_not_assignable_to_1, + reportError(Diagnostics.Type_predicate_0_is_not_assignable_to_1, `${sourceParamText} is ${sourceTypeText}`, `${targetParamText} is ${targetTypeText}`); } - return Ternary.False; } + return Ternary.True; } else if (!source.typePredicate && target.typePredicate) { if (reportErrors) { @@ -5223,12 +5228,15 @@ module ts { function inferFromSignature(source: Signature, target: Signature) { forEachMatchingParameterType(source, target, inferFromTypes); - if (source.typePredicate && - target.typePredicate && - target.typePredicate.parameterIndex === source.typePredicate.parameterIndex) { - - inferFromTypes(source.typePredicate.type, target.typePredicate.type); - return; + if (source.typePredicate && target.typePredicate) { + if (target.typePredicate.parameterIndex === source.typePredicate.parameterIndex) { + // Return types from type predicates are treated as booleans. In order to infer types + // from type predicates we would need infer from the type from type predicates. Since + // we can't infer any type information from the return types. We can just add a return + // statement after the below infer statement. + inferFromTypes(source.typePredicate.type, target.typePredicate.type); + return; + } } inferFromTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target)); } @@ -5633,19 +5641,24 @@ module ts { } if (targetType) { - // Narrow to the target type if it's a subtype of the current type - if (isTypeSubtypeOf(targetType, type)) { - return targetType; - } - // If the current type is a union type, remove all constituents that aren't subtypes of the target. - if (type.flags & TypeFlags.Union) { - return getUnionType(filter((type).types, t => isTypeSubtypeOf(t, targetType))); - } + return getOptionalNarrowedType(type, targetType); } return type; } + function getOptionalNarrowedType(originalType: Type, narrowedTypeCandidate: Type) { + // Narrow to the target type if it's a subtype of the current type + if (isTypeSubtypeOf(narrowedTypeCandidate, originalType)) { + return narrowedTypeCandidate; + } + // If the current type is a union type, remove all constituents that aren't subtypes of the target. + if (originalType.flags & TypeFlags.Union) { + return getUnionType(filter((originalType).types, t => isTypeSubtypeOf(t, narrowedTypeCandidate))); + } + return originalType; + } + function shouldNarrowTypeByTypePredicate(signature: Signature, expr: CallExpression): boolean { if (!signature.typePredicate) { return false; @@ -5670,18 +5683,16 @@ module ts { } let signature = getResolvedSignature(expr); if (!assumeTrue) { - if (type.flags & TypeFlags.Union && signature.typePredicate) { + if (type.flags & TypeFlags.Union && + signature.typePredicate && + getSymbolAtLocation(expr.arguments[signature.typePredicate.parameterIndex]) === symbol) { + return getUnionType(filter((type).types, t => !isTypeSubtypeOf(t, signature.typePredicate.type))); } return type; } if (shouldNarrowTypeByTypePredicate(signature, expr)) { - if (isTypeSubtypeOf(signature.typePredicate.type, type)) { - return signature.typePredicate.type; - } - if (type.flags & TypeFlags.Union) { - return getUnionType(filter((type).types, t => isTypeSubtypeOf(t, signature.typePredicate.type))); - } + return getOptionalNarrowedType(type, signature.typePredicate.type); } return type; } @@ -8640,7 +8651,7 @@ module ts { getTypeAtLocation(node.parameters[links.typePredicateParameterIndex]), node.typePredicate.type); } - else if(node.typePredicate.parameterName) { + else if (node.typePredicate.parameterName) { error(node.typePredicate.parameterName, Diagnostics.Cannot_find_parameter_0, node.typePredicate.parameterName.text); @@ -10217,6 +10228,9 @@ module ts { if (node.expression) { let func = getContainingFunction(node); if (func) { + let signature = getSignatureFromDeclaration(func); + let exprType = checkExpressionCached(node.expression); + if (func.asteriskToken) { // A generator does not need its return expressions checked against its return type. // Instead, the yield expressions are checked against the element type. @@ -10225,13 +10239,7 @@ module ts { return; } - let signature = getSignatureFromDeclaration(func); - let exprType = checkExpressionCached(node.expression); - if (signature.typePredicate && exprType !== booleanType) { - error(node.expression, Diagnostics.A_type_guard_function_can_only_return_a_boolean); - } let returnType = getReturnTypeOfSignature(signature); - if (func.kind === SyntaxKind.SetAccessor) { error(node.expression, Diagnostics.Setters_cannot_return_a_value); } @@ -10240,7 +10248,7 @@ module ts { error(node.expression, Diagnostics.Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class); } } - else if (func.type || isGetAccessorWithAnnotatatedSetAccessor(func)) { + else if (func.type || isGetAccessorWithAnnotatatedSetAccessor(func) || signature.typePredicate) { checkTypeAssignableTo(exprType, returnType, node.expression, /*headMessage*/ undefined); } } diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index aba138b9a1b..46c1cd37b3f 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -182,8 +182,8 @@ module ts { A_non_type_guard_function_is_not_assignable_to_a_type_guard_function: { code: 1224, category: DiagnosticCategory.Error, key: "A non-type guard function is not assignable to a type guard function." }, A_type_guard_function_can_only_return_a_boolean: { code: 1225, category: DiagnosticCategory.Error, key: "A type-guard function can only return a boolean." }, Cannot_find_parameter_0: { code: 1226, category: DiagnosticCategory.Error, key: "Cannot find parameter '{0}'." }, - Type_guard_annotation_0_is_not_assignable_to_1: { code: 1227, category: DiagnosticCategory.Error, key: "Type-guard annotation '{0}' is not assignable to '{1}'." }, - Parameter_index_from_0_does_not_match_the_parameter_index_from_1: { code: 1228, category: DiagnosticCategory.Error, key: "Parameter index from '{0}' does not match the parameter index from '{1}'." }, + Type_predicate_0_is_not_assignable_to_1: { code: 1227, category: DiagnosticCategory.Error, key: "Type predicate '{0}' is not assignable to '{1}'." }, + Parameter_0_is_not_in_the_same_position_as_parameter_1: { code: 1228, category: DiagnosticCategory.Error, key: "Parameter '{0}' is not in the same position as parameter '{1}'." }, Type_0_and_type_1_are_disjoint_types: { code: 1229, category: DiagnosticCategory.Error, key: "Type '{0}' and type '{1}' are disjoint types." }, Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." }, Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index a94839fba7d..ebcba6386ff 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -715,11 +715,11 @@ "category": "Error", "code": 1226 }, - "Type-guard annotation '{0}' is not assignable to '{1}'.": { + "Type predicate '{0}' is not assignable to '{1}'.": { "category": "Error", "code": 1227 }, - "Parameter index from '{0}' does not match the parameter index from '{1}'.": { + "Parameter '{0}' is not in the same position as parameter '{1}'.": { "category": "Error", "code": 1228 }, diff --git a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt index 8b5ed551dff..001fe8a14ae 100644 --- a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt +++ b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(15,12): error TS1225: A type-guard function can only return a boolean. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(15,12): error TS2322: Type 'string' is not assignable to type 'boolean'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,55): error TS2304: Cannot find name 'x'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,57): error TS1144: '{' or ';' expected. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,57): error TS2304: Cannot find name 'is'. @@ -17,13 +17,13 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(56,7): tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(61,7): error TS2339: Property 'propB' does not exist on type 'A'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(66,7): error TS2339: Property 'propB' does not exist on type 'A'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(71,46): error TS2345: Argument of type '(p1: any) => boolean' is not assignable to parameter of type '(p1: any) => boolean'. - Type-guard annotation 'p1 is C' is not assignable to 'p1 is B'. + Type predicate 'p1 is C' is not assignable to 'p1 is B'. Type 'C' is not assignable to type 'B'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(75,1): error TS2322: Type '(p1: any, p2: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. A non-type guard function is not assignable to a type guard function. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(81,1): error TS2322: Type '(p1: any, p2: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. - Type-guard annotation 'p2 is A' is not assignable to 'p1 is A'. - Parameter index from 'p2' does not match the parameter index from 'p1'. + Type predicate 'p2 is A' is not assignable to 'p1 is A'. + Parameter 'p2' is not in the same position as parameter 'p1'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(87,1): error TS2322: Type '(p1: any, p2: any, p3: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,56): error TS1226: Cannot find parameter 'p1'. @@ -45,7 +45,7 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,56) function hasANonBooleanReturnStatement(x): x is A { return ''; ~~ -!!! error TS1225: A type-guard function can only return a boolean. +!!! error TS2322: Type 'string' is not assignable to type 'boolean'. } function hasTypeGuardTypeInsideTypeGuardType(x): x is x is A { @@ -137,7 +137,7 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,56) acceptingDifferentSignatureTypeGuardFunction(isC); ~~~ !!! error TS2345: Argument of type '(p1: any) => boolean' is not assignable to parameter of type '(p1: any) => boolean'. -!!! error TS2345: Type-guard annotation 'p1 is C' is not assignable to 'p1 is B'. +!!! error TS2345: Type predicate 'p1 is C' is not assignable to 'p1 is B'. !!! error TS2345: Type 'C' is not assignable to type 'B'. // Boolean not assignable to type guard @@ -154,8 +154,8 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,56) assign2 = function(p1, p2): p2 is A { ~~~~~~~ !!! error TS2322: Type '(p1: any, p2: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. -!!! error TS2322: Type-guard annotation 'p2 is A' is not assignable to 'p1 is A'. -!!! error TS2322: Parameter index from 'p2' does not match the parameter index from 'p1'. +!!! error TS2322: Type predicate 'p2 is A' is not assignable to 'p1 is A'. +!!! error TS2322: Parameter 'p2' is not in the same position as parameter 'p1'. return true; }; From 3aa0839d1ba9a510dccd8ea7cf65501aae18dd43 Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Wed, 3 Jun 2015 17:11:11 +0800 Subject: [PATCH 027/107] Fixes rebase issues --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 80477ea1841..c75ba19df2f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3267,7 +3267,7 @@ module ts { } links.resolvedSignature = createSignature(declaration, typeParameters, parameters, returnType, typePredicate, - minArgumentCount, hasRestParameters(declaration), hasStringLiterals); + minArgumentCount, hasRestParameter(declaration), hasStringLiterals); } return links.resolvedSignature; } From 1e39130f41a702e3f8ff53d939c87115bb53c5d8 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 3 Jun 2015 06:57:20 -0700 Subject: [PATCH 028/107] Unified logic for renamed block scoped locals and other generated names --- src/compiler/checker.ts | 47 ++++++++-- src/compiler/emitter.ts | 195 ++++++++++++++-------------------------- src/compiler/types.ts | 6 +- 3 files changed, 112 insertions(+), 136 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6257031afbd..78dbe9077c6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11821,6 +11821,38 @@ module ts { } } + function isStatementWithLocals(node: Node) { + switch (node.kind) { + case SyntaxKind.Block: + case SyntaxKind.CaseBlock: + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + return true; + } + return false; + } + + function getIsNestedRedeclaration(symbol: Symbol): boolean { + let links = getSymbolLinks(symbol); + if (links.isNestedRedeclaration === undefined) { + let container = getEnclosingBlockScopeContainer(symbol.valueDeclaration); + links.isNestedRedeclaration = isStatementWithLocals(container) && + !!resolveName(container.parent, symbol.name, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined); + } + return links.isNestedRedeclaration; + } + + function getReferencedNestedRedeclaration(node: Identifier): Declaration { + let symbol = getReferencedValueSymbol(node); + return symbol && symbol.flags & SymbolFlags.BlockScoped && getIsNestedRedeclaration(symbol) ? symbol.valueDeclaration : undefined; + } + + function isNestedRedeclaration(node: Declaration): boolean { + let symbol = getSymbolOfNode(node); + return symbol.flags & SymbolFlags.BlockScoped && getIsNestedRedeclaration(symbol); + } + function isValueAliasDeclaration(node: Node): boolean { switch (node.kind) { case SyntaxKind.ImportEqualsDeclaration: @@ -11924,8 +11956,10 @@ module ts { /** Serializes an EntityName (with substitutions) to an appropriate JS constructor value. Used by the __metadata decorator. */ function serializeEntityName(node: EntityName, getGeneratedNameForNode: (Node: Node) => string, fallbackPath?: string[]): string { if (node.kind === SyntaxKind.Identifier) { - var substitution = getExpressionNameSubstitution(node, getGeneratedNameForNode); - var text = substitution || (node).text; + // TODO(andersh): Fix this + // var substitution = getExpressionNameSubstitution(node, getGeneratedNameForNode); + // var text = substitution || (node).text; + var text = (node).text; if (fallbackPath) { fallbackPath.push(text); } @@ -12140,11 +12174,6 @@ module ts { return hasProperty(globals, name); } - function resolvesToSomeValue(location: Node, name: string): boolean { - Debug.assert(!nodeIsSynthesized(location), "resolvesToSomeValue called with a synthesized location"); - return !!resolveName(location, name, SymbolFlags.Value, /*nodeNotFoundMessage*/ undefined, /*nameArg*/ undefined); - } - function getReferencedValueSymbol(reference: Identifier): Symbol { return getNodeLinks(reference).resolvedSymbol || resolveName(reference, reference.text, SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias, @@ -12198,9 +12227,10 @@ module ts { function createResolver(): EmitResolver { return { - getExpressionNameSubstitution, getReferencedExportContainer, getReferencedImportDeclaration, + getReferencedNestedRedeclaration, + isNestedRedeclaration, isValueAliasDeclaration, hasGlobalName, isReferencedAliasDeclaration, @@ -12214,7 +12244,6 @@ module ts { isSymbolAccessible, isEntityNameVisible, getConstantValue, - resolvesToSomeValue, collectLinkedAliases, getBlockScopedVariableId, getReferencedValueDeclaration, diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 2414c88a7a9..96dec48d82c 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -125,7 +125,6 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { let generatedNameSet: Map = {}; let nodeToGeneratedName: string[] = []; - let blockScopedVariableToGeneratedName: string[]; let computedPropertyNamesToGeneratedNames: string[]; let extendsEmitted = false; @@ -268,6 +267,8 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { function generateNameForNode(node: Node) { switch (node.kind) { + case SyntaxKind.Identifier: + return makeUniqueName((node).text); case SyntaxKind.ModuleDeclaration: case SyntaxKind.EnumDeclaration: return generateNameForModuleOrEnum(node); @@ -648,19 +649,19 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { sourceMapDir = getDirectoryPath(normalizePath(jsFilePath)); } - function emitNodeWithSourceMap(node: Node, allowGeneratedIdentifiers?: boolean) { + function emitNodeWithSourceMap(node: Node) { if (node) { if (nodeIsSynthesized(node)) { - return emitNodeWithoutSourceMap(node, /*allowGeneratedIdentifiers*/ false); + return emitNodeWithoutSourceMap(node); } if (node.kind != SyntaxKind.SourceFile) { recordEmitNodeStartSpan(node); - emitNodeWithoutSourceMap(node, allowGeneratedIdentifiers); + emitNodeWithoutSourceMap(node); recordEmitNodeEndSpan(node); } else { recordNewSourceFileStart(node); - emitNodeWithoutSourceMap(node, /*allowGeneratedIdentifiers*/ false); + emitNodeWithoutSourceMap(node); } } } @@ -1187,6 +1188,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { case SyntaxKind.PostfixUnaryExpression: case SyntaxKind.PrefixUnaryExpression: case SyntaxKind.ReturnStatement: + case SyntaxKind.ShorthandPropertyAssignment: case SyntaxKind.SpreadElementExpression: case SyntaxKind.SwitchStatement: case SyntaxKind.TaggedTemplateExpression: @@ -1235,52 +1237,54 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { } } else if (languageVersion < ScriptTarget.ES6) { - let declaration = resolver.getReferencedImportDeclaration(node); - if (declaration) { - if (declaration.kind === SyntaxKind.ImportClause) { + let alias = resolver.getReferencedImportDeclaration(node); + if (alias) { + if (alias.kind === SyntaxKind.ImportClause) { // Identifier references default import - write(getGeneratedNameForNode(declaration.parent)); + write(getGeneratedNameForNode(alias.parent)); write(languageVersion === ScriptTarget.ES3 ? '["default"]' : ".default"); } else { // Identifier references named import - write(getGeneratedNameForNode(declaration.parent.parent.parent)); + write(getGeneratedNameForNode(alias.parent.parent.parent)); write("."); - writeTextOfNode(currentSourceFile, (declaration).propertyName || (declaration).name); + writeTextOfNode(currentSourceFile, (alias).propertyName || (alias).name); } return; } + let local = resolver.getReferencedNestedRedeclaration(node); + if (local) { + write(getGeneratedNameForNode(local.name)); + return; + } } writeTextOfNode(currentSourceFile, node); } - function getGeneratedNameForIdentifier(node: Identifier): string { - if (nodeIsSynthesized(node) || !blockScopedVariableToGeneratedName) { - return undefined; - } - - var variableId = resolver.getBlockScopedVariableId(node) - if (variableId === undefined) { - return undefined; - } - - return blockScopedVariableToGeneratedName[variableId]; - } - - function emitIdentifier(node: Identifier, allowGeneratedIdentifiers: boolean) { - if (allowGeneratedIdentifiers) { - let generatedName = getGeneratedNameForIdentifier(node); - if (generatedName) { - write(generatedName); - return; + function isNameOfNestedRedeclaration(node: Identifier) { + if (languageVersion < ScriptTarget.ES6) { + let parent = node.parent; + switch (parent.kind) { + case SyntaxKind.BindingElement: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.VariableDeclaration: + return (parent).name === node && resolver.isNestedRedeclaration(parent); } } + return false; + } + + function emitIdentifier(node: Identifier) { if (!node.parent) { write(node.text); } else if (isExpressionIdentifier(node)) { emitExpressionIdentifier(node); } + else if (isNameOfNestedRedeclaration(node)) { + write(getGeneratedNameForNode(node)); + } else { writeTextOfNode(currentSourceFile, node); } @@ -1326,7 +1330,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { function emitBindingElement(node: BindingElement) { if (node.propertyName) { - emit(node.propertyName, /*allowGeneratedIdentifiers*/ false); + emit(node.propertyName); write(": "); } if (node.dotDotDotToken) { @@ -1679,7 +1683,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { write("*"); } - emit(node.name, /*allowGeneratedIdentifiers*/ false); + emit(node.name); if (languageVersion < ScriptTarget.ES6) { write(": function "); } @@ -1687,43 +1691,34 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { } function emitPropertyAssignment(node: PropertyDeclaration) { - emit(node.name, /*allowGeneratedIdentifiers*/ false); + emit(node.name); write(": "); emit(node.initializer); } + // Return true if identifier resolves to an exported member of a namespace + function isNamespaceExportReference(node: Identifier) { + let container = resolver.getReferencedExportContainer(node); + return container && container.kind !== SyntaxKind.SourceFile; + } + function emitShorthandPropertyAssignment(node: ShorthandPropertyAssignment) { - emit(node.name, /*allowGeneratedIdentifiers*/ false); - // If short-hand property has a prefix, then regardless of the target version, we will emit it as normal property assignment. For example: - // module m { - // export let y; - // } - // module m { - // export let obj = { y }; - // } - // The short-hand property in obj need to emit as such ... = { y : m.y } regardless of the TargetScript version - if (languageVersion < ScriptTarget.ES6) { + // The name property of a short-hand property assignment is considered an expression position, so here + // we manually emit the identifier to avoid rewriting. + writeTextOfNode(currentSourceFile, node.name); + // If emitting pre-ES6 code, or if the name requires rewriting when resolved as an expression identifier, + // we emit a normal property assignment. For example: + // module m { + // export let y; + // } + // module m { + // let obj = { y }; + // } + // Here we need to emit obj = { y : m.y } regardless of the output target. + if (languageVersion < ScriptTarget.ES6 || isNamespaceExportReference(node.name)) { // Emit identifier as an identifier write(": "); - var generatedName = getGeneratedNameForIdentifier(node.name); - if (generatedName) { - write(generatedName); - } - else { - // Even though this is stored as identifier treat it as an expression - // Short-hand, { x }, is equivalent of normal form { x: x } - emitExpressionIdentifier(node.name); - } - } - else { - let container = resolver.getReferencedExportContainer(node.name); - if (container && container.kind !== SyntaxKind.SourceFile) { - // Emit identifier as an identifier - write(": "); - // Even though this is stored as identifier treat it as an expression - // Short-hand, { x }, is equivalent of normal form { x: x } - emitExpressionIdentifier(node.name); - } + emit(node.name); } } @@ -1776,7 +1771,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { let indentedBeforeDot = indentIfOnDifferentLines(node, node.expression, node.dotToken); write("."); let indentedAfterDot = indentIfOnDifferentLines(node, node.dotToken, node.name); - emit(node.name, /*allowGeneratedIdentifiers*/ false); + emit(node.name); decreaseIndentIf(indentedBeforeDot, indentedAfterDot); } @@ -2778,8 +2773,6 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { write(", "); } - renameNonTopLevelLetAndConst(name); - const isVariableDeclarationOrBindingElement = name.parent && (name.parent.kind === SyntaxKind.VariableDeclaration || name.parent.kind === SyntaxKind.BindingElement); @@ -2847,11 +2840,12 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { } function createPropertyAccessForDestructuringProperty(object: Expression, propName: Identifier | LiteralExpression): Expression { - if (propName.kind !== SyntaxKind.Identifier) { - return createElementAccessExpression(object, propName); + let syntheticName = createSynthesizedNode(propName.kind); + syntheticName.text = propName.text; + if (syntheticName.kind !== SyntaxKind.Identifier) { + return createElementAccessExpression(object, syntheticName); } - - return createPropertyAccessExpression(object, propName); + return createPropertyAccessExpression(object, syntheticName); } function createSliceCall(value: Expression, sliceIndex: number): CallExpression { @@ -2873,8 +2867,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { } for (let p of properties) { if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) { - // TODO(andersh): Computed property support - let propName = ((p).name); + let propName = (p).name; emitDestructuringAssignment((p).initializer || propName, createPropertyAccessForDestructuringProperty(value, propName)); } } @@ -2988,8 +2981,6 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { } } else { - renameNonTopLevelLetAndConst(node.name); - let initializer = node.initializer; if (!initializer && languageVersion < ScriptTarget.ES6) { @@ -3049,54 +3040,6 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { return getCombinedNodeFlags(node.parent); } - function renameNonTopLevelLetAndConst(node: Node): void { - // do not rename if - // - language version is ES6+ - // - node is synthesized - // - node is not identifier (can happen when tree is malformed) - // - node is definitely not name of variable declaration. - // it still can be part of parameter declaration, this check will be done next - if (languageVersion >= ScriptTarget.ES6 || - nodeIsSynthesized(node) || - node.kind !== SyntaxKind.Identifier || - (node.parent.kind !== SyntaxKind.VariableDeclaration && node.parent.kind !== SyntaxKind.BindingElement)) { - return; - } - - let combinedFlags = getCombinedFlagsForIdentifier(node); - if (((combinedFlags & NodeFlags.BlockScoped) === 0) || combinedFlags & NodeFlags.Export) { - // do not rename exported or non-block scoped variables - return; - } - - // here it is known that node is a block scoped variable - let list = getAncestor(node, SyntaxKind.VariableDeclarationList); - if (list.parent.kind === SyntaxKind.VariableStatement) { - let isSourceFileLevelBinding = list.parent.parent.kind === SyntaxKind.SourceFile; - let isModuleLevelBinding = list.parent.parent.kind === SyntaxKind.ModuleBlock; - let isFunctionLevelBinding = - list.parent.parent.kind === SyntaxKind.Block && isFunctionLike(list.parent.parent.parent); - if (isSourceFileLevelBinding || isModuleLevelBinding || isFunctionLevelBinding) { - return; - } - } - - let blockScopeContainer = getEnclosingBlockScopeContainer(node); - let parent = blockScopeContainer.kind === SyntaxKind.SourceFile - ? blockScopeContainer - : blockScopeContainer.parent; - - if (resolver.resolvesToSomeValue(parent, (node).text)) { - let variableId = resolver.getBlockScopedVariableId(node); - if (!blockScopedVariableToGeneratedName) { - blockScopedVariableToGeneratedName = []; - } - - let generatedName = makeUniqueName((node).text); - blockScopedVariableToGeneratedName[variableId] = generatedName; - } - } - function isES6ExportedDeclaration(node: Node) { return !!(node.flags & NodeFlags.Export) && languageVersion >= ScriptTarget.ES6 && @@ -3260,7 +3203,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { function emitAccessor(node: AccessorDeclaration) { write(node.kind === SyntaxKind.GetAccessor ? "get " : "set "); - emit(node.name, /*allowGeneratedIdentifiers*/ false); + emit(node.name); emitSignatureAndBody(node); } @@ -5786,7 +5729,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { emitLeadingComments(node.endOfFileToken); } - function emitNodeWithoutSourceMap(node: Node, allowGeneratedIdentifiers?: boolean): void { + function emitNodeWithoutSourceMap(node: Node): void { if (!node) { return; } @@ -5800,7 +5743,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { emitLeadingComments(node); } - emitJavaScriptWorker(node, allowGeneratedIdentifiers); + emitJavaScriptWorker(node); if (emitComments) { emitTrailingComments(node); @@ -5850,11 +5793,11 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { return true; } - function emitJavaScriptWorker(node: Node, allowGeneratedIdentifiers: boolean = true) { + function emitJavaScriptWorker(node: Node) { // Check if the node can be emitted regardless of the ScriptTarget switch (node.kind) { case SyntaxKind.Identifier: - return emitIdentifier(node, allowGeneratedIdentifiers); + return emitIdentifier(node); case SyntaxKind.Parameter: return emitParameter(node); case SyntaxKind.MethodDeclaration: diff --git a/src/compiler/types.ts b/src/compiler/types.ts index e64d6afad8e..a8478a82797 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1398,6 +1398,8 @@ module ts { hasGlobalName(name: string): boolean; getReferencedExportContainer(node: Identifier): SourceFile | ModuleDeclaration | EnumDeclaration; getReferencedImportDeclaration(node: Identifier): ImportClause | ImportSpecifier; + getReferencedNestedRedeclaration(node: Identifier): Declaration; + isNestedRedeclaration(node: Declaration): boolean; isValueAliasDeclaration(node: Node): boolean; isReferencedAliasDeclaration(node: Node, checkChildren?: boolean): boolean; isTopLevelValueImportEqualsWithEntityName(node: ImportEqualsDeclaration): boolean; @@ -1412,7 +1414,6 @@ module ts { isEntityNameVisible(entityName: EntityName | Expression, enclosingDeclaration: Node): SymbolVisibilityResult; // Returns the constant value this property access resolves to, or 'undefined' for a non-constant getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number; - resolvesToSomeValue(location: Node, name: string): boolean; getBlockScopedVariableId(node: Identifier): number; getReferencedValueDeclaration(reference: Identifier): Declaration; serializeTypeOfNode(node: Node, getGeneratedNameForNode: (Node: Node) => string): string | string[]; @@ -1494,6 +1495,8 @@ module ts { HasExports = Class | Enum | Module, HasMembers = Class | Interface | TypeLiteral | ObjectLiteral, + BlockScoped = BlockScopedVariable | Class | Enum, + IsContainer = HasLocals | HasExports | HasMembers, PropertyOrAccessor = Property | Accessor, Export = ExportNamespace | ExportType | ExportValue, @@ -1523,6 +1526,7 @@ module ts { unionType?: UnionType; // Containing union type for union property resolvedExports?: SymbolTable; // Resolved exports of module exportsChecked?: boolean; // True if exports of external module have been checked + isNestedRedeclaration?: boolean; // True if symbol is block scoped redeclaration } /* @internal */ From 86d9398a929de9c5816e664a271ff392687107d2 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Mon, 1 Jun 2015 16:08:58 -0700 Subject: [PATCH 029/107] clean hostCache to avoid extending lifetime of script snapshots --- src/services/services.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/services/services.ts b/src/services/services.ts index 58155f2a691..6a497c87307 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2487,6 +2487,10 @@ module ts { } } + // hostCache is captured in the closure for 'getOrCreateSourceFile' but it should not be used past this point. + // It needs to be cleared to allow all collected snapshots to be released + hostCache = undefined; + program = newProgram; // Make sure all the nodes in the program are both bound, and have their parent @@ -2495,6 +2499,7 @@ module ts { return; function getOrCreateSourceFile(fileName: string): SourceFile { + Debug.assert(hostCache !== undefined); // The program is asking for this file, check first if the host can locate it. // If the host can not locate the file, then it does not exist. return undefined // to the program to allow reporting of errors for missing files. From 334b22452a038725bad262c64fedea725eeefc41 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 3 Jun 2015 10:59:14 -0700 Subject: [PATCH 030/107] Moving logic around in getReferencedImportDeclaration --- src/compiler/checker.ts | 39 ++++++++++++++++++++------------------- src/compiler/emitter.ts | 23 ++++++++++++----------- src/compiler/types.ts | 2 +- 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 78dbe9077c6..85bb37c135e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11809,16 +11809,11 @@ module ts { } } - // When resolved as an expression identifier, if the given node references a default import or a named import, return - // the declaration node of that import. Otherwise, return undefined. - function getReferencedImportDeclaration(node: Identifier): ImportClause | ImportSpecifier { + // When resolved as an expression identifier, if the given node references an import, return the declaration of + // that import. Otherwise, return undefined. + function getReferencedImportDeclaration(node: Identifier): Declaration { let symbol = getReferencedValueSymbol(node); - if (symbol && symbol.flags & SymbolFlags.Alias) { - let declaration = getDeclarationOfAliasSymbol(symbol); - if (declaration.kind === SyntaxKind.ImportClause || declaration.kind === SyntaxKind.ImportSpecifier) { - return declaration; - } - } + return symbol && symbol.flags & SymbolFlags.Alias ? getDeclarationOfAliasSymbol(symbol) : undefined; } function isStatementWithLocals(node: Node) { @@ -11833,24 +11828,30 @@ module ts { return false; } - function getIsNestedRedeclaration(symbol: Symbol): boolean { - let links = getSymbolLinks(symbol); - if (links.isNestedRedeclaration === undefined) { - let container = getEnclosingBlockScopeContainer(symbol.valueDeclaration); - links.isNestedRedeclaration = isStatementWithLocals(container) && - !!resolveName(container.parent, symbol.name, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined); + function isNestedRedeclarationSymbol(symbol: Symbol): boolean { + if (symbol.flags & SymbolFlags.BlockScoped) { + let links = getSymbolLinks(symbol); + if (links.isNestedRedeclaration === undefined) { + let container = getEnclosingBlockScopeContainer(symbol.valueDeclaration); + links.isNestedRedeclaration = isStatementWithLocals(container) && + !!resolveName(container.parent, symbol.name, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined); + } + return links.isNestedRedeclaration; } - return links.isNestedRedeclaration; + return false; } + // When resolved as an expression identifier, if the given node references a nested block scoped entity with + // a name that hides an existing name, return the declaration of that entity. Otherwise, return undefined. function getReferencedNestedRedeclaration(node: Identifier): Declaration { let symbol = getReferencedValueSymbol(node); - return symbol && symbol.flags & SymbolFlags.BlockScoped && getIsNestedRedeclaration(symbol) ? symbol.valueDeclaration : undefined; + return symbol && isNestedRedeclarationSymbol(symbol) ? symbol.valueDeclaration : undefined; } + // Return true if the given node is a declaration of a nested block scoped entity with a name that hides an + // existing name. function isNestedRedeclaration(node: Declaration): boolean { - let symbol = getSymbolOfNode(node); - return symbol.flags & SymbolFlags.BlockScoped && getIsNestedRedeclaration(symbol); + return isNestedRedeclarationSymbol(getSymbolOfNode(node)); } function isValueAliasDeclaration(node: Node): boolean { diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 96dec48d82c..6a68c6b0e85 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1237,24 +1237,25 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { } } else if (languageVersion < ScriptTarget.ES6) { - let alias = resolver.getReferencedImportDeclaration(node); - if (alias) { - if (alias.kind === SyntaxKind.ImportClause) { + let declaration = resolver.getReferencedImportDeclaration(node); + if (declaration) { + if (declaration.kind === SyntaxKind.ImportClause) { // Identifier references default import - write(getGeneratedNameForNode(alias.parent)); + write(getGeneratedNameForNode(declaration.parent)); write(languageVersion === ScriptTarget.ES3 ? '["default"]' : ".default"); + return; } - else { + else if (declaration.kind === SyntaxKind.ImportSpecifier) { // Identifier references named import - write(getGeneratedNameForNode(alias.parent.parent.parent)); + write(getGeneratedNameForNode(declaration.parent.parent.parent)); write("."); - writeTextOfNode(currentSourceFile, (alias).propertyName || (alias).name); + writeTextOfNode(currentSourceFile, (declaration).propertyName || (declaration).name); + return; } - return; } - let local = resolver.getReferencedNestedRedeclaration(node); - if (local) { - write(getGeneratedNameForNode(local.name)); + declaration = resolver.getReferencedNestedRedeclaration(node); + if (declaration) { + write(getGeneratedNameForNode(declaration.name)); return; } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index a8478a82797..205e1034448 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1397,7 +1397,7 @@ module ts { export interface EmitResolver { hasGlobalName(name: string): boolean; getReferencedExportContainer(node: Identifier): SourceFile | ModuleDeclaration | EnumDeclaration; - getReferencedImportDeclaration(node: Identifier): ImportClause | ImportSpecifier; + getReferencedImportDeclaration(node: Identifier): Declaration; getReferencedNestedRedeclaration(node: Identifier): Declaration; isNestedRedeclaration(node: Declaration): boolean; isValueAliasDeclaration(node: Node): boolean; From 3cac56af1ab7bb7c51a192a4f8ff8d4e9dbc06e6 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 3 Jun 2015 12:05:12 -0700 Subject: [PATCH 031/107] Fixed case for the 'declare' keyword. --- src/compiler/parser.ts | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 4a46e375f87..72cd3bb620d 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1818,7 +1818,7 @@ module ts { if (matchesPattern) { // Report that we need an identifier. However, report it right after the dot, // and not on the next token. This is because the next token might actually - // be an identifier and the error woudl be quite confusing. + // be an identifier and the error would be quite confusing. return createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentToken*/ true, Diagnostics.Identifier_expected); } } @@ -3981,19 +3981,31 @@ module ts { return parseDebuggerStatement(); case SyntaxKind.AtToken: return parseDeclaration(); - case SyntaxKind.ConstKeyword: case SyntaxKind.DeclareKeyword: + if (lookAhead(isFollowedByIdentifierOrKeywordOnSameLine) && getDeclarationFlags() & flags) { + return parseDeclaration(); + } + break; + case SyntaxKind.ModuleKeyword: + if (lookAhead(isFollowedByIdentifierOrStringOnSameLine) && getDeclarationFlags() & flags) { + return parseDeclaration(); + } + break; + case SyntaxKind.NamespaceKeyword: + case SyntaxKind.TypeKeyword: + if (lookAhead(isFollowedByIdentifierOnSameLine) && getDeclarationFlags() & flags) { + return parseDeclaration(); + } + break; + case SyntaxKind.ConstKeyword: case SyntaxKind.EnumKeyword: case SyntaxKind.ExportKeyword: case SyntaxKind.ImportKeyword: case SyntaxKind.InterfaceKeyword: - case SyntaxKind.ModuleKeyword: - case SyntaxKind.NamespaceKeyword: case SyntaxKind.PrivateKeyword: case SyntaxKind.ProtectedKeyword: case SyntaxKind.PublicKeyword: case SyntaxKind.StaticKeyword: - case SyntaxKind.TypeKeyword: if (getDeclarationFlags() & flags) { return parseDeclaration(); } @@ -4044,6 +4056,21 @@ module ts { } } + function isFollowedByIdentifierOrKeywordOnSameLine() { + nextToken(); + return !scanner.hasPrecedingLineBreak() && isIdentifierOrKeyword(); + } + + function isFollowedByIdentifierOrStringOnSameLine() { + nextToken(); + return !scanner.hasPrecedingLineBreak() && (isIdentifier() || token === SyntaxKind.StringLiteral); + } + + function isFollowedByIdentifierOnSameLine() { + nextToken(); + return !scanner.hasPrecedingLineBreak() && isIdentifier(); + } + function parseFunctionBlockOrSemicolon(isGenerator: boolean, diagnosticMessage?: DiagnosticMessage): Block { if (token !== SyntaxKind.OpenBraceToken && canParseSemicolon()) { parseSemicolon(); From 3cd480ddb6e5aae35d7504de9de5fb8ee4ea8b1d Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 3 Jun 2015 12:05:53 -0700 Subject: [PATCH 032/107] Accepted baselines. --- ...reventsParsingAsAmbientExternalModule01.js | 4 ++++ ...tsParsingAsAmbientExternalModule01.symbols | 4 ++++ ...entsParsingAsAmbientExternalModule01.types | 6 +++++ ...arsingAsAmbientExternalModule02.errors.txt | 16 -------------- ...reventsParsingAsAmbientExternalModule02.js | 7 ++++++ ...tsParsingAsAmbientExternalModule02.symbols | 20 +++++++++++++++++ ...entsParsingAsAmbientExternalModule02.types | 22 +++++++++++++++++++ .../asiPreventsParsingAsNamespace01.js | 3 +++ .../asiPreventsParsingAsNamespace01.symbols | 6 +++-- .../asiPreventsParsingAsNamespace01.types | 2 ++ .../asiPreventsParsingAsNamespace02.js | 3 +++ .../asiPreventsParsingAsNamespace02.symbols | 6 +++-- .../asiPreventsParsingAsNamespace02.types | 2 ++ .../asiPreventsParsingAsNamespace03.js | 6 +++++ .../asiPreventsParsingAsNamespace03.symbols | 4 +++- .../asiPreventsParsingAsNamespace03.types | 6 +++-- ...asiPreventsParsingAsNamespace04.errors.txt | 9 -------- .../asiPreventsParsingAsNamespace04.js | 2 +- .../asiPreventsParsingAsNamespace04.symbols | 8 +++++++ .../asiPreventsParsingAsNamespace04.types | 11 ++++++++++ .../asiPreventsParsingAsNamespace05.js | 14 ++++++++++++ .../asiPreventsParsingAsNamespace05.symbols | 20 +++++++++++++---- .../asiPreventsParsingAsNamespace05.types | 19 +++++++++++++--- .../asiPreventsParsingAsTypeAlias01.js | 2 ++ .../asiPreventsParsingAsTypeAlias01.symbols | 7 ++++-- .../asiPreventsParsingAsTypeAlias01.types | 6 ++++- .../asiPreventsParsingAsTypeAlias02.js | 5 +++++ .../asiPreventsParsingAsTypeAlias02.symbols | 5 ++++- .../asiPreventsParsingAsTypeAlias02.types | 8 +++++-- .../reservedNamesInAliases.errors.txt | 13 ++++++----- .../reference/reservedNamesInAliases.js | 2 ++ .../reference/reservedWords2.errors.txt | 10 ++++----- tests/baselines/reference/reservedWords2.js | 1 + 33 files changed, 203 insertions(+), 56 deletions(-) delete mode 100644 tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule02.errors.txt create mode 100644 tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule02.symbols create mode 100644 tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule02.types delete mode 100644 tests/baselines/reference/asiPreventsParsingAsNamespace04.errors.txt create mode 100644 tests/baselines/reference/asiPreventsParsingAsNamespace04.symbols create mode 100644 tests/baselines/reference/asiPreventsParsingAsNamespace04.types diff --git a/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule01.js b/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule01.js index efd82f27d1f..caf90acae5f 100644 --- a/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule01.js +++ b/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule01.js @@ -11,3 +11,7 @@ module // this is the identifier 'module' //// [asiPreventsParsingAsAmbientExternalModule01.js] var declare; var module; +declare; // this is the identifier 'declare' +module; // this is the identifier 'module' +"my external module"; // this is just a string +{ } // this is a block body diff --git a/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule01.symbols b/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule01.symbols index 87eb8daf7e2..c35432b7ece 100644 --- a/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule01.symbols +++ b/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule01.symbols @@ -7,6 +7,10 @@ var module: string; >module : Symbol(module, Decl(asiPreventsParsingAsAmbientExternalModule01.ts, 2, 3)) declare // this is the identifier 'declare' +>declare : Symbol(declare, Decl(asiPreventsParsingAsAmbientExternalModule01.ts, 1, 3)) + module // this is the identifier 'module' +>module : Symbol(module, Decl(asiPreventsParsingAsAmbientExternalModule01.ts, 2, 3)) + "my external module" // this is just a string { } // this is a block body diff --git a/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule01.types b/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule01.types index 94a2cc8d6a1..3e6aade9a21 100644 --- a/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule01.types +++ b/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule01.types @@ -7,6 +7,12 @@ var module: string; >module : string declare // this is the identifier 'declare' +>declare : number + module // this is the identifier 'module' +>module : string + "my external module" // this is just a string +>"my external module" : string + { } // this is a block body diff --git a/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule02.errors.txt b/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule02.errors.txt deleted file mode 100644 index 3064b137a19..00000000000 --- a/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule02.errors.txt +++ /dev/null @@ -1,16 +0,0 @@ -tests/cases/conformance/externalModules/asiPreventsParsingAsAmbientExternalModule02.ts(8,5): error TS2435: Ambient modules cannot be nested in other modules. - - -==== tests/cases/conformance/externalModules/asiPreventsParsingAsAmbientExternalModule02.ts (1 errors) ==== - - var declare: number; - var module: string; - - module container { - declare // this is the identifier 'declare' - module // this is the identifier 'module' - "my external module" // this is just a string - ~~~~~~~~~~~~~~~~~~~~ -!!! error TS2435: Ambient modules cannot be nested in other modules. - { } // this is a block body - } \ No newline at end of file diff --git a/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule02.js b/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule02.js index 444b4b392c9..20e2693ba7f 100644 --- a/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule02.js +++ b/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule02.js @@ -13,3 +13,10 @@ module container { //// [asiPreventsParsingAsAmbientExternalModule02.js] var declare; var module; +var container; +(function (container) { + declare; // this is the identifier 'declare' + module; // this is the identifier 'module' + "my external module"; // this is just a string + { } // this is a block body +})(container || (container = {})); diff --git a/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule02.symbols b/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule02.symbols new file mode 100644 index 00000000000..ed97f39fc11 --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule02.symbols @@ -0,0 +1,20 @@ +=== tests/cases/conformance/externalModules/asiPreventsParsingAsAmbientExternalModule02.ts === + +var declare: number; +>declare : Symbol(declare, Decl(asiPreventsParsingAsAmbientExternalModule02.ts, 1, 3)) + +var module: string; +>module : Symbol(module, Decl(asiPreventsParsingAsAmbientExternalModule02.ts, 2, 3)) + +module container { +>container : Symbol(container, Decl(asiPreventsParsingAsAmbientExternalModule02.ts, 2, 19)) + + declare // this is the identifier 'declare' +>declare : Symbol(declare, Decl(asiPreventsParsingAsAmbientExternalModule02.ts, 1, 3)) + + module // this is the identifier 'module' +>module : Symbol(module, Decl(asiPreventsParsingAsAmbientExternalModule02.ts, 2, 3)) + + "my external module" // this is just a string + { } // this is a block body +} diff --git a/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule02.types b/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule02.types new file mode 100644 index 00000000000..67671853993 --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsAmbientExternalModule02.types @@ -0,0 +1,22 @@ +=== tests/cases/conformance/externalModules/asiPreventsParsingAsAmbientExternalModule02.ts === + +var declare: number; +>declare : number + +var module: string; +>module : string + +module container { +>container : typeof container + + declare // this is the identifier 'declare' +>declare : number + + module // this is the identifier 'module' +>module : string + + "my external module" // this is just a string +>"my external module" : string + + { } // this is a block body +} diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace01.js b/tests/baselines/reference/asiPreventsParsingAsNamespace01.js index eed9769da69..282d9dd1c7c 100644 --- a/tests/baselines/reference/asiPreventsParsingAsNamespace01.js +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace01.js @@ -10,3 +10,6 @@ n // this is the identifier 'n' //// [asiPreventsParsingAsNamespace01.js] var namespace; var n; +namespace; // this is the identifier 'namespace' +n; // this is the identifier 'n' +{ } // this is a block body diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace01.symbols b/tests/baselines/reference/asiPreventsParsingAsNamespace01.symbols index a2494904bed..b196d733352 100644 --- a/tests/baselines/reference/asiPreventsParsingAsNamespace01.symbols +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace01.symbols @@ -4,10 +4,12 @@ var namespace: number; >namespace : Symbol(namespace, Decl(asiPreventsParsingAsNamespace01.ts, 1, 3)) var n: string; ->n : Symbol(n, Decl(asiPreventsParsingAsNamespace01.ts, 2, 3), Decl(asiPreventsParsingAsNamespace01.ts, 2, 14)) +>n : Symbol(n, Decl(asiPreventsParsingAsNamespace01.ts, 2, 3)) namespace // this is the identifier 'namespace' +>namespace : Symbol(namespace, Decl(asiPreventsParsingAsNamespace01.ts, 1, 3)) + n // this is the identifier 'n' ->n : Symbol(n, Decl(asiPreventsParsingAsNamespace01.ts, 2, 3), Decl(asiPreventsParsingAsNamespace01.ts, 2, 14)) +>n : Symbol(n, Decl(asiPreventsParsingAsNamespace01.ts, 2, 3)) { } // this is a block body diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace01.types b/tests/baselines/reference/asiPreventsParsingAsNamespace01.types index 87044c58066..417a96dbed4 100644 --- a/tests/baselines/reference/asiPreventsParsingAsNamespace01.types +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace01.types @@ -7,6 +7,8 @@ var n: string; >n : string namespace // this is the identifier 'namespace' +>namespace : number + n // this is the identifier 'n' >n : string diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace02.js b/tests/baselines/reference/asiPreventsParsingAsNamespace02.js index de2bdfa8a9e..514a026dc78 100644 --- a/tests/baselines/reference/asiPreventsParsingAsNamespace02.js +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace02.js @@ -10,3 +10,6 @@ m // this is the identifier 'm' //// [asiPreventsParsingAsNamespace02.js] var module; var m; +module; // this is the identifier 'namespace' +m; // this is the identifier 'm' +{ } // this is a block body diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace02.symbols b/tests/baselines/reference/asiPreventsParsingAsNamespace02.symbols index 70024a8de62..a3bb37c73bc 100644 --- a/tests/baselines/reference/asiPreventsParsingAsNamespace02.symbols +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace02.symbols @@ -4,10 +4,12 @@ var module: number; >module : Symbol(module, Decl(asiPreventsParsingAsNamespace02.ts, 1, 3)) var m: string; ->m : Symbol(m, Decl(asiPreventsParsingAsNamespace02.ts, 2, 3), Decl(asiPreventsParsingAsNamespace02.ts, 2, 14)) +>m : Symbol(m, Decl(asiPreventsParsingAsNamespace02.ts, 2, 3)) module // this is the identifier 'namespace' +>module : Symbol(module, Decl(asiPreventsParsingAsNamespace02.ts, 1, 3)) + m // this is the identifier 'm' ->m : Symbol(m, Decl(asiPreventsParsingAsNamespace02.ts, 2, 3), Decl(asiPreventsParsingAsNamespace02.ts, 2, 14)) +>m : Symbol(m, Decl(asiPreventsParsingAsNamespace02.ts, 2, 3)) { } // this is a block body diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace02.types b/tests/baselines/reference/asiPreventsParsingAsNamespace02.types index 8f6dec87a00..e9e1433be7a 100644 --- a/tests/baselines/reference/asiPreventsParsingAsNamespace02.types +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace02.types @@ -7,6 +7,8 @@ var m: string; >m : string module // this is the identifier 'namespace' +>module : number + m // this is the identifier 'm' >m : string diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace03.js b/tests/baselines/reference/asiPreventsParsingAsNamespace03.js index 6d8b8970977..3c27694f5ce 100644 --- a/tests/baselines/reference/asiPreventsParsingAsNamespace03.js +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace03.js @@ -12,3 +12,9 @@ namespace container { //// [asiPreventsParsingAsNamespace03.js] var namespace; var n; +var container; +(function (container) { + namespace; // this is the identifier 'namespace' + n; // this is the identifier 'n' + { } // this is a block body +})(container || (container = {})); diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace03.symbols b/tests/baselines/reference/asiPreventsParsingAsNamespace03.symbols index 8dfa30c17a4..e77d012a1bf 100644 --- a/tests/baselines/reference/asiPreventsParsingAsNamespace03.symbols +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace03.symbols @@ -10,8 +10,10 @@ namespace container { >container : Symbol(container, Decl(asiPreventsParsingAsNamespace03.ts, 2, 14)) namespace // this is the identifier 'namespace' +>namespace : Symbol(namespace, Decl(asiPreventsParsingAsNamespace03.ts, 1, 3)) + n // this is the identifier 'n' ->n : Symbol(n, Decl(asiPreventsParsingAsNamespace03.ts, 4, 21)) +>n : Symbol(n, Decl(asiPreventsParsingAsNamespace03.ts, 2, 3)) { } // this is a block body } diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace03.types b/tests/baselines/reference/asiPreventsParsingAsNamespace03.types index 37423757159..f119a789e11 100644 --- a/tests/baselines/reference/asiPreventsParsingAsNamespace03.types +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace03.types @@ -7,11 +7,13 @@ var n: string; >n : string namespace container { ->container : any +>container : typeof container namespace // this is the identifier 'namespace' +>namespace : number + n // this is the identifier 'n' ->n : any +>n : string { } // this is a block body } diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace04.errors.txt b/tests/baselines/reference/asiPreventsParsingAsNamespace04.errors.txt deleted file mode 100644 index d0a6be446aa..00000000000 --- a/tests/baselines/reference/asiPreventsParsingAsNamespace04.errors.txt +++ /dev/null @@ -1,9 +0,0 @@ -tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace04.ts(3,8): error TS1003: Identifier expected. - - -==== tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace04.ts (1 errors) ==== - - let module = 10; - module in {} - ~~ -!!! error TS1003: Identifier expected. \ No newline at end of file diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace04.js b/tests/baselines/reference/asiPreventsParsingAsNamespace04.js index bcd8975d46d..704c8893e76 100644 --- a/tests/baselines/reference/asiPreventsParsingAsNamespace04.js +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace04.js @@ -5,4 +5,4 @@ module in {} //// [asiPreventsParsingAsNamespace04.js] var module = 10; - in {}; +module in {}; diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace04.symbols b/tests/baselines/reference/asiPreventsParsingAsNamespace04.symbols new file mode 100644 index 00000000000..60d1f8fcc48 --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace04.symbols @@ -0,0 +1,8 @@ +=== tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace04.ts === + +let module = 10; +>module : Symbol(module, Decl(asiPreventsParsingAsNamespace04.ts, 1, 3)) + +module in {} +>module : Symbol(module, Decl(asiPreventsParsingAsNamespace04.ts, 1, 3)) + diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace04.types b/tests/baselines/reference/asiPreventsParsingAsNamespace04.types new file mode 100644 index 00000000000..3fa2a448cf9 --- /dev/null +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace04.types @@ -0,0 +1,11 @@ +=== tests/cases/conformance/internalModules/moduleDeclarations/asiPreventsParsingAsNamespace04.ts === + +let module = 10; +>module : number +>10 : number + +module in {} +>module in {} : boolean +>module : number +>{} : {} + diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace05.js b/tests/baselines/reference/asiPreventsParsingAsNamespace05.js index 0a525179d2d..35f557328c0 100644 --- a/tests/baselines/reference/asiPreventsParsingAsNamespace05.js +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace05.js @@ -1,6 +1,9 @@ //// [asiPreventsParsingAsNamespace05.ts] let namespace = 10; +namespace a.b { + export let c = 20; +} namespace a.b.c @@ -9,3 +12,14 @@ a.b.c //// [asiPreventsParsingAsNamespace05.js] var namespace = 10; +var a; +(function (a) { + var b; + (function (b) { + b.c = 20; + })(b = a.b || (a.b = {})); +})(a || (a = {})); +namespace; +a.b.c; +{ +} diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace05.symbols b/tests/baselines/reference/asiPreventsParsingAsNamespace05.symbols index 65125806b61..47f05862b0a 100644 --- a/tests/baselines/reference/asiPreventsParsingAsNamespace05.symbols +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace05.symbols @@ -3,10 +3,22 @@ let namespace = 10; >namespace : Symbol(namespace, Decl(asiPreventsParsingAsNamespace05.ts, 1, 3)) -namespace -a.b.c +namespace a.b { >a : Symbol(a, Decl(asiPreventsParsingAsNamespace05.ts, 1, 19)) ->b : Symbol(b, Decl(asiPreventsParsingAsNamespace05.ts, 4, 2)) ->c : Symbol(c, Decl(asiPreventsParsingAsNamespace05.ts, 4, 4)) +>b : Symbol(b, Decl(asiPreventsParsingAsNamespace05.ts, 2, 12)) + + export let c = 20; +>c : Symbol(c, Decl(asiPreventsParsingAsNamespace05.ts, 3, 14)) +} + +namespace +>namespace : Symbol(namespace, Decl(asiPreventsParsingAsNamespace05.ts, 1, 3)) + +a.b.c +>a.b.c : Symbol(a.b.c, Decl(asiPreventsParsingAsNamespace05.ts, 3, 14)) +>a.b : Symbol(a.b, Decl(asiPreventsParsingAsNamespace05.ts, 2, 12)) +>a : Symbol(a, Decl(asiPreventsParsingAsNamespace05.ts, 1, 19)) +>b : Symbol(a.b, Decl(asiPreventsParsingAsNamespace05.ts, 2, 12)) +>c : Symbol(a.b.c, Decl(asiPreventsParsingAsNamespace05.ts, 3, 14)) { } diff --git a/tests/baselines/reference/asiPreventsParsingAsNamespace05.types b/tests/baselines/reference/asiPreventsParsingAsNamespace05.types index f17ad1f2a1e..515147c1096 100644 --- a/tests/baselines/reference/asiPreventsParsingAsNamespace05.types +++ b/tests/baselines/reference/asiPreventsParsingAsNamespace05.types @@ -4,10 +4,23 @@ let namespace = 10; >namespace : number >10 : number +namespace a.b { +>a : typeof a +>b : typeof b + + export let c = 20; +>c : number +>20 : number +} + namespace +>namespace : number + a.b.c ->a : any ->b : any ->c : any +>a.b.c : number +>a.b : typeof a.b +>a : typeof a +>b : typeof a.b +>c : number { } diff --git a/tests/baselines/reference/asiPreventsParsingAsTypeAlias01.js b/tests/baselines/reference/asiPreventsParsingAsTypeAlias01.js index 33e3895fab4..b05988290cb 100644 --- a/tests/baselines/reference/asiPreventsParsingAsTypeAlias01.js +++ b/tests/baselines/reference/asiPreventsParsingAsTypeAlias01.js @@ -11,3 +11,5 @@ Foo = string; var type; var string; var Foo; +type; +Foo = string; diff --git a/tests/baselines/reference/asiPreventsParsingAsTypeAlias01.symbols b/tests/baselines/reference/asiPreventsParsingAsTypeAlias01.symbols index d11c9ff5c13..fa82d53ac70 100644 --- a/tests/baselines/reference/asiPreventsParsingAsTypeAlias01.symbols +++ b/tests/baselines/reference/asiPreventsParsingAsTypeAlias01.symbols @@ -7,9 +7,12 @@ var string; >string : Symbol(string, Decl(asiPreventsParsingAsTypeAlias01.ts, 2, 3)) var Foo; ->Foo : Symbol(Foo, Decl(asiPreventsParsingAsTypeAlias01.ts, 3, 3), Decl(asiPreventsParsingAsTypeAlias01.ts, 3, 8)) +>Foo : Symbol(Foo, Decl(asiPreventsParsingAsTypeAlias01.ts, 3, 3)) type +>type : Symbol(type, Decl(asiPreventsParsingAsTypeAlias01.ts, 1, 3)) + Foo = string; ->Foo : Symbol(Foo, Decl(asiPreventsParsingAsTypeAlias01.ts, 3, 3), Decl(asiPreventsParsingAsTypeAlias01.ts, 3, 8)) +>Foo : Symbol(Foo, Decl(asiPreventsParsingAsTypeAlias01.ts, 3, 3)) +>string : Symbol(string, Decl(asiPreventsParsingAsTypeAlias01.ts, 2, 3)) diff --git a/tests/baselines/reference/asiPreventsParsingAsTypeAlias01.types b/tests/baselines/reference/asiPreventsParsingAsTypeAlias01.types index d112022afa4..7492a698e3a 100644 --- a/tests/baselines/reference/asiPreventsParsingAsTypeAlias01.types +++ b/tests/baselines/reference/asiPreventsParsingAsTypeAlias01.types @@ -10,6 +10,10 @@ var Foo; >Foo : any type +>type : any + Foo = string; ->Foo : string +>Foo = string : any +>Foo : any +>string : any diff --git a/tests/baselines/reference/asiPreventsParsingAsTypeAlias02.js b/tests/baselines/reference/asiPreventsParsingAsTypeAlias02.js index 4a8298b2bdf..eae9898c8d4 100644 --- a/tests/baselines/reference/asiPreventsParsingAsTypeAlias02.js +++ b/tests/baselines/reference/asiPreventsParsingAsTypeAlias02.js @@ -13,3 +13,8 @@ namespace container { var type; var string; var Foo; +var container; +(function (container) { + type; + Foo = string; +})(container || (container = {})); diff --git a/tests/baselines/reference/asiPreventsParsingAsTypeAlias02.symbols b/tests/baselines/reference/asiPreventsParsingAsTypeAlias02.symbols index 0da88560109..4b83dba4c5d 100644 --- a/tests/baselines/reference/asiPreventsParsingAsTypeAlias02.symbols +++ b/tests/baselines/reference/asiPreventsParsingAsTypeAlias02.symbols @@ -13,6 +13,9 @@ namespace container { >container : Symbol(container, Decl(asiPreventsParsingAsTypeAlias02.ts, 3, 8)) type +>type : Symbol(type, Decl(asiPreventsParsingAsTypeAlias02.ts, 1, 3)) + Foo = string; ->Foo : Symbol(Foo, Decl(asiPreventsParsingAsTypeAlias02.ts, 5, 21)) +>Foo : Symbol(Foo, Decl(asiPreventsParsingAsTypeAlias02.ts, 3, 3)) +>string : Symbol(string, Decl(asiPreventsParsingAsTypeAlias02.ts, 2, 3)) } diff --git a/tests/baselines/reference/asiPreventsParsingAsTypeAlias02.types b/tests/baselines/reference/asiPreventsParsingAsTypeAlias02.types index 4af0721ec24..1e6c7a8caf1 100644 --- a/tests/baselines/reference/asiPreventsParsingAsTypeAlias02.types +++ b/tests/baselines/reference/asiPreventsParsingAsTypeAlias02.types @@ -10,9 +10,13 @@ var Foo; >Foo : any namespace container { ->container : any +>container : typeof container type +>type : any + Foo = string; ->Foo : string +>Foo = string : any +>Foo : any +>string : any } diff --git a/tests/baselines/reference/reservedNamesInAliases.errors.txt b/tests/baselines/reference/reservedNamesInAliases.errors.txt index 277e06111c4..5c17158053e 100644 --- a/tests/baselines/reference/reservedNamesInAliases.errors.txt +++ b/tests/baselines/reference/reservedNamesInAliases.errors.txt @@ -2,12 +2,13 @@ tests/cases/conformance/types/typeAliases/reservedNamesInAliases.ts(2,6): error tests/cases/conformance/types/typeAliases/reservedNamesInAliases.ts(3,6): error TS2457: Type alias name cannot be 'number' tests/cases/conformance/types/typeAliases/reservedNamesInAliases.ts(4,6): error TS2457: Type alias name cannot be 'boolean' tests/cases/conformance/types/typeAliases/reservedNamesInAliases.ts(5,6): error TS2457: Type alias name cannot be 'string' -tests/cases/conformance/types/typeAliases/reservedNamesInAliases.ts(6,6): error TS1003: Identifier expected. -tests/cases/conformance/types/typeAliases/reservedNamesInAliases.ts(6,11): error TS1005: ';' expected. +tests/cases/conformance/types/typeAliases/reservedNamesInAliases.ts(6,1): error TS2304: Cannot find name 'type'. +tests/cases/conformance/types/typeAliases/reservedNamesInAliases.ts(6,6): error TS1005: ';' expected. +tests/cases/conformance/types/typeAliases/reservedNamesInAliases.ts(6,11): error TS1109: Expression expected. tests/cases/conformance/types/typeAliases/reservedNamesInAliases.ts(6,13): error TS2304: Cannot find name 'I'. -==== tests/cases/conformance/types/typeAliases/reservedNamesInAliases.ts (7 errors) ==== +==== tests/cases/conformance/types/typeAliases/reservedNamesInAliases.ts (8 errors) ==== interface I {} type any = I; ~~~ @@ -22,9 +23,11 @@ tests/cases/conformance/types/typeAliases/reservedNamesInAliases.ts(6,13): error ~~~~~~ !!! error TS2457: Type alias name cannot be 'string' type void = I; + ~~~~ +!!! error TS2304: Cannot find name 'type'. ~~~~ -!!! error TS1003: Identifier expected. - ~ !!! error TS1005: ';' expected. + ~ +!!! error TS1109: Expression expected. ~ !!! error TS2304: Cannot find name 'I'. \ No newline at end of file diff --git a/tests/baselines/reference/reservedNamesInAliases.js b/tests/baselines/reference/reservedNamesInAliases.js index 773cc3ca84a..4ebc3bdb95f 100644 --- a/tests/baselines/reference/reservedNamesInAliases.js +++ b/tests/baselines/reference/reservedNamesInAliases.js @@ -7,4 +7,6 @@ type string = I; type void = I; //// [reservedNamesInAliases.js] +type; +void ; I; diff --git a/tests/baselines/reference/reservedWords2.errors.txt b/tests/baselines/reference/reservedWords2.errors.txt index 471eef4710a..090b2d0d43e 100644 --- a/tests/baselines/reference/reservedWords2.errors.txt +++ b/tests/baselines/reference/reservedWords2.errors.txt @@ -13,8 +13,8 @@ tests/cases/compiler/reservedWords2.ts(4,12): error TS1109: Expression expected. tests/cases/compiler/reservedWords2.ts(5,9): error TS2300: Duplicate identifier '(Missing)'. tests/cases/compiler/reservedWords2.ts(5,10): error TS1003: Identifier expected. tests/cases/compiler/reservedWords2.ts(5,18): error TS1005: '=>' expected. -tests/cases/compiler/reservedWords2.ts(6,7): error TS2300: Duplicate identifier '(Missing)'. -tests/cases/compiler/reservedWords2.ts(6,8): error TS1003: Identifier expected. +tests/cases/compiler/reservedWords2.ts(6,1): error TS2304: Cannot find name 'module'. +tests/cases/compiler/reservedWords2.ts(6,8): error TS1005: ';' expected. tests/cases/compiler/reservedWords2.ts(7,11): error TS2300: Duplicate identifier '(Missing)'. tests/cases/compiler/reservedWords2.ts(7,11): error TS1005: ':' expected. tests/cases/compiler/reservedWords2.ts(7,19): error TS2300: Duplicate identifier '(Missing)'. @@ -68,10 +68,10 @@ tests/cases/compiler/reservedWords2.ts(10,6): error TS1003: Identifier expected. ~ !!! error TS1005: '=>' expected. module void {} - -!!! error TS2300: Duplicate identifier '(Missing)'. + ~~~~~~ +!!! error TS2304: Cannot find name 'module'. ~~~~ -!!! error TS1003: Identifier expected. +!!! error TS1005: ';' expected. var {while, return} = { while: 1, return: 2 }; !!! error TS2300: Duplicate identifier '(Missing)'. diff --git a/tests/baselines/reference/reservedWords2.js b/tests/baselines/reference/reservedWords2.js index 6d5a5f530c5..fb90a718ec3 100644 --- a/tests/baselines/reference/reservedWords2.js +++ b/tests/baselines/reference/reservedWords2.js @@ -23,6 +23,7 @@ var ; typeof ; 10; throw function () { }; +module; void {}; var _a = { while: 1, return: 2 }, = _a.while, = _a.return; var _b = { this: 1, switch: { continue: 2 } }, = _b.this, = _b.switch.continue; From 46da6678ad082b53de4698740fa751bba7c8c29a Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Tue, 2 Jun 2015 17:33:57 -0700 Subject: [PATCH 033/107] Return expressions always need to be type checked --- src/compiler/checker.ts | 4 ++++ ...ltiLinePropertyAccessAndArrowFunctionIndent1.errors.txt | 5 ++++- .../reference/typeCheckReturnExpression.errors.txt | 7 +++++++ tests/baselines/reference/typeCheckReturnExpression.js | 5 +++++ tests/cases/compiler/typeCheckReturnExpression.ts | 2 ++ 5 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/typeCheckReturnExpression.errors.txt create mode 100644 tests/baselines/reference/typeCheckReturnExpression.js create mode 100644 tests/cases/compiler/typeCheckReturnExpression.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ab5d8e4207f..aa3b69d9b34 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7454,6 +7454,10 @@ module ts { } if (node.body) { + if (!node.type) { + getReturnTypeOfSignature(getSignatureFromDeclaration(node)); + } + if (node.body.kind === SyntaxKind.Block) { checkSourceElement(node.body); } diff --git a/tests/baselines/reference/multiLinePropertyAccessAndArrowFunctionIndent1.errors.txt b/tests/baselines/reference/multiLinePropertyAccessAndArrowFunctionIndent1.errors.txt index 14b7769d22f..abf11dc9dba 100644 --- a/tests/baselines/reference/multiLinePropertyAccessAndArrowFunctionIndent1.errors.txt +++ b/tests/baselines/reference/multiLinePropertyAccessAndArrowFunctionIndent1.errors.txt @@ -1,12 +1,15 @@ tests/cases/compiler/multiLinePropertyAccessAndArrowFunctionIndent1.ts(1,1): error TS1108: A 'return' statement can only be used within a function body. +tests/cases/compiler/multiLinePropertyAccessAndArrowFunctionIndent1.ts(1,18): error TS2304: Cannot find name 'role'. tests/cases/compiler/multiLinePropertyAccessAndArrowFunctionIndent1.ts(2,18): error TS2304: Cannot find name 'Role'. tests/cases/compiler/multiLinePropertyAccessAndArrowFunctionIndent1.ts(4,26): error TS2503: Cannot find namespace 'ng'. -==== tests/cases/compiler/multiLinePropertyAccessAndArrowFunctionIndent1.ts (3 errors) ==== +==== tests/cases/compiler/multiLinePropertyAccessAndArrowFunctionIndent1.ts (4 errors) ==== return this.edit(role) ~~~~~~ !!! error TS1108: A 'return' statement can only be used within a function body. + ~~~~ +!!! error TS2304: Cannot find name 'role'. .then((role: Role) => ~~~~ !!! error TS2304: Cannot find name 'Role'. diff --git a/tests/baselines/reference/typeCheckReturnExpression.errors.txt b/tests/baselines/reference/typeCheckReturnExpression.errors.txt new file mode 100644 index 00000000000..c648c57799d --- /dev/null +++ b/tests/baselines/reference/typeCheckReturnExpression.errors.txt @@ -0,0 +1,7 @@ +tests/cases/compiler/typeCheckReturnExpression.ts(1,11): error TS7011: Function expression, which lacks return-type annotation, implicitly has an 'any' return type. + + +==== tests/cases/compiler/typeCheckReturnExpression.ts (1 errors) ==== + var foo = () => undefined; + ~~~~~~~~~~~~~~~ +!!! error TS7011: Function expression, which lacks return-type annotation, implicitly has an 'any' return type. \ No newline at end of file diff --git a/tests/baselines/reference/typeCheckReturnExpression.js b/tests/baselines/reference/typeCheckReturnExpression.js new file mode 100644 index 00000000000..ba71780b48d --- /dev/null +++ b/tests/baselines/reference/typeCheckReturnExpression.js @@ -0,0 +1,5 @@ +//// [typeCheckReturnExpression.ts] +var foo = () => undefined; + +//// [typeCheckReturnExpression.js] +var foo = function () { return undefined; }; diff --git a/tests/cases/compiler/typeCheckReturnExpression.ts b/tests/cases/compiler/typeCheckReturnExpression.ts new file mode 100644 index 00000000000..00f75912bd1 --- /dev/null +++ b/tests/cases/compiler/typeCheckReturnExpression.ts @@ -0,0 +1,2 @@ +//@noImplicitAny: true +var foo = () => undefined; \ No newline at end of file From 22cc3a7d848fa3adfbbeb58ec359dc5a201221c8 Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Tue, 2 Jun 2015 17:54:08 -0700 Subject: [PATCH 034/107] Add hopefully helpful comment --- src/compiler/checker.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index aa3b69d9b34..8ee39ab18f3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7455,6 +7455,11 @@ module ts { if (node.body) { if (!node.type) { + // There are some checks that are only performed in getReturnTypeFromBody, that may produce errors + // we need. An example is the noImplicitAny errors resulting from widening the return expression + // of a function. Because checking of function expression bodies is deferred, there was never an + // appropriate time to do this during the main walk of the file (see the comment at the top of + // checkFunctionExpressionBodies). So it must be done now. getReturnTypeOfSignature(getSignatureFromDeclaration(node)); } From 9394c5ca04231ec17626ea4867042dcfd61b0443 Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Tue, 2 Jun 2015 18:06:05 -0700 Subject: [PATCH 035/107] Add test for object literal methods --- .../typeCheckReturnExpressionMethodBody.errors.txt | 7 +++++++ .../reference/typeCheckReturnExpressionMethodBody.js | 5 +++++ .../cases/compiler/typeCheckReturnExpressionMethodBody.ts | 2 ++ 3 files changed, 14 insertions(+) create mode 100644 tests/baselines/reference/typeCheckReturnExpressionMethodBody.errors.txt create mode 100644 tests/baselines/reference/typeCheckReturnExpressionMethodBody.js create mode 100644 tests/cases/compiler/typeCheckReturnExpressionMethodBody.ts diff --git a/tests/baselines/reference/typeCheckReturnExpressionMethodBody.errors.txt b/tests/baselines/reference/typeCheckReturnExpressionMethodBody.errors.txt new file mode 100644 index 00000000000..a32f6548c9f --- /dev/null +++ b/tests/baselines/reference/typeCheckReturnExpressionMethodBody.errors.txt @@ -0,0 +1,7 @@ +tests/cases/compiler/typeCheckReturnExpressionMethodBody.ts(1,13): error TS7010: 'bar', which lacks return-type annotation, implicitly has an 'any' return type. + + +==== tests/cases/compiler/typeCheckReturnExpressionMethodBody.ts (1 errors) ==== + var foo = { bar() { return undefined } }; + ~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS7010: 'bar', which lacks return-type annotation, implicitly has an 'any' return type. \ No newline at end of file diff --git a/tests/baselines/reference/typeCheckReturnExpressionMethodBody.js b/tests/baselines/reference/typeCheckReturnExpressionMethodBody.js new file mode 100644 index 00000000000..3050b05268f --- /dev/null +++ b/tests/baselines/reference/typeCheckReturnExpressionMethodBody.js @@ -0,0 +1,5 @@ +//// [typeCheckReturnExpressionMethodBody.ts] +var foo = { bar() { return undefined } }; + +//// [typeCheckReturnExpressionMethodBody.js] +var foo = { bar: function () { return undefined; } }; diff --git a/tests/cases/compiler/typeCheckReturnExpressionMethodBody.ts b/tests/cases/compiler/typeCheckReturnExpressionMethodBody.ts new file mode 100644 index 00000000000..316572466df --- /dev/null +++ b/tests/cases/compiler/typeCheckReturnExpressionMethodBody.ts @@ -0,0 +1,2 @@ +//@noImplicitAny: true +var foo = { bar() { return undefined } }; \ No newline at end of file From 34a5514fef25125b56dfff49fb0357aee2d1bb90 Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Tue, 2 Jun 2015 18:21:39 -0700 Subject: [PATCH 036/107] Rename new test --- .../reference/typeCheckObjectLiteralMethodBody.errors.txt | 7 +++++++ ...onMethodBody.js => typeCheckObjectLiteralMethodBody.js} | 4 ++-- .../typeCheckReturnExpressionMethodBody.errors.txt | 7 ------- ...onMethodBody.ts => typeCheckObjectLiteralMethodBody.ts} | 0 4 files changed, 9 insertions(+), 9 deletions(-) create mode 100644 tests/baselines/reference/typeCheckObjectLiteralMethodBody.errors.txt rename tests/baselines/reference/{typeCheckReturnExpressionMethodBody.js => typeCheckObjectLiteralMethodBody.js} (50%) delete mode 100644 tests/baselines/reference/typeCheckReturnExpressionMethodBody.errors.txt rename tests/cases/compiler/{typeCheckReturnExpressionMethodBody.ts => typeCheckObjectLiteralMethodBody.ts} (100%) diff --git a/tests/baselines/reference/typeCheckObjectLiteralMethodBody.errors.txt b/tests/baselines/reference/typeCheckObjectLiteralMethodBody.errors.txt new file mode 100644 index 00000000000..7db4c2506cc --- /dev/null +++ b/tests/baselines/reference/typeCheckObjectLiteralMethodBody.errors.txt @@ -0,0 +1,7 @@ +tests/cases/compiler/typeCheckObjectLiteralMethodBody.ts(1,13): error TS7010: 'bar', which lacks return-type annotation, implicitly has an 'any' return type. + + +==== tests/cases/compiler/typeCheckObjectLiteralMethodBody.ts (1 errors) ==== + var foo = { bar() { return undefined } }; + ~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS7010: 'bar', which lacks return-type annotation, implicitly has an 'any' return type. \ No newline at end of file diff --git a/tests/baselines/reference/typeCheckReturnExpressionMethodBody.js b/tests/baselines/reference/typeCheckObjectLiteralMethodBody.js similarity index 50% rename from tests/baselines/reference/typeCheckReturnExpressionMethodBody.js rename to tests/baselines/reference/typeCheckObjectLiteralMethodBody.js index 3050b05268f..1339315e93c 100644 --- a/tests/baselines/reference/typeCheckReturnExpressionMethodBody.js +++ b/tests/baselines/reference/typeCheckObjectLiteralMethodBody.js @@ -1,5 +1,5 @@ -//// [typeCheckReturnExpressionMethodBody.ts] +//// [typeCheckObjectLiteralMethodBody.ts] var foo = { bar() { return undefined } }; -//// [typeCheckReturnExpressionMethodBody.js] +//// [typeCheckObjectLiteralMethodBody.js] var foo = { bar: function () { return undefined; } }; diff --git a/tests/baselines/reference/typeCheckReturnExpressionMethodBody.errors.txt b/tests/baselines/reference/typeCheckReturnExpressionMethodBody.errors.txt deleted file mode 100644 index a32f6548c9f..00000000000 --- a/tests/baselines/reference/typeCheckReturnExpressionMethodBody.errors.txt +++ /dev/null @@ -1,7 +0,0 @@ -tests/cases/compiler/typeCheckReturnExpressionMethodBody.ts(1,13): error TS7010: 'bar', which lacks return-type annotation, implicitly has an 'any' return type. - - -==== tests/cases/compiler/typeCheckReturnExpressionMethodBody.ts (1 errors) ==== - var foo = { bar() { return undefined } }; - ~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS7010: 'bar', which lacks return-type annotation, implicitly has an 'any' return type. \ No newline at end of file diff --git a/tests/cases/compiler/typeCheckReturnExpressionMethodBody.ts b/tests/cases/compiler/typeCheckObjectLiteralMethodBody.ts similarity index 100% rename from tests/cases/compiler/typeCheckReturnExpressionMethodBody.ts rename to tests/cases/compiler/typeCheckObjectLiteralMethodBody.ts From 1bb46e3f332c41612b166fc12608b34f02809c92 Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Wed, 3 Jun 2015 13:39:25 -0700 Subject: [PATCH 037/107] Update LKG after commit 34a5514fef25125b56dfff49fb0357aee2d1bb90 --- bin/tsc.js | 30 ++++++++++++++++++---- bin/tsserver.js | 39 +++++++++++++++++++++++------ bin/typescript.js | 52 +++++++++++++++++++++++++++++++++------ bin/typescriptServices.js | 52 +++++++++++++++++++++++++++++++++------ 4 files changed, 147 insertions(+), 26 deletions(-) diff --git a/bin/tsc.js b/bin/tsc.js index 01d312f2083..a6d28976046 100644 --- a/bin/tsc.js +++ b/bin/tsc.js @@ -4688,6 +4688,21 @@ var ts; return result; } ts.convertToBase64 = convertToBase64; + var carriageReturnLineFeed = "\r\n"; + var lineFeed = "\n"; + function getNewLineCharacter(options) { + if (options.newLine === 0) { + return carriageReturnLineFeed; + } + else if (options.newLine === 1) { + return lineFeed; + } + else if (ts.sys) { + return ts.sys.newLine; + } + return carriageReturnLineFeed; + } + ts.getNewLineCharacter = getNewLineCharacter; })(ts || (ts = {})); var ts; (function (ts) { @@ -14454,6 +14469,9 @@ var ts; checkIfNonVoidFunctionHasReturnExpressionsOrSingleThrowStatment(node, getTypeFromTypeNode(node.type)); } if (node.body) { + if (!node.type) { + getReturnTypeOfSignature(getSignatureFromDeclaration(node)); + } if (node.body.kind === 180) { checkSourceElement(node.body); } @@ -25062,8 +25080,6 @@ var ts; ts.ioReadTime = 0; ts.ioWriteTime = 0; ts.version = "1.5.3"; - var carriageReturnLineFeed = "\r\n"; - var lineFeed = "\n"; function findConfigFile(searchPath) { var fileName = "tsconfig.json"; while (true) { @@ -25134,9 +25150,7 @@ var ts; } } } - var newLine = options.newLine === 0 ? carriageReturnLineFeed : - options.newLine === 1 ? lineFeed : - ts.sys.newLine; + var newLine = ts.getNewLineCharacter(options); return { getSourceFile: getSourceFile, getDefaultLibFileName: function (options) { return ts.combinePaths(ts.getDirectoryPath(ts.normalizePath(ts.sys.getExecutingFilePath())), ts.getDefaultLibFileName(options)); }, @@ -25204,6 +25218,7 @@ var ts; getGlobalDiagnostics: getGlobalDiagnostics, getSemanticDiagnostics: getSemanticDiagnostics, getDeclarationDiagnostics: getDeclarationDiagnostics, + getCompilerOptionsDiagnostics: getCompilerOptionsDiagnostics, getTypeChecker: getTypeChecker, getDiagnosticsProducingTypeChecker: getDiagnosticsProducingTypeChecker, getCommonSourceDirectory: function () { return commonSourceDirectory; }, @@ -25284,6 +25299,11 @@ var ts; return ts.getDeclarationDiagnostics(getEmitHost(writeFile), resolver, sourceFile); } } + function getCompilerOptionsDiagnostics() { + var allDiagnostics = []; + ts.addRange(allDiagnostics, diagnostics.getGlobalDiagnostics()); + return ts.sortAndDeduplicateDiagnostics(allDiagnostics); + } function getGlobalDiagnostics() { var typeChecker = getDiagnosticsProducingTypeChecker(); var allDiagnostics = []; diff --git a/bin/tsserver.js b/bin/tsserver.js index 6cdb8f9560c..194f0768196 100644 --- a/bin/tsserver.js +++ b/bin/tsserver.js @@ -4565,6 +4565,21 @@ var ts; return result; } ts.convertToBase64 = convertToBase64; + var carriageReturnLineFeed = "\r\n"; + var lineFeed = "\n"; + function getNewLineCharacter(options) { + if (options.newLine === 0) { + return carriageReturnLineFeed; + } + else if (options.newLine === 1) { + return lineFeed; + } + else if (ts.sys) { + return ts.sys.newLine; + } + return carriageReturnLineFeed; + } + ts.getNewLineCharacter = getNewLineCharacter; })(ts || (ts = {})); var ts; (function (ts) { @@ -14844,6 +14859,9 @@ var ts; checkIfNonVoidFunctionHasReturnExpressionsOrSingleThrowStatment(node, getTypeFromTypeNode(node.type)); } if (node.body) { + if (!node.type) { + getReturnTypeOfSignature(getSignatureFromDeclaration(node)); + } if (node.body.kind === 180) { checkSourceElement(node.body); } @@ -25452,8 +25470,6 @@ var ts; ts.ioReadTime = 0; ts.ioWriteTime = 0; ts.version = "1.5.3"; - var carriageReturnLineFeed = "\r\n"; - var lineFeed = "\n"; function findConfigFile(searchPath) { var fileName = "tsconfig.json"; while (true) { @@ -25524,9 +25540,7 @@ var ts; } } } - var newLine = options.newLine === 0 ? carriageReturnLineFeed : - options.newLine === 1 ? lineFeed : - ts.sys.newLine; + var newLine = ts.getNewLineCharacter(options); return { getSourceFile: getSourceFile, getDefaultLibFileName: function (options) { return ts.combinePaths(ts.getDirectoryPath(ts.normalizePath(ts.sys.getExecutingFilePath())), ts.getDefaultLibFileName(options)); }, @@ -25594,6 +25608,7 @@ var ts; getGlobalDiagnostics: getGlobalDiagnostics, getSemanticDiagnostics: getSemanticDiagnostics, getDeclarationDiagnostics: getDeclarationDiagnostics, + getCompilerOptionsDiagnostics: getCompilerOptionsDiagnostics, getTypeChecker: getTypeChecker, getDiagnosticsProducingTypeChecker: getDiagnosticsProducingTypeChecker, getCommonSourceDirectory: function () { return commonSourceDirectory; }, @@ -25674,6 +25689,11 @@ var ts; return ts.getDeclarationDiagnostics(getEmitHost(writeFile), resolver, sourceFile); } } + function getCompilerOptionsDiagnostics() { + var allDiagnostics = []; + ts.addRange(allDiagnostics, diagnostics.getGlobalDiagnostics()); + return ts.sortAndDeduplicateDiagnostics(allDiagnostics); + } function getGlobalDiagnostics() { var typeChecker = getDiagnosticsProducingTypeChecker(); var allDiagnostics = []; @@ -31379,11 +31399,14 @@ var ts; var options = compilerOptions ? ts.clone(compilerOptions) : getDefaultCompilerOptions(); options.isolatedModules = true; options.allowNonTsExtensions = true; + options.noLib = true; + options.noResolve = true; var inputFileName = fileName || "module.ts"; var sourceFile = ts.createSourceFile(inputFileName, input, options.target); if (diagnostics && sourceFile.parseDiagnostics) { diagnostics.push.apply(diagnostics, sourceFile.parseDiagnostics); } + var newLine = ts.getNewLineCharacter(options); var outputText; var compilerHost = { getSourceFile: function (fileName, target) { return fileName === inputFileName ? sourceFile : undefined; }, @@ -31395,11 +31418,11 @@ var ts; useCaseSensitiveFileNames: function () { return false; }, getCanonicalFileName: function (fileName) { return fileName; }, getCurrentDirectory: function () { return ""; }, - getNewLine: function () { return (ts.sys && ts.sys.newLine) || "\r\n"; } + getNewLine: function () { return newLine; } }; var program = ts.createProgram([inputFileName], options, compilerHost); if (diagnostics) { - diagnostics.push.apply(diagnostics, program.getGlobalDiagnostics()); + diagnostics.push.apply(diagnostics, program.getCompilerOptionsDiagnostics()); } program.emit(); ts.Debug.assert(outputText !== undefined, "Output generation failed"); @@ -31914,10 +31937,12 @@ var ts; } } } + hostCache = undefined; program = newProgram; program.getTypeChecker(); return; function getOrCreateSourceFile(fileName) { + ts.Debug.assert(hostCache !== undefined); var hostFileInformation = hostCache.getOrCreateEntry(fileName); if (!hostFileInformation) { return undefined; diff --git a/bin/typescript.js b/bin/typescript.js index dbede84a76e..dac610e2504 100644 --- a/bin/typescript.js +++ b/bin/typescript.js @@ -5793,6 +5793,21 @@ var ts; return result; } ts.convertToBase64 = convertToBase64; + var carriageReturnLineFeed = "\r\n"; + var lineFeed = "\n"; + function getNewLineCharacter(options) { + if (options.newLine === 0 /* CarriageReturnLineFeed */) { + return carriageReturnLineFeed; + } + else if (options.newLine === 1 /* LineFeed */) { + return lineFeed; + } + else if (ts.sys) { + return ts.sys.newLine; + } + return carriageReturnLineFeed; + } + ts.getNewLineCharacter = getNewLineCharacter; })(ts || (ts = {})); var ts; (function (ts) { @@ -17596,6 +17611,14 @@ var ts; checkIfNonVoidFunctionHasReturnExpressionsOrSingleThrowStatment(node, getTypeFromTypeNode(node.type)); } if (node.body) { + if (!node.type) { + // There are some checks that are only performed in getReturnTypeFromBody, that may produce errors + // we need. An example is the noImplicitAny errors resulting from widening the return expression + // of a function. Because checking of function expression bodies is deferred, there was never an + // appropriate time to do this during the main walk of the file (see the comment at the top of + // checkFunctionExpressionBodies). So it must be done now. + getReturnTypeOfSignature(getSignatureFromDeclaration(node)); + } if (node.body.kind === 180 /* Block */) { checkSourceElement(node.body); } @@ -29658,8 +29681,6 @@ var ts; /* @internal */ ts.ioWriteTime = 0; /** The version of the TypeScript compiler release */ ts.version = "1.5.3"; - var carriageReturnLineFeed = "\r\n"; - var lineFeed = "\n"; function findConfigFile(searchPath) { var fileName = "tsconfig.json"; while (true) { @@ -29733,9 +29754,7 @@ var ts; } } } - var newLine = options.newLine === 0 /* CarriageReturnLineFeed */ ? carriageReturnLineFeed : - options.newLine === 1 /* LineFeed */ ? lineFeed : - ts.sys.newLine; + var newLine = ts.getNewLineCharacter(options); return { getSourceFile: getSourceFile, getDefaultLibFileName: function (options) { return ts.combinePaths(ts.getDirectoryPath(ts.normalizePath(ts.sys.getExecutingFilePath())), ts.getDefaultLibFileName(options)); }, @@ -29803,6 +29822,7 @@ var ts; getGlobalDiagnostics: getGlobalDiagnostics, getSemanticDiagnostics: getSemanticDiagnostics, getDeclarationDiagnostics: getDeclarationDiagnostics, + getCompilerOptionsDiagnostics: getCompilerOptionsDiagnostics, getTypeChecker: getTypeChecker, getDiagnosticsProducingTypeChecker: getDiagnosticsProducingTypeChecker, getCommonSourceDirectory: function () { return commonSourceDirectory; }, @@ -29894,6 +29914,11 @@ var ts; return ts.getDeclarationDiagnostics(getEmitHost(writeFile), resolver, sourceFile); } } + function getCompilerOptionsDiagnostics() { + var allDiagnostics = []; + ts.addRange(allDiagnostics, diagnostics.getGlobalDiagnostics()); + return ts.sortAndDeduplicateDiagnostics(allDiagnostics); + } function getGlobalDiagnostics() { var typeChecker = getDiagnosticsProducingTypeChecker(); var allDiagnostics = []; @@ -36695,12 +36720,20 @@ var ts; * Extra compiler options that will unconditionally be used bu this function are: * - isolatedModules = true * - allowNonTsExtensions = true + * - noLib = true + * - noResolve = true */ function transpile(input, compilerOptions, fileName, diagnostics) { var options = compilerOptions ? ts.clone(compilerOptions) : getDefaultCompilerOptions(); options.isolatedModules = true; // Filename can be non-ts file. options.allowNonTsExtensions = true; + // We are not returning a sourceFile for lib file when asked by the program, + // so pass --noLib to avoid reporting a file not found error. + options.noLib = true; + // We are not doing a full typecheck, we are not resolving the whole context, + // so pass --noResolve to avoid reporting missing file errors. + options.noResolve = true; // Parse var inputFileName = fileName || "module.ts"; var sourceFile = ts.createSourceFile(inputFileName, input, options.target); @@ -36708,6 +36741,7 @@ var ts; if (diagnostics && sourceFile.parseDiagnostics) { diagnostics.push.apply(diagnostics, sourceFile.parseDiagnostics); } + var newLine = ts.getNewLineCharacter(options); // Output var outputText; // Create a compilerHost object to allow the compiler to read and write files @@ -36721,11 +36755,11 @@ var ts; useCaseSensitiveFileNames: function () { return false; }, getCanonicalFileName: function (fileName) { return fileName; }, getCurrentDirectory: function () { return ""; }, - getNewLine: function () { return (ts.sys && ts.sys.newLine) || "\r\n"; } + getNewLine: function () { return newLine; } }; var program = ts.createProgram([inputFileName], options, compilerHost); if (diagnostics) { - diagnostics.push.apply(diagnostics, program.getGlobalDiagnostics()); + diagnostics.push.apply(diagnostics, program.getCompilerOptionsDiagnostics()); } // Emit program.emit(); @@ -37328,12 +37362,16 @@ var ts; } } } + // hostCache is captured in the closure for 'getOrCreateSourceFile' but it should not be used past this point. + // It needs to be cleared to allow all collected snapshots to be released + hostCache = undefined; program = newProgram; // Make sure all the nodes in the program are both bound, and have their parent // pointers set property. program.getTypeChecker(); return; function getOrCreateSourceFile(fileName) { + ts.Debug.assert(hostCache !== undefined); // The program is asking for this file, check first if the host can locate it. // If the host can not locate the file, then it does not exist. return undefined // to the program to allow reporting of errors for missing files. diff --git a/bin/typescriptServices.js b/bin/typescriptServices.js index dbede84a76e..dac610e2504 100644 --- a/bin/typescriptServices.js +++ b/bin/typescriptServices.js @@ -5793,6 +5793,21 @@ var ts; return result; } ts.convertToBase64 = convertToBase64; + var carriageReturnLineFeed = "\r\n"; + var lineFeed = "\n"; + function getNewLineCharacter(options) { + if (options.newLine === 0 /* CarriageReturnLineFeed */) { + return carriageReturnLineFeed; + } + else if (options.newLine === 1 /* LineFeed */) { + return lineFeed; + } + else if (ts.sys) { + return ts.sys.newLine; + } + return carriageReturnLineFeed; + } + ts.getNewLineCharacter = getNewLineCharacter; })(ts || (ts = {})); var ts; (function (ts) { @@ -17596,6 +17611,14 @@ var ts; checkIfNonVoidFunctionHasReturnExpressionsOrSingleThrowStatment(node, getTypeFromTypeNode(node.type)); } if (node.body) { + if (!node.type) { + // There are some checks that are only performed in getReturnTypeFromBody, that may produce errors + // we need. An example is the noImplicitAny errors resulting from widening the return expression + // of a function. Because checking of function expression bodies is deferred, there was never an + // appropriate time to do this during the main walk of the file (see the comment at the top of + // checkFunctionExpressionBodies). So it must be done now. + getReturnTypeOfSignature(getSignatureFromDeclaration(node)); + } if (node.body.kind === 180 /* Block */) { checkSourceElement(node.body); } @@ -29658,8 +29681,6 @@ var ts; /* @internal */ ts.ioWriteTime = 0; /** The version of the TypeScript compiler release */ ts.version = "1.5.3"; - var carriageReturnLineFeed = "\r\n"; - var lineFeed = "\n"; function findConfigFile(searchPath) { var fileName = "tsconfig.json"; while (true) { @@ -29733,9 +29754,7 @@ var ts; } } } - var newLine = options.newLine === 0 /* CarriageReturnLineFeed */ ? carriageReturnLineFeed : - options.newLine === 1 /* LineFeed */ ? lineFeed : - ts.sys.newLine; + var newLine = ts.getNewLineCharacter(options); return { getSourceFile: getSourceFile, getDefaultLibFileName: function (options) { return ts.combinePaths(ts.getDirectoryPath(ts.normalizePath(ts.sys.getExecutingFilePath())), ts.getDefaultLibFileName(options)); }, @@ -29803,6 +29822,7 @@ var ts; getGlobalDiagnostics: getGlobalDiagnostics, getSemanticDiagnostics: getSemanticDiagnostics, getDeclarationDiagnostics: getDeclarationDiagnostics, + getCompilerOptionsDiagnostics: getCompilerOptionsDiagnostics, getTypeChecker: getTypeChecker, getDiagnosticsProducingTypeChecker: getDiagnosticsProducingTypeChecker, getCommonSourceDirectory: function () { return commonSourceDirectory; }, @@ -29894,6 +29914,11 @@ var ts; return ts.getDeclarationDiagnostics(getEmitHost(writeFile), resolver, sourceFile); } } + function getCompilerOptionsDiagnostics() { + var allDiagnostics = []; + ts.addRange(allDiagnostics, diagnostics.getGlobalDiagnostics()); + return ts.sortAndDeduplicateDiagnostics(allDiagnostics); + } function getGlobalDiagnostics() { var typeChecker = getDiagnosticsProducingTypeChecker(); var allDiagnostics = []; @@ -36695,12 +36720,20 @@ var ts; * Extra compiler options that will unconditionally be used bu this function are: * - isolatedModules = true * - allowNonTsExtensions = true + * - noLib = true + * - noResolve = true */ function transpile(input, compilerOptions, fileName, diagnostics) { var options = compilerOptions ? ts.clone(compilerOptions) : getDefaultCompilerOptions(); options.isolatedModules = true; // Filename can be non-ts file. options.allowNonTsExtensions = true; + // We are not returning a sourceFile for lib file when asked by the program, + // so pass --noLib to avoid reporting a file not found error. + options.noLib = true; + // We are not doing a full typecheck, we are not resolving the whole context, + // so pass --noResolve to avoid reporting missing file errors. + options.noResolve = true; // Parse var inputFileName = fileName || "module.ts"; var sourceFile = ts.createSourceFile(inputFileName, input, options.target); @@ -36708,6 +36741,7 @@ var ts; if (diagnostics && sourceFile.parseDiagnostics) { diagnostics.push.apply(diagnostics, sourceFile.parseDiagnostics); } + var newLine = ts.getNewLineCharacter(options); // Output var outputText; // Create a compilerHost object to allow the compiler to read and write files @@ -36721,11 +36755,11 @@ var ts; useCaseSensitiveFileNames: function () { return false; }, getCanonicalFileName: function (fileName) { return fileName; }, getCurrentDirectory: function () { return ""; }, - getNewLine: function () { return (ts.sys && ts.sys.newLine) || "\r\n"; } + getNewLine: function () { return newLine; } }; var program = ts.createProgram([inputFileName], options, compilerHost); if (diagnostics) { - diagnostics.push.apply(diagnostics, program.getGlobalDiagnostics()); + diagnostics.push.apply(diagnostics, program.getCompilerOptionsDiagnostics()); } // Emit program.emit(); @@ -37328,12 +37362,16 @@ var ts; } } } + // hostCache is captured in the closure for 'getOrCreateSourceFile' but it should not be used past this point. + // It needs to be cleared to allow all collected snapshots to be released + hostCache = undefined; program = newProgram; // Make sure all the nodes in the program are both bound, and have their parent // pointers set property. program.getTypeChecker(); return; function getOrCreateSourceFile(fileName) { + ts.Debug.assert(hostCache !== undefined); // The program is asking for this file, check first if the host can locate it. // If the host can not locate the file, then it does not exist. return undefined // to the program to allow reporting of errors for missing files. From c7b2fe016d06fd4c9da9b4b44a61ea1288fd5b07 Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Wed, 3 Jun 2015 13:40:36 -0700 Subject: [PATCH 038/107] Remove the DocumentEvent itself from createEvent overload. --- src/lib/dom.generated.d.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/dom.generated.d.ts b/src/lib/dom.generated.d.ts index d9daefa1aeb..31bf794d8fd 100644 --- a/src/lib/dom.generated.d.ts +++ b/src/lib/dom.generated.d.ts @@ -12340,7 +12340,6 @@ interface DocumentEvent { createEvent(eventInterface:"CustomEvent"): CustomEvent; createEvent(eventInterface:"DeviceMotionEvent"): DeviceMotionEvent; createEvent(eventInterface:"DeviceOrientationEvent"): DeviceOrientationEvent; - createEvent(eventInterface:"DocumentEvent"): DocumentEvent; createEvent(eventInterface:"DragEvent"): DragEvent; createEvent(eventInterface:"ErrorEvent"): ErrorEvent; createEvent(eventInterface:"Event"): Event; From 3fe308d2a6b642704942cb4b1ee8fe8438d22e3f Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 3 Jun 2015 13:46:13 -0700 Subject: [PATCH 039/107] Added an explanation for the lookahead. --- src/compiler/parser.ts | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 72cd3bb620d..914952d5169 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3973,7 +3973,7 @@ module ts { case SyntaxKind.ThrowKeyword: return parseThrowStatement(); case SyntaxKind.TryKeyword: - // Include the next two for error recovery. + // Include 'catch' and 'finally' for error recovery. case SyntaxKind.CatchKeyword: case SyntaxKind.FinallyKeyword: return parseTryStatement(); @@ -3981,6 +3981,33 @@ module ts { return parseDebuggerStatement(); case SyntaxKind.AtToken: return parseDeclaration(); + + case SyntaxKind.ConstKeyword: + case SyntaxKind.EnumKeyword: + case SyntaxKind.ExportKeyword: + case SyntaxKind.ImportKeyword: + case SyntaxKind.InterfaceKeyword: + case SyntaxKind.PrivateKeyword: + case SyntaxKind.ProtectedKeyword: + case SyntaxKind.PublicKeyword: + case SyntaxKind.StaticKeyword: + if (getDeclarationFlags() & flags) { + return parseDeclaration(); + } + break; + + // 'declare', 'module', 'namespace', and 'type' are all legal JavaScript identifiers when ASI + // takes effect. In such cases, we cannot parse out the "expected" declarations. For instance, while + // + // namespace n + // + // can be none other than the beginning of a namespace declaration, JavaScript sees + // + // namespace + // n + // + // as the identifier 'namespace' on one line followed by the identifier 'n' on another. + // We need to look one token ahead to see if it permissible to try parsing a declaration. case SyntaxKind.DeclareKeyword: if (lookAhead(isFollowedByIdentifierOrKeywordOnSameLine) && getDeclarationFlags() & flags) { return parseDeclaration(); @@ -3997,19 +4024,6 @@ module ts { return parseDeclaration(); } break; - case SyntaxKind.ConstKeyword: - case SyntaxKind.EnumKeyword: - case SyntaxKind.ExportKeyword: - case SyntaxKind.ImportKeyword: - case SyntaxKind.InterfaceKeyword: - case SyntaxKind.PrivateKeyword: - case SyntaxKind.ProtectedKeyword: - case SyntaxKind.PublicKeyword: - case SyntaxKind.StaticKeyword: - if (getDeclarationFlags() & flags) { - return parseDeclaration(); - } - break; } return parseExpressionOrLabeledStatement(); } From 269ae3ab995847d0e0db00d546486cfbfbf24ff7 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Wed, 3 Jun 2015 13:48:34 -0700 Subject: [PATCH 040/107] introduce FileMap to store mappings with filenames as keys --- src/compiler/core.ts | 32 +++++++++++++++++++++++ src/compiler/program.ts | 17 ++++++------ src/services/services.ts | 56 +++++++++++++++++++++------------------- src/services/shims.ts | 10 ++++++- 4 files changed, 80 insertions(+), 35 deletions(-) diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 281bfa36ece..b798bd8771d 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -15,6 +15,38 @@ module ts { True = -1 } + export class FileMap { + private files: Map = {}; + + constructor(private getCanonicalFileName: (fileName: string) => string) { + } + + public set(fileName: string, value: T) { + this.files[this.normalizeKey(fileName)] = value; + } + + public get(fileName: string) { + return this.files[this.normalizeKey(fileName)]; + } + + public contains(fileName: string) { + return hasProperty(this.files, this.normalizeKey(fileName)); + } + + public delete(fileName: string) { + let key = this.normalizeKey(fileName); + delete this.files[key]; + } + + public forEachValue(f: (value: T) => void) { + forEachValue(this.files, f); + } + + private normalizeKey(key: string) { + return this.getCanonicalFileName(normalizeSlashes(key)); + } + } + export const enum Comparison { LessThan = -1, EqualTo = 0, diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 955e24fd1de..dd693b55907 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -149,7 +149,6 @@ module ts { export function createProgram(rootNames: string[], options: CompilerOptions, host?: CompilerHost): Program { let program: Program; let files: SourceFile[] = []; - let filesByName: Map = {}; let diagnostics = createDiagnosticCollection(); let seenNoDefaultLib = options.noLib; let commonSourceDirectory: string; @@ -159,6 +158,8 @@ module ts { let start = new Date().getTime(); host = host || createCompilerHost(options); + let filesByName: FileMap = new FileMap(host.getCanonicalFileName); + forEach(rootNames, name => processRootFile(name, false)); if (!seenNoDefaultLib) { processRootFile(host.getDefaultLibFileName(options), true); @@ -238,8 +239,7 @@ module ts { } function getSourceFile(fileName: string) { - fileName = host.getCanonicalFileName(normalizeSlashes(fileName)); - return hasProperty(filesByName, fileName) ? filesByName[fileName] : undefined; + return filesByName.get(fileName); } function getDiagnosticsHelper(sourceFile: SourceFile, getDiagnostics: (sourceFile: SourceFile) => Diagnostic[]): Diagnostic[] { @@ -358,19 +358,19 @@ module ts { // Get source file from normalized fileName function findSourceFile(fileName: string, isDefaultLib: boolean, refFile?: SourceFile, refStart?: number, refLength?: number): SourceFile { let canonicalName = host.getCanonicalFileName(normalizeSlashes(fileName)); - if (hasProperty(filesByName, canonicalName)) { + if (filesByName.contains(canonicalName)) { // We've already looked for this file, use cached result return getSourceFileFromCache(fileName, canonicalName, /*useAbsolutePath*/ false); } else { let normalizedAbsolutePath = getNormalizedAbsolutePath(fileName, host.getCurrentDirectory()); let canonicalAbsolutePath = host.getCanonicalFileName(normalizedAbsolutePath); - if (hasProperty(filesByName, canonicalAbsolutePath)) { + if (filesByName.contains(canonicalAbsolutePath)) { return getSourceFileFromCache(normalizedAbsolutePath, canonicalAbsolutePath, /*useAbsolutePath*/ true); } // We haven't looked for this file, do so now and cache result - let file = filesByName[canonicalName] = host.getSourceFile(fileName, options.target, hostErrorMessage => { + let file = host.getSourceFile(fileName, options.target, hostErrorMessage => { if (refFile) { diagnostics.add(createFileDiagnostic(refFile, refStart, refLength, Diagnostics.Cannot_read_file_0_Colon_1, fileName, hostErrorMessage)); @@ -379,11 +379,12 @@ module ts { diagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, fileName, hostErrorMessage)); } }); + filesByName.set(canonicalName, file); if (file) { seenNoDefaultLib = seenNoDefaultLib || file.hasNoDefaultLib; // Set the source file for normalized absolute path - filesByName[canonicalAbsolutePath] = file; + filesByName.set(canonicalAbsolutePath, file); if (!options.noResolve) { let basePath = getDirectoryPath(fileName); @@ -402,7 +403,7 @@ module ts { } function getSourceFileFromCache(fileName: string, canonicalName: string, useAbsolutePath: boolean): SourceFile { - let file = filesByName[canonicalName]; + let file = filesByName.get(canonicalName); if (file && host.useCaseSensitiveFileNames()) { let sourceFileName = useAbsolutePath ? getNormalizedAbsolutePath(file.fileName, host.getCurrentDirectory()) : file.fileName; if (canonicalName !== sourceFileName) { diff --git a/src/services/services.ts b/src/services/services.ts index 400bf754a00..908d9efbaca 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -960,6 +960,7 @@ module ts { log? (s: string): void; trace? (s: string): void; error? (s: string): void; + useCaseSensitiveFileNames? (): boolean; } // @@ -1632,12 +1633,12 @@ module ts { // at each language service public entry point, since we don't know when // set of scripts handled by the host changes. class HostCache { - private fileNameToEntry: Map; + private fileNameToEntry: FileMap; private _compilationSettings: CompilerOptions; - constructor(private host: LanguageServiceHost, private getCanonicalFileName: (fileName: string) => string) { + constructor(private host: LanguageServiceHost, getCanonicalFileName: (fileName: string) => string) { // script id => script index - this.fileNameToEntry = {}; + this.fileNameToEntry = new FileMap(getCanonicalFileName); // Initialize the list with the root file names let rootFileNames = host.getScriptFileNames(); @@ -1653,10 +1654,6 @@ module ts { return this._compilationSettings; } - private normalizeFileName(fileName: string): string { - return this.getCanonicalFileName(normalizeSlashes(fileName)); - } - private createEntry(fileName: string) { let entry: HostFileInformation; let scriptSnapshot = this.host.getScriptSnapshot(fileName); @@ -1668,15 +1665,16 @@ module ts { }; } - return this.fileNameToEntry[this.normalizeFileName(fileName)] = entry; + this.fileNameToEntry.set(fileName, entry); + return entry; } private getEntry(fileName: string): HostFileInformation { - return lookUp(this.fileNameToEntry, this.normalizeFileName(fileName)); + return this.fileNameToEntry.get(fileName); } private contains(fileName: string): boolean { - return hasProperty(this.fileNameToEntry, this.normalizeFileName(fileName)); + return this.fileNameToEntry.contains(fileName); } public getOrCreateEntry(fileName: string): HostFileInformation { @@ -1690,10 +1688,9 @@ module ts { public getRootFileNames(): string[] { let fileNames: string[] = []; - forEachKey(this.fileNameToEntry, key => { - let entry = this.getEntry(key); - if (entry) { - fileNames.push(entry.hostFileName); + this.fileNameToEntry.forEachValue(value => { + if (value) { + fileNames.push(value.hostFileName); } }); @@ -1873,20 +1870,28 @@ module ts { return createLanguageServiceSourceFile(sourceFile.fileName, scriptSnapshot, sourceFile.languageVersion, version, /*setNodeParents:*/ true); } - export function createDocumentRegistry(): DocumentRegistry { + function createGetCanonicalFileName(useCaseSensitivefileNames: boolean): (fileName: string) => string { + return useCaseSensitivefileNames + ? ((fileName) => fileName) + : ((fileName) => fileName.toLowerCase()); + } + + + export function createDocumentRegistry(useCaseSensitiveFileNames?: boolean): DocumentRegistry { // Maps from compiler setting target (ES3, ES5, etc.) to all the cached documents we have // for those settings. - let buckets: Map> = {}; + let buckets: Map> = {}; + let getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames || false); function getKeyFromCompilationSettings(settings: CompilerOptions): string { return "_" + settings.target; // + "|" + settings.propagateEnumConstantoString() } - function getBucketForCompilationSettings(settings: CompilerOptions, createIfMissing: boolean): Map { + function getBucketForCompilationSettings(settings: CompilerOptions, createIfMissing: boolean): FileMap { let key = getKeyFromCompilationSettings(settings); let bucket = lookUp(buckets, key); if (!bucket && createIfMissing) { - buckets[key] = bucket = {}; + buckets[key] = bucket = new FileMap(getCanonicalFileName); } return bucket; } @@ -1896,7 +1901,7 @@ module ts { let entries = lookUp(buckets, name); let sourceFiles: { name: string; refCount: number; references: string[]; }[] = []; for (let i in entries) { - let entry = entries[i]; + let entry = entries.get(i); sourceFiles.push({ name: i, refCount: entry.languageServiceRefCount, @@ -1928,18 +1933,19 @@ module ts { acquiring: boolean): SourceFile { let bucket = getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ true); - let entry = lookUp(bucket, fileName); + let entry = bucket.get(fileName); if (!entry) { Debug.assert(acquiring, "How could we be trying to update a document that the registry doesn't have?"); // Have never seen this file with these settings. Create a new source file for it. let sourceFile = createLanguageServiceSourceFile(fileName, scriptSnapshot, compilationSettings.target, version, /*setNodeParents:*/ false); - bucket[fileName] = entry = { + entry = { sourceFile: sourceFile, languageServiceRefCount: 0, owners: [] }; + bucket.set(fileName, entry); } else { // We have an entry for this file. However, it may be for a different version of @@ -1967,12 +1973,12 @@ module ts { let bucket = getBucketForCompilationSettings(compilationSettings, false); Debug.assert(bucket !== undefined); - let entry = lookUp(bucket, fileName); + let entry = bucket.get(fileName); entry.languageServiceRefCount--; Debug.assert(entry.languageServiceRefCount >= 0); if (entry.languageServiceRefCount === 0) { - delete bucket[fileName]; + bucket.delete(fileName); } } @@ -2400,9 +2406,7 @@ module ts { } } - function getCanonicalFileName(fileName: string) { - return useCaseSensitivefileNames ? fileName : fileName.toLowerCase(); - } + let getCanonicalFileName = createGetCanonicalFileName(useCaseSensitivefileNames); function getValidSourceFile(fileName: string): SourceFile { fileName = normalizeSlashes(fileName); diff --git a/src/services/shims.ts b/src/services/shims.ts index d3f59737538..4dfab444cde 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -56,6 +56,7 @@ module ts { getDefaultLibFileName(options: string): string; getNewLine?(): string; getProjectVersion?(): string; + useCaseSensitiveFileNames?(): boolean; } /** Public interface of the the of a config service shim instance.*/ @@ -270,6 +271,10 @@ module ts { return this.shimHost.getProjectVersion(); } + public useCaseSensitiveFileNames(): boolean { + return this.shimHost.useCaseSensitiveFileNames && this.useCaseSensitiveFileNames(); + } + public getCompilationSettings(): CompilerOptions { var settingsJson = this.shimHost.getCompilationSettings(); if (settingsJson == null || settingsJson == "") { @@ -909,7 +914,7 @@ module ts { export class TypeScriptServicesFactory implements ShimFactory { private _shims: Shim[] = []; - private documentRegistry: DocumentRegistry = createDocumentRegistry(); + private documentRegistry: DocumentRegistry; /* * Returns script API version. @@ -920,6 +925,9 @@ module ts { public createLanguageServiceShim(host: LanguageServiceShimHost): LanguageServiceShim { try { + if (this.documentRegistry === undefined) { + this.documentRegistry = createDocumentRegistry(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames()); + } var hostAdapter = new LanguageServiceShimHostAdapter(host); var languageService = createLanguageService(hostAdapter, this.documentRegistry); return new LanguageServiceShimObject(this, host, languageService); From 64a31e2e51e7911db411a6f22fa46896f23d7121 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 3 Jun 2015 13:51:53 -0700 Subject: [PATCH 041/107] Renamed functions, removed the duplicates found from renaming. --- src/compiler/parser.ts | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 914952d5169..b430a27e2b4 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2688,7 +2688,7 @@ module ts { function nextTokenIsIdentifierOnSameLine() { nextToken(); - return !scanner.hasPrecedingLineBreak() && isIdentifier() + return !scanner.hasPrecedingLineBreak() && isIdentifier(); } function parseYieldExpression(): YieldExpression { @@ -4009,18 +4009,18 @@ module ts { // as the identifier 'namespace' on one line followed by the identifier 'n' on another. // We need to look one token ahead to see if it permissible to try parsing a declaration. case SyntaxKind.DeclareKeyword: - if (lookAhead(isFollowedByIdentifierOrKeywordOnSameLine) && getDeclarationFlags() & flags) { + if (lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine) && getDeclarationFlags() & flags) { return parseDeclaration(); } break; case SyntaxKind.ModuleKeyword: - if (lookAhead(isFollowedByIdentifierOrStringOnSameLine) && getDeclarationFlags() & flags) { + if (lookAhead(nextTokenIsIdentifierOrStringLiteralOnSameLine) && getDeclarationFlags() & flags) { return parseDeclaration(); } break; case SyntaxKind.NamespaceKeyword: case SyntaxKind.TypeKeyword: - if (lookAhead(isFollowedByIdentifierOnSameLine) && getDeclarationFlags() & flags) { + if (lookAhead(nextTokenIsIdentifierOnSameLine) && getDeclarationFlags() & flags) { return parseDeclaration(); } break; @@ -4070,21 +4070,11 @@ module ts { } } - function isFollowedByIdentifierOrKeywordOnSameLine() { - nextToken(); - return !scanner.hasPrecedingLineBreak() && isIdentifierOrKeyword(); - } - - function isFollowedByIdentifierOrStringOnSameLine() { + function nextTokenIsIdentifierOrStringLiteralOnSameLine() { nextToken(); return !scanner.hasPrecedingLineBreak() && (isIdentifier() || token === SyntaxKind.StringLiteral); } - function isFollowedByIdentifierOnSameLine() { - nextToken(); - return !scanner.hasPrecedingLineBreak() && isIdentifier(); - } - function parseFunctionBlockOrSemicolon(isGenerator: boolean, diagnosticMessage?: DiagnosticMessage): Block { if (token !== SyntaxKind.OpenBraceToken && canParseSemicolon()) { parseSemicolon(); From cdb6d5bca5cafb37bc5efc0ab24e018d200d1c97 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 3 Jun 2015 13:56:55 -0700 Subject: [PATCH 042/107] Don't access the anyType directly. Encapsulate all access to it behind a helper. --- src/compiler/checker.ts | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index aa2207d5431..903d5964a44 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2131,6 +2131,10 @@ module ts { return prop ? getTypeOfSymbol(prop) : undefined; } + function isTheAnyType(type: Type) { + return type === anyType; + } + // Return the inferred type for a binding element function getTypeForBindingElement(declaration: BindingElement): Type { let pattern = declaration.parent; @@ -2142,7 +2146,7 @@ module ts { // If no type was specified or inferred for parent, or if the specified or inferred type is any, // infer from the initializer of the binding element if one is present. Otherwise, go with the // undefined or any type of the parent. - if (!parentType || parentType === anyType) { + if (!parentType || isTheAnyType(parentType)) { if (declaration.initializer) { return checkExpressionCached(declaration.initializer); } @@ -5547,7 +5551,7 @@ module ts { if (prototypeProperty) { // Target type is type of the protoype property let prototypePropertyType = getTypeOfSymbol(prototypeProperty); - if (prototypePropertyType !== anyType) { + if (!isTheAnyType(prototypePropertyType)) { targetType = prototypePropertyType; } } @@ -6496,7 +6500,7 @@ module ts { function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, right: Identifier) { let type = checkExpressionOrQualifiedName(left); if (type === unknownType) return type; - if (type !== anyType) { + if (!isTheAnyType(type)) { let apparentType = getApparentType(getWidenedType(type)); if (apparentType === unknownType) { // handle cases when type is Type parameter with invalid constraint @@ -6536,7 +6540,7 @@ module ts { : (node).left; let type = checkExpressionOrQualifiedName(left); - if (type !== unknownType && type !== anyType) { + if (type !== unknownType && !isTheAnyType(type)) { let prop = getPropertyOfType(getWidenedType(type), propertyName); if (prop && prop.parent && prop.parent.flags & SymbolFlags.Class) { if (left.kind === SyntaxKind.SuperKeyword && getDeclarationKindFromSymbol(prop) !== SyntaxKind.MethodDeclaration) { @@ -6626,7 +6630,7 @@ module ts { } // Fall back to any. - if (compilerOptions.noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors && objectType !== anyType) { + if (compilerOptions.noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors && !isTheAnyType(objectType)) { error(node, Diagnostics.Index_signature_of_object_type_implicitly_has_an_any_type); } @@ -7276,7 +7280,7 @@ module ts { // types are provided for the argument expressions, and the result is always of type Any. // We exclude union types because we may have a union of function types that happen to have // no common signatures. - if (funcType === anyType || (!callSignatures.length && !constructSignatures.length && !(funcType.flags & TypeFlags.Union) && isTypeAssignableTo(funcType, globalFunctionType))) { + if (isTheAnyType(funcType) || (!callSignatures.length && !constructSignatures.length && !(funcType.flags & TypeFlags.Union) && isTypeAssignableTo(funcType, globalFunctionType))) { if (node.typeArguments) { error(node, Diagnostics.Untyped_function_calls_may_not_accept_type_arguments); } @@ -7309,7 +7313,7 @@ module ts { // TS 1.0 spec: 4.11 // If ConstructExpr is of type Any, Args can be any argument // list and the result of the operation is of type Any. - if (expressionType === anyType) { + if (isTheAnyType(expressionType)) { if (node.typeArguments) { error(node, Diagnostics.Untyped_function_calls_may_not_accept_type_arguments); } @@ -7364,7 +7368,7 @@ module ts { let callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call); - if (tagType === anyType || (!callSignatures.length && !(tagType.flags & TypeFlags.Union) && isTypeAssignableTo(tagType, globalFunctionType))) { + if (isTheAnyType(tagType) || (!callSignatures.length && !(tagType.flags & TypeFlags.Union) && isTypeAssignableTo(tagType, globalFunctionType))) { return resolveUntypedCall(node); } @@ -7576,7 +7580,7 @@ module ts { } // Functions that return 'void' or 'any' don't need any return expressions. - if (returnType === voidType || returnType === anyType) { + if (returnType === voidType || isTheAnyType(returnType)) { return; } From dd8f3c41ad9eb06ddfd40b5d76a2cd4d2155b1db Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 3 Jun 2015 14:08:37 -0700 Subject: [PATCH 043/107] Addressing CR feedback --- src/compiler/checker.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c180d8425f2..45a40135be8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4306,6 +4306,7 @@ module ts { // Effectively, we will generate a false positive when two types are structurally equal to at least 10 levels, but unequal at // some level beyond that. function isDeeplyNestedGeneric(type: ObjectType, stack: ObjectType[]): boolean { + // We track type references (created by createTypeReference) and instantiated types (created by instantiateType) if (type.flags & (TypeFlags.Reference | TypeFlags.Instantiated) && depth >= 10) { let symbol = type.symbol; let count = 0; From 7e3a3f45e15cc8cd9f13106f8c3140cb5a63eaf9 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Wed, 3 Jun 2015 14:55:42 -0700 Subject: [PATCH 044/107] emit module name for system modules, add moduleName argument to 'transpile' function --- src/compiler/emitter.ts | 10 +++++++--- src/compiler/parser.ts | 2 +- src/compiler/types.ts | 2 +- src/services/services.ts | 7 +++++-- .../baselines/reference/systemModule12.errors.txt | 10 ++++++++++ tests/baselines/reference/systemModule12.js | 14 ++++++++++++++ tests/cases/compiler/systemModule12.ts | 5 +++++ 7 files changed, 43 insertions(+), 7 deletions(-) create mode 100644 tests/baselines/reference/systemModule12.errors.txt create mode 100644 tests/baselines/reference/systemModule12.js create mode 100644 tests/cases/compiler/systemModule12.ts diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index d0d65aec2fb..794d0d59382 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -5527,7 +5527,11 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { Debug.assert(!exportFunctionForFile); // make sure that name of 'exports' function does not conflict with existing identifiers exportFunctionForFile = makeUniqueName("exports"); - write("System.register(["); + write("System.register("); + if (node.moduleName) { + write(`"${node.moduleName}", `); + } + write("[") for (let i = 0; i < externalImports.length; ++i) { let text = getExternalModuleNameText(externalImports[i]); if (i !== 0) { @@ -5613,8 +5617,8 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { writeLine(); write("define("); - if (node.amdModuleName) { - write("\"" + node.amdModuleName + "\", "); + if (node.moduleName) { + write("\"" + node.moduleName + "\", "); } emitAMDDependencies(node, /*includeNonAmdDependencies*/ true); write(") {"); diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 80c70a250fb..9129a606f89 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -4895,7 +4895,7 @@ module ts { sourceFile.referencedFiles = referencedFiles; sourceFile.amdDependencies = amdDependencies; - sourceFile.amdModuleName = amdModuleName; + sourceFile.moduleName = amdModuleName; } function setExternalModuleIndicator(sourceFile: SourceFile) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 0fcf0e1f67a..a10c1c52c37 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1134,7 +1134,7 @@ module ts { text: string; amdDependencies: {path: string; name: string}[]; - amdModuleName: string; + moduleName: string; referencedFiles: FileReference[]; hasNoDefaultLib: boolean; diff --git a/src/services/services.ts b/src/services/services.ts index 400bf754a00..f56a41178a4 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -735,7 +735,7 @@ module ts { public endOfFileToken: Node; public amdDependencies: { name: string; path: string }[]; - public amdModuleName: string; + public moduleName: string; public referencedFiles: FileReference[]; public syntacticDiagnostics: Diagnostic[]; @@ -1766,7 +1766,7 @@ module ts { * - isolatedModules = true * - allowNonTsExtensions = true */ - export function transpile(input: string, compilerOptions?: CompilerOptions, fileName?: string, diagnostics?: Diagnostic[]): string { + export function transpile(input: string, compilerOptions?: CompilerOptions, fileName?: string, diagnostics?: Diagnostic[], moduleName?: string): string { let options = compilerOptions ? clone(compilerOptions) : getDefaultCompilerOptions(); options.isolatedModules = true; @@ -1777,6 +1777,9 @@ module ts { // Parse var inputFileName = fileName || "module.ts"; var sourceFile = createSourceFile(inputFileName, input, options.target); + if (moduleName) { + sourceFile.moduleName = moduleName; + } // Store syntactic diagnostics if (diagnostics && sourceFile.parseDiagnostics) { diff --git a/tests/baselines/reference/systemModule12.errors.txt b/tests/baselines/reference/systemModule12.errors.txt new file mode 100644 index 00000000000..5c89e2e65d6 --- /dev/null +++ b/tests/baselines/reference/systemModule12.errors.txt @@ -0,0 +1,10 @@ +tests/cases/compiler/systemModule12.ts(3,15): error TS2307: Cannot find module 'file1'. + + +==== tests/cases/compiler/systemModule12.ts (1 errors) ==== + + /// + import n from 'file1' + ~~~~~~~ +!!! error TS2307: Cannot find module 'file1'. + \ No newline at end of file diff --git a/tests/baselines/reference/systemModule12.js b/tests/baselines/reference/systemModule12.js new file mode 100644 index 00000000000..0b5f5a3e850 --- /dev/null +++ b/tests/baselines/reference/systemModule12.js @@ -0,0 +1,14 @@ +//// [systemModule12.ts] + +/// +import n from 'file1' + + +//// [systemModule12.js] +System.register("NamedModule", [], function(exports_1) { + return { + setters:[], + execute: function() { + } + } +}); diff --git a/tests/cases/compiler/systemModule12.ts b/tests/cases/compiler/systemModule12.ts new file mode 100644 index 00000000000..690fabc0a28 --- /dev/null +++ b/tests/cases/compiler/systemModule12.ts @@ -0,0 +1,5 @@ +// @module: system +// @isolatedModules: true + +/// +import n from 'file1' From 7ca13ee945ddf019bed048ab8cd81687e4746d74 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 3 Jun 2015 15:06:58 -0700 Subject: [PATCH 045/107] Check for 'any' only by using the flag, not by checking for instance equality. --- src/compiler/checker.ts | 158 +++++++++--------- .../reference/ArrowFunction3.errors.txt | 5 +- ...rsiveImplicitConstructorErrors3.errors.txt | 5 +- .../parserGenericsInTypeContexts1.errors.txt | 5 +- .../parserGenericsInTypeContexts2.errors.txt | 5 +- .../parserX_ArrowFunction3.errors.txt | 5 +- ...rUsedAsTypeParameterConstraint4.errors.txt | 14 +- .../reference/unknownSymbols1.errors.txt | 5 +- 8 files changed, 89 insertions(+), 113 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 903d5964a44..03a029d4b84 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1493,8 +1493,9 @@ module ts { // Write undefined/null type as any if (type.flags & TypeFlags.Intrinsic) { // Special handling for unknown / resolving types, they should show up as any and not unknown or __resolving - writer.writeKeyword(!(globalFlags & TypeFormatFlags.WriteOwnNameForAnyLike) && - (type.flags & TypeFlags.Any) ? "any" : (type).intrinsicName); + writer.writeKeyword(!(globalFlags & TypeFormatFlags.WriteOwnNameForAnyLike) && isTypeAny(type) + ? "any" + : (type).intrinsicName); } else if (type.flags & TypeFlags.Reference) { writeTypeReference(type, flags); @@ -2131,8 +2132,8 @@ module ts { return prop ? getTypeOfSymbol(prop) : undefined; } - function isTheAnyType(type: Type) { - return type === anyType; + function isTypeAny(type: Type) { + return type && type.flags & TypeFlags.Any; } // Return the inferred type for a binding element @@ -2146,7 +2147,7 @@ module ts { // If no type was specified or inferred for parent, or if the specified or inferred type is any, // infer from the initializer of the binding element if one is present. Otherwise, go with the // undefined or any type of the parent. - if (!parentType || isTheAnyType(parentType)) { + if (!parentType || isTypeAny(parentType)) { if (declaration.initializer) { return checkExpressionCached(declaration.initializer); } @@ -2173,7 +2174,7 @@ module ts { // fact an iterable or array (depending on target language). let elementType = checkIteratedTypeOrElementType(parentType, pattern, /*allowStringInput*/ false); if (!declaration.dotDotDotToken) { - if (elementType.flags & TypeFlags.Any) { + if (isTypeAny(elementType)) { return elementType; } @@ -3720,9 +3721,9 @@ module ts { } } - function containsAnyType(types: Type[]) { + function containsTypeAny(types: Type[]) { for (let type of types) { - if (type.flags & TypeFlags.Any) { + if (isTypeAny(type)) { return true; } } @@ -3750,7 +3751,7 @@ module ts { let sortedTypes: Type[] = []; addTypesToSortedSet(sortedTypes, types); if (noSubtypeReduction) { - if (containsAnyType(sortedTypes)) { + if (containsTypeAny(sortedTypes)) { return anyType; } removeAllButLast(sortedTypes, undefinedType); @@ -4186,13 +4187,13 @@ module ts { // both types are the same - covers 'they are the same primitive type or both are Any' or the same type parameter cases if (source === target) return Ternary.True; if (relation !== identityRelation) { - if (target.flags & TypeFlags.Any) return Ternary.True; + if (isTypeAny(target)) return Ternary.True; if (source === undefinedType) return Ternary.True; if (source === nullType && target !== undefinedType) return Ternary.True; if (source.flags & TypeFlags.Enum && target === numberType) return Ternary.True; if (source.flags & TypeFlags.StringLiteral && target === stringType) return Ternary.True; if (relation === assignableRelation) { - if (source.flags & TypeFlags.Any) return Ternary.True; + if (isTypeAny(source)) return Ternary.True; if (source === numberType && target.flags & TypeFlags.Enum) return Ternary.True; } } @@ -5537,7 +5538,7 @@ module ts { function narrowTypeByInstanceof(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type { // Check that type is not any, assumed result is true, and we have variable symbol on the left - if (type.flags & TypeFlags.Any || !assumeTrue || expr.left.kind !== SyntaxKind.Identifier || getResolvedSymbol(expr.left) !== symbol) { + if (isTypeAny(type) || !assumeTrue || expr.left.kind !== SyntaxKind.Identifier || getResolvedSymbol(expr.left) !== symbol) { return type; } // Check that right operand is a function type with a prototype property @@ -5551,7 +5552,7 @@ module ts { if (prototypeProperty) { // Target type is type of the protoype property let prototypePropertyType = getTypeOfSymbol(prototypeProperty); - if (!isTheAnyType(prototypePropertyType)) { + if (!isTypeAny(prototypePropertyType)) { targetType = prototypePropertyType; } } @@ -6499,39 +6500,39 @@ module ts { function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, right: Identifier) { let type = checkExpressionOrQualifiedName(left); - if (type === unknownType) return type; - if (!isTheAnyType(type)) { - let apparentType = getApparentType(getWidenedType(type)); - if (apparentType === unknownType) { - // handle cases when type is Type parameter with invalid constraint - return unknownType; - } - let prop = getPropertyOfType(apparentType, right.text); - if (!prop) { - if (right.text) { - error(right, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(right), typeToString(type)); - } - return unknownType; - } - getNodeLinks(node).resolvedSymbol = prop; - if (prop.parent && prop.parent.flags & SymbolFlags.Class) { - // TS 1.0 spec (April 2014): 4.8.2 - // - In a constructor, instance member function, instance member accessor, or - // instance member variable initializer where this references a derived class instance, - // a super property access is permitted and must specify a public instance member function of the base class. - // - In a static member function or static member accessor - // where this references the constructor function object of a derived class, - // a super property access is permitted and must specify a public static member function of the base class. - if (left.kind === SyntaxKind.SuperKeyword && getDeclarationKindFromSymbol(prop) !== SyntaxKind.MethodDeclaration) { - error(right, Diagnostics.Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword); - } - else { - checkClassPropertyAccess(node, left, type, prop); - } - } - return getTypeOfSymbol(prop); + if (isTypeAny(type)) { + return type; } - return anyType; + + let apparentType = getApparentType(getWidenedType(type)); + if (apparentType === unknownType) { + // handle cases when type is Type parameter with invalid constraint + return unknownType; + } + let prop = getPropertyOfType(apparentType, right.text); + if (!prop) { + if (right.text) { + error(right, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(right), typeToString(type)); + } + return unknownType; + } + getNodeLinks(node).resolvedSymbol = prop; + if (prop.parent && prop.parent.flags & SymbolFlags.Class) { + // TS 1.0 spec (April 2014): 4.8.2 + // - In a constructor, instance member function, instance member accessor, or + // instance member variable initializer where this references a derived class instance, + // a super property access is permitted and must specify a public instance member function of the base class. + // - In a static member function or static member accessor + // where this references the constructor function object of a derived class, + // a super property access is permitted and must specify a public static member function of the base class. + if (left.kind === SyntaxKind.SuperKeyword && getDeclarationKindFromSymbol(prop) !== SyntaxKind.MethodDeclaration) { + error(right, Diagnostics.Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword); + } + else { + checkClassPropertyAccess(node, left, type, prop); + } + } + return getTypeOfSymbol(prop); } function isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean { @@ -6540,7 +6541,7 @@ module ts { : (node).left; let type = checkExpressionOrQualifiedName(left); - if (type !== unknownType && !isTheAnyType(type)) { + if (type !== unknownType && !isTypeAny(type)) { let prop = getPropertyOfType(getWidenedType(type), propertyName); if (prop && prop.parent && prop.parent.flags & SymbolFlags.Class) { if (left.kind === SyntaxKind.SuperKeyword && getDeclarationKindFromSymbol(prop) !== SyntaxKind.MethodDeclaration) { @@ -6630,7 +6631,7 @@ module ts { } // Fall back to any. - if (compilerOptions.noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors && !isTheAnyType(objectType)) { + if (compilerOptions.noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors && !isTypeAny(objectType)) { error(node, Diagnostics.Index_signature_of_object_type_implicitly_has_an_any_type); } @@ -7280,8 +7281,10 @@ module ts { // types are provided for the argument expressions, and the result is always of type Any. // We exclude union types because we may have a union of function types that happen to have // no common signatures. - if (isTheAnyType(funcType) || (!callSignatures.length && !constructSignatures.length && !(funcType.flags & TypeFlags.Union) && isTypeAssignableTo(funcType, globalFunctionType))) { - if (node.typeArguments) { + if (isTypeAny(funcType) || (!callSignatures.length && !constructSignatures.length && !(funcType.flags & TypeFlags.Union) && isTypeAssignableTo(funcType, globalFunctionType))) { + // The unknownType indicates that an error already occured (and was reported). No + // need to report another error in this case. + if (funcType !== unknownType && node.typeArguments) { error(node, Diagnostics.Untyped_function_calls_may_not_accept_type_arguments); } return resolveUntypedCall(node); @@ -7310,15 +7313,6 @@ module ts { } let expressionType = checkExpression(node.expression); - // TS 1.0 spec: 4.11 - // If ConstructExpr is of type Any, Args can be any argument - // list and the result of the operation is of type Any. - if (isTheAnyType(expressionType)) { - if (node.typeArguments) { - error(node, Diagnostics.Untyped_function_calls_may_not_accept_type_arguments); - } - return resolveUntypedCall(node); - } // If ConstructExpr's apparent type(section 3.8.1) is an object type with one or // more construct signatures, the expression is processed in the same manner as a @@ -7331,6 +7325,16 @@ module ts { return resolveErrorCall(node); } + // TS 1.0 spec: 4.11 + // If ConstructExpr is of type Any, Args can be any argument + // list and the result of the operation is of type Any. + if (isTypeAny(expressionType)) { + if (node.typeArguments) { + error(node, Diagnostics.Untyped_function_calls_may_not_accept_type_arguments); + } + return resolveUntypedCall(node); + } + // Technically, this signatures list may be incomplete. We are taking the apparent type, // but we are not including construct signatures that may have been added to the Object or // Function interface, since they have none by default. This is a bit of a leap of faith @@ -7368,7 +7372,7 @@ module ts { let callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call); - if (isTheAnyType(tagType) || (!callSignatures.length && !(tagType.flags & TypeFlags.Union) && isTypeAssignableTo(tagType, globalFunctionType))) { + if (isTypeAny(tagType) || (!callSignatures.length && !(tagType.flags & TypeFlags.Union) && isTypeAssignableTo(tagType, globalFunctionType))) { return resolveUntypedCall(node); } @@ -7580,7 +7584,7 @@ module ts { } // Functions that return 'void' or 'any' don't need any return expressions. - if (returnType === voidType || isTheAnyType(returnType)) { + if (returnType === voidType || isTypeAny(returnType)) { return; } @@ -7896,7 +7900,7 @@ module ts { error(node.left, Diagnostics.The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter); } // NOTE: do not raise error if right is unknown as related error was already reported - if (!(rightType.flags & TypeFlags.Any || isTypeSubtypeOf(rightType, globalFunctionType))) { + if (!(isTypeAny(rightType) || isTypeSubtypeOf(rightType, globalFunctionType))) { error(node.right, Diagnostics.The_right_hand_side_of_an_instanceof_expression_must_be_of_type_any_or_of_a_type_assignable_to_the_Function_interface_type); } return booleanType; @@ -7922,10 +7926,11 @@ module ts { if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) { // TODO(andersh): Computed property support let name = (p).name; - let type = sourceType.flags & TypeFlags.Any ? sourceType : - getTypeOfPropertyOfType(sourceType, name.text) || - isNumericLiteralName(name.text) && getIndexTypeOfType(sourceType, IndexKind.Number) || - getIndexTypeOfType(sourceType, IndexKind.String); + let type = isTypeAny(sourceType) + ? sourceType + : getTypeOfPropertyOfType(sourceType, name.text) || + isNumericLiteralName(name.text) && getIndexTypeOfType(sourceType, IndexKind.Number) || + getIndexTypeOfType(sourceType, IndexKind.String); if (type) { checkDestructuringAssignment((p).initializer || name, type); } @@ -7951,8 +7956,9 @@ module ts { if (e.kind !== SyntaxKind.OmittedExpression) { if (e.kind !== SyntaxKind.SpreadElementExpression) { let propName = "" + i; - let type = sourceType.flags & TypeFlags.Any ? sourceType : - isTupleLikeType(sourceType) + let type = isTypeAny(sourceType) + ? sourceType + : isTupleLikeType(sourceType) ? getTypeOfPropertyOfType(sourceType, propName) : elementType; if (type) { @@ -8091,10 +8097,10 @@ module ts { // If one or both operands are of the String primitive type, the result is of the String primitive type. resultType = stringType; } - else if (leftType.flags & TypeFlags.Any || rightType.flags & TypeFlags.Any) { + else if (isTypeAny(leftType) || isTypeAny(rightType)) { // Otherwise, the result is of type Any. // NOTE: unknown type here denotes error type. Old compiler treated this case as any type so do we. - resultType = anyType; + resultType = leftType === unknownType || rightType === unknownType ? unknownType : anyType; } // Symbols are not allowed at all in arithmetic expressions @@ -9824,7 +9830,7 @@ module ts { } function checkIteratedTypeOrElementType(inputType: Type, errorNode: Node, allowStringInput: boolean): Type { - if (inputType.flags & TypeFlags.Any) { + if (isTypeAny(inputType)) { return inputType; } @@ -9883,7 +9889,7 @@ module ts { * whole pattern and that T (above) is 'any'. */ function getElementTypeOfIterable(type: Type, errorNode: Node): Type { - if (type.flags & TypeFlags.Any) { + if (isTypeAny(type)) { return undefined; } @@ -9896,7 +9902,7 @@ module ts { } else { let iteratorFunction = getTypeOfPropertyOfType(type, getPropertyNameForKnownSymbolName("iterator")); - if (iteratorFunction && iteratorFunction.flags & TypeFlags.Any) { + if (isTypeAny(iteratorFunction)) { return undefined; } @@ -9929,7 +9935,7 @@ module ts { * */ function getElementTypeOfIterator(type: Type, errorNode: Node): Type { - if (type.flags & TypeFlags.Any) { + if (isTypeAny(type)) { return undefined; } @@ -9942,7 +9948,7 @@ module ts { } else { let iteratorNextFunction = getTypeOfPropertyOfType(type, "next"); - if (iteratorNextFunction && iteratorNextFunction.flags & TypeFlags.Any) { + if (isTypeAny(iteratorNextFunction)) { return undefined; } @@ -9955,7 +9961,7 @@ module ts { } let iteratorNextResult = getUnionType(map(iteratorNextFunctionSignatures, getReturnTypeOfSignature)); - if (iteratorNextResult.flags & TypeFlags.Any) { + if (isTypeAny(iteratorNextResult)) { return undefined; } @@ -9975,7 +9981,7 @@ module ts { } function getElementTypeOfIterableIterator(type: Type): Type { - if (type.flags & TypeFlags.Any) { + if (isTypeAny(type)) { return undefined; } diff --git a/tests/baselines/reference/ArrowFunction3.errors.txt b/tests/baselines/reference/ArrowFunction3.errors.txt index b931fcb1cd8..aa5d1bfb725 100644 --- a/tests/baselines/reference/ArrowFunction3.errors.txt +++ b/tests/baselines/reference/ArrowFunction3.errors.txt @@ -1,11 +1,8 @@ -tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ArrowFunctions/ArrowFunction3.ts(1,13): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement. tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ArrowFunctions/ArrowFunction3.ts(1,14): error TS1110: Type expected. -==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ArrowFunctions/ArrowFunction3.ts (2 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ArrowFunctions/ArrowFunction3.ts (1 errors) ==== var v = (a): => { - -!!! error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement. ~~ !!! error TS1110: Type expected. diff --git a/tests/baselines/reference/genericRecursiveImplicitConstructorErrors3.errors.txt b/tests/baselines/reference/genericRecursiveImplicitConstructorErrors3.errors.txt index 760d1561113..1a04e356296 100644 --- a/tests/baselines/reference/genericRecursiveImplicitConstructorErrors3.errors.txt +++ b/tests/baselines/reference/genericRecursiveImplicitConstructorErrors3.errors.txt @@ -1,5 +1,4 @@ tests/cases/compiler/genericRecursiveImplicitConstructorErrors3.ts(3,66): error TS2314: Generic type 'MemberName' requires 3 type argument(s). -tests/cases/compiler/genericRecursiveImplicitConstructorErrors3.ts(3,66): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement. tests/cases/compiler/genericRecursiveImplicitConstructorErrors3.ts(10,22): error TS2314: Generic type 'PullTypeSymbol' requires 3 type argument(s). tests/cases/compiler/genericRecursiveImplicitConstructorErrors3.ts(12,48): error TS2314: Generic type 'PullSymbol' requires 3 type argument(s). tests/cases/compiler/genericRecursiveImplicitConstructorErrors3.ts(13,31): error TS2314: Generic type 'PullTypeSymbol' requires 3 type argument(s). @@ -8,14 +7,12 @@ tests/cases/compiler/genericRecursiveImplicitConstructorErrors3.ts(18,53): error tests/cases/compiler/genericRecursiveImplicitConstructorErrors3.ts(19,22): error TS2339: Property 'isArray' does not exist on type 'PullTypeSymbol'. -==== tests/cases/compiler/genericRecursiveImplicitConstructorErrors3.ts (8 errors) ==== +==== tests/cases/compiler/genericRecursiveImplicitConstructorErrors3.ts (7 errors) ==== module TypeScript { export class MemberName { static create(arg1: any, arg2?: any, arg3?: any): MemberName { ~~~~~~~~~~ !!! error TS2314: Generic type 'MemberName' requires 3 type argument(s). - ~~~~~~~~~~ -!!! error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement. } } } diff --git a/tests/baselines/reference/parserGenericsInTypeContexts1.errors.txt b/tests/baselines/reference/parserGenericsInTypeContexts1.errors.txt index 75652c829ee..477cc3edcdc 100644 --- a/tests/baselines/reference/parserGenericsInTypeContexts1.errors.txt +++ b/tests/baselines/reference/parserGenericsInTypeContexts1.errors.txt @@ -7,10 +7,9 @@ tests/cases/conformance/parser/ecmascript5/Generics/parserGenericsInTypeContexts tests/cases/conformance/parser/ecmascript5/Generics/parserGenericsInTypeContexts1.ts(8,9): error TS2304: Cannot find name 'K'. tests/cases/conformance/parser/ecmascript5/Generics/parserGenericsInTypeContexts1.ts(11,16): error TS2304: Cannot find name 'E'. tests/cases/conformance/parser/ecmascript5/Generics/parserGenericsInTypeContexts1.ts(14,16): error TS2304: Cannot find name 'F'. -tests/cases/conformance/parser/ecmascript5/Generics/parserGenericsInTypeContexts1.ts(14,16): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement. -==== tests/cases/conformance/parser/ecmascript5/Generics/parserGenericsInTypeContexts1.ts (10 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/Generics/parserGenericsInTypeContexts1.ts (9 errors) ==== class C extends A implements B { ~ !!! error TS2304: Cannot find name 'A'. @@ -43,8 +42,6 @@ tests/cases/conformance/parser/ecmascript5/Generics/parserGenericsInTypeContexts function f2(): F { ~ !!! error TS2304: Cannot find name 'F'. - ~~~~ -!!! error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement. } \ No newline at end of file diff --git a/tests/baselines/reference/parserGenericsInTypeContexts2.errors.txt b/tests/baselines/reference/parserGenericsInTypeContexts2.errors.txt index c365f461b7c..f686b56bf89 100644 --- a/tests/baselines/reference/parserGenericsInTypeContexts2.errors.txt +++ b/tests/baselines/reference/parserGenericsInTypeContexts2.errors.txt @@ -7,10 +7,9 @@ tests/cases/conformance/parser/ecmascript5/Generics/parserGenericsInTypeContexts tests/cases/conformance/parser/ecmascript5/Generics/parserGenericsInTypeContexts2.ts(8,9): error TS2304: Cannot find name 'K'. tests/cases/conformance/parser/ecmascript5/Generics/parserGenericsInTypeContexts2.ts(11,16): error TS2304: Cannot find name 'E'. tests/cases/conformance/parser/ecmascript5/Generics/parserGenericsInTypeContexts2.ts(14,16): error TS2304: Cannot find name 'F'. -tests/cases/conformance/parser/ecmascript5/Generics/parserGenericsInTypeContexts2.ts(14,16): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement. -==== tests/cases/conformance/parser/ecmascript5/Generics/parserGenericsInTypeContexts2.ts (10 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/Generics/parserGenericsInTypeContexts2.ts (9 errors) ==== class C extends A, Y>> implements B, Y>> { ~ !!! error TS2304: Cannot find name 'A'. @@ -43,8 +42,6 @@ tests/cases/conformance/parser/ecmascript5/Generics/parserGenericsInTypeContexts function f2(): F, Y>> { ~ !!! error TS2304: Cannot find name 'F'. - ~~~~~~~~~~~~~~~~ -!!! error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement. } \ No newline at end of file diff --git a/tests/baselines/reference/parserX_ArrowFunction3.errors.txt b/tests/baselines/reference/parserX_ArrowFunction3.errors.txt index 4ef812dc797..aa4a4c55a9f 100644 --- a/tests/baselines/reference/parserX_ArrowFunction3.errors.txt +++ b/tests/baselines/reference/parserX_ArrowFunction3.errors.txt @@ -1,11 +1,8 @@ -tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ArrowFunctions/parserX_ArrowFunction3.ts(1,13): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement. tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ArrowFunctions/parserX_ArrowFunction3.ts(1,14): error TS1110: Type expected. -==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ArrowFunctions/parserX_ArrowFunction3.ts (2 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ArrowFunctions/parserX_ArrowFunction3.ts (1 errors) ==== var v = (a): => { - -!!! error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement. ~~ !!! error TS1110: Type expected. diff --git a/tests/baselines/reference/typeParameterUsedAsTypeParameterConstraint4.errors.txt b/tests/baselines/reference/typeParameterUsedAsTypeParameterConstraint4.errors.txt index 983f2798554..d86b63d2ce3 100644 --- a/tests/baselines/reference/typeParameterUsedAsTypeParameterConstraint4.errors.txt +++ b/tests/baselines/reference/typeParameterUsedAsTypeParameterConstraint4.errors.txt @@ -7,16 +7,12 @@ tests/cases/conformance/types/objectTypeLiteral/callSignatures/typeParameterUsed tests/cases/conformance/types/objectTypeLiteral/callSignatures/typeParameterUsedAsTypeParameterConstraint4.ts(15,8): error TS2304: Cannot find name 'W'. tests/cases/conformance/types/objectTypeLiteral/callSignatures/typeParameterUsedAsTypeParameterConstraint4.ts(19,17): error TS2313: Constraint of a type parameter cannot reference any type parameter from the same type parameter list. tests/cases/conformance/types/objectTypeLiteral/callSignatures/typeParameterUsedAsTypeParameterConstraint4.ts(19,43): error TS2304: Cannot find name 'V'. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/typeParameterUsedAsTypeParameterConstraint4.ts(19,43): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement. tests/cases/conformance/types/objectTypeLiteral/callSignatures/typeParameterUsedAsTypeParameterConstraint4.ts(20,47): error TS2304: Cannot find name 'X'. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/typeParameterUsedAsTypeParameterConstraint4.ts(20,47): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement. tests/cases/conformance/types/objectTypeLiteral/callSignatures/typeParameterUsedAsTypeParameterConstraint4.ts(22,13): error TS2322: Type 'U' is not assignable to type 'T'. tests/cases/conformance/types/objectTypeLiteral/callSignatures/typeParameterUsedAsTypeParameterConstraint4.ts(23,20): error TS2322: Type 'U' is not assignable to type 'T'. tests/cases/conformance/types/objectTypeLiteral/callSignatures/typeParameterUsedAsTypeParameterConstraint4.ts(28,15): error TS2313: Constraint of a type parameter cannot reference any type parameter from the same type parameter list. tests/cases/conformance/types/objectTypeLiteral/callSignatures/typeParameterUsedAsTypeParameterConstraint4.ts(28,44): error TS2304: Cannot find name 'W'. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/typeParameterUsedAsTypeParameterConstraint4.ts(28,44): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement. tests/cases/conformance/types/objectTypeLiteral/callSignatures/typeParameterUsedAsTypeParameterConstraint4.ts(29,47): error TS2304: Cannot find name 'Y'. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/typeParameterUsedAsTypeParameterConstraint4.ts(29,47): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement. tests/cases/conformance/types/objectTypeLiteral/callSignatures/typeParameterUsedAsTypeParameterConstraint4.ts(31,13): error TS2322: Type 'U' is not assignable to type 'T'. tests/cases/conformance/types/objectTypeLiteral/callSignatures/typeParameterUsedAsTypeParameterConstraint4.ts(32,20): error TS2322: Type 'U' is not assignable to type 'T'. tests/cases/conformance/types/objectTypeLiteral/callSignatures/typeParameterUsedAsTypeParameterConstraint4.ts(37,14): error TS2313: Constraint of a type parameter cannot reference any type parameter from the same type parameter list. @@ -29,7 +25,7 @@ tests/cases/conformance/types/objectTypeLiteral/callSignatures/typeParameterUsed tests/cases/conformance/types/objectTypeLiteral/callSignatures/typeParameterUsedAsTypeParameterConstraint4.ts(46,36): error TS2304: Cannot find name 'X'. -==== tests/cases/conformance/types/objectTypeLiteral/callSignatures/typeParameterUsedAsTypeParameterConstraint4.ts (29 errors) ==== +==== tests/cases/conformance/types/objectTypeLiteral/callSignatures/typeParameterUsedAsTypeParameterConstraint4.ts (25 errors) ==== // Type parameters are in scope in their own and other type parameter lists // Some negative cases @@ -67,13 +63,9 @@ tests/cases/conformance/types/objectTypeLiteral/callSignatures/typeParameterUsed !!! error TS2313: Constraint of a type parameter cannot reference any type parameter from the same type parameter list. ~ !!! error TS2304: Cannot find name 'V'. - ~ -!!! error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement. function bar(): X { // error ~ !!! error TS2304: Cannot find name 'X'. - ~ -!!! error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement. function baz(a: X, b: Y): T { x = y; ~ @@ -90,13 +82,9 @@ tests/cases/conformance/types/objectTypeLiteral/callSignatures/typeParameterUsed !!! error TS2313: Constraint of a type parameter cannot reference any type parameter from the same type parameter list. ~ !!! error TS2304: Cannot find name 'W'. - ~ -!!! error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement. function bar(): Y { // error ~ !!! error TS2304: Cannot find name 'Y'. - ~ -!!! error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement. function baz(a: X, b: Y): T { x = y; ~ diff --git a/tests/baselines/reference/unknownSymbols1.errors.txt b/tests/baselines/reference/unknownSymbols1.errors.txt index dcf6894f324..a757ab9613b 100644 --- a/tests/baselines/reference/unknownSymbols1.errors.txt +++ b/tests/baselines/reference/unknownSymbols1.errors.txt @@ -2,7 +2,6 @@ tests/cases/compiler/unknownSymbols1.ts(1,9): error TS2304: Cannot find name 'as tests/cases/compiler/unknownSymbols1.ts(2,8): error TS2304: Cannot find name 'asdf'. tests/cases/compiler/unknownSymbols1.ts(4,17): error TS2304: Cannot find name 'asdf'. tests/cases/compiler/unknownSymbols1.ts(4,35): error TS2304: Cannot find name 'asdf'. -tests/cases/compiler/unknownSymbols1.ts(4,35): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement. tests/cases/compiler/unknownSymbols1.ts(6,12): error TS2304: Cannot find name 'asdf'. tests/cases/compiler/unknownSymbols1.ts(9,10): error TS2304: Cannot find name 'asdf'. tests/cases/compiler/unknownSymbols1.ts(12,10): error TS2304: Cannot find name 'asdf'. @@ -14,7 +13,7 @@ tests/cases/compiler/unknownSymbols1.ts(30,14): error TS2339: Property 'asdf' do tests/cases/compiler/unknownSymbols1.ts(30,21): error TS2304: Cannot find name 'asdf'. -==== tests/cases/compiler/unknownSymbols1.ts (14 errors) ==== +==== tests/cases/compiler/unknownSymbols1.ts (13 errors) ==== var x = asdf; ~~~~ !!! error TS2304: Cannot find name 'asdf'. @@ -27,8 +26,6 @@ tests/cases/compiler/unknownSymbols1.ts(30,21): error TS2304: Cannot find name ' !!! error TS2304: Cannot find name 'asdf'. ~~~~ !!! error TS2304: Cannot find name 'asdf'. - ~~~~ -!!! error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement. function foo2() { return asdf; ~~~~ From 7b17f6ec8c2a1a6a2a0bc1144318d714d814de9b Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 3 Jun 2015 15:16:16 -0700 Subject: [PATCH 046/107] Don't check if *all* constituent types are 'any'. Instead check if *any* of hte constituent types are 'any', or if *all* if the constituent types have some other flag. --- src/compiler/checker.ts | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 03a029d4b84..389881f1b5e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2133,7 +2133,7 @@ module ts { } function isTypeAny(type: Type) { - return type && type.flags & TypeFlags.Any; + return type && (type.flags & TypeFlags.Any) !== 0; } // Return the inferred type for a binding element @@ -6313,7 +6313,11 @@ module ts { function isNumericComputedName(name: ComputedPropertyName): boolean { // It seems odd to consider an expression of type Any to result in a numeric name, // but this behavior is consistent with checkIndexedAccess - return allConstituentTypesHaveKind(checkComputedPropertyName(name), TypeFlags.Any | TypeFlags.NumberLike); + return isTypeAnyOrAllConstituentTypesHaveKind(checkComputedPropertyName(name), TypeFlags.NumberLike); + } + + function isTypeAnyOrAllConstituentTypesHaveKind(type: Type, kind: TypeFlags): boolean { + return isTypeAny(type) || allConstituentTypesHaveKind(type, kind); } function isNumericLiteralName(name: string) { @@ -6348,7 +6352,7 @@ module ts { // This will allow types number, string, symbol or any. It will also allow enums, the unknown // type, and any union of these types (like string | number). - if (!allConstituentTypesHaveKind(links.resolvedType, TypeFlags.Any | TypeFlags.NumberLike | TypeFlags.StringLike | TypeFlags.ESSymbol)) { + if (!isTypeAnyOrAllConstituentTypesHaveKind(links.resolvedType, TypeFlags.NumberLike | TypeFlags.StringLike | TypeFlags.ESSymbol)) { error(node, Diagnostics.A_computed_property_name_must_be_of_type_string_number_symbol_or_any); } else { @@ -6614,10 +6618,10 @@ module ts { } // Check for compatible indexer types. - if (allConstituentTypesHaveKind(indexType, TypeFlags.Any | TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbol)) { + if (isTypeAnyOrAllConstituentTypesHaveKind(indexType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbol)) { // Try to use a number indexer. - if (allConstituentTypesHaveKind(indexType, TypeFlags.Any | TypeFlags.NumberLike)) { + if (isTypeAnyOrAllConstituentTypesHaveKind(indexType, TypeFlags.NumberLike)) { let numberIndexType = getIndexTypeOfType(objectType, IndexKind.Number); if (numberIndexType) { return numberIndexType; @@ -7688,7 +7692,7 @@ module ts { } function checkArithmeticOperandType(operand: Node, type: Type, diagnostic: DiagnosticMessage): boolean { - if (!allConstituentTypesHaveKind(type, TypeFlags.Any | TypeFlags.NumberLike)) { + if (!isTypeAnyOrAllConstituentTypesHaveKind(type, TypeFlags.NumberLike)) { error(operand, diagnostic); return false; } @@ -7911,10 +7915,10 @@ module ts { // The in operator requires the left operand to be of type Any, the String primitive type, or the Number primitive type, // and the right operand to be of type Any, an object type, or a type parameter type. // The result is always of the Boolean primitive type. - if (!allConstituentTypesHaveKind(leftType, TypeFlags.Any | TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbol)) { + if (!isTypeAnyOrAllConstituentTypesHaveKind(leftType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbol)) { error(node.left, Diagnostics.The_left_hand_side_of_an_in_expression_must_be_of_type_any_string_number_or_symbol); } - if (!allConstituentTypesHaveKind(rightType, TypeFlags.Any | TypeFlags.ObjectType | TypeFlags.TypeParameter)) { + if (!isTypeAnyOrAllConstituentTypesHaveKind(rightType, TypeFlags.ObjectType | TypeFlags.TypeParameter)) { error(node.right, Diagnostics.The_right_hand_side_of_an_in_expression_must_be_of_type_any_an_object_type_or_a_type_parameter); } return booleanType; @@ -9796,7 +9800,7 @@ module ts { if (varExpr.kind === SyntaxKind.ArrayLiteralExpression || varExpr.kind === SyntaxKind.ObjectLiteralExpression) { error(varExpr, Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_a_destructuring_pattern); } - else if (!allConstituentTypesHaveKind(leftType, TypeFlags.Any | TypeFlags.StringLike)) { + else if (!isTypeAnyOrAllConstituentTypesHaveKind(leftType, TypeFlags.StringLike)) { error(varExpr, Diagnostics.The_left_hand_side_of_a_for_in_statement_must_be_of_type_string_or_any); } else { @@ -9808,7 +9812,7 @@ module ts { let rightType = checkExpression(node.expression); // unknownType is returned i.e. if node.expression is identifier whose name cannot be resolved // in this case error about missing name is already reported - do not report extra one - if (!allConstituentTypesHaveKind(rightType, TypeFlags.Any | TypeFlags.ObjectType | TypeFlags.TypeParameter)) { + if (!isTypeAnyOrAllConstituentTypesHaveKind(rightType, TypeFlags.ObjectType | TypeFlags.TypeParameter)) { error(node.expression, Diagnostics.The_right_hand_side_of_a_for_in_statement_must_be_of_type_any_an_object_type_or_a_type_parameter); } From ef54047a65c963201d972bccec5d5e08d53f6091 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Wed, 3 Jun 2015 15:22:17 -0700 Subject: [PATCH 047/107] address PR feedback --- src/compiler/core.ts | 38 +++++++++++++++++++++----------------- src/compiler/program.ts | 2 +- src/compiler/types.ts | 8 ++++++++ src/services/services.ts | 6 +++--- src/services/shims.ts | 2 +- 5 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/compiler/core.ts b/src/compiler/core.ts index b798bd8771d..ed9647970c0 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -15,35 +15,39 @@ module ts { True = -1 } - export class FileMap { - private files: Map = {}; - - constructor(private getCanonicalFileName: (fileName: string) => string) { + export function createFileMap(getCanonicalFileName: (fileName: string) => string): FileMap { + let files: Map = {}; + return { + get, + set, + contains, + delete: deleteItem, + forEachValue: forEachValueInMap } - public set(fileName: string, value: T) { - this.files[this.normalizeKey(fileName)] = value; + function set(fileName: string, value: T) { + files[normalizeKey(fileName)] = value; } - public get(fileName: string) { - return this.files[this.normalizeKey(fileName)]; + function get(fileName: string) { + return files[normalizeKey(fileName)]; } - public contains(fileName: string) { - return hasProperty(this.files, this.normalizeKey(fileName)); + function contains(fileName: string) { + return hasProperty(files, normalizeKey(fileName)); } - public delete(fileName: string) { - let key = this.normalizeKey(fileName); - delete this.files[key]; + function deleteItem (fileName: string) { + let key = normalizeKey(fileName); + delete files[key]; } - public forEachValue(f: (value: T) => void) { - forEachValue(this.files, f); + function forEachValueInMap(f: (value: T) => void) { + forEachValue(files, f); } - private normalizeKey(key: string) { - return this.getCanonicalFileName(normalizeSlashes(key)); + function normalizeKey(key: string) { + return getCanonicalFileName(normalizeSlashes(key)); } } diff --git a/src/compiler/program.ts b/src/compiler/program.ts index dd693b55907..74c0ac7fefb 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -158,7 +158,7 @@ module ts { let start = new Date().getTime(); host = host || createCompilerHost(options); - let filesByName: FileMap = new FileMap(host.getCanonicalFileName); + let filesByName = createFileMap(host.getCanonicalFileName); forEach(rootNames, name => processRootFile(name, false)); if (!seenNoDefaultLib) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 0fcf0e1f67a..638dd0b79ec 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3,6 +3,14 @@ module ts { [index: string]: T; } + export interface FileMap { + get(fileName: string): T; + set(fileName: string, value: T): void; + contains(fileName: string): boolean; + delete(fileName: string): void; + forEachValue(f: (v: T) => void): void; + } + export interface TextRange { pos: number; end: number; diff --git a/src/services/services.ts b/src/services/services.ts index 908d9efbaca..f2aa6dfee7f 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1638,7 +1638,7 @@ module ts { constructor(private host: LanguageServiceHost, getCanonicalFileName: (fileName: string) => string) { // script id => script index - this.fileNameToEntry = new FileMap(getCanonicalFileName); + this.fileNameToEntry = createFileMap(getCanonicalFileName); // Initialize the list with the root file names let rootFileNames = host.getScriptFileNames(); @@ -1881,7 +1881,7 @@ module ts { // Maps from compiler setting target (ES3, ES5, etc.) to all the cached documents we have // for those settings. let buckets: Map> = {}; - let getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames || false); + let getCanonicalFileName = createGetCanonicalFileName(!!useCaseSensitiveFileNames); function getKeyFromCompilationSettings(settings: CompilerOptions): string { return "_" + settings.target; // + "|" + settings.propagateEnumConstantoString() @@ -1891,7 +1891,7 @@ module ts { let key = getKeyFromCompilationSettings(settings); let bucket = lookUp(buckets, key); if (!bucket && createIfMissing) { - buckets[key] = bucket = new FileMap(getCanonicalFileName); + buckets[key] = bucket = createFileMap(getCanonicalFileName); } return bucket; } diff --git a/src/services/shims.ts b/src/services/shims.ts index 4dfab444cde..004393fb3b5 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -272,7 +272,7 @@ module ts { } public useCaseSensitiveFileNames(): boolean { - return this.shimHost.useCaseSensitiveFileNames && this.useCaseSensitiveFileNames(); + return this.shimHost.useCaseSensitiveFileNames ? this.shimHost.useCaseSensitiveFileNames() : false; } public getCompilationSettings(): CompilerOptions { From 12bea33fe37652b570ec9f245b7a019f88003370 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 3 Jun 2015 15:37:09 -0700 Subject: [PATCH 048/107] Remove last read reference of TypeFlags.Any --- src/compiler/checker.ts | 87 +++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 42 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 389881f1b5e..82c70861101 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5417,55 +5417,58 @@ module ts { function getNarrowedTypeOfSymbol(symbol: Symbol, node: Node) { let type = getTypeOfSymbol(symbol); // Only narrow when symbol is variable of type any or an object, union, or type parameter type - if (node && symbol.flags & SymbolFlags.Variable && type.flags & (TypeFlags.Any | TypeFlags.ObjectType | TypeFlags.Union | TypeFlags.TypeParameter)) { - loop: while (node.parent) { - let child = node; - node = node.parent; - let narrowedType = type; - switch (node.kind) { - case SyntaxKind.IfStatement: - // In a branch of an if statement, narrow based on controlling expression - if (child !== (node).expression) { - narrowedType = narrowType(type, (node).expression, /*assumeTrue*/ child === (node).thenStatement); - } - break; - case SyntaxKind.ConditionalExpression: - // In a branch of a conditional expression, narrow based on controlling condition - if (child !== (node).condition) { - narrowedType = narrowType(type, (node).condition, /*assumeTrue*/ child === (node).whenTrue); - } - break; - case SyntaxKind.BinaryExpression: - // In the right operand of an && or ||, narrow based on left operand - if (child === (node).right) { - if ((node).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) { - narrowedType = narrowType(type, (node).left, /*assumeTrue*/ true); + if (node && symbol.flags & SymbolFlags.Variable) { + if (isTypeAny(type) || type.flags & (TypeFlags.ObjectType | TypeFlags.Union | TypeFlags.TypeParameter)) { + loop: while (node.parent) { + let child = node; + node = node.parent; + let narrowedType = type; + switch (node.kind) { + case SyntaxKind.IfStatement: + // In a branch of an if statement, narrow based on controlling expression + if (child !== (node).expression) { + narrowedType = narrowType(type, (node).expression, /*assumeTrue*/ child === (node).thenStatement); } - else if ((node).operatorToken.kind === SyntaxKind.BarBarToken) { - narrowedType = narrowType(type, (node).left, /*assumeTrue*/ false); + break; + case SyntaxKind.ConditionalExpression: + // In a branch of a conditional expression, narrow based on controlling condition + if (child !== (node).condition) { + narrowedType = narrowType(type, (node).condition, /*assumeTrue*/ child === (node).whenTrue); } + break; + case SyntaxKind.BinaryExpression: + // In the right operand of an && or ||, narrow based on left operand + if (child === (node).right) { + if ((node).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) { + narrowedType = narrowType(type, (node).left, /*assumeTrue*/ true); + } + else if ((node).operatorToken.kind === SyntaxKind.BarBarToken) { + narrowedType = narrowType(type, (node).left, /*assumeTrue*/ false); + } + } + break; + case SyntaxKind.SourceFile: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.Constructor: + // Stop at the first containing function or module declaration + break loop; + } + // Use narrowed type if construct contains no assignments to variable + if (narrowedType !== type) { + if (isVariableAssignedWithin(symbol, node)) { + break; } - break; - case SyntaxKind.SourceFile: - case SyntaxKind.ModuleDeclaration: - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.MethodDeclaration: - case SyntaxKind.MethodSignature: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - case SyntaxKind.Constructor: - // Stop at the first containing function or module declaration - break loop; - } - // Use narrowed type if construct contains no assignments to variable - if (narrowedType !== type) { - if (isVariableAssignedWithin(symbol, node)) { - break; + type = narrowedType; } - type = narrowedType; } } } + return type; function narrowTypeByEquality(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type { From b5077bf3729c8d65c9f559c813860298899d82a2 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 3 Jun 2015 16:28:14 -0700 Subject: [PATCH 049/107] Remove HarnessDiagnostics. Just use the normal ts Diagnostic instead. --- src/harness/harness.ts | 99 +++++-------------- src/harness/projectsRunner.ts | 3 +- .../reference/contextualTyping.errors.txt | 10 +- .../reference/inlineSourceMap2.errors.txt | 8 +- .../reference/noDefaultLib.errors.txt | 4 +- .../reference/parser509698.errors.txt | 28 +++--- .../amd/invalidRootFile.errors.txt | 6 +- .../node/invalidRootFile.errors.txt | 6 +- ...SourceRootWithNoSourceMapOption.errors.txt | 4 +- ...SourceRootWithNoSourceMapOption.errors.txt | 4 +- .../noDefaultLib/amd/noDefaultLib.errors.txt | 28 +++--- .../noDefaultLib/node/noDefaultLib.errors.txt | 28 +++--- .../typeCheckTypeArgument.errors.txt | 20 ++-- tests/cases/compiler/contextualTyping.ts | 1 - 14 files changed, 103 insertions(+), 146 deletions(-) diff --git a/src/harness/harness.ts b/src/harness/harness.ts index b3791283a63..86cc255b063 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -899,7 +899,7 @@ module Harness { private compileOptions: ts.CompilerOptions; private settings: Harness.TestCaseParser.CompilerSetting[] = []; - private lastErrors: HarnessDiagnostic[]; + private lastErrors: ts.Diagnostic[]; public reset() { this.inputFiles = []; @@ -1078,10 +1078,6 @@ module Harness { } break; - case 'normalizenewline': - newLine = setting.value; - break; - case 'comments': options.removeComments = setting.value === 'false'; break; @@ -1144,11 +1140,7 @@ module Harness { var emitResult = program.emit(); - var errors: HarnessDiagnostic[] = []; - ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics).forEach(err => { - // TODO: new compiler formats errors after this point to add . and newlines so we'll just do it manually for now - errors.push(getMinimalDiagnostic(err)); - }); + var errors = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics); this.lastErrors = errors; var result = new CompilerResult(fileOutputs, errors, program, ts.sys.getCurrentDirectory(), emitResult.sourceMaps); @@ -1235,70 +1227,50 @@ module Harness { return normalized; } - export function getMinimalDiagnostic(err: ts.Diagnostic): HarnessDiagnostic { - var errorLineInfo = err.file ? err.file.getLineAndCharacterOfPosition(err.start) : { line: -1, character: -1 }; - return { - fileName: err.file && err.file.fileName, - start: err.start, - end: err.start + err.length, - line: errorLineInfo.line + 1, - character: errorLineInfo.character + 1, - message: ts.flattenDiagnosticMessageText(err.messageText, ts.sys.newLine), - category: ts.DiagnosticCategory[err.category].toLowerCase(), - code: err.code - }; - } - - export function minimalDiagnosticsToString(diagnostics: HarnessDiagnostic[]) { + export function minimalDiagnosticsToString(diagnostics: ts.Diagnostic[]) { // This is basically copied from tsc.ts's reportError to replicate what tsc does var errorOutput = ""; - ts.forEach(diagnostics, diagnotic => { - if (diagnotic.fileName) { - errorOutput += diagnotic.fileName + "(" + diagnotic.line + "," + diagnotic.character + "): "; + ts.forEach(diagnostics, diagnostic => { + if (diagnostic.file) { + var lineAndCharacter = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start); + errorOutput += diagnostic.file.fileName + "(" + (lineAndCharacter.line + 1) + "," + (lineAndCharacter.character + 1) + "): "; } - errorOutput += diagnotic.category + " TS" + diagnotic.code + ": " + diagnotic.message + ts.sys.newLine; + errorOutput += ts.DiagnosticCategory[diagnostic.category].toLowerCase() + " TS" + diagnostic.code + ": " + ts.flattenDiagnosticMessageText(diagnostic.messageText, ts.sys.newLine) + ts.sys.newLine; }); return errorOutput; } - function compareDiagnostics(d1: HarnessDiagnostic, d2: HarnessDiagnostic) { - return ts.compareValues(d1.fileName, d2.fileName) || - ts.compareValues(d1.start, d2.start) || - ts.compareValues(d1.end, d2.end) || - ts.compareValues(d1.code, d2.code) || - ts.compareValues(d1.message, d2.message) || - 0; - } - - export function getErrorBaseline(inputFiles: { unitName: string; content: string }[], diagnostics: HarnessDiagnostic[]) { - diagnostics.sort(compareDiagnostics); + export function getErrorBaseline(inputFiles: { unitName: string; content: string }[], diagnostics: ts.Diagnostic[]) { + diagnostics.sort(ts.compareDiagnostics); var outputLines: string[] = []; // Count up all the errors we find so we don't miss any var totalErrorsReported = 0; - function outputErrorText(error: Harness.Compiler.HarnessDiagnostic) { - var errLines = RunnerBase.removeFullPaths(error.message) + function outputErrorText(error: ts.Diagnostic) { + var message = ts.flattenDiagnosticMessageText(error.messageText, ts.sys.newLine); + + var errLines = RunnerBase.removeFullPaths(message) .split('\n') .map(s => s.length > 0 && s.charAt(s.length - 1) === '\r' ? s.substr(0, s.length - 1) : s) .filter(s => s.length > 0) - .map(s => '!!! ' + error.category + " TS" + error.code + ": " + s); + .map(s => '!!! ' + ts.DiagnosticCategory[error.category].toLowerCase() + " TS" + error.code + ": " + s); errLines.forEach(e => outputLines.push(e)); totalErrorsReported++; } // Report global errors - var globalErrors = diagnostics.filter(err => !err.fileName); + var globalErrors = diagnostics.filter(err => !err.file); globalErrors.forEach(outputErrorText); // 'merge' the lines of each input file with any errors associated with it inputFiles.filter(f => f.content !== undefined).forEach(inputFile => { // Filter down to the errors in the file var fileErrors = diagnostics.filter(e => { - var errFn = e.fileName; - return errFn && errFn === inputFile.unitName; + var errFn = e.file; + return errFn && errFn.fileName === inputFile.unitName; }); @@ -1334,18 +1306,19 @@ module Harness { outputLines.push(' ' + line); fileErrors.forEach(err => { // Does any error start or continue on to this line? Emit squiggles - if ((err.end >= thisLineStart) && ((err.start < nextLineStart) || (lineIndex === lines.length - 1))) { + let end = ts.textSpanEnd(err); + if ((end >= thisLineStart) && ((err.start < nextLineStart) || (lineIndex === lines.length - 1))) { // How many characters from the start of this line the error starts at (could be positive or negative) var relativeOffset = err.start - thisLineStart; // How many characters of the error are on this line (might be longer than this line in reality) - var length = (err.end - err.start) - Math.max(0, thisLineStart - err.start); + var length = (end - err.start) - Math.max(0, thisLineStart - err.start); // Calculate the start of the squiggle var squiggleStart = Math.max(0, relativeOffset); // TODO/REVIEW: this doesn't work quite right in the browser if a multi file test has files whose names are just the right length relative to one another outputLines.push(' ' + line.substr(0, squiggleStart).replace(/[^\s]/g, ' ') + new Array(Math.min(length, line.length - squiggleStart) + 1).join('~')); // If the error ended here, or we're at the end of the file, emit its message - if ((lineIndex === lines.length - 1) || nextLineStart > err.end) { + if ((lineIndex === lines.length - 1) || nextLineStart > end) { // Just like above, we need to do a split on a string instead of on a regex // because the JS engine does regexes wrong @@ -1361,12 +1334,12 @@ module Harness { }); var numLibraryDiagnostics = ts.countWhere(diagnostics, diagnostic => { - return diagnostic.fileName && (isLibraryFile(diagnostic.fileName) || isBuiltFile(diagnostic.fileName)); + return diagnostic.file && (isLibraryFile(diagnostic.file.fileName) || isBuiltFile(diagnostic.file.fileName)); }); var numTest262HarnessDiagnostics = ts.countWhere(diagnostics, diagnostic => { // Count an error generated from tests262-harness folder.This should only apply for test262 - return diagnostic.fileName && diagnostic.fileName.indexOf("test262-harness") >= 0; + return diagnostic.file && diagnostic.file.fileName.indexOf("test262-harness") >= 0; }); // Verify we didn't miss any errors in total @@ -1419,17 +1392,6 @@ module Harness { //harnessCompiler.compileString(code, unitName, callback); } - export interface HarnessDiagnostic { - fileName: string; - start: number; - end: number; - line: number; - character: number; - message: string; - category: string; - code: number; - } - export interface GeneratedFile { fileName: string; code: string; @@ -1459,12 +1421,12 @@ module Harness { /** Contains the code and errors of a compilation and some helper methods to check its status. */ export class CompilerResult { public files: GeneratedFile[] = []; - public errors: HarnessDiagnostic[] = []; + public errors: ts.Diagnostic[] = []; public declFilesCode: GeneratedFile[] = []; public sourceMaps: GeneratedFile[] = []; /** @param fileResults an array of strings for the fileName and an ITextWriter with its code */ - constructor(fileResults: GeneratedFile[], errors: HarnessDiagnostic[], public program: ts.Program, + constructor(fileResults: GeneratedFile[], errors: ts.Diagnostic[], public program: ts.Program, public currentDirectoryForProgram: string, private sourceMapData: ts.SourceMapData[]) { fileResults.forEach(emittedFile => { @@ -1489,15 +1451,6 @@ module Harness { return Harness.SourceMapRecoder.getSourceMapRecord(this.sourceMapData, this.program, this.files); } } - - public isErrorAt(line: number, column: number, message: string) { - for (var i = 0; i < this.errors.length; i++) { - if ((this.errors[i].line + 1) === line && (this.errors[i].character + 1) === column && this.errors[i].message === message) - return true; - } - - return false; - } } } diff --git a/src/harness/projectsRunner.ts b/src/harness/projectsRunner.ts index 39221d55b29..324524272e0 100644 --- a/src/harness/projectsRunner.ts +++ b/src/harness/projectsRunner.ts @@ -323,9 +323,8 @@ class ProjectRunner extends RunnerBase { sourceFile => { return { unitName: sourceFile.fileName, content: sourceFile.text }; }); - var diagnostics = ts.map(compilerResult.errors, error => Harness.Compiler.getMinimalDiagnostic(error)); - return Harness.Compiler.getErrorBaseline(inputFiles, diagnostics); + return Harness.Compiler.getErrorBaseline(inputFiles, compilerResult.errors); } var name = 'Compiling project for ' + testCase.scenario + ': testcase ' + testCaseFileName; diff --git a/tests/baselines/reference/contextualTyping.errors.txt b/tests/baselines/reference/contextualTyping.errors.txt index f6941b7b92d..2e050777bfd 100644 --- a/tests/baselines/reference/contextualTyping.errors.txt +++ b/tests/baselines/reference/contextualTyping.errors.txt @@ -1,5 +1,11 @@ -tests/cases/compiler/contextualTyping.ts(189,18): error TS2384: Overload signatures must all be ambient or non-ambient.\ntests/cases/compiler/contextualTyping.ts(197,15): error TS2300: Duplicate identifier 'Point'.\ntests/cases/compiler/contextualTyping.ts(207,10): error TS2300: Duplicate identifier 'Point'.\ntests/cases/compiler/contextualTyping.ts(230,5): error TS2322: Type '{}' is not assignable to type 'B'. - Property 'x' is missing in type '{}'.\n\n\n==== tests/cases/compiler/contextualTyping.ts (4 errors) ==== +tests/cases/compiler/contextualTyping.ts(189,18): error TS2384: Overload signatures must all be ambient or non-ambient. +tests/cases/compiler/contextualTyping.ts(197,15): error TS2300: Duplicate identifier 'Point'. +tests/cases/compiler/contextualTyping.ts(207,10): error TS2300: Duplicate identifier 'Point'. +tests/cases/compiler/contextualTyping.ts(230,5): error TS2322: Type '{}' is not assignable to type 'B'. + Property 'x' is missing in type '{}'. + + +==== tests/cases/compiler/contextualTyping.ts (4 errors) ==== // DEFAULT INTERFACES interface IFoo { n: number; diff --git a/tests/baselines/reference/inlineSourceMap2.errors.txt b/tests/baselines/reference/inlineSourceMap2.errors.txt index 75db5689c66..2d8bc4be0c1 100644 --- a/tests/baselines/reference/inlineSourceMap2.errors.txt +++ b/tests/baselines/reference/inlineSourceMap2.errors.txt @@ -1,12 +1,12 @@ -error TS5050: Option 'mapRoot' cannot be specified with option 'inlineSourceMap'. -error TS5049: Option 'sourceRoot' cannot be specified with option 'inlineSourceMap'. error TS5048: Option 'sourceMap' cannot be specified with option 'inlineSourceMap'. +error TS5049: Option 'sourceRoot' cannot be specified with option 'inlineSourceMap'. +error TS5050: Option 'mapRoot' cannot be specified with option 'inlineSourceMap'. tests/cases/compiler/inlineSourceMap2.ts(5,1): error TS2304: Cannot find name 'console'. -!!! error TS5050: Option 'mapRoot' cannot be specified with option 'inlineSourceMap'. -!!! error TS5049: Option 'sourceRoot' cannot be specified with option 'inlineSourceMap'. !!! error TS5048: Option 'sourceMap' cannot be specified with option 'inlineSourceMap'. +!!! error TS5049: Option 'sourceRoot' cannot be specified with option 'inlineSourceMap'. +!!! error TS5050: Option 'mapRoot' cannot be specified with option 'inlineSourceMap'. ==== tests/cases/compiler/inlineSourceMap2.ts (1 errors) ==== // configuration errors diff --git a/tests/baselines/reference/noDefaultLib.errors.txt b/tests/baselines/reference/noDefaultLib.errors.txt index b8f42ba7c33..02098950055 100644 --- a/tests/baselines/reference/noDefaultLib.errors.txt +++ b/tests/baselines/reference/noDefaultLib.errors.txt @@ -1,10 +1,10 @@ -error TS2318: Cannot find global type 'IArguments'. error TS2318: Cannot find global type 'Boolean'. +error TS2318: Cannot find global type 'IArguments'. tests/cases/compiler/noDefaultLib.ts(4,11): error TS2317: Global type 'Array' must have 1 type parameter(s). -!!! error TS2318: Cannot find global type 'IArguments'. !!! error TS2318: Cannot find global type 'Boolean'. +!!! error TS2318: Cannot find global type 'IArguments'. ==== tests/cases/compiler/noDefaultLib.ts (1 errors) ==== /// var x; diff --git a/tests/baselines/reference/parser509698.errors.txt b/tests/baselines/reference/parser509698.errors.txt index 85485dd6501..2aaaec18dc2 100644 --- a/tests/baselines/reference/parser509698.errors.txt +++ b/tests/baselines/reference/parser509698.errors.txt @@ -1,21 +1,21 @@ -error TS2318: Cannot find global type 'String'. -error TS2318: Cannot find global type 'RegExp'. -error TS2318: Cannot find global type 'Object'. -error TS2318: Cannot find global type 'Number'. -error TS2318: Cannot find global type 'IArguments'. -error TS2318: Cannot find global type 'Function'. -error TS2318: Cannot find global type 'Boolean'. error TS2318: Cannot find global type 'Array'. +error TS2318: Cannot find global type 'Boolean'. +error TS2318: Cannot find global type 'Function'. +error TS2318: Cannot find global type 'IArguments'. +error TS2318: Cannot find global type 'Number'. +error TS2318: Cannot find global type 'Object'. +error TS2318: Cannot find global type 'RegExp'. +error TS2318: Cannot find global type 'String'. -!!! error TS2318: Cannot find global type 'String'. -!!! error TS2318: Cannot find global type 'RegExp'. -!!! error TS2318: Cannot find global type 'Object'. -!!! error TS2318: Cannot find global type 'Number'. -!!! error TS2318: Cannot find global type 'IArguments'. -!!! error TS2318: Cannot find global type 'Function'. -!!! error TS2318: Cannot find global type 'Boolean'. !!! error TS2318: Cannot find global type 'Array'. +!!! error TS2318: Cannot find global type 'Boolean'. +!!! error TS2318: Cannot find global type 'Function'. +!!! error TS2318: Cannot find global type 'IArguments'. +!!! error TS2318: Cannot find global type 'Number'. +!!! error TS2318: Cannot find global type 'Object'. +!!! error TS2318: Cannot find global type 'RegExp'. +!!! error TS2318: Cannot find global type 'String'. ==== tests/cases/conformance/parser/ecmascript5/RegressionTests/parser509698.ts (0 errors) ==== ///