From 39eb187e5c530ac1124bfeefd7c2c811493e55de Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 11 Nov 2016 01:22:06 -0800 Subject: [PATCH 01/63] Added diagnostic. --- src/compiler/diagnosticMessages.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 9a353e6fb36..1ae59b61acc 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3159,6 +3159,10 @@ "category": "Message", "code": 90007 }, + "Add 'this.' to unresolved variable.": { + "category": "Message", + "code": 90008 + }, "Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig": { "category": "Error", "code": 90009 From da356b075a4829e616bebe26196c5944ac9393c9 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 11 Nov 2016 01:25:50 -0800 Subject: [PATCH 02/63] Added tests for missing 'this' property accesses. --- tests/cases/fourslash/codeFixAddForgottenThis01.ts | 10 ++++++++++ tests/cases/fourslash/codeFixAddForgottenThis02.ts | 9 +++++++++ 2 files changed, 19 insertions(+) create mode 100644 tests/cases/fourslash/codeFixAddForgottenThis01.ts create mode 100644 tests/cases/fourslash/codeFixAddForgottenThis02.ts diff --git a/tests/cases/fourslash/codeFixAddForgottenThis01.ts b/tests/cases/fourslash/codeFixAddForgottenThis01.ts new file mode 100644 index 00000000000..90d191b6ba5 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddForgottenThis01.ts @@ -0,0 +1,10 @@ +/// + +////class C { +//// foo: number; +//// constructor() { +//// [|foo = 10|]; +//// } +////} + +verify.rangeAfterCodeFix("this.foo = 10"); \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixAddForgottenThis02.ts b/tests/cases/fourslash/codeFixAddForgottenThis02.ts new file mode 100644 index 00000000000..b387f349073 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddForgottenThis02.ts @@ -0,0 +1,9 @@ +/// + +////class C { +//// constructor(public foo) { +//// } +//// bar() { [|foo = 10|] }; +////} + +verify.rangeAfterCodeFix("this.foo = 10"); \ No newline at end of file From f2c0aa4444db61ee3870c6d3dc7b8cb74cc44e05 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 11 Nov 2016 01:27:26 -0800 Subject: [PATCH 03/63] Added fix for missing 'this.' property accesses. --- .../codefixes/fixForgottenThisPropertyAccess.ts | 16 ++++++++++++++++ src/services/codefixes/fixes.ts | 3 ++- src/services/tsconfig.json | 3 ++- 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 src/services/codefixes/fixForgottenThisPropertyAccess.ts diff --git a/src/services/codefixes/fixForgottenThisPropertyAccess.ts b/src/services/codefixes/fixForgottenThisPropertyAccess.ts new file mode 100644 index 00000000000..c9d59dd8337 --- /dev/null +++ b/src/services/codefixes/fixForgottenThisPropertyAccess.ts @@ -0,0 +1,16 @@ +/* @internal */ +namespace ts.codefix { + registerCodeFix({ + errorCodes: [Diagnostics.Cannot_find_name_0_Did_you_mean_the_instance_member_this_0.code], + getCodeActions: (context: CodeFixContext) => { + const sourceFile = context.sourceFile; + const token = getTokenAtPosition(sourceFile, context.span.start); + const start = token.getStart(sourceFile); + + return [{ + description: getLocaleSpecificMessage(Diagnostics.Add_this_to_unresolved_variable), + changes: [{ fileName: sourceFile.fileName, textChanges: [{ newText: "this.", span: { start, length: 0 } }] }] + }]; + } + }); +} \ No newline at end of file diff --git a/src/services/codefixes/fixes.ts b/src/services/codefixes/fixes.ts index 982b6abc84b..da51f04ff8c 100644 --- a/src/services/codefixes/fixes.ts +++ b/src/services/codefixes/fixes.ts @@ -3,4 +3,5 @@ /// /// /// -/// \ No newline at end of file +/// +/// \ No newline at end of file diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json index 69efe29ba39..699ffcd7612 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -91,6 +91,7 @@ "codeFixes/fixClassIncorrectlyImplementsInterface.ts", "codeFixes/fixClassDoesntImplementInheritedAbstractMember.ts", "codeFixes/fixClassSuperMustPrecedeThisAccess.ts", - "codeFixes/fixConstructorForDerivedNeedSuperCall.ts" + "codeFixes/fixConstructorForDerivedNeedSuperCall.ts", + "codefixes/fixForgottenThisPropertyAccess.ts" ] } From b220831ab7a89fd7e03889911cea738e9daafd31 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Tue, 29 Nov 2016 07:01:31 -0800 Subject: [PATCH 04/63] Sort matched files by include order --- src/compiler/commandLineParser.ts | 1 - src/compiler/core.ts | 123 +++++++++++------- src/harness/unittests/matchFiles.ts | 52 ++++++-- .../nodeModulesMaxDepthExceeded.errors.txt | 20 +-- .../amd/nodeModulesMaxDepthExceeded.json | 4 +- .../nodeModulesMaxDepthExceeded.errors.txt | 20 +-- .../node/nodeModulesMaxDepthExceeded.json | 4 +- 7 files changed, 141 insertions(+), 83 deletions(-) diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 3c6a86134ea..a81698469e7 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -1264,7 +1264,6 @@ namespace ts { const literalFiles = reduceProperties(literalFileMap, addFileToOutput, []); const wildcardFiles = reduceProperties(wildcardFileMap, addFileToOutput, []); - wildcardFiles.sort(host.useCaseSensitiveFileNames ? compareStrings : compareStringsCaseInsensitive); return { fileNames: literalFiles.concat(wildcardFiles), wildcardDirectories diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 89057dd2939..8406404132d 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -1668,7 +1668,19 @@ namespace ts { const singleAsteriskRegexFragmentFiles = "([^./]|(\\.(?!min\\.js$))?)*"; const singleAsteriskRegexFragmentOther = "[^/]*"; - export function getRegularExpressionForWildcard(specs: string[], basePath: string, usage: "files" | "directories" | "exclude") { + export function getRegularExpressionForWildcard(specs: string[], basePath: string, usage: "files" | "directories" | "exclude"): string | undefined { + const patterns = getRegularExpressionsForWildcards(specs, basePath, usage); + if (!patterns || !patterns.length) { + return undefined; + } + + const pattern = patterns.map(pattern => `(${pattern})`).join("|"); + // If excluding, match "foo/bar/baz...", but if including, only allow "foo". + const terminator = usage === "exclude" ? "($|/)" : "$"; + return `^(${pattern})${terminator}`; + } + + function getRegularExpressionsForWildcards(specs: string[], basePath: string, usage: "files" | "directories" | "exclude"): string[] | undefined { if (specs === undefined || specs.length === 0) { return undefined; } @@ -1682,33 +1694,8 @@ namespace ts { */ const doubleAsteriskRegexFragment = usage === "exclude" ? "(/.+?)?" : "(/[^/.][^/]*)*?"; - let pattern = ""; - let hasWrittenSubpattern = false; - for (const spec of specs) { - if (!spec) { - continue; - } - - const subPattern = getSubPatternFromSpec(spec, basePath, usage, singleAsteriskRegexFragment, doubleAsteriskRegexFragment, replaceWildcardCharacter); - if (subPattern === undefined) { - continue; - } - - if (hasWrittenSubpattern) { - pattern += "|"; - } - - pattern += "(" + subPattern + ")"; - hasWrittenSubpattern = true; - } - - if (!pattern) { - return undefined; - } - - // If excluding, match "foo/bar/baz...", but if including, only allow "foo". - const terminator = usage === "exclude" ? "($|/)" : "$"; - return `^(${pattern})${terminator}`; + return flatMap(specs, spec => + spec && getSubPatternFromSpec(spec, basePath, usage, singleAsteriskRegexFragment, doubleAsteriskRegexFragment, replaceWildcardCharacter)); } /** @@ -1803,6 +1790,9 @@ namespace ts { } export interface FileMatcherPatterns { + /** One pattern for each "include" spec. */ + includeFilePatterns: string[]; + /** One pattern matching one of any of the "include" specs. */ includeFilePattern: string; includeDirectoryPattern: string; excludePattern: string; @@ -1815,6 +1805,7 @@ namespace ts { const absolutePath = combinePaths(currentDirectory, path); return { + includeFilePatterns: map(getRegularExpressionsForWildcards(includes, absolutePath, "files"), pattern => `^${pattern}$`), includeFilePattern: getRegularExpressionForWildcard(includes, absolutePath, "files"), includeDirectoryPattern: getRegularExpressionForWildcard(includes, absolutePath, "directories"), excludePattern: getRegularExpressionForWildcard(excludes, absolutePath, "exclude"), @@ -1829,38 +1820,76 @@ namespace ts { const patterns = getFileMatcherPatterns(path, excludes, includes, useCaseSensitiveFileNames, currentDirectory); const regexFlag = useCaseSensitiveFileNames ? "" : "i"; - const includeFileRegex = patterns.includeFilePattern && new RegExp(patterns.includeFilePattern, regexFlag); + const includeFileRegexes = patterns.includeFilePatterns && patterns.includeFilePatterns.map(pattern => new RegExp(pattern, regexFlag)); const includeDirectoryRegex = patterns.includeDirectoryPattern && new RegExp(patterns.includeDirectoryPattern, regexFlag); const excludeRegex = patterns.excludePattern && new RegExp(patterns.excludePattern, regexFlag); - const result: string[] = []; + // Associate an array of results with each include regex. This keeps results in order of the "include" order. + // If there are no "includes", then just put everything in results[0]. + const results: string[][] = includeFileRegexes ? includeFileRegexes.map(() => []) : [[]]; + for (const basePath of patterns.basePaths) { - visitDirectory(basePath, combinePaths(currentDirectory, basePath)); + forEachFileInRecursiveDirectories(basePath, combinePaths(currentDirectory, basePath), { useCaseSensitiveFileNames, getFileSystemEntries, includeDirectory, visitFile }); } - return result; + + return flatten(results); + + function includeDirectory(absoluteDirectoryName: string): boolean { + return (!includeDirectoryRegex || includeDirectoryRegex.test(absoluteDirectoryName)) && + (!excludeRegex || !excludeRegex.test(absoluteDirectoryName)); + } + + function visitFile(fileName: string, absoluteFileName: string): void { + if (extensions && !fileExtensionIsAny(fileName, extensions) || + excludeRegex && excludeRegex.test(absoluteFileName)) { + return; + } + + if (!includeFileRegexes) { + results[0].push(fileName); + } + else { + for (let i = 0; i < includeFileRegexes.length; i++) { + if (includeFileRegexes[i].test(absoluteFileName)) { + results[i].push(fileName); + // Only include a file once. + break; + } + } + } + } + } + + interface RecursiveDirectoryVisitor { + useCaseSensitiveFileNames: boolean; + getFileSystemEntries: (path: string) => FileSystemEntries; + includeDirectory: (absoluteDirectoryName: string) => boolean; + visitFile: (fileName: string, absoluteFileName: string) => void; + } + + function forEachFileInRecursiveDirectories(start: string, absoluteStart: string, visitor: RecursiveDirectoryVisitor): void { + visitDirectory(start, absoluteStart); function visitDirectory(path: string, absolutePath: string) { - const { files, directories } = getFileSystemEntries(path); + let { files, directories } = visitor.getFileSystemEntries(path); + files = sorted(files); + directories = sorted(directories); - for (const current of files) { - const name = combinePaths(path, current); - const absoluteName = combinePaths(absolutePath, current); - if ((!extensions || fileExtensionIsAny(name, extensions)) && - (!includeFileRegex || includeFileRegex.test(absoluteName)) && - (!excludeRegex || !excludeRegex.test(absoluteName))) { - result.push(name); - } + for (const file of files) { + visitor.visitFile(combinePaths(path, file), combinePaths(absolutePath, file)); } - for (const current of directories) { - const name = combinePaths(path, current); - const absoluteName = combinePaths(absolutePath, current); - if ((!includeDirectoryRegex || includeDirectoryRegex.test(absoluteName)) && - (!excludeRegex || !excludeRegex.test(absoluteName))) { - visitDirectory(name, absoluteName); + for (const dir of directories) { + const absoluteName = combinePaths(absolutePath, dir); + if (visitor.includeDirectory(absoluteName)) { + visitDirectory(combinePaths(path, dir), absoluteName); } } } + + function sorted(names: string[]): string[] { + return names.slice().sort(visitor.useCaseSensitiveFileNames ? compareStrings : compareStringsCaseInsensitive); + } } /** diff --git a/src/harness/unittests/matchFiles.ts b/src/harness/unittests/matchFiles.ts index c562fcefe91..00efe73c3e2 100644 --- a/src/harness/unittests/matchFiles.ts +++ b/src/harness/unittests/matchFiles.ts @@ -346,9 +346,9 @@ namespace ts { fileNames: [ "c:/dev/a.ts", "c:/dev/b.ts", + "c:/dev/node_modules/a.ts", "c:/dev/bower_components/a.ts", - "c:/dev/jspm_packages/a.ts", - "c:/dev/node_modules/a.ts" + "c:/dev/jspm_packages/a.ts" ], wildcardDirectories: {}, }; @@ -373,9 +373,9 @@ namespace ts { options: {}, errors: [], fileNames: [ + "c:/dev/node_modules/a.ts", "c:/dev/bower_components/a.ts", - "c:/dev/jspm_packages/a.ts", - "c:/dev/node_modules/a.ts" + "c:/dev/jspm_packages/a.ts" ], wildcardDirectories: {}, }; @@ -398,9 +398,9 @@ namespace ts { fileNames: [ "c:/dev/a.ts", "c:/dev/b.ts", + "c:/dev/node_modules/a.ts", "c:/dev/bower_components/a.ts", - "c:/dev/jspm_packages/a.ts", - "c:/dev/node_modules/a.ts" + "c:/dev/jspm_packages/a.ts" ], wildcardDirectories: {}, }; @@ -410,6 +410,36 @@ namespace ts { }); describe("with wildcard include list", () => { + it("is sorted in include order, then in alphabetical order", () => { + const json = { + include: [ + "z/*.ts", + "x/*.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/z/a.ts", + "c:/dev/z/aba.ts", + "c:/dev/z/abz.ts", + "c:/dev/z/b.ts", + "c:/dev/z/bba.ts", + "c:/dev/z/bbz.ts", + "c:/dev/x/a.ts", + "c:/dev/x/aa.ts", + "c:/dev/x/b.ts" + ], + wildcardDirectories: { + "c:/dev/z": ts.WatchDirectoryFlags.None, + "c:/dev/x": ts.WatchDirectoryFlags.None + }, + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assertParsed(actual, expected); + }); + it("same named declarations are excluded", () => { const json = { include: [ @@ -506,8 +536,8 @@ namespace ts { options: {}, errors: [], fileNames: [ - "c:/dev/x/a.ts", "c:/dev/x/y/a.ts", + "c:/dev/x/a.ts", "c:/dev/z/a.ts" ], wildcardDirectories: { @@ -1230,8 +1260,8 @@ namespace ts { options: {}, errors: [], fileNames: [ - "c:/dev/.z/.b.ts", - "c:/dev/x/.y/a.ts" + "c:/dev/x/.y/a.ts", + "c:/dev/.z/.b.ts" ], wildcardDirectories: {} }; @@ -1271,8 +1301,8 @@ namespace ts { options: {}, errors: [], fileNames: [ - "c:/dev/.z/.b.ts", - "c:/dev/x/.y/a.ts" + "c:/dev/x/.y/a.ts", + "c:/dev/.z/.b.ts" ], wildcardDirectories: { "c:/dev/.z": ts.WatchDirectoryFlags.Recursive, diff --git a/tests/baselines/reference/project/nodeModulesMaxDepthExceeded/amd/nodeModulesMaxDepthExceeded.errors.txt b/tests/baselines/reference/project/nodeModulesMaxDepthExceeded/amd/nodeModulesMaxDepthExceeded.errors.txt index 99e7b193f0c..5b5199ad7ae 100644 --- a/tests/baselines/reference/project/nodeModulesMaxDepthExceeded/amd/nodeModulesMaxDepthExceeded.errors.txt +++ b/tests/baselines/reference/project/nodeModulesMaxDepthExceeded/amd/nodeModulesMaxDepthExceeded.errors.txt @@ -2,19 +2,10 @@ maxDepthExceeded/root.ts(3,1): error TS2322: Type '"10"' is not assignable to ty maxDepthExceeded/root.ts(4,4): error TS2540: Cannot assign to 'rel' because it is a constant or a read-only property. -==== entry.js (0 errors) ==== - var m3 = require("m3"); - - module.exports = { - "a": 42, - "b": "hello, world", - "person": m3.person - }; - ==== relative.js (0 errors) ==== exports.relativeProp = true; -==== maxDepthExceeded/node_modules/m1/index.js (0 errors) ==== +==== index.js (0 errors) ==== var m2 = require('m2'); var rel = require('./relative'); @@ -40,4 +31,13 @@ maxDepthExceeded/root.ts(4,4): error TS2540: Cannot assign to 'rel' because it i !!! error TS2540: Cannot assign to 'rel' because it is a constant or a read-only property. m1.f2.person.age = "10"; // OK if stopped at 2 modules: person will be "any". + +==== entry.js (0 errors) ==== + var m3 = require("m3"); + + module.exports = { + "a": 42, + "b": "hello, world", + "person": m3.person + }; \ No newline at end of file diff --git a/tests/baselines/reference/project/nodeModulesMaxDepthExceeded/amd/nodeModulesMaxDepthExceeded.json b/tests/baselines/reference/project/nodeModulesMaxDepthExceeded/amd/nodeModulesMaxDepthExceeded.json index 86e856dc7b8..9efa0e936ac 100644 --- a/tests/baselines/reference/project/nodeModulesMaxDepthExceeded/amd/nodeModulesMaxDepthExceeded.json +++ b/tests/baselines/reference/project/nodeModulesMaxDepthExceeded/amd/nodeModulesMaxDepthExceeded.json @@ -7,10 +7,10 @@ "project": "maxDepthExceeded", "resolvedInputFiles": [ "lib.d.ts", - "maxDepthExceeded/node_modules/m2/entry.js", "maxDepthExceeded/node_modules/m1/relative.js", "maxDepthExceeded/node_modules/m1/index.js", - "maxDepthExceeded/root.ts" + "maxDepthExceeded/root.ts", + "maxDepthExceeded/node_modules/m2/entry.js" ], "emittedFiles": [ "maxDepthExceeded/built/node_modules/m1/relative.js", diff --git a/tests/baselines/reference/project/nodeModulesMaxDepthExceeded/node/nodeModulesMaxDepthExceeded.errors.txt b/tests/baselines/reference/project/nodeModulesMaxDepthExceeded/node/nodeModulesMaxDepthExceeded.errors.txt index 99e7b193f0c..5b5199ad7ae 100644 --- a/tests/baselines/reference/project/nodeModulesMaxDepthExceeded/node/nodeModulesMaxDepthExceeded.errors.txt +++ b/tests/baselines/reference/project/nodeModulesMaxDepthExceeded/node/nodeModulesMaxDepthExceeded.errors.txt @@ -2,19 +2,10 @@ maxDepthExceeded/root.ts(3,1): error TS2322: Type '"10"' is not assignable to ty maxDepthExceeded/root.ts(4,4): error TS2540: Cannot assign to 'rel' because it is a constant or a read-only property. -==== entry.js (0 errors) ==== - var m3 = require("m3"); - - module.exports = { - "a": 42, - "b": "hello, world", - "person": m3.person - }; - ==== relative.js (0 errors) ==== exports.relativeProp = true; -==== maxDepthExceeded/node_modules/m1/index.js (0 errors) ==== +==== index.js (0 errors) ==== var m2 = require('m2'); var rel = require('./relative'); @@ -40,4 +31,13 @@ maxDepthExceeded/root.ts(4,4): error TS2540: Cannot assign to 'rel' because it i !!! error TS2540: Cannot assign to 'rel' because it is a constant or a read-only property. m1.f2.person.age = "10"; // OK if stopped at 2 modules: person will be "any". + +==== entry.js (0 errors) ==== + var m3 = require("m3"); + + module.exports = { + "a": 42, + "b": "hello, world", + "person": m3.person + }; \ No newline at end of file diff --git a/tests/baselines/reference/project/nodeModulesMaxDepthExceeded/node/nodeModulesMaxDepthExceeded.json b/tests/baselines/reference/project/nodeModulesMaxDepthExceeded/node/nodeModulesMaxDepthExceeded.json index 86e856dc7b8..9efa0e936ac 100644 --- a/tests/baselines/reference/project/nodeModulesMaxDepthExceeded/node/nodeModulesMaxDepthExceeded.json +++ b/tests/baselines/reference/project/nodeModulesMaxDepthExceeded/node/nodeModulesMaxDepthExceeded.json @@ -7,10 +7,10 @@ "project": "maxDepthExceeded", "resolvedInputFiles": [ "lib.d.ts", - "maxDepthExceeded/node_modules/m2/entry.js", "maxDepthExceeded/node_modules/m1/relative.js", "maxDepthExceeded/node_modules/m1/index.js", - "maxDepthExceeded/root.ts" + "maxDepthExceeded/root.ts", + "maxDepthExceeded/node_modules/m2/entry.js" ], "emittedFiles": [ "maxDepthExceeded/built/node_modules/m1/relative.js", From 157a9b02fc5e9aa825697bd7779145eded74cdf5 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Mon, 5 Dec 2016 08:43:16 -0800 Subject: [PATCH 05/63] Properly determine whether an augmentation is a ValueModule or NamespaceModule --- src/compiler/binder.ts | 19 ++++++++++------ .../reference/augmentExportEquals7.errors.txt | 22 +++++++++++++++++++ tests/cases/compiler/augmentExportEquals7.ts | 10 +++++++++ 3 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 tests/baselines/reference/augmentExportEquals7.errors.txt create mode 100644 tests/cases/compiler/augmentExportEquals7.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index a6f5993f6c8..e00e9294529 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1509,7 +1509,7 @@ namespace ts { errorOnFirstToken(node, Diagnostics.export_modifier_cannot_be_applied_to_ambient_modules_and_module_augmentations_since_they_are_always_visible); } if (isExternalModuleAugmentation(node)) { - declareSymbolAndAddToSymbolTable(node, SymbolFlags.NamespaceModule, SymbolFlags.NamespaceModuleExcludes); + declareModuleSymbol(node); } else { let pattern: Pattern | undefined; @@ -1531,12 +1531,8 @@ namespace ts { } } else { - const state = getModuleInstanceState(node); - if (state === ModuleInstanceState.NonInstantiated) { - declareSymbolAndAddToSymbolTable(node, SymbolFlags.NamespaceModule, SymbolFlags.NamespaceModuleExcludes); - } - else { - declareSymbolAndAddToSymbolTable(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes); + const state = declareModuleSymbol(node); + if (state !== ModuleInstanceState.NonInstantiated) { if (node.symbol.flags & (SymbolFlags.Function | SymbolFlags.Class | SymbolFlags.RegularEnum)) { // if module was already merged with some function, class or non-const enum // treat is a non-const-enum-only @@ -1557,6 +1553,15 @@ namespace ts { } } + function declareModuleSymbol(node: ModuleDeclaration): ModuleInstanceState { + const state = getModuleInstanceState(node); + const instantiated = state !== ModuleInstanceState.NonInstantiated; + declareSymbolAndAddToSymbolTable(node, + instantiated ? SymbolFlags.ValueModule : SymbolFlags.NamespaceModule, + instantiated ? SymbolFlags.ValueModuleExcludes : SymbolFlags.NamespaceModuleExcludes); + return state; + } + function bindFunctionOrConstructorType(node: SignatureDeclaration): void { // For a given function symbol "<...>(...) => T" we want to generate a symbol identical // to the one we would get for: { <...>(...): T } diff --git a/tests/baselines/reference/augmentExportEquals7.errors.txt b/tests/baselines/reference/augmentExportEquals7.errors.txt new file mode 100644 index 00000000000..1cb9ddc041c --- /dev/null +++ b/tests/baselines/reference/augmentExportEquals7.errors.txt @@ -0,0 +1,22 @@ +/node_modules/@types/lib-extender/index.d.ts(2,16): error TS2300: Duplicate identifier '"lib"'. +/node_modules/lib/index.d.ts(1,13): error TS2300: Duplicate identifier '"lib"'. +/node_modules/lib/index.d.ts(2,19): error TS2300: Duplicate identifier '"lib"'. + + +==== /node_modules/lib/index.d.ts (2 errors) ==== + declare var lib: () => void; + ~~~ +!!! error TS2300: Duplicate identifier '"lib"'. + declare namespace lib {} + ~~~ +!!! error TS2300: Duplicate identifier '"lib"'. + export = lib; + +==== /node_modules/@types/lib-extender/index.d.ts (1 errors) ==== + import * as lib from "lib"; + declare module "lib" { + ~~~~~ +!!! error TS2300: Duplicate identifier '"lib"'. + export function fn(): void; + } + \ No newline at end of file diff --git a/tests/cases/compiler/augmentExportEquals7.ts b/tests/cases/compiler/augmentExportEquals7.ts new file mode 100644 index 00000000000..c287bcbe8c4 --- /dev/null +++ b/tests/cases/compiler/augmentExportEquals7.ts @@ -0,0 +1,10 @@ +// @Filename: /node_modules/lib/index.d.ts +declare var lib: () => void; +declare namespace lib {} +export = lib; + +// @Filename: /node_modules/@types/lib-extender/index.d.ts +import * as lib from "lib"; +declare module "lib" { + export function fn(): void; +} From 7beeb77201450aa8a95d494f3fde167c1fb9b550 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Mon, 5 Dec 2016 10:58:47 -0800 Subject: [PATCH 06/63] Update baseline --- .../reference/globalAugmentationModuleResolution.types | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/baselines/reference/globalAugmentationModuleResolution.types b/tests/baselines/reference/globalAugmentationModuleResolution.types index c057ea2943d..75f23b0cd6b 100644 --- a/tests/baselines/reference/globalAugmentationModuleResolution.types +++ b/tests/baselines/reference/globalAugmentationModuleResolution.types @@ -3,7 +3,7 @@ export { }; declare global { ->global : any +>global : typeof global var x: number; >x : number From 39040f61540c2a2ec3cb9a9cc5c2920a3a0188fe Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Wed, 7 Dec 2016 13:13:21 -0800 Subject: [PATCH 07/63] Provide better error message --- src/compiler/checker.ts | 3 +++ src/compiler/diagnosticMessages.json | 4 ++++ .../reference/augmentExportEquals7.errors.txt | 12 +++--------- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 903c8cfda1c..d2d4502c79d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -479,6 +479,9 @@ namespace ts { } recordMergedSymbol(target, source); } + else if (target.flags & SymbolFlags.NamespaceModule) { + error(source.valueDeclaration.name, Diagnostics.Cannot_augment_module_0_with_value_exports_because_it_resolves_to_a_non_module_entity, symbolToString(target)); + } else { const message = target.flags & SymbolFlags.BlockScopedVariable || source.flags & SymbolFlags.BlockScopedVariable ? Diagnostics.Cannot_redeclare_block_scoped_variable_0 : Diagnostics.Duplicate_identifier_0; diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 4d42c77e566..19b297fd4a9 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1807,6 +1807,10 @@ "category": "Error", "code": 2608 }, + "Cannot augment module '{0}' with value exports because it resolves to a non-module entity.": { + "category": "Error", + "code": 2649 + }, "Cannot emit namespaced JSX elements in React": { "category": "Error", "code": 2650 diff --git a/tests/baselines/reference/augmentExportEquals7.errors.txt b/tests/baselines/reference/augmentExportEquals7.errors.txt index 1cb9ddc041c..e13cf037023 100644 --- a/tests/baselines/reference/augmentExportEquals7.errors.txt +++ b/tests/baselines/reference/augmentExportEquals7.errors.txt @@ -1,22 +1,16 @@ -/node_modules/@types/lib-extender/index.d.ts(2,16): error TS2300: Duplicate identifier '"lib"'. -/node_modules/lib/index.d.ts(1,13): error TS2300: Duplicate identifier '"lib"'. -/node_modules/lib/index.d.ts(2,19): error TS2300: Duplicate identifier '"lib"'. +/node_modules/@types/lib-extender/index.d.ts(2,16): error TS2649: Cannot augment module 'lib' with value exports because it resolves to a non-module entity. -==== /node_modules/lib/index.d.ts (2 errors) ==== +==== /node_modules/lib/index.d.ts (0 errors) ==== declare var lib: () => void; - ~~~ -!!! error TS2300: Duplicate identifier '"lib"'. declare namespace lib {} - ~~~ -!!! error TS2300: Duplicate identifier '"lib"'. export = lib; ==== /node_modules/@types/lib-extender/index.d.ts (1 errors) ==== import * as lib from "lib"; declare module "lib" { ~~~~~ -!!! error TS2300: Duplicate identifier '"lib"'. +!!! error TS2649: Cannot augment module 'lib' with value exports because it resolves to a non-module entity. export function fn(): void; } \ No newline at end of file From e8af1d285beb1f3517fd049fb6373958b1b15c4a Mon Sep 17 00:00:00 2001 From: Herrington Darkholme Date: Sun, 8 Jan 2017 18:31:56 +0800 Subject: [PATCH 08/63] update declaration file to use intrinsic object type --- src/lib/es2015.collection.d.ts | 4 ++-- src/lib/es2015.core.d.ts | 2 +- src/lib/es2015.iterable.d.ts | 6 +++--- src/lib/es2015.proxy.d.ts | 4 ++-- src/lib/es2015.symbol.wellknown.d.ts | 4 ++-- src/lib/es5.d.ts | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/lib/es2015.collection.d.ts b/src/lib/es2015.collection.d.ts index 6a2c43cd050..f93053e4288 100644 --- a/src/lib/es2015.collection.d.ts +++ b/src/lib/es2015.collection.d.ts @@ -22,7 +22,7 @@ interface ReadonlyMap { readonly size: number; } -interface WeakMap { +interface WeakMap { delete(key: K): boolean; get(key: K): V | undefined; has(key: K): boolean; @@ -31,7 +31,7 @@ interface WeakMap { interface WeakMapConstructor { new (): WeakMap; - new (entries?: [K, V][]): WeakMap; + new (entries?: [K, V][]): WeakMap; readonly prototype: WeakMap; } declare var WeakMap: WeakMapConstructor; diff --git a/src/lib/es2015.core.d.ts b/src/lib/es2015.core.d.ts index 356512ecf58..eb23ce7901f 100644 --- a/src/lib/es2015.core.d.ts +++ b/src/lib/es2015.core.d.ts @@ -325,7 +325,7 @@ interface ObjectConstructor { * @param o The object to change its prototype. * @param proto The value of the new prototype or null. */ - setPrototypeOf(o: any, proto: any): any; + setPrototypeOf(o: any, proto: object | null): any; /** * Gets the own property descriptor of the specified object. diff --git a/src/lib/es2015.iterable.d.ts b/src/lib/es2015.iterable.d.ts index de339e2bf2c..c8b5158bcd6 100644 --- a/src/lib/es2015.iterable.d.ts +++ b/src/lib/es2015.iterable.d.ts @@ -99,10 +99,10 @@ interface MapConstructor { new (iterable: Iterable<[K, V]>): Map; } -interface WeakMap { } +interface WeakMap { } interface WeakMapConstructor { - new (iterable: Iterable<[K, V]>): WeakMap; + new (iterable: Iterable<[K, V]>): WeakMap; } interface Set { @@ -442,4 +442,4 @@ interface Float64ArrayConstructor { * @param thisArg Value of 'this' used to invoke the mapfn. */ from(arrayLike: Iterable, mapfn?: (v: number, k: number) => number, thisArg?: any): Float64Array; -} \ No newline at end of file +} diff --git a/src/lib/es2015.proxy.d.ts b/src/lib/es2015.proxy.d.ts index 34aedce0128..efccfd47cc5 100644 --- a/src/lib/es2015.proxy.d.ts +++ b/src/lib/es2015.proxy.d.ts @@ -1,5 +1,5 @@ interface ProxyHandler { - getPrototypeOf? (target: T): {} | null; + getPrototypeOf? (target: T): object | null; setPrototypeOf? (target: T, v: any): boolean; isExtensible? (target: T): boolean; preventExtensions? (target: T): boolean; @@ -12,7 +12,7 @@ interface ProxyHandler { enumerate? (target: T): PropertyKey[]; ownKeys? (target: T): PropertyKey[]; apply? (target: T, thisArg: any, argArray?: any): any; - construct? (target: T, argArray: any, newTarget?: any): {}; + construct? (target: T, argArray: any, newTarget?: any): object } interface ProxyConstructor { diff --git a/src/lib/es2015.symbol.wellknown.d.ts b/src/lib/es2015.symbol.wellknown.d.ts index 145d8af6b10..7177b78e483 100644 --- a/src/lib/es2015.symbol.wellknown.d.ts +++ b/src/lib/es2015.symbol.wellknown.d.ts @@ -110,7 +110,7 @@ interface Map { readonly [Symbol.toStringTag]: "Map"; } -interface WeakMap{ +interface WeakMap{ readonly [Symbol.toStringTag]: "WeakMap"; } @@ -324,4 +324,4 @@ interface Float32Array { */ interface Float64Array { readonly [Symbol.toStringTag]: "Float64Array"; -} \ No newline at end of file +} diff --git a/src/lib/es5.d.ts b/src/lib/es5.d.ts index e5eabe950a2..038d0344fda 100644 --- a/src/lib/es5.d.ts +++ b/src/lib/es5.d.ts @@ -146,14 +146,14 @@ interface ObjectConstructor { * Creates an object that has the specified prototype, and that optionally contains specified properties. * @param o Object to use as a prototype. May be null */ - create(o: T): T; + create(o: T): T; /** * Creates an object that has the specified prototype, and that optionally contains specified properties. * @param o Object to use as a prototype. May be null * @param properties JavaScript object that contains one or more property descriptors. */ - create(o: any, properties: PropertyDescriptorMap): any; + create(o: object | null, properties: PropertyDescriptorMap): any; /** * Adds a property to an object, or modifies attributes of an existing property. From 54d64ceb98425d13ae038e91e46849c5c93ab151 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Mon, 9 Jan 2017 06:55:42 -0800 Subject: [PATCH 09/63] Respond to PR comment --- src/compiler/core.ts | 83 ++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 49 deletions(-) diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 3aab91f53ad..89131e16359 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -164,6 +164,16 @@ namespace ts { return undefined; } + /** Works like Array.prototype.findIndex, returning `-1` if no element satisfying the predicate is found. */ + export function findIndex(array: T[], predicate: (element: T, index: number) => boolean): number { + for (let i = 0; i < array.length; i++) { + if (predicate(array[i], i)) { + return i; + } + } + return -1; + } + /** * Returns the first truthy result of `callback`, or else fails. * This is like `forEach`, but never returns undefined. @@ -1810,68 +1820,43 @@ namespace ts { // If there are no "includes", then just put everything in results[0]. const results: string[][] = includeFileRegexes ? includeFileRegexes.map(() => []) : [[]]; + const comparer = useCaseSensitiveFileNames ? compareStrings : compareStringsCaseInsensitive; for (const basePath of patterns.basePaths) { - forEachFileInRecursiveDirectories(basePath, combinePaths(currentDirectory, basePath), { useCaseSensitiveFileNames, getFileSystemEntries, includeDirectory, visitFile }); + visitDirectory(basePath, combinePaths(currentDirectory, basePath)); } return flatten(results); - function includeDirectory(absoluteDirectoryName: string): boolean { - return (!includeDirectoryRegex || includeDirectoryRegex.test(absoluteDirectoryName)) && - (!excludeRegex || !excludeRegex.test(absoluteDirectoryName)); - } + function visitDirectory(path: string, absolutePath: string) { + let { files, directories } = getFileSystemEntries(path); + files = files.slice().sort(comparer); + directories = directories.slice().sort(comparer); - function visitFile(fileName: string, absoluteFileName: string): void { - if (extensions && !fileExtensionIsAny(fileName, extensions) || - excludeRegex && excludeRegex.test(absoluteFileName)) { - return; - } - - if (!includeFileRegexes) { - results[0].push(fileName); - } - else { - for (let i = 0; i < includeFileRegexes.length; i++) { - if (includeFileRegexes[i].test(absoluteFileName)) { - results[i].push(fileName); - // Only include a file once. - break; + for (const current of files) { + const name = combinePaths(path, current); + const absoluteName = combinePaths(absolutePath, current); + if (extensions && !fileExtensionIsAny(name, extensions)) continue; + if (excludeRegex && excludeRegex.test(absoluteName)) continue; + if (!includeFileRegexes) { + results[0].push(name); + } + else { + const includeIndex = findIndex(includeFileRegexes, re => re.test(absoluteName)); + if (includeIndex !== -1) { + results[includeIndex].push(name); } } } - } - } - interface RecursiveDirectoryVisitor { - useCaseSensitiveFileNames: boolean; - getFileSystemEntries: (path: string) => FileSystemEntries; - includeDirectory: (absoluteDirectoryName: string) => boolean; - visitFile: (fileName: string, absoluteFileName: string) => void; - } - - function forEachFileInRecursiveDirectories(start: string, absoluteStart: string, visitor: RecursiveDirectoryVisitor): void { - visitDirectory(start, absoluteStart); - - function visitDirectory(path: string, absolutePath: string) { - let { files, directories } = visitor.getFileSystemEntries(path); - files = sorted(files); - directories = sorted(directories); - - for (const file of files) { - visitor.visitFile(combinePaths(path, file), combinePaths(absolutePath, file)); - } - - for (const dir of directories) { - const absoluteName = combinePaths(absolutePath, dir); - if (visitor.includeDirectory(absoluteName)) { - visitDirectory(combinePaths(path, dir), absoluteName); + for (const current of directories) { + const name = combinePaths(path, current); + const absoluteName = combinePaths(absolutePath, current); + if ((!includeDirectoryRegex || includeDirectoryRegex.test(absoluteName)) && + (!excludeRegex || !excludeRegex.test(absoluteName))) { + visitDirectory(name, absoluteName); } } } - - function sorted(names: string[]): string[] { - return names.slice().sort(visitor.useCaseSensitiveFileNames ? compareStrings : compareStringsCaseInsensitive); - } } /** From b4c15982ff1caceedc496e6fbdee276a793de554 Mon Sep 17 00:00:00 2001 From: Herrington Darkholme Date: Wed, 18 Jan 2017 14:57:20 +0800 Subject: [PATCH 10/63] fix #13556: enable rest/spread on `object` --- src/compiler/checker.ts | 4 ++-- .../nonPrimitiveAccessProperty.errors.txt | 8 +++++++- .../reference/nonPrimitiveAccessProperty.js | 14 ++++++++++++++ tests/baselines/reference/objectSpread.js | 4 ++++ tests/baselines/reference/objectSpread.symbols | 4 ++++ tests/baselines/reference/objectSpread.types | 7 +++++++ .../reference/objectSpreadNegative.errors.txt | 14 +++++++++++--- tests/baselines/reference/objectSpreadNegative.js | 9 +++++++++ .../nonPrimitive/nonPrimitiveAccessProperty.ts | 3 +++ .../cases/conformance/types/spread/objectSpread.ts | 2 ++ .../types/spread/objectSpreadNegative.ts | 5 +++++ 11 files changed, 68 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 963d2e77c1b..97ca01bc086 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1,4 +1,4 @@ -/// +/// /// /* @internal */ @@ -11784,7 +11784,7 @@ namespace ts { } function isValidSpreadType(type: Type): boolean { - return !!(type.flags & (TypeFlags.Any | TypeFlags.Null | TypeFlags.Undefined) || + return !!(type.flags & (TypeFlags.Any | TypeFlags.Null | TypeFlags.Undefined | TypeFlags.NonPrimitive) || type.flags & TypeFlags.Object && !isGenericMappedType(type) || type.flags & TypeFlags.UnionOrIntersection && !forEach((type).types, t => !isValidSpreadType(t))); } diff --git a/tests/baselines/reference/nonPrimitiveAccessProperty.errors.txt b/tests/baselines/reference/nonPrimitiveAccessProperty.errors.txt index 8ef94c64448..0a6dfa66b86 100644 --- a/tests/baselines/reference/nonPrimitiveAccessProperty.errors.txt +++ b/tests/baselines/reference/nonPrimitiveAccessProperty.errors.txt @@ -1,10 +1,16 @@ tests/cases/conformance/types/nonPrimitive/nonPrimitiveAccessProperty.ts(3,3): error TS2339: Property 'nonExist' does not exist on type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveAccessProperty.ts(5,7): error TS2459: Type 'object' has no property 'destructuring' and no string index signature. -==== tests/cases/conformance/types/nonPrimitive/nonPrimitiveAccessProperty.ts (1 errors) ==== +==== tests/cases/conformance/types/nonPrimitive/nonPrimitiveAccessProperty.ts (2 errors) ==== var a: object; a.toString(); a.nonExist(); // error ~~~~~~~~ !!! error TS2339: Property 'nonExist' does not exist on type 'object'. + + var { destructuring } = a; // error + ~~~~~~~~~~~~~ +!!! error TS2459: Type 'object' has no property 'destructuring' and no string index signature. + var { ...rest } = a; // ok \ No newline at end of file diff --git a/tests/baselines/reference/nonPrimitiveAccessProperty.js b/tests/baselines/reference/nonPrimitiveAccessProperty.js index a71b2aba865..abfe2605e32 100644 --- a/tests/baselines/reference/nonPrimitiveAccessProperty.js +++ b/tests/baselines/reference/nonPrimitiveAccessProperty.js @@ -2,9 +2,23 @@ var a: object; a.toString(); a.nonExist(); // error + +var { destructuring } = a; // error +var { ...rest } = a; // ok //// [nonPrimitiveAccessProperty.js] +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) + t[p[i]] = s[p[i]]; + return t; +}; var a; a.toString(); a.nonExist(); // error +var destructuring = a.destructuring; // error +var rest = __rest(a, []); // ok diff --git a/tests/baselines/reference/objectSpread.js b/tests/baselines/reference/objectSpread.js index 4305e17ab31..259b86628a5 100644 --- a/tests/baselines/reference/objectSpread.js +++ b/tests/baselines/reference/objectSpread.js @@ -78,6 +78,8 @@ let computedAfter: { a: number, b: string, "at the end": number } = // shortcut syntax let a = 12; let shortCutted: { a: number, b: string } = { ...o, a } +// non primitive +let spreadNonPrimitve = { ...{}} @@ -148,4 +150,6 @@ var computedAfter = __assign({}, o, (_c = { b: 'yeah' }, _c['at the end'] = 14, // shortcut syntax var a = 12; var shortCutted = __assign({}, o, { a: a }); +// non primitive +var spreadNonPrimitve = __assign({}, {}); var _a, _b, _c; diff --git a/tests/baselines/reference/objectSpread.symbols b/tests/baselines/reference/objectSpread.symbols index 35c10faa9c0..69c9ed34341 100644 --- a/tests/baselines/reference/objectSpread.symbols +++ b/tests/baselines/reference/objectSpread.symbols @@ -316,4 +316,8 @@ let shortCutted: { a: number, b: string } = { ...o, a } >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) >a : Symbol(a, Decl(objectSpread.ts, 78, 51)) +// non primitive +let spreadNonPrimitve = { ...{}} +>spreadNonPrimitve : Symbol(spreadNonPrimitve, Decl(objectSpread.ts, 80, 3)) + diff --git a/tests/baselines/reference/objectSpread.types b/tests/baselines/reference/objectSpread.types index a571bd0bb63..8a8df1a497f 100644 --- a/tests/baselines/reference/objectSpread.types +++ b/tests/baselines/reference/objectSpread.types @@ -407,4 +407,11 @@ let shortCutted: { a: number, b: string } = { ...o, a } >o : { a: number; b: string; } >a : number +// non primitive +let spreadNonPrimitve = { ...{}} +>spreadNonPrimitve : { constructor: Function; toString(): string; toLocaleString(): string; valueOf(): Object; hasOwnProperty(v: string): boolean; isPrototypeOf(v: Object): boolean; propertyIsEnumerable(v: string): boolean; } +>{ ...{}} : { constructor: Function; toString(): string; toLocaleString(): string; valueOf(): Object; hasOwnProperty(v: string): boolean; isPrototypeOf(v: Object): boolean; propertyIsEnumerable(v: string): boolean; } +>{} : object +>{} : {} + diff --git a/tests/baselines/reference/objectSpreadNegative.errors.txt b/tests/baselines/reference/objectSpreadNegative.errors.txt index 17f07bc06a2..2b0960996ff 100644 --- a/tests/baselines/reference/objectSpreadNegative.errors.txt +++ b/tests/baselines/reference/objectSpreadNegative.errors.txt @@ -14,11 +14,12 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(37,19): error TS269 tests/cases/conformance/types/spread/objectSpreadNegative.ts(42,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures. tests/cases/conformance/types/spread/objectSpreadNegative.ts(46,12): error TS2339: Property 'b' does not exist on type '{}'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(52,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(56,14): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(59,14): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(57,11): error TS2339: Property 'a' does not exist on type '{ constructor: Function; toString(): string; toLocaleString(): string; valueOf(): Object; hasOwnProperty(v: string): boolean; isPrototypeOf(v: Object): boolean; propertyIsEnumerable(v: string): boolean; }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(61,14): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(64,14): error TS2698: Spread types may only be created from object types. -==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (15 errors) ==== +==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (16 errors) ==== let o = { a: 1, b: 'no' } /// private propagates @@ -101,6 +102,13 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(59,14): error TS269 ~ !!! error TS2339: Property 'm' does not exist on type '{ p: number; }'. + // non primitive + let obj: object = { a: 123 }; + let spreadObj = { ...obj }; + spreadObj.a; // error 'a' is not in {} + ~ +!!! error TS2339: Property 'a' does not exist on type '{ constructor: Function; toString(): string; toLocaleString(): string; valueOf(): Object; hasOwnProperty(v: string): boolean; isPrototypeOf(v: Object): boolean; propertyIsEnumerable(v: string): boolean; }'. + // generics function f(t: T, u: U) { return { ...t, ...u, id: 'id' }; diff --git a/tests/baselines/reference/objectSpreadNegative.js b/tests/baselines/reference/objectSpreadNegative.js index dff84355370..fd834b6ef9c 100644 --- a/tests/baselines/reference/objectSpreadNegative.js +++ b/tests/baselines/reference/objectSpreadNegative.js @@ -52,6 +52,11 @@ let c: C = new C() let spreadC = { ...c } spreadC.m(); // error 'm' is not in '{ ... c }' +// non primitive +let obj: object = { a: 123 }; +let spreadObj = { ...obj }; +spreadObj.a; // error 'a' is not in {} + // generics function f(t: T, u: U) { return { ...t, ...u, id: 'id' }; @@ -132,6 +137,10 @@ var C = (function () { var c = new C(); var spreadC = __assign({}, c); spreadC.m(); // error 'm' is not in '{ ... c }' +// non primitive +var obj = { a: 123 }; +var spreadObj = __assign({}, obj); +spreadObj.a; // error 'a' is not in {} // generics function f(t, u) { return __assign({}, t, u, { id: 'id' }); diff --git a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAccessProperty.ts b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAccessProperty.ts index 2febbb1e2ca..cf902c12e65 100644 --- a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAccessProperty.ts +++ b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAccessProperty.ts @@ -1,3 +1,6 @@ var a: object; a.toString(); a.nonExist(); // error + +var { destructuring } = a; // error +var { ...rest } = a; // ok diff --git a/tests/cases/conformance/types/spread/objectSpread.ts b/tests/cases/conformance/types/spread/objectSpread.ts index ebf2bdb2ade..c4562e6f196 100644 --- a/tests/cases/conformance/types/spread/objectSpread.ts +++ b/tests/cases/conformance/types/spread/objectSpread.ts @@ -78,4 +78,6 @@ let computedAfter: { a: number, b: string, "at the end": number } = // shortcut syntax let a = 12; let shortCutted: { a: number, b: string } = { ...o, a } +// non primitive +let spreadNonPrimitve = { ...{}} diff --git a/tests/cases/conformance/types/spread/objectSpreadNegative.ts b/tests/cases/conformance/types/spread/objectSpreadNegative.ts index 6d1e0dde429..c3b42b31aa9 100644 --- a/tests/cases/conformance/types/spread/objectSpreadNegative.ts +++ b/tests/cases/conformance/types/spread/objectSpreadNegative.ts @@ -52,6 +52,11 @@ let c: C = new C() let spreadC = { ...c } spreadC.m(); // error 'm' is not in '{ ... c }' +// non primitive +let obj: object = { a: 123 }; +let spreadObj = { ...obj }; +spreadObj.a; // error 'a' is not in {} + // generics function f(t: T, u: U) { return { ...t, ...u, id: 'id' }; From a6c5306479d1ca150657967f77fa2a195db4b793 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 19 Jan 2017 13:58:09 -0800 Subject: [PATCH 11/63] Allow object intersection types as class/interface base types --- src/compiler/checker.ts | 53 ++++++++++++++++++++++++++-------------- src/compiler/types.ts | 7 ++++-- src/services/services.ts | 2 +- src/services/types.ts | 2 +- 4 files changed, 42 insertions(+), 22 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 756a2b2d3b1..9cc5fb111cd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3732,11 +3732,16 @@ namespace ts { return getObjectFlags(type) & ObjectFlags.Reference ? (type).target : type; } - function hasBaseType(type: InterfaceType, checkBase: InterfaceType) { + function hasBaseType(type: BaseType, checkBase: BaseType) { return check(type); - function check(type: InterfaceType): boolean { - const target = getTargetType(type); - return target === checkBase || forEach(getBaseTypes(target), check); + function check(type: BaseType): boolean { + if (getObjectFlags(type) & (ObjectFlags.ClassOrInterface | ObjectFlags.Reference)) { + const target = getTargetType(type); + return target === checkBase || forEach(getBaseTypes(target), check); + } + else if (type.flags & TypeFlags.Intersection) { + return forEach((type).types, check); + } } } @@ -3862,7 +3867,7 @@ namespace ts { return type.resolvedBaseConstructorType; } - function getBaseTypes(type: InterfaceType): ObjectType[] { + function getBaseTypes(type: InterfaceType): BaseType[] { if (!type.resolvedBaseTypes) { if (type.objectFlags & ObjectFlags.Tuple) { type.resolvedBaseTypes = [createArrayType(getUnionType(type.typeParameters))]; @@ -3922,11 +3927,11 @@ namespace ts { if (baseType === unknownType) { return; } - if (!(getObjectFlags(getTargetType(baseType)) & ObjectFlags.ClassOrInterface)) { + if (!isValidBaseType(baseType)) { error(baseTypeNode.expression, Diagnostics.Base_constructor_return_type_0_is_not_a_class_or_interface_type, typeToString(baseType)); return; } - if (type === baseType || hasBaseType(baseType, type)) { + if (type === baseType || hasBaseType(baseType, type)) { error(valueDecl, Diagnostics.Type_0_recursively_references_itself_as_a_base_type, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType)); return; @@ -3951,6 +3956,13 @@ namespace ts { return true; } + // A valid base type is any non-generic object type or intersection of non-generic + // object types. + function isValidBaseType(type: Type): boolean { + return type.flags & TypeFlags.Object && !isGenericMappedType(type) || + type.flags & TypeFlags.Intersection && !forEach((type).types, t => !isValidBaseType(t)); + } + function resolveBaseTypesOfInterface(type: InterfaceType): void { type.resolvedBaseTypes = type.resolvedBaseTypes || emptyArray; for (const declaration of type.symbol.declarations) { @@ -3958,8 +3970,8 @@ namespace ts { for (const node of getInterfaceBaseTypeNodes(declaration)) { const baseType = getTypeFromTypeNode(node); if (baseType !== unknownType) { - if (getObjectFlags(getTargetType(baseType)) & ObjectFlags.ClassOrInterface) { - if (type !== baseType && !hasBaseType(baseType, type)) { + if (isValidBaseType(baseType)) { + if (type !== baseType && !hasBaseType(baseType, type)) { if (type.resolvedBaseTypes === emptyArray) { type.resolvedBaseTypes = [baseType]; } @@ -4317,6 +4329,9 @@ namespace ts { return createTypeReference((type).target, concatenate((type).typeArguments, [thisArgument || (type).target.thisType])); } + if (type.flags & TypeFlags.Intersection) { + return getIntersectionType(map((type).types, t => getTypeWithThisArgument(t, thisArgument))); + } return type; } @@ -4350,8 +4365,8 @@ namespace ts { } const thisArgument = lastOrUndefined(typeArguments); for (const baseType of baseTypes) { - const instantiatedBaseType = thisArgument ? getTypeWithThisArgument(instantiateType(baseType, mapper), thisArgument) : baseType; - addInheritedMembers(members, getPropertiesOfObjectType(instantiatedBaseType)); + const instantiatedBaseType = thisArgument ? getTypeWithThisArgument(instantiateType(baseType, mapper), thisArgument) : baseType; + addInheritedMembers(members, getPropertiesOfType(instantiatedBaseType)); callSignatures = concatenate(callSignatures, getSignaturesOfType(instantiatedBaseType, SignatureKind.Call)); constructSignatures = concatenate(constructSignatures, getSignaturesOfType(instantiatedBaseType, SignatureKind.Construct)); stringIndexInfo = stringIndexInfo || getIndexInfoOfType(instantiatedBaseType, IndexKind.String); @@ -18216,16 +18231,18 @@ namespace ts { return; } + const propDeclaration = prop.valueDeclaration; + // index is numeric and property name is not valid numeric literal - if (indexKind === IndexKind.Number && !isNumericName(prop.valueDeclaration.name)) { + if (indexKind === IndexKind.Number && propDeclaration && !isNumericName(propDeclaration.name)) { return; } // perform property check if property or indexer is declared in 'type' // this allows to rule out cases when both property and indexer are inherited from the base class let errorNode: Node; - if (prop.valueDeclaration.name.kind === SyntaxKind.ComputedPropertyName || prop.parent === containingType.symbol) { - errorNode = prop.valueDeclaration; + if (propDeclaration && propDeclaration.name.kind === SyntaxKind.ComputedPropertyName || prop.parent === containingType.symbol) { + errorNode = propDeclaration; } else if (indexDeclaration) { errorNode = indexDeclaration; @@ -18364,7 +18381,7 @@ namespace ts { checkTypeAssignableTo(staticType, getTypeWithoutSignatures(staticBaseType), node.name || node, Diagnostics.Class_static_side_0_incorrectly_extends_base_class_static_side_1); - if (baseType.symbol.valueDeclaration && + if (baseType.symbol && baseType.symbol.valueDeclaration && !isInAmbientContext(baseType.symbol.valueDeclaration) && baseType.symbol.valueDeclaration.kind === SyntaxKind.ClassDeclaration) { if (!isBlockScopedNameDeclaredBeforeUse(baseType.symbol.valueDeclaration, node)) { @@ -18437,7 +18454,7 @@ namespace ts { return forEach(symbol.declarations, d => isClassLike(d) ? d : undefined); } - function checkKindsOfPropertyMemberOverrides(type: InterfaceType, baseType: ObjectType): void { + function checkKindsOfPropertyMemberOverrides(type: InterfaceType, baseType: BaseType): void { // TypeScript 1.0 spec (April 2014): 8.2.3 // A derived class inherits all members from its base class it doesn't override. @@ -18454,7 +18471,7 @@ namespace ts { // derived class instance member variables and accessors, but not by other kinds of members. // NOTE: assignability is checked in checkClassDeclaration - const baseProperties = getPropertiesOfObjectType(baseType); + const baseProperties = getPropertiesOfType(baseType); for (const baseProperty of baseProperties) { const base = getTargetSymbol(baseProperty); @@ -18578,7 +18595,7 @@ namespace ts { let ok = true; for (const base of baseTypes) { - const properties = getPropertiesOfObjectType(getTypeWithThisArgument(base, type.thisType)); + const properties = getPropertiesOfType(getTypeWithThisArgument(base, type.thisType)); for (const prop of properties) { const existing = seen.get(prop.name); if (!existing) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 51347c8d3df..b834d73300a 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2358,7 +2358,7 @@ getIndexInfoOfType(type: Type, kind: IndexKind): IndexInfo; getSignaturesOfType(type: Type, kind: SignatureKind): Signature[]; getIndexTypeOfType(type: Type, kind: IndexKind): Type; - getBaseTypes(type: InterfaceType): ObjectType[]; + getBaseTypes(type: InterfaceType): BaseType[]; getReturnTypeOfSignature(signature: Signature): Type; /** * Gets the type of a parameter at a given position in a signature. @@ -2910,9 +2910,12 @@ /* @internal */ resolvedBaseConstructorType?: Type; // Resolved base constructor type of class /* @internal */ - resolvedBaseTypes: ObjectType[]; // Resolved base types + resolvedBaseTypes: BaseType[]; // Resolved base types } + // Object type or intersection of object types + export type BaseType = ObjectType | IntersectionType; + export interface InterfaceTypeWithDeclaredMembers extends InterfaceType { declaredProperties: Symbol[]; // Declared members declaredCallSignatures: Signature[]; // Declared call signatures diff --git a/src/services/services.ts b/src/services/services.ts index 26374eccbfd..04cb233557f 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -379,7 +379,7 @@ namespace ts { getNumberIndexType(): Type { return this.checker.getIndexTypeOfType(this, IndexKind.Number); } - getBaseTypes(): ObjectType[] { + getBaseTypes(): BaseType[] { return this.flags & TypeFlags.Object && this.objectFlags & (ObjectFlags.Class | ObjectFlags.Interface) ? this.checker.getBaseTypes(this) : undefined; diff --git a/src/services/types.ts b/src/services/types.ts index 88ffe2950ce..f410eb5b401 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -33,7 +33,7 @@ namespace ts { getConstructSignatures(): Signature[]; getStringIndexType(): Type; getNumberIndexType(): Type; - getBaseTypes(): ObjectType[]; + getBaseTypes(): BaseType[]; getNonNullableType(): Type; } From 1c2f7f866bd19d8ebbf3a4fe35b096bf512efba2 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 19 Jan 2017 14:30:53 -0800 Subject: [PATCH 12/63] Improve efficiency of union/intersection resolved property caching --- src/compiler/checker.ts | 40 +++++++++++++++++++--------------------- src/compiler/types.ts | 4 +++- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9cc5fb111cd..1ca1cd9cf74 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4754,28 +4754,26 @@ namespace ts { } function getPropertiesOfUnionOrIntersectionType(type: UnionOrIntersectionType): Symbol[] { - for (const current of type.types) { - for (const prop of getPropertiesOfType(current)) { - getUnionOrIntersectionProperty(type, prop.name); - } - // The properties of a union type are those that are present in all constituent types, so - // we only need to check the properties of the first type - if (type.flags & TypeFlags.Union) { - break; - } - } - const props = type.resolvedProperties; - if (props) { - const result: Symbol[] = []; - props.forEach(prop => { - // We need to filter out partial properties in union types - if (!(prop.flags & SymbolFlags.SyntheticProperty && (prop).isPartial)) { - result.push(prop); + if (!type.resolvedProperties) { + const members = createMap(); + for (const current of type.types) { + for (const prop of getPropertiesOfType(current)) { + if (!members.has(prop.name)) { + const combinedProp = getPropertyOfUnionOrIntersectionType(type, prop.name); + if (combinedProp) { + members.set(prop.name, combinedProp); + } + } } - }); - return result; + // The properties of a union type are those that are present in all constituent types, so + // we only need to check the properties of the first type + if (type.flags & TypeFlags.Union) { + break; + } + } + type.resolvedProperties = getNamedMembers(members); } - return emptyArray; + return type.resolvedProperties; } function getPropertiesOfType(type: Type): Symbol[] { @@ -4943,7 +4941,7 @@ namespace ts { // these partial properties when identifying discriminant properties, but otherwise they are filtered out // and do not appear to be present in the union type. function getUnionOrIntersectionProperty(type: UnionOrIntersectionType, name: string): Symbol { - const properties = type.resolvedProperties || (type.resolvedProperties = createMap()); + const properties = type.propertyCache || (type.propertyCache = createMap()); let property = properties.get(name); if (!property) { property = createUnionOrIntersectionProperty(type, name); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index b834d73300a..65cd4031613 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2948,7 +2948,9 @@ export interface UnionOrIntersectionType extends Type { types: Type[]; // Constituent types /* @internal */ - resolvedProperties: SymbolTable; // Cache of resolved properties + propertyCache: SymbolTable; // Cache of resolved properties + /* @internal */ + resolvedProperties: Symbol[]; /* @internal */ resolvedIndexType: IndexType; /* @internal */ From c51e2867f50de63db151310da03b829d667becc9 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 19 Jan 2017 14:47:26 -0800 Subject: [PATCH 13/63] Allow object intersection types in class implements clauses --- src/compiler/checker.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1ca1cd9cf74..450fcfe1da4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -18411,8 +18411,7 @@ namespace ts { if (produceDiagnostics) { const t = getTypeFromTypeNode(typeRefNode); if (t !== unknownType) { - const declaredType = getObjectFlags(t) & ObjectFlags.Reference ? (t).target : t; - if (getObjectFlags(declaredType) & ObjectFlags.ClassOrInterface) { + if (isValidBaseType(t)) { checkTypeAssignableTo(typeWithThis, getTypeWithThisArgument(t, type.thisType), node.name || node, Diagnostics.Class_0_incorrectly_implements_interface_1); } else { From f9a65e436c67b1da2e0a80274e1fba5a9afc6d61 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 19 Jan 2017 14:47:38 -0800 Subject: [PATCH 14/63] Accept new baselines --- .../reference/typeAliasesForObjectTypes.errors.txt | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/tests/baselines/reference/typeAliasesForObjectTypes.errors.txt b/tests/baselines/reference/typeAliasesForObjectTypes.errors.txt index d5bc01f93ba..b4ae5978049 100644 --- a/tests/baselines/reference/typeAliasesForObjectTypes.errors.txt +++ b/tests/baselines/reference/typeAliasesForObjectTypes.errors.txt @@ -1,19 +1,13 @@ -tests/cases/conformance/types/typeAliases/typeAliasesForObjectTypes.ts(4,22): error TS2312: An interface may only extend a class or another interface. -tests/cases/conformance/types/typeAliases/typeAliasesForObjectTypes.ts(5,21): error TS2422: A class may only implement another class or interface. tests/cases/conformance/types/typeAliases/typeAliasesForObjectTypes.ts(10,6): error TS2300: Duplicate identifier 'T2'. tests/cases/conformance/types/typeAliases/typeAliasesForObjectTypes.ts(11,6): error TS2300: Duplicate identifier 'T2'. -==== tests/cases/conformance/types/typeAliases/typeAliasesForObjectTypes.ts (4 errors) ==== +==== tests/cases/conformance/types/typeAliases/typeAliasesForObjectTypes.ts (2 errors) ==== type T1 = { x: string } // An interface can be named in an extends or implements clause, but a type alias for an object type literal cannot. interface I1 extends T1 { y: string } - ~~ -!!! error TS2312: An interface may only extend a class or another interface. class C1 implements T1 { - ~~ -!!! error TS2422: A class may only implement another class or interface. x: string; } From a9af10b030d2167ad7612a98df28f4084e95a005 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 20 Jan 2017 06:16:08 -0800 Subject: [PATCH 15/63] Intersections as their own 'this' type --- src/compiler/checker.ts | 16 ++++++++++++---- src/compiler/core.ts | 4 ++++ src/compiler/types.ts | 5 ++++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 450fcfe1da4..6de1b5aa624 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4326,10 +4326,13 @@ namespace ts { function getTypeWithThisArgument(type: Type, thisArgument?: Type): Type { if (getObjectFlags(type) & ObjectFlags.Reference) { - return createTypeReference((type).target, - concatenate((type).typeArguments, [thisArgument || (type).target.thisType])); + const target = (type).target; + const typeArguments = (type).typeArguments; + if (length(target.typeParameters) === length(typeArguments)) { + return createTypeReference(target, concatenate(typeArguments, [thisArgument || target.thisType])); + } } - if (type.flags & TypeFlags.Intersection) { + else if (type.flags & TypeFlags.Intersection) { return getIntersectionType(map((type).types, t => getTypeWithThisArgument(t, thisArgument))); } return type; @@ -4858,6 +4861,10 @@ namespace ts { } } + function getApparentTypeOfIntersectionType(type: IntersectionType) { + return type.resolvedIndexType || (type.resolvedApparentType = getTypeWithThisArgument(type, type)); + } + /** * For a type parameter, return the base constraint of the type parameter. For the string, number, * boolean, and symbol primitive types, return the corresponding object types. Otherwise return the @@ -4865,7 +4872,8 @@ namespace ts { */ function getApparentType(type: Type): Type { const t = type.flags & TypeFlags.TypeVariable ? getBaseConstraintOfType(type) || emptyObjectType : type; - return t.flags & TypeFlags.StringLike ? globalStringType : + return t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(type) : + t.flags & TypeFlags.StringLike ? globalStringType : t.flags & TypeFlags.NumberLike ? globalNumberType : t.flags & TypeFlags.BooleanLike ? globalBooleanType : t.flags & TypeFlags.ESSymbol ? getGlobalESSymbolType() : diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 654b1bc2912..47a6e2e70a8 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -202,6 +202,10 @@ namespace ts { GreaterThan = 1 } + export function length(array: any[]) { + return array ? array.length : 0; + } + /** * Iterates through 'array' by index and performs the callback on each element of array until the callback * returns a truthy value, then returns that value. diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 65cd4031613..6b5c670a9fa 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2961,7 +2961,10 @@ export interface UnionType extends UnionOrIntersectionType { } - export interface IntersectionType extends UnionOrIntersectionType { } + export interface IntersectionType extends UnionOrIntersectionType { + /* @internal */ + resolvedApparentType: Type; + } export type StructuredType = ObjectType | UnionType | IntersectionType; From c16c7d56c0a4e9f7e11dd134cffcdbb1eef5916c Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 20 Jan 2017 09:17:14 -0800 Subject: [PATCH 16/63] Allow base constructor types to be intersections --- src/compiler/checker.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6de1b5aa624..a5058bdf7f2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3810,7 +3810,7 @@ namespace ts { } function isConstructorType(type: Type): boolean { - return type.flags & TypeFlags.Object && getSignaturesOfType(type, SignatureKind.Construct).length > 0; + return isValidBaseType(type) && getSignaturesOfType(type, SignatureKind.Construct).length > 0; } function getBaseTypeNodeOfClass(type: InterfaceType): ExpressionWithTypeArguments { @@ -3849,7 +3849,7 @@ namespace ts { return unknownType; } const baseConstructorType = checkExpression(baseTypeNode.expression); - if (baseConstructorType.flags & TypeFlags.Object) { + if (baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection)) { // Resolving the members of a class requires us to resolve the base class of that class. // We force resolution here such that we catch circularities now. resolveStructuredTypeMembers(baseConstructorType); @@ -3890,7 +3890,7 @@ namespace ts { function resolveBaseTypesOfClass(type: InterfaceType): void { type.resolvedBaseTypes = type.resolvedBaseTypes || emptyArray; const baseConstructorType = getBaseConstructorTypeOfClass(type); - if (!(baseConstructorType.flags & TypeFlags.Object)) { + if (!(baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection))) { return; } const baseTypeNode = getBaseTypeNodeOfClass(type); @@ -4591,9 +4591,9 @@ namespace ts { constructSignatures = getDefaultConstructSignatures(classType); } const baseConstructorType = getBaseConstructorTypeOfClass(classType); - if (baseConstructorType.flags & TypeFlags.Object) { + if (baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection)) { members = createSymbolTable(getNamedMembers(members)); - addInheritedMembers(members, getPropertiesOfObjectType(baseConstructorType)); + addInheritedMembers(members, getPropertiesOfType(baseConstructorType)); } } const numberIndexInfo = symbol.flags & SymbolFlags.Enum ? enumNumberIndexInfo : undefined; From 8886cefe58c4674589f8f96067effcbb3dc77aa8 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Fri, 20 Jan 2017 08:12:00 -0800 Subject: [PATCH 17/63] Clean up code for getting emitted files --- src/compiler/emitter.ts | 4 +- src/compiler/program.ts | 2 +- src/compiler/utilities.ts | 186 +++++------------- .../reference/noBundledEmitFromNodeModules.js | 20 ++ .../noBundledEmitFromNodeModules.symbols | 9 + .../noBundledEmitFromNodeModules.types | 9 + .../compiler/noBundledEmitFromNodeModules.ts | 10 + 7 files changed, 98 insertions(+), 142 deletions(-) create mode 100644 tests/baselines/reference/noBundledEmitFromNodeModules.js create mode 100644 tests/baselines/reference/noBundledEmitFromNodeModules.symbols create mode 100644 tests/baselines/reference/noBundledEmitFromNodeModules.types create mode 100644 tests/cases/compiler/noBundledEmitFromNodeModules.ts diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 2ff342138c8..1c4662fa587 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -73,7 +73,7 @@ namespace ts { // Emit each output file performance.mark("beforePrint"); - forEachTransformedEmitFile(host, transformed, emitFile, emitOnlyDtsFiles); + forEachEmittedFile(host, transformed, emitFile, emitOnlyDtsFiles); performance.measure("printTime", "beforePrint"); // Clean up emit nodes on parse tree @@ -88,7 +88,7 @@ namespace ts { sourceMaps: sourceMapDataList }; - function emitFile(jsFilePath: string, sourceMapFilePath: string, declarationFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean) { + function emitFile({ jsFilePath, sourceMapFilePath, declarationFilePath }: EmitFileNames, sourceFiles: SourceFile[], isBundledEmit: boolean) { // Make sure not to write js file and source map file if any of them cannot be written if (!host.isEmitBlocked(jsFilePath) && !compilerOptions.noEmit) { if (!emitOnlyDtsFiles) { diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 324a21f229e..851e206d448 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -439,7 +439,7 @@ namespace ts { function getCommonSourceDirectory() { if (commonSourceDirectory === undefined) { - const emittedFiles = filterSourceFilesInDirectory(files, isSourceFileFromExternalLibrary); + const emittedFiles = filter(files, file => sourceFileMayBeEmitted(file, options, isSourceFileFromExternalLibrary)); if (options.rootDir && checkSourceFilesBelongToPath(emittedFiles, options.rootDir)) { // If a rootDir is specified and is valid use it as the commonSourceDirectory commonSourceDirectory = getNormalizedAbsolutePath(options.rootDir, currentDirectory); diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 932e75d0345..f59d384e490 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2568,108 +2568,25 @@ namespace ts { * @param host An EmitHost. * @param targetSourceFile An optional target source file to emit. */ - export function getSourceFilesToEmit(host: EmitHost, targetSourceFile?: SourceFile) { + export function getSourceFilesToEmit(host: EmitHost, targetSourceFile?: SourceFile): SourceFile[] { const options = host.getCompilerOptions(); + const isSourceFileFromExternalLibrary = (file: SourceFile) => host.isSourceFileFromExternalLibrary(file); if (options.outFile || options.out) { const moduleKind = getEmitModuleKind(options); const moduleEmitEnabled = moduleKind === ModuleKind.AMD || moduleKind === ModuleKind.System; - const sourceFiles = getAllEmittableSourceFiles(); // Can emit only sources that are not declaration file and are either non module code or module with --module or --target es6 specified - return filter(sourceFiles, moduleEmitEnabled ? isNonDeclarationFile : isBundleEmitNonExternalModule); + return filter(host.getSourceFiles(), sourceFile => + (moduleEmitEnabled || !isExternalModule(sourceFile)) && sourceFileMayBeEmitted(sourceFile, options, isSourceFileFromExternalLibrary)); } else { - const sourceFiles = targetSourceFile === undefined ? getAllEmittableSourceFiles() : [targetSourceFile]; - return filterSourceFilesInDirectory(sourceFiles, file => host.isSourceFileFromExternalLibrary(file)); - } - - function getAllEmittableSourceFiles() { - return options.noEmitForJsFiles ? filter(host.getSourceFiles(), sourceFile => !isSourceFileJavaScript(sourceFile)) : host.getSourceFiles(); + const sourceFiles = targetSourceFile === undefined ? host.getSourceFiles() : [targetSourceFile]; + return filter(sourceFiles, sourceFile => sourceFileMayBeEmitted(sourceFile, options, isSourceFileFromExternalLibrary)); } } - /** Don't call this for `--outFile`, just for `--outDir` or plain emit. */ - export function filterSourceFilesInDirectory(sourceFiles: SourceFile[], isSourceFileFromExternalLibrary: (file: SourceFile) => boolean): SourceFile[] { - return filter(sourceFiles, file => shouldEmitInDirectory(file, isSourceFileFromExternalLibrary)); - } - - function isNonDeclarationFile(sourceFile: SourceFile) { - return !isDeclarationFile(sourceFile); - } - - /** - * Whether a file should be emitted in a non-`--outFile` case. - * Don't emit if source file is a declaration file, or was located under node_modules - */ - function shouldEmitInDirectory(sourceFile: SourceFile, isSourceFileFromExternalLibrary: (file: SourceFile) => boolean): boolean { - return isNonDeclarationFile(sourceFile) && !isSourceFileFromExternalLibrary(sourceFile); - } - - function isBundleEmitNonExternalModule(sourceFile: SourceFile) { - return isNonDeclarationFile(sourceFile) && !isExternalModule(sourceFile); - } - - /** - * Iterates over each source file to emit. The source files are expected to have been - * transformed for use by the pretty printer. - * - * Originally part of `forEachExpectedEmitFile`, this functionality was extracted to support - * transformations. - * - * @param host An EmitHost. - * @param sourceFiles The transformed source files to emit. - * @param action The action to execute. - */ - export function forEachTransformedEmitFile(host: EmitHost, sourceFiles: SourceFile[], - action: (jsFilePath: string, sourceMapFilePath: string, declarationFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean) => void, - emitOnlyDtsFiles?: boolean) { - const options = host.getCompilerOptions(); - // Emit on each source file - if (options.outFile || options.out) { - onBundledEmit(sourceFiles); - } - else { - for (const sourceFile of sourceFiles) { - // Don't emit if source file is a declaration file, or was located under node_modules - if (!isDeclarationFile(sourceFile) && !host.isSourceFileFromExternalLibrary(sourceFile)) { - onSingleFileEmit(host, sourceFile); - } - } - } - - function onSingleFileEmit(host: EmitHost, sourceFile: SourceFile) { - // JavaScript files are always LanguageVariant.JSX, as JSX syntax is allowed in .js files also. - // So for JavaScript files, '.jsx' is only emitted if the input was '.jsx', and JsxEmit.Preserve. - // For TypeScript, the only time to emit with a '.jsx' extension, is on JSX input, and JsxEmit.Preserve - let extension = ".js"; - if (options.jsx === JsxEmit.Preserve) { - if (isSourceFileJavaScript(sourceFile)) { - if (fileExtensionIs(sourceFile.fileName, ".jsx")) { - extension = ".jsx"; - } - } - else if (sourceFile.languageVariant === LanguageVariant.JSX) { - // TypeScript source file preserving JSX syntax - extension = ".jsx"; - } - } - const jsFilePath = getOwnEmitOutputFilePath(sourceFile, host, extension); - const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options); - const declarationFilePath = !isSourceFileJavaScript(sourceFile) && (options.declaration || emitOnlyDtsFiles) ? getDeclarationEmitOutputFilePath(sourceFile, host) : undefined; - action(jsFilePath, sourceMapFilePath, declarationFilePath, [sourceFile], /*isBundledEmit*/ false); - } - - function onBundledEmit(sourceFiles: SourceFile[]) { - if (sourceFiles.length) { - const jsFilePath = options.outFile || options.out; - const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options); - const declarationFilePath = options.declaration ? removeFileExtension(jsFilePath) + ".d.ts" : undefined; - action(jsFilePath, sourceMapFilePath, declarationFilePath, sourceFiles, /*isBundledEmit*/ true); - } - } - } - - function getSourceMapFilePath(jsFilePath: string, options: CompilerOptions) { - return options.sourceMap ? jsFilePath + ".map" : undefined; + /** Don't call this for `--outFile`, just for `--outDir` or plain emit. `--outFile` needs additional checks. */ + export function sourceFileMayBeEmitted(sourceFile: SourceFile, options: CompilerOptions, isSourceFileFromExternalLibrary: (file: SourceFile) => boolean) { + return !(options.noEmitForJsFiles && isSourceFileJavaScript(sourceFile)) && !isDeclarationFile(sourceFile) && !isSourceFileFromExternalLibrary(sourceFile); } /** @@ -2685,64 +2602,55 @@ namespace ts { action: (emitFileNames: EmitFileNames, sourceFiles: SourceFile[], isBundledEmit: boolean, emitOnlyDtsFiles: boolean) => void, targetSourceFile?: SourceFile, emitOnlyDtsFiles?: boolean) { + forEachEmittedFile(host, getSourceFilesToEmit(host, targetSourceFile), action, emitOnlyDtsFiles); + } + + /** + * Iterates over each source file to emit. + */ + export function forEachEmittedFile(host: EmitHost, sourceFiles: SourceFile[], + action: (emitFileNames: EmitFileNames, sourceFiles: SourceFile[], isBundledEmit: boolean, emitOnlyDtsFiles: boolean) => void, + emitOnlyDtsFiles?: boolean) { const options = host.getCompilerOptions(); - // Emit on each source file if (options.outFile || options.out) { - onBundledEmit(host); + if (sourceFiles.length) { + const jsFilePath = options.outFile || options.out; + const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options); + const declarationFilePath = options.declaration ? removeFileExtension(jsFilePath) + ".d.ts" : undefined; + action({ jsFilePath, sourceMapFilePath, declarationFilePath }, sourceFiles, /*isBundledEmit*/true, emitOnlyDtsFiles); + } } else { - const sourceFiles = targetSourceFile === undefined ? getSourceFilesToEmit(host) : [targetSourceFile]; for (const sourceFile of sourceFiles) { - if (shouldEmitInDirectory(sourceFile, file => host.isSourceFileFromExternalLibrary(file))) { - onSingleFileEmit(host, sourceFile); - } + const options = host.getCompilerOptions(); + const jsFilePath = getOwnEmitOutputFilePath(sourceFile, host, getOutputExtension(sourceFile, options)); + const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options); + const declarationFilePath = !isSourceFileJavaScript(sourceFile) && (emitOnlyDtsFiles || options.declaration) ? getDeclarationEmitOutputFilePath(sourceFile, host) : undefined; + action({ jsFilePath, sourceMapFilePath, declarationFilePath }, [sourceFile], /*isBundledEmit*/false, emitOnlyDtsFiles); } } + } - function onSingleFileEmit(host: EmitHost, sourceFile: SourceFile) { - // JavaScript files are always LanguageVariant.JSX, as JSX syntax is allowed in .js files also. - // So for JavaScript files, '.jsx' is only emitted if the input was '.jsx', and JsxEmit.Preserve. - // For TypeScript, the only time to emit with a '.jsx' extension, is on JSX input, and JsxEmit.Preserve - let extension = ".js"; - if (options.jsx === JsxEmit.Preserve) { - if (isSourceFileJavaScript(sourceFile)) { - if (fileExtensionIs(sourceFile.fileName, ".jsx")) { - extension = ".jsx"; - } - } - else if (sourceFile.languageVariant === LanguageVariant.JSX) { - // TypeScript source file preserving JSX syntax - extension = ".jsx"; - } - } - const jsFilePath = getOwnEmitOutputFilePath(sourceFile, host, extension); - const declarationFilePath = !isSourceFileJavaScript(sourceFile) && (emitOnlyDtsFiles || options.declaration) ? getDeclarationEmitOutputFilePath(sourceFile, host) : undefined; - const emitFileNames: EmitFileNames = { - jsFilePath, - sourceMapFilePath: getSourceMapFilePath(jsFilePath, options), - declarationFilePath - }; - action(emitFileNames, [sourceFile], /*isBundledEmit*/false, emitOnlyDtsFiles); - } + function getSourceMapFilePath(jsFilePath: string, options: CompilerOptions) { + return options.sourceMap ? jsFilePath + ".map" : undefined; + } - function onBundledEmit(host: EmitHost) { - // Can emit only sources that are not declaration file and are either non module code or module with - // --module or --target es6 specified. Files included by searching under node_modules are also not emitted. - const bundledSources = filter(getSourceFilesToEmit(host), - sourceFile => !isDeclarationFile(sourceFile) && - !host.isSourceFileFromExternalLibrary(sourceFile) && - (!isExternalModule(sourceFile) || - !!getEmitModuleKind(options))); - if (bundledSources.length) { - const jsFilePath = options.outFile || options.out; - const emitFileNames: EmitFileNames = { - jsFilePath, - sourceMapFilePath: getSourceMapFilePath(jsFilePath, options), - declarationFilePath: options.declaration ? removeFileExtension(jsFilePath) + ".d.ts" : undefined - }; - action(emitFileNames, bundledSources, /*isBundledEmit*/true, emitOnlyDtsFiles); + // JavaScript files are always LanguageVariant.JSX, as JSX syntax is allowed in .js files also. + // So for JavaScript files, '.jsx' is only emitted if the input was '.jsx', and JsxEmit.Preserve. + // For TypeScript, the only time to emit with a '.jsx' extension, is on JSX input, and JsxEmit.Preserve + function getOutputExtension(sourceFile: SourceFile, options: CompilerOptions): string { + if (options.jsx === JsxEmit.Preserve) { + if (isSourceFileJavaScript(sourceFile)) { + if (fileExtensionIs(sourceFile.fileName, ".jsx")) { + return ".jsx"; + } + } + else if (sourceFile.languageVariant === LanguageVariant.JSX) { + // TypeScript source file preserving JSX syntax + return ".jsx"; } } + return ".js"; } export function getSourceFilePathInNewDir(sourceFile: SourceFile, host: EmitHost, newDirPath: string) { diff --git a/tests/baselines/reference/noBundledEmitFromNodeModules.js b/tests/baselines/reference/noBundledEmitFromNodeModules.js new file mode 100644 index 00000000000..67216a408af --- /dev/null +++ b/tests/baselines/reference/noBundledEmitFromNodeModules.js @@ -0,0 +1,20 @@ +//// [tests/cases/compiler/noBundledEmitFromNodeModules.ts] //// + +//// [index.ts] + +export class C {} + +//// [a.ts] +import { C } from "projB"; + + +//// [out.js] +System.register("a", [], function (exports_1, context_1) { + "use strict"; + var __moduleName = context_1 && context_1.id; + return { + setters: [], + execute: function () { + } + }; +}); diff --git a/tests/baselines/reference/noBundledEmitFromNodeModules.symbols b/tests/baselines/reference/noBundledEmitFromNodeModules.symbols new file mode 100644 index 00000000000..a1f6c67e4b4 --- /dev/null +++ b/tests/baselines/reference/noBundledEmitFromNodeModules.symbols @@ -0,0 +1,9 @@ +=== /a.ts === +import { C } from "projB"; +>C : Symbol(C, Decl(a.ts, 0, 8)) + +=== /node_modules/projB/index.ts === + +export class C {} +>C : Symbol(C, Decl(index.ts, 0, 0)) + diff --git a/tests/baselines/reference/noBundledEmitFromNodeModules.types b/tests/baselines/reference/noBundledEmitFromNodeModules.types new file mode 100644 index 00000000000..a11bad24aaf --- /dev/null +++ b/tests/baselines/reference/noBundledEmitFromNodeModules.types @@ -0,0 +1,9 @@ +=== /a.ts === +import { C } from "projB"; +>C : typeof C + +=== /node_modules/projB/index.ts === + +export class C {} +>C : C + diff --git a/tests/cases/compiler/noBundledEmitFromNodeModules.ts b/tests/cases/compiler/noBundledEmitFromNodeModules.ts new file mode 100644 index 00000000000..66c71a58489 --- /dev/null +++ b/tests/cases/compiler/noBundledEmitFromNodeModules.ts @@ -0,0 +1,10 @@ +// @outFile: out.js +// @module: system +// @moduleResolution: node +// @noImplicitReferences: true + +// @fileName: /node_modules/projB/index.ts +export class C {} + +// @fileName: /a.ts +import { C } from "projB"; From 7d773f18e09de59fc49090307b5980529fe97d0d Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Sat, 21 Jan 2017 17:07:37 +0100 Subject: [PATCH 18/63] Adds non-ambient context check --- src/compiler/checker.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5f80444c73e..2cac77bf576 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1,4 +1,4 @@ -/// +/// /// /* @internal */ @@ -18337,7 +18337,11 @@ namespace ts { const staticType = getTypeOfSymbol(symbol); checkTypeParameterListsIdentical(node, symbol); checkClassForDuplicateDeclarations(node); + + // Only check for reserved static identifiers on non-ambient context. + if (!isInAmbientContext(node)) { checkClassForStaticPropertyNameConflicts(node); + } const baseTypeNode = getClassExtendsHeritageClauseElement(node); if (baseTypeNode) { From 02af00fae7ce4ad63ffa9a566e6f46d48e7ca333 Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Sat, 21 Jan 2017 17:08:48 +0100 Subject: [PATCH 19/63] Fixes formatting --- src/compiler/checker.ts | 12 +- ...pertyNameConflictsInAmbientContext.symbols | 107 ++++++++++++++++++ 2 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 tests/baselines/reference/staticPropertyNameConflictsInAmbientContext.symbols diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2cac77bf576..383b92b7074 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1,4 +1,4 @@ -/// +/// /// /* @internal */ @@ -15722,12 +15722,12 @@ namespace ts { } } - /** + /** * Static members being set on a constructor function may conflict with built-in properties - * of Function. Esp. in ECMAScript 5 there are non-configurable and non-writable - * built-in properties. This check issues a transpile error when a class has a static + * of Function. Esp. in ECMAScript 5 there are non-configurable and non-writable + * built-in properties. This check issues a transpile error when a class has a static * member with the same name as a non-writable built-in property. - * + * * @see http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.3 * @see http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.5 * @see http://www.ecma-international.org/ecma-262/6.0/#sec-properties-of-the-function-constructor @@ -18340,7 +18340,7 @@ namespace ts { // Only check for reserved static identifiers on non-ambient context. if (!isInAmbientContext(node)) { - checkClassForStaticPropertyNameConflicts(node); + checkClassForStaticPropertyNameConflicts(node); } const baseTypeNode = getClassExtendsHeritageClauseElement(node); diff --git a/tests/baselines/reference/staticPropertyNameConflictsInAmbientContext.symbols b/tests/baselines/reference/staticPropertyNameConflictsInAmbientContext.symbols new file mode 100644 index 00000000000..46297eab86a --- /dev/null +++ b/tests/baselines/reference/staticPropertyNameConflictsInAmbientContext.symbols @@ -0,0 +1,107 @@ +=== tests/cases/conformance/classes/propertyMemberDeclarations/decl.d.ts === + +// name +declare class StaticName { +>StaticName : Symbol(StaticName, Decl(decl.d.ts, 0, 0)) + + static name: number; // ok +>name : Symbol(StaticName.name, Decl(decl.d.ts, 2, 26)) + + name: string; // ok +>name : Symbol(StaticName.name, Decl(decl.d.ts, 3, 24)) +} + +declare class StaticNameFn { +>StaticNameFn : Symbol(StaticNameFn, Decl(decl.d.ts, 5, 1)) + + static name(): string; // ok +>name : Symbol(StaticNameFn.name, Decl(decl.d.ts, 7, 28)) + + name(): string; // ok +>name : Symbol(StaticNameFn.name, Decl(decl.d.ts, 8, 26)) +} + +// length +declare class StaticLength { +>StaticLength : Symbol(StaticLength, Decl(decl.d.ts, 10, 1)) + + static length: number; // ok +>length : Symbol(StaticLength.length, Decl(decl.d.ts, 13, 28)) + + length: string; // ok +>length : Symbol(StaticLength.length, Decl(decl.d.ts, 14, 26)) +} + +declare class StaticLengthFn { +>StaticLengthFn : Symbol(StaticLengthFn, Decl(decl.d.ts, 16, 1)) + + static length(): number; // ok +>length : Symbol(StaticLengthFn.length, Decl(decl.d.ts, 18, 30)) + + length(): number; // ok +>length : Symbol(StaticLengthFn.length, Decl(decl.d.ts, 19, 28)) +} + +// prototype +declare class StaticPrototype { +>StaticPrototype : Symbol(StaticPrototype, Decl(decl.d.ts, 21, 1)) + + static prototype: number; // ok +>prototype : Symbol(StaticPrototype.prototype, Decl(decl.d.ts, 24, 31)) + + prototype: string; // ok +>prototype : Symbol(StaticPrototype.prototype, Decl(decl.d.ts, 25, 29)) +} + +declare class StaticPrototypeFn { +>StaticPrototypeFn : Symbol(StaticPrototypeFn, Decl(decl.d.ts, 27, 1)) + + static prototype: any; // ok +>prototype : Symbol(StaticPrototypeFn.prototype, Decl(decl.d.ts, 29, 33)) + + prototype(): any; // ok +>prototype : Symbol(StaticPrototypeFn.prototype, Decl(decl.d.ts, 30, 26)) +} + +// caller +declare class StaticCaller { +>StaticCaller : Symbol(StaticCaller, Decl(decl.d.ts, 32, 1)) + + static caller: number; // ok +>caller : Symbol(StaticCaller.caller, Decl(decl.d.ts, 35, 28)) + + caller: string; // ok +>caller : Symbol(StaticCaller.caller, Decl(decl.d.ts, 36, 26)) +} + +declare class StaticCallerFn { +>StaticCallerFn : Symbol(StaticCallerFn, Decl(decl.d.ts, 38, 1)) + + static caller(): any; // ok +>caller : Symbol(StaticCallerFn.caller, Decl(decl.d.ts, 40, 30)) + + caller(): any; // ok +>caller : Symbol(StaticCallerFn.caller, Decl(decl.d.ts, 41, 25)) +} + +// arguments +declare class StaticArguments { +>StaticArguments : Symbol(StaticArguments, Decl(decl.d.ts, 43, 1)) + + static arguments: number; // ok +>arguments : Symbol(StaticArguments.arguments, Decl(decl.d.ts, 46, 31)) + + arguments: string; // ok +>arguments : Symbol(StaticArguments.arguments, Decl(decl.d.ts, 47, 29)) +} + +declare class StaticArgumentsFn { +>StaticArgumentsFn : Symbol(StaticArgumentsFn, Decl(decl.d.ts, 49, 1)) + + static arguments(): any; // ok +>arguments : Symbol(StaticArgumentsFn.arguments, Decl(decl.d.ts, 51, 33)) + + arguments(): any; // ok +>arguments : Symbol(StaticArgumentsFn.arguments, Decl(decl.d.ts, 52, 28)) +} + From 1e5b7c5564eeae81b4ee750703cb9cd79ae8e47f Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Sat, 21 Jan 2017 17:09:09 +0100 Subject: [PATCH 20/63] Add tests --- ...icPropertyNameConflictsInAmbientContext.ts | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflictsInAmbientContext.ts diff --git a/tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflictsInAmbientContext.ts b/tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflictsInAmbientContext.ts new file mode 100644 index 00000000000..198c923b0dd --- /dev/null +++ b/tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflictsInAmbientContext.ts @@ -0,0 +1,56 @@ + +//@Filename: decl.d.ts +// name +declare class StaticName { + static name: number; // ok + name: string; // ok +} + +declare class StaticNameFn { + static name(): string; // ok + name(): string; // ok +} + +// length +declare class StaticLength { + static length: number; // ok + length: string; // ok +} + +declare class StaticLengthFn { + static length(): number; // ok + length(): number; // ok +} + +// prototype +declare class StaticPrototype { + static prototype: number; // ok + prototype: string; // ok +} + +declare class StaticPrototypeFn { + static prototype: any; // ok + prototype(): any; // ok +} + +// caller +declare class StaticCaller { + static caller: number; // ok + caller: string; // ok +} + +declare class StaticCallerFn { + static caller(): any; // ok + caller(): any; // ok +} + +// arguments +declare class StaticArguments { + static arguments: number; // ok + arguments: string; // ok +} + +declare class StaticArgumentsFn { + static arguments(): any; // ok + arguments(): any; // ok +} From 36f6e19d9eeb1f7da92e466dede07f800d8c14a9 Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Sat, 21 Jan 2017 17:09:26 +0100 Subject: [PATCH 21/63] Add reference baseline --- ...ropertyNameConflictsInAmbientContext.types | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 tests/baselines/reference/staticPropertyNameConflictsInAmbientContext.types diff --git a/tests/baselines/reference/staticPropertyNameConflictsInAmbientContext.types b/tests/baselines/reference/staticPropertyNameConflictsInAmbientContext.types new file mode 100644 index 00000000000..233bd8a46fc --- /dev/null +++ b/tests/baselines/reference/staticPropertyNameConflictsInAmbientContext.types @@ -0,0 +1,107 @@ +=== tests/cases/conformance/classes/propertyMemberDeclarations/decl.d.ts === + +// name +declare class StaticName { +>StaticName : StaticName + + static name: number; // ok +>name : number + + name: string; // ok +>name : string +} + +declare class StaticNameFn { +>StaticNameFn : StaticNameFn + + static name(): string; // ok +>name : () => string + + name(): string; // ok +>name : () => string +} + +// length +declare class StaticLength { +>StaticLength : StaticLength + + static length: number; // ok +>length : number + + length: string; // ok +>length : string +} + +declare class StaticLengthFn { +>StaticLengthFn : StaticLengthFn + + static length(): number; // ok +>length : () => number + + length(): number; // ok +>length : () => number +} + +// prototype +declare class StaticPrototype { +>StaticPrototype : StaticPrototype + + static prototype: number; // ok +>prototype : StaticPrototype + + prototype: string; // ok +>prototype : string +} + +declare class StaticPrototypeFn { +>StaticPrototypeFn : StaticPrototypeFn + + static prototype: any; // ok +>prototype : StaticPrototypeFn + + prototype(): any; // ok +>prototype : () => any +} + +// caller +declare class StaticCaller { +>StaticCaller : StaticCaller + + static caller: number; // ok +>caller : number + + caller: string; // ok +>caller : string +} + +declare class StaticCallerFn { +>StaticCallerFn : StaticCallerFn + + static caller(): any; // ok +>caller : () => any + + caller(): any; // ok +>caller : () => any +} + +// arguments +declare class StaticArguments { +>StaticArguments : StaticArguments + + static arguments: number; // ok +>arguments : number + + arguments: string; // ok +>arguments : string +} + +declare class StaticArgumentsFn { +>StaticArgumentsFn : StaticArgumentsFn + + static arguments(): any; // ok +>arguments : () => any + + arguments(): any; // ok +>arguments : () => any +} + From ad71da0a7f36fafa8e940c388fd503c60ae6afee Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 21 Jan 2017 13:06:54 -0800 Subject: [PATCH 22/63] Fix error reporting bug --- src/compiler/checker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a5058bdf7f2..3242a30d381 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -18240,14 +18240,14 @@ namespace ts { const propDeclaration = prop.valueDeclaration; // index is numeric and property name is not valid numeric literal - if (indexKind === IndexKind.Number && propDeclaration && !isNumericName(propDeclaration.name)) { + if (indexKind === IndexKind.Number && !(propDeclaration ? isNumericName(propDeclaration.name) : isNumericLiteralName(prop.name))) { return; } // perform property check if property or indexer is declared in 'type' // this allows to rule out cases when both property and indexer are inherited from the base class let errorNode: Node; - if (propDeclaration && propDeclaration.name.kind === SyntaxKind.ComputedPropertyName || prop.parent === containingType.symbol) { + if (propDeclaration && (propDeclaration.name.kind === SyntaxKind.ComputedPropertyName || prop.parent === containingType.symbol)) { errorNode = propDeclaration; } else if (indexDeclaration) { From 615784ad944a3e7ec392e6043c41028558aab5b4 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 21 Jan 2017 13:07:06 -0800 Subject: [PATCH 23/63] Add tests --- .../interfaceExtendsObjectIntersection.ts | 55 +++++++++++++++++++ ...nterfaceExtendsObjectIntersectionErrors.ts | 49 +++++++++++++++++ .../intersection/intersectionThisTypes.ts | 40 ++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersection.ts create mode 100644 tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts create mode 100644 tests/cases/conformance/types/intersection/intersectionThisTypes.ts diff --git a/tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersection.ts b/tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersection.ts new file mode 100644 index 00000000000..003976a2b27 --- /dev/null +++ b/tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersection.ts @@ -0,0 +1,55 @@ +// @strictNullChecks: true + +type T1 = { a: number }; +type T2 = T1 & { b: number }; +type T3 = () => void; +type T4 = new () => { a: number }; +type T5 = number[]; +type T6 = [string, number]; +type T7 = { [P in 'a' | 'b' | 'c']: string }; + +interface I1 extends T1 { x: string } +interface I2 extends T2 { x: string } +interface I3 extends T3 { x: string } +interface I4 extends T4 { x: string } +interface I5 extends T5 { x: string } +interface I6 extends T6 { x: string } +interface I7 extends T7 { x: string } + +type Constructor = new () => T; +declare function Constructor(): Constructor; + +class C1 extends Constructor() { x: string } +class C2 extends Constructor() { x: string } +class C3 extends Constructor() { x: string } +class C4 extends Constructor() { x: string } +class C5 extends Constructor() { x: string } +class C6 extends Constructor() { x: string } +class C7 extends Constructor() { x: string } + +declare function fx(x: string): string; +declare class CX { a: number } +declare enum EX { A, B, C } +declare namespace NX { export const a = 1 } + +type T10 = typeof fx; +type T11 = typeof CX; +type T12 = typeof EX; +type T13 = typeof NX; + +interface I10 extends T10 { x: string } +interface I11 extends T11 { x: string } +interface I12 extends T12 { x: string } +interface I13 extends T13 { x: string } + +type Identifiable = { _id: string } & T; + +interface I20 extends Partial { x: string } +interface I21 extends Readonly { x: string } +interface I22 extends Identifiable { x: string } +interface I23 extends Identifiable { x: string } + +class C20 extends Constructor>() { x: string } +class C21 extends Constructor>() { x: string } +class C22 extends Constructor>() { x: string } +class C23 extends Constructor>() { x: string } diff --git a/tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts b/tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts new file mode 100644 index 00000000000..5a2a37fc227 --- /dev/null +++ b/tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts @@ -0,0 +1,49 @@ +// @strictNullChecks: true + +type T1 = { a: number }; +type T2 = T1 & { b: number }; +type T3 = number[]; +type T4 = [string, number]; +type T5 = { [P in 'a' | 'b' | 'c']: string }; + +interface I1 extends T1 { a: string } +interface I2 extends T2 { b: string } +interface I3 extends T3 { length: string } +interface I4 extends T4 { 0: number } +interface I5 extends T5 { c: number } + +type Constructor = new () => T; +declare function Constructor(): Constructor; + +class C1 extends Constructor() { a: string } +class C2 extends Constructor() { b: string } +class C3 extends Constructor() { length: string } +class C4 extends Constructor() { 0: number } +class C5 extends Constructor() { c: number } + +declare class CX { static a: string } +declare enum EX { A, B, C } +declare namespace NX { export const a = "hello" } + +type TCX = typeof CX; +type TEX = typeof EX; +type TNX = typeof NX; + +interface I10 extends TCX { a: number } +interface I11 extends TEX { C: string } +interface I12 extends TNX { a: number } +interface I14 extends TCX { [x: string]: number } +interface I15 extends TEX { [x: string]: number } +interface I16 extends TNX { [x: string]: number } + +type Identifiable = { _id: string } & T; + +interface I20 extends Partial { a: string } +interface I21 extends Readonly { a: string } +interface I22 extends Identifiable { a: string } +interface I23 extends Identifiable { a: string } + +type U = { a: number } | { b: string }; + +interface I30 extends U { x: string } +interface I31 extends T { x: string } diff --git a/tests/cases/conformance/types/intersection/intersectionThisTypes.ts b/tests/cases/conformance/types/intersection/intersectionThisTypes.ts new file mode 100644 index 00000000000..8819148dc9e --- /dev/null +++ b/tests/cases/conformance/types/intersection/intersectionThisTypes.ts @@ -0,0 +1,40 @@ +interface Thing1 { + a: number; + self(): this; +} + +interface Thing2 { + b: number; + me(): this; +} + +type Thing3 = Thing1 & Thing2; +type Thing4 = Thing3 & string[]; + +function f1(t: Thing3) { + t = t.self(); + t = t.me().self().me(); +} + +interface Thing5 extends Thing4 { + c: string; +} + +function f2(t: Thing5) { + t = t.self(); + t = t.me().self().me(); +} + +interface Component { + extend(props: T): this & T; +} + +interface Label extends Component { + title: string; +} + +function test(label: Label) { + const extended = label.extend({ id: 67 }).extend({ tag: "hello" }); + extended.id; // Ok + extended.tag; // Ok +} From 3a34cb3088632f2361b7adafdb16fe802febcd8e Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 21 Jan 2017 13:12:02 -0800 Subject: [PATCH 24/63] Accept new baselines --- .../interfaceExtendsObjectIntersection.js | 145 +++++++++++ ...interfaceExtendsObjectIntersection.symbols | 230 +++++++++++++++++ .../interfaceExtendsObjectIntersection.types | 242 ++++++++++++++++++ ...ExtendsObjectIntersectionErrors.errors.txt | 197 ++++++++++++++ ...nterfaceExtendsObjectIntersectionErrors.js | 97 +++++++ .../reference/intersectionThisTypes.js | 57 +++++ .../reference/intersectionThisTypes.symbols | 127 +++++++++ .../reference/intersectionThisTypes.types | 145 +++++++++++ 8 files changed, 1240 insertions(+) create mode 100644 tests/baselines/reference/interfaceExtendsObjectIntersection.js create mode 100644 tests/baselines/reference/interfaceExtendsObjectIntersection.symbols create mode 100644 tests/baselines/reference/interfaceExtendsObjectIntersection.types create mode 100644 tests/baselines/reference/interfaceExtendsObjectIntersectionErrors.errors.txt create mode 100644 tests/baselines/reference/interfaceExtendsObjectIntersectionErrors.js create mode 100644 tests/baselines/reference/intersectionThisTypes.js create mode 100644 tests/baselines/reference/intersectionThisTypes.symbols create mode 100644 tests/baselines/reference/intersectionThisTypes.types diff --git a/tests/baselines/reference/interfaceExtendsObjectIntersection.js b/tests/baselines/reference/interfaceExtendsObjectIntersection.js new file mode 100644 index 00000000000..a6fb62f5070 --- /dev/null +++ b/tests/baselines/reference/interfaceExtendsObjectIntersection.js @@ -0,0 +1,145 @@ +//// [interfaceExtendsObjectIntersection.ts] + +type T1 = { a: number }; +type T2 = T1 & { b: number }; +type T3 = () => void; +type T4 = new () => { a: number }; +type T5 = number[]; +type T6 = [string, number]; +type T7 = { [P in 'a' | 'b' | 'c']: string }; + +interface I1 extends T1 { x: string } +interface I2 extends T2 { x: string } +interface I3 extends T3 { x: string } +interface I4 extends T4 { x: string } +interface I5 extends T5 { x: string } +interface I6 extends T6 { x: string } +interface I7 extends T7 { x: string } + +type Constructor = new () => T; +declare function Constructor(): Constructor; + +class C1 extends Constructor() { x: string } +class C2 extends Constructor() { x: string } +class C3 extends Constructor() { x: string } +class C4 extends Constructor() { x: string } +class C5 extends Constructor() { x: string } +class C6 extends Constructor() { x: string } +class C7 extends Constructor() { x: string } + +declare function fx(x: string): string; +declare class CX { a: number } +declare enum EX { A, B, C } +declare namespace NX { export const a = 1 } + +type T10 = typeof fx; +type T11 = typeof CX; +type T12 = typeof EX; +type T13 = typeof NX; + +interface I10 extends T10 { x: string } +interface I11 extends T11 { x: string } +interface I12 extends T12 { x: string } +interface I13 extends T13 { x: string } + +type Identifiable = { _id: string } & T; + +interface I20 extends Partial { x: string } +interface I21 extends Readonly { x: string } +interface I22 extends Identifiable { x: string } +interface I23 extends Identifiable { x: string } + +class C20 extends Constructor>() { x: string } +class C21 extends Constructor>() { x: string } +class C22 extends Constructor>() { x: string } +class C23 extends Constructor>() { x: string } + + +//// [interfaceExtendsObjectIntersection.js] +var __extends = (this && this.__extends) || (function () { + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var C1 = (function (_super) { + __extends(C1, _super); + function C1() { + return _super !== null && _super.apply(this, arguments) || this; + } + return C1; +}(Constructor())); +var C2 = (function (_super) { + __extends(C2, _super); + function C2() { + return _super !== null && _super.apply(this, arguments) || this; + } + return C2; +}(Constructor())); +var C3 = (function (_super) { + __extends(C3, _super); + function C3() { + return _super !== null && _super.apply(this, arguments) || this; + } + return C3; +}(Constructor())); +var C4 = (function (_super) { + __extends(C4, _super); + function C4() { + return _super !== null && _super.apply(this, arguments) || this; + } + return C4; +}(Constructor())); +var C5 = (function (_super) { + __extends(C5, _super); + function C5() { + return _super !== null && _super.apply(this, arguments) || this; + } + return C5; +}(Constructor())); +var C6 = (function (_super) { + __extends(C6, _super); + function C6() { + return _super !== null && _super.apply(this, arguments) || this; + } + return C6; +}(Constructor())); +var C7 = (function (_super) { + __extends(C7, _super); + function C7() { + return _super !== null && _super.apply(this, arguments) || this; + } + return C7; +}(Constructor())); +var C20 = (function (_super) { + __extends(C20, _super); + function C20() { + return _super !== null && _super.apply(this, arguments) || this; + } + return C20; +}(Constructor())); +var C21 = (function (_super) { + __extends(C21, _super); + function C21() { + return _super !== null && _super.apply(this, arguments) || this; + } + return C21; +}(Constructor())); +var C22 = (function (_super) { + __extends(C22, _super); + function C22() { + return _super !== null && _super.apply(this, arguments) || this; + } + return C22; +}(Constructor())); +var C23 = (function (_super) { + __extends(C23, _super); + function C23() { + return _super !== null && _super.apply(this, arguments) || this; + } + return C23; +}(Constructor())); diff --git a/tests/baselines/reference/interfaceExtendsObjectIntersection.symbols b/tests/baselines/reference/interfaceExtendsObjectIntersection.symbols new file mode 100644 index 00000000000..16c8c51cf47 --- /dev/null +++ b/tests/baselines/reference/interfaceExtendsObjectIntersection.symbols @@ -0,0 +1,230 @@ +=== tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersection.ts === + +type T1 = { a: number }; +>T1 : Symbol(T1, Decl(interfaceExtendsObjectIntersection.ts, 0, 0)) +>a : Symbol(a, Decl(interfaceExtendsObjectIntersection.ts, 1, 11)) + +type T2 = T1 & { b: number }; +>T2 : Symbol(T2, Decl(interfaceExtendsObjectIntersection.ts, 1, 24)) +>T1 : Symbol(T1, Decl(interfaceExtendsObjectIntersection.ts, 0, 0)) +>b : Symbol(b, Decl(interfaceExtendsObjectIntersection.ts, 2, 16)) + +type T3 = () => void; +>T3 : Symbol(T3, Decl(interfaceExtendsObjectIntersection.ts, 2, 29)) + +type T4 = new () => { a: number }; +>T4 : Symbol(T4, Decl(interfaceExtendsObjectIntersection.ts, 3, 21)) +>a : Symbol(a, Decl(interfaceExtendsObjectIntersection.ts, 4, 21)) + +type T5 = number[]; +>T5 : Symbol(T5, Decl(interfaceExtendsObjectIntersection.ts, 4, 34)) + +type T6 = [string, number]; +>T6 : Symbol(T6, Decl(interfaceExtendsObjectIntersection.ts, 5, 19)) + +type T7 = { [P in 'a' | 'b' | 'c']: string }; +>T7 : Symbol(T7, Decl(interfaceExtendsObjectIntersection.ts, 6, 27)) +>P : Symbol(P, Decl(interfaceExtendsObjectIntersection.ts, 7, 13)) + +interface I1 extends T1 { x: string } +>I1 : Symbol(I1, Decl(interfaceExtendsObjectIntersection.ts, 7, 45)) +>T1 : Symbol(T1, Decl(interfaceExtendsObjectIntersection.ts, 0, 0)) +>x : Symbol(I1.x, Decl(interfaceExtendsObjectIntersection.ts, 9, 25)) + +interface I2 extends T2 { x: string } +>I2 : Symbol(I2, Decl(interfaceExtendsObjectIntersection.ts, 9, 37)) +>T2 : Symbol(T2, Decl(interfaceExtendsObjectIntersection.ts, 1, 24)) +>x : Symbol(I2.x, Decl(interfaceExtendsObjectIntersection.ts, 10, 25)) + +interface I3 extends T3 { x: string } +>I3 : Symbol(I3, Decl(interfaceExtendsObjectIntersection.ts, 10, 37)) +>T3 : Symbol(T3, Decl(interfaceExtendsObjectIntersection.ts, 2, 29)) +>x : Symbol(I3.x, Decl(interfaceExtendsObjectIntersection.ts, 11, 25)) + +interface I4 extends T4 { x: string } +>I4 : Symbol(I4, Decl(interfaceExtendsObjectIntersection.ts, 11, 37)) +>T4 : Symbol(T4, Decl(interfaceExtendsObjectIntersection.ts, 3, 21)) +>x : Symbol(I4.x, Decl(interfaceExtendsObjectIntersection.ts, 12, 25)) + +interface I5 extends T5 { x: string } +>I5 : Symbol(I5, Decl(interfaceExtendsObjectIntersection.ts, 12, 37)) +>T5 : Symbol(T5, Decl(interfaceExtendsObjectIntersection.ts, 4, 34)) +>x : Symbol(I5.x, Decl(interfaceExtendsObjectIntersection.ts, 13, 25)) + +interface I6 extends T6 { x: string } +>I6 : Symbol(I6, Decl(interfaceExtendsObjectIntersection.ts, 13, 37)) +>T6 : Symbol(T6, Decl(interfaceExtendsObjectIntersection.ts, 5, 19)) +>x : Symbol(I6.x, Decl(interfaceExtendsObjectIntersection.ts, 14, 25)) + +interface I7 extends T7 { x: string } +>I7 : Symbol(I7, Decl(interfaceExtendsObjectIntersection.ts, 14, 37)) +>T7 : Symbol(T7, Decl(interfaceExtendsObjectIntersection.ts, 6, 27)) +>x : Symbol(I7.x, Decl(interfaceExtendsObjectIntersection.ts, 15, 25)) + +type Constructor = new () => T; +>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34)) +>T : Symbol(T, Decl(interfaceExtendsObjectIntersection.ts, 17, 17)) +>T : Symbol(T, Decl(interfaceExtendsObjectIntersection.ts, 17, 17)) + +declare function Constructor(): Constructor; +>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34)) +>T : Symbol(T, Decl(interfaceExtendsObjectIntersection.ts, 18, 29)) +>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34)) +>T : Symbol(T, Decl(interfaceExtendsObjectIntersection.ts, 18, 29)) + +class C1 extends Constructor() { x: string } +>C1 : Symbol(C1, Decl(interfaceExtendsObjectIntersection.ts, 18, 50)) +>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34)) +>I1 : Symbol(I1, Decl(interfaceExtendsObjectIntersection.ts, 7, 45)) +>x : Symbol(C1.x, Decl(interfaceExtendsObjectIntersection.ts, 20, 36)) + +class C2 extends Constructor() { x: string } +>C2 : Symbol(C2, Decl(interfaceExtendsObjectIntersection.ts, 20, 48)) +>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34)) +>I2 : Symbol(I2, Decl(interfaceExtendsObjectIntersection.ts, 9, 37)) +>x : Symbol(C2.x, Decl(interfaceExtendsObjectIntersection.ts, 21, 36)) + +class C3 extends Constructor() { x: string } +>C3 : Symbol(C3, Decl(interfaceExtendsObjectIntersection.ts, 21, 48)) +>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34)) +>I3 : Symbol(I3, Decl(interfaceExtendsObjectIntersection.ts, 10, 37)) +>x : Symbol(C3.x, Decl(interfaceExtendsObjectIntersection.ts, 22, 36)) + +class C4 extends Constructor() { x: string } +>C4 : Symbol(C4, Decl(interfaceExtendsObjectIntersection.ts, 22, 48)) +>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34)) +>I4 : Symbol(I4, Decl(interfaceExtendsObjectIntersection.ts, 11, 37)) +>x : Symbol(C4.x, Decl(interfaceExtendsObjectIntersection.ts, 23, 36)) + +class C5 extends Constructor() { x: string } +>C5 : Symbol(C5, Decl(interfaceExtendsObjectIntersection.ts, 23, 48)) +>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34)) +>I5 : Symbol(I5, Decl(interfaceExtendsObjectIntersection.ts, 12, 37)) +>x : Symbol(C5.x, Decl(interfaceExtendsObjectIntersection.ts, 24, 36)) + +class C6 extends Constructor() { x: string } +>C6 : Symbol(C6, Decl(interfaceExtendsObjectIntersection.ts, 24, 48)) +>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34)) +>I6 : Symbol(I6, Decl(interfaceExtendsObjectIntersection.ts, 13, 37)) +>x : Symbol(C6.x, Decl(interfaceExtendsObjectIntersection.ts, 25, 36)) + +class C7 extends Constructor() { x: string } +>C7 : Symbol(C7, Decl(interfaceExtendsObjectIntersection.ts, 25, 48)) +>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34)) +>I7 : Symbol(I7, Decl(interfaceExtendsObjectIntersection.ts, 14, 37)) +>x : Symbol(C7.x, Decl(interfaceExtendsObjectIntersection.ts, 26, 36)) + +declare function fx(x: string): string; +>fx : Symbol(fx, Decl(interfaceExtendsObjectIntersection.ts, 26, 48)) +>x : Symbol(x, Decl(interfaceExtendsObjectIntersection.ts, 28, 20)) + +declare class CX { a: number } +>CX : Symbol(CX, Decl(interfaceExtendsObjectIntersection.ts, 28, 39)) +>a : Symbol(CX.a, Decl(interfaceExtendsObjectIntersection.ts, 29, 18)) + +declare enum EX { A, B, C } +>EX : Symbol(EX, Decl(interfaceExtendsObjectIntersection.ts, 29, 30)) +>A : Symbol(EX.A, Decl(interfaceExtendsObjectIntersection.ts, 30, 17)) +>B : Symbol(EX.B, Decl(interfaceExtendsObjectIntersection.ts, 30, 20)) +>C : Symbol(EX.C, Decl(interfaceExtendsObjectIntersection.ts, 30, 23)) + +declare namespace NX { export const a = 1 } +>NX : Symbol(NX, Decl(interfaceExtendsObjectIntersection.ts, 30, 27)) +>a : Symbol(a, Decl(interfaceExtendsObjectIntersection.ts, 31, 35)) + +type T10 = typeof fx; +>T10 : Symbol(T10, Decl(interfaceExtendsObjectIntersection.ts, 31, 43)) +>fx : Symbol(fx, Decl(interfaceExtendsObjectIntersection.ts, 26, 48)) + +type T11 = typeof CX; +>T11 : Symbol(T11, Decl(interfaceExtendsObjectIntersection.ts, 33, 21)) +>CX : Symbol(CX, Decl(interfaceExtendsObjectIntersection.ts, 28, 39)) + +type T12 = typeof EX; +>T12 : Symbol(T12, Decl(interfaceExtendsObjectIntersection.ts, 34, 21)) +>EX : Symbol(EX, Decl(interfaceExtendsObjectIntersection.ts, 29, 30)) + +type T13 = typeof NX; +>T13 : Symbol(T13, Decl(interfaceExtendsObjectIntersection.ts, 35, 21)) +>NX : Symbol(NX, Decl(interfaceExtendsObjectIntersection.ts, 30, 27)) + +interface I10 extends T10 { x: string } +>I10 : Symbol(I10, Decl(interfaceExtendsObjectIntersection.ts, 36, 21)) +>T10 : Symbol(T10, Decl(interfaceExtendsObjectIntersection.ts, 31, 43)) +>x : Symbol(I10.x, Decl(interfaceExtendsObjectIntersection.ts, 38, 27)) + +interface I11 extends T11 { x: string } +>I11 : Symbol(I11, Decl(interfaceExtendsObjectIntersection.ts, 38, 39)) +>T11 : Symbol(T11, Decl(interfaceExtendsObjectIntersection.ts, 33, 21)) +>x : Symbol(I11.x, Decl(interfaceExtendsObjectIntersection.ts, 39, 27)) + +interface I12 extends T12 { x: string } +>I12 : Symbol(I12, Decl(interfaceExtendsObjectIntersection.ts, 39, 39)) +>T12 : Symbol(T12, Decl(interfaceExtendsObjectIntersection.ts, 34, 21)) +>x : Symbol(I12.x, Decl(interfaceExtendsObjectIntersection.ts, 40, 27)) + +interface I13 extends T13 { x: string } +>I13 : Symbol(I13, Decl(interfaceExtendsObjectIntersection.ts, 40, 39)) +>T13 : Symbol(T13, Decl(interfaceExtendsObjectIntersection.ts, 35, 21)) +>x : Symbol(I13.x, Decl(interfaceExtendsObjectIntersection.ts, 41, 27)) + +type Identifiable = { _id: string } & T; +>Identifiable : Symbol(Identifiable, Decl(interfaceExtendsObjectIntersection.ts, 41, 39)) +>T : Symbol(T, Decl(interfaceExtendsObjectIntersection.ts, 43, 18)) +>_id : Symbol(_id, Decl(interfaceExtendsObjectIntersection.ts, 43, 24)) +>T : Symbol(T, Decl(interfaceExtendsObjectIntersection.ts, 43, 18)) + +interface I20 extends Partial { x: string } +>I20 : Symbol(I20, Decl(interfaceExtendsObjectIntersection.ts, 43, 43)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>T1 : Symbol(T1, Decl(interfaceExtendsObjectIntersection.ts, 0, 0)) +>x : Symbol(I20.x, Decl(interfaceExtendsObjectIntersection.ts, 45, 35)) + +interface I21 extends Readonly { x: string } +>I21 : Symbol(I21, Decl(interfaceExtendsObjectIntersection.ts, 45, 47)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>T1 : Symbol(T1, Decl(interfaceExtendsObjectIntersection.ts, 0, 0)) +>x : Symbol(I21.x, Decl(interfaceExtendsObjectIntersection.ts, 46, 36)) + +interface I22 extends Identifiable { x: string } +>I22 : Symbol(I22, Decl(interfaceExtendsObjectIntersection.ts, 46, 48)) +>Identifiable : Symbol(Identifiable, Decl(interfaceExtendsObjectIntersection.ts, 41, 39)) +>T1 : Symbol(T1, Decl(interfaceExtendsObjectIntersection.ts, 0, 0)) +>x : Symbol(I22.x, Decl(interfaceExtendsObjectIntersection.ts, 47, 40)) + +interface I23 extends Identifiable { x: string } +>I23 : Symbol(I23, Decl(interfaceExtendsObjectIntersection.ts, 47, 52)) +>Identifiable : Symbol(Identifiable, Decl(interfaceExtendsObjectIntersection.ts, 41, 39)) +>T1 : Symbol(T1, Decl(interfaceExtendsObjectIntersection.ts, 0, 0)) +>b : Symbol(b, Decl(interfaceExtendsObjectIntersection.ts, 48, 41)) +>x : Symbol(I23.x, Decl(interfaceExtendsObjectIntersection.ts, 48, 55)) + +class C20 extends Constructor>() { x: string } +>C20 : Symbol(C20, Decl(interfaceExtendsObjectIntersection.ts, 48, 67)) +>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>T1 : Symbol(T1, Decl(interfaceExtendsObjectIntersection.ts, 0, 0)) +>x : Symbol(C20.x, Decl(interfaceExtendsObjectIntersection.ts, 50, 46)) + +class C21 extends Constructor>() { x: string } +>C21 : Symbol(C21, Decl(interfaceExtendsObjectIntersection.ts, 50, 58)) +>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>T1 : Symbol(T1, Decl(interfaceExtendsObjectIntersection.ts, 0, 0)) +>x : Symbol(C21.x, Decl(interfaceExtendsObjectIntersection.ts, 51, 47)) + +class C22 extends Constructor>() { x: string } +>C22 : Symbol(C22, Decl(interfaceExtendsObjectIntersection.ts, 51, 59)) +>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34)) +>Identifiable : Symbol(Identifiable, Decl(interfaceExtendsObjectIntersection.ts, 41, 39)) +>T1 : Symbol(T1, Decl(interfaceExtendsObjectIntersection.ts, 0, 0)) +>x : Symbol(C22.x, Decl(interfaceExtendsObjectIntersection.ts, 52, 51)) + +class C23 extends Constructor>() { x: string } +>C23 : Symbol(C23, Decl(interfaceExtendsObjectIntersection.ts, 52, 63)) +>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34)) +>Identifiable : Symbol(Identifiable, Decl(interfaceExtendsObjectIntersection.ts, 41, 39)) +>T1 : Symbol(T1, Decl(interfaceExtendsObjectIntersection.ts, 0, 0)) +>b : Symbol(b, Decl(interfaceExtendsObjectIntersection.ts, 53, 49)) +>x : Symbol(C23.x, Decl(interfaceExtendsObjectIntersection.ts, 53, 66)) + diff --git a/tests/baselines/reference/interfaceExtendsObjectIntersection.types b/tests/baselines/reference/interfaceExtendsObjectIntersection.types new file mode 100644 index 00000000000..1ff550df7b4 --- /dev/null +++ b/tests/baselines/reference/interfaceExtendsObjectIntersection.types @@ -0,0 +1,242 @@ +=== tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersection.ts === + +type T1 = { a: number }; +>T1 : T1 +>a : number + +type T2 = T1 & { b: number }; +>T2 : T2 +>T1 : T1 +>b : number + +type T3 = () => void; +>T3 : T3 + +type T4 = new () => { a: number }; +>T4 : T4 +>a : number + +type T5 = number[]; +>T5 : number[] + +type T6 = [string, number]; +>T6 : [string, number] + +type T7 = { [P in 'a' | 'b' | 'c']: string }; +>T7 : T7 +>P : P + +interface I1 extends T1 { x: string } +>I1 : I1 +>T1 : T1 +>x : string + +interface I2 extends T2 { x: string } +>I2 : I2 +>T2 : T2 +>x : string + +interface I3 extends T3 { x: string } +>I3 : I3 +>T3 : T3 +>x : string + +interface I4 extends T4 { x: string } +>I4 : I4 +>T4 : T4 +>x : string + +interface I5 extends T5 { x: string } +>I5 : I5 +>T5 : number[] +>x : string + +interface I6 extends T6 { x: string } +>I6 : I6 +>T6 : [string, number] +>x : string + +interface I7 extends T7 { x: string } +>I7 : I7 +>T7 : T7 +>x : string + +type Constructor = new () => T; +>Constructor : Constructor +>T : T +>T : T + +declare function Constructor(): Constructor; +>Constructor : () => Constructor +>T : T +>Constructor : Constructor +>T : T + +class C1 extends Constructor() { x: string } +>C1 : C1 +>Constructor() : I1 +>Constructor : () => Constructor +>I1 : I1 +>x : string + +class C2 extends Constructor() { x: string } +>C2 : C2 +>Constructor() : I2 +>Constructor : () => Constructor +>I2 : I2 +>x : string + +class C3 extends Constructor() { x: string } +>C3 : C3 +>Constructor() : I3 +>Constructor : () => Constructor +>I3 : I3 +>x : string + +class C4 extends Constructor() { x: string } +>C4 : C4 +>Constructor() : I4 +>Constructor : () => Constructor +>I4 : I4 +>x : string + +class C5 extends Constructor() { x: string } +>C5 : C5 +>Constructor() : I5 +>Constructor : () => Constructor +>I5 : I5 +>x : string + +class C6 extends Constructor() { x: string } +>C6 : C6 +>Constructor() : I6 +>Constructor : () => Constructor +>I6 : I6 +>x : string + +class C7 extends Constructor() { x: string } +>C7 : C7 +>Constructor() : I7 +>Constructor : () => Constructor +>I7 : I7 +>x : string + +declare function fx(x: string): string; +>fx : (x: string) => string +>x : string + +declare class CX { a: number } +>CX : CX +>a : number + +declare enum EX { A, B, C } +>EX : EX +>A : EX +>B : EX +>C : EX + +declare namespace NX { export const a = 1 } +>NX : typeof NX +>a : 1 +>1 : 1 + +type T10 = typeof fx; +>T10 : (x: string) => string +>fx : (x: string) => string + +type T11 = typeof CX; +>T11 : typeof CX +>CX : typeof CX + +type T12 = typeof EX; +>T12 : typeof EX +>EX : typeof EX + +type T13 = typeof NX; +>T13 : typeof NX +>NX : typeof NX + +interface I10 extends T10 { x: string } +>I10 : I10 +>T10 : (x: string) => string +>x : string + +interface I11 extends T11 { x: string } +>I11 : I11 +>T11 : typeof CX +>x : string + +interface I12 extends T12 { x: string } +>I12 : I12 +>T12 : typeof EX +>x : string + +interface I13 extends T13 { x: string } +>I13 : I13 +>T13 : typeof NX +>x : string + +type Identifiable = { _id: string } & T; +>Identifiable : Identifiable +>T : T +>_id : string +>T : T + +interface I20 extends Partial { x: string } +>I20 : I20 +>Partial : Partial +>T1 : T1 +>x : string + +interface I21 extends Readonly { x: string } +>I21 : I21 +>Readonly : Readonly +>T1 : T1 +>x : string + +interface I22 extends Identifiable { x: string } +>I22 : I22 +>Identifiable : Identifiable +>T1 : T1 +>x : string + +interface I23 extends Identifiable { x: string } +>I23 : I23 +>Identifiable : Identifiable +>T1 : T1 +>b : number +>x : string + +class C20 extends Constructor>() { x: string } +>C20 : C20 +>Constructor>() : Partial +>Constructor : () => Constructor +>Partial : Partial +>T1 : T1 +>x : string + +class C21 extends Constructor>() { x: string } +>C21 : C21 +>Constructor>() : Readonly +>Constructor : () => Constructor +>Readonly : Readonly +>T1 : T1 +>x : string + +class C22 extends Constructor>() { x: string } +>C22 : C22 +>Constructor>() : Identifiable +>Constructor : () => Constructor +>Identifiable : Identifiable +>T1 : T1 +>x : string + +class C23 extends Constructor>() { x: string } +>C23 : C23 +>Constructor>() : Identifiable +>Constructor : () => Constructor +>Identifiable : Identifiable +>T1 : T1 +>b : number +>x : string + diff --git a/tests/baselines/reference/interfaceExtendsObjectIntersectionErrors.errors.txt b/tests/baselines/reference/interfaceExtendsObjectIntersectionErrors.errors.txt new file mode 100644 index 00000000000..839474b3bdc --- /dev/null +++ b/tests/baselines/reference/interfaceExtendsObjectIntersectionErrors.errors.txt @@ -0,0 +1,197 @@ +tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(8,11): error TS2430: Interface 'I1' incorrectly extends interface 'T1'. + Types of property 'a' are incompatible. + Type 'string' is not assignable to type 'number'. +tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(9,11): error TS2430: Interface 'I2' incorrectly extends interface 'T2'. + Type 'I2' is not assignable to type '{ b: number; }'. + Types of property 'b' are incompatible. + Type 'string' is not assignable to type 'number'. +tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(10,11): error TS2430: Interface 'I3' incorrectly extends interface 'number[]'. + Types of property 'length' are incompatible. + Type 'string' is not assignable to type 'number'. +tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(11,11): error TS2430: Interface 'I4' incorrectly extends interface '[string, number]'. + Types of property '0' are incompatible. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(12,11): error TS2430: Interface 'I5' incorrectly extends interface 'T5'. + Types of property 'c' are incompatible. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(17,7): error TS2415: Class 'C1' incorrectly extends base class 'T1'. + Types of property 'a' are incompatible. + Type 'string' is not assignable to type 'number'. +tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(18,7): error TS2415: Class 'C2' incorrectly extends base class 'T2'. + Type 'C2' is not assignable to type '{ b: number; }'. + Types of property 'b' are incompatible. + Type 'string' is not assignable to type 'number'. +tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(19,7): error TS2415: Class 'C3' incorrectly extends base class 'number[]'. + Types of property 'length' are incompatible. + Type 'string' is not assignable to type 'number'. +tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(20,7): error TS2415: Class 'C4' incorrectly extends base class '[string, number]'. + Types of property '0' are incompatible. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(21,7): error TS2415: Class 'C5' incorrectly extends base class 'T5'. + Types of property 'c' are incompatible. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(31,11): error TS2430: Interface 'I10' incorrectly extends interface 'typeof CX'. + Types of property 'a' are incompatible. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(32,11): error TS2430: Interface 'I11' incorrectly extends interface 'typeof EX'. + Types of property 'C' are incompatible. + Type 'string' is not assignable to type 'EX'. +tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(33,11): error TS2430: Interface 'I12' incorrectly extends interface 'typeof NX'. + Types of property 'a' are incompatible. + Type 'number' is not assignable to type '"hello"'. +tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(34,29): error TS2411: Property 'a' of type 'string' is not assignable to string index type 'number'. +tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(34,29): error TS2411: Property 'prototype' of type 'CX' is not assignable to string index type 'number'. +tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(35,29): error TS2413: Numeric index type 'string' is not assignable to string index type 'number'. +tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(36,29): error TS2411: Property 'a' of type '"hello"' is not assignable to string index type 'number'. +tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(40,11): error TS2430: Interface 'I20' incorrectly extends interface 'Partial'. + Types of property 'a' are incompatible. + Type 'string' is not assignable to type 'number | undefined'. +tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(41,11): error TS2430: Interface 'I21' incorrectly extends interface 'Readonly'. + Types of property 'a' are incompatible. + Type 'string' is not assignable to type 'number'. +tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(42,11): error TS2430: Interface 'I22' incorrectly extends interface 'Identifiable'. + Type 'I22' is not assignable to type 'T1'. + Types of property 'a' are incompatible. + Type 'string' is not assignable to type 'number'. +tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(43,11): error TS2430: Interface 'I23' incorrectly extends interface 'Identifiable'. + Type 'I23' is not assignable to type 'T1'. + Types of property 'a' are incompatible. + Type 'string' is not assignable to type 'number'. +tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(47,23): error TS2312: An interface may only extend a class or another interface. +tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(48,26): error TS2312: An interface may only extend a class or another interface. + + +==== tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts (23 errors) ==== + + type T1 = { a: number }; + type T2 = T1 & { b: number }; + type T3 = number[]; + type T4 = [string, number]; + type T5 = { [P in 'a' | 'b' | 'c']: string }; + + interface I1 extends T1 { a: string } + ~~ +!!! error TS2430: Interface 'I1' incorrectly extends interface 'T1'. +!!! error TS2430: Types of property 'a' are incompatible. +!!! error TS2430: Type 'string' is not assignable to type 'number'. + interface I2 extends T2 { b: string } + ~~ +!!! error TS2430: Interface 'I2' incorrectly extends interface 'T2'. +!!! error TS2430: Type 'I2' is not assignable to type '{ b: number; }'. +!!! error TS2430: Types of property 'b' are incompatible. +!!! error TS2430: Type 'string' is not assignable to type 'number'. + interface I3 extends T3 { length: string } + ~~ +!!! error TS2430: Interface 'I3' incorrectly extends interface 'number[]'. +!!! error TS2430: Types of property 'length' are incompatible. +!!! error TS2430: Type 'string' is not assignable to type 'number'. + interface I4 extends T4 { 0: number } + ~~ +!!! error TS2430: Interface 'I4' incorrectly extends interface '[string, number]'. +!!! error TS2430: Types of property '0' are incompatible. +!!! error TS2430: Type 'number' is not assignable to type 'string'. + interface I5 extends T5 { c: number } + ~~ +!!! error TS2430: Interface 'I5' incorrectly extends interface 'T5'. +!!! error TS2430: Types of property 'c' are incompatible. +!!! error TS2430: Type 'number' is not assignable to type 'string'. + + type Constructor = new () => T; + declare function Constructor(): Constructor; + + class C1 extends Constructor() { a: string } + ~~ +!!! error TS2415: Class 'C1' incorrectly extends base class 'T1'. +!!! error TS2415: Types of property 'a' are incompatible. +!!! error TS2415: Type 'string' is not assignable to type 'number'. + class C2 extends Constructor() { b: string } + ~~ +!!! error TS2415: Class 'C2' incorrectly extends base class 'T2'. +!!! error TS2415: Type 'C2' is not assignable to type '{ b: number; }'. +!!! error TS2415: Types of property 'b' are incompatible. +!!! error TS2415: Type 'string' is not assignable to type 'number'. + class C3 extends Constructor() { length: string } + ~~ +!!! error TS2415: Class 'C3' incorrectly extends base class 'number[]'. +!!! error TS2415: Types of property 'length' are incompatible. +!!! error TS2415: Type 'string' is not assignable to type 'number'. + class C4 extends Constructor() { 0: number } + ~~ +!!! error TS2415: Class 'C4' incorrectly extends base class '[string, number]'. +!!! error TS2415: Types of property '0' are incompatible. +!!! error TS2415: Type 'number' is not assignable to type 'string'. + class C5 extends Constructor() { c: number } + ~~ +!!! error TS2415: Class 'C5' incorrectly extends base class 'T5'. +!!! error TS2415: Types of property 'c' are incompatible. +!!! error TS2415: Type 'number' is not assignable to type 'string'. + + declare class CX { static a: string } + declare enum EX { A, B, C } + declare namespace NX { export const a = "hello" } + + type TCX = typeof CX; + type TEX = typeof EX; + type TNX = typeof NX; + + interface I10 extends TCX { a: number } + ~~~ +!!! error TS2430: Interface 'I10' incorrectly extends interface 'typeof CX'. +!!! error TS2430: Types of property 'a' are incompatible. +!!! error TS2430: Type 'number' is not assignable to type 'string'. + interface I11 extends TEX { C: string } + ~~~ +!!! error TS2430: Interface 'I11' incorrectly extends interface 'typeof EX'. +!!! error TS2430: Types of property 'C' are incompatible. +!!! error TS2430: Type 'string' is not assignable to type 'EX'. + interface I12 extends TNX { a: number } + ~~~ +!!! error TS2430: Interface 'I12' incorrectly extends interface 'typeof NX'. +!!! error TS2430: Types of property 'a' are incompatible. +!!! error TS2430: Type 'number' is not assignable to type '"hello"'. + interface I14 extends TCX { [x: string]: number } + ~~~~~~~~~~~~~~~~~~~ +!!! error TS2411: Property 'a' of type 'string' is not assignable to string index type 'number'. + ~~~~~~~~~~~~~~~~~~~ +!!! error TS2411: Property 'prototype' of type 'CX' is not assignable to string index type 'number'. + interface I15 extends TEX { [x: string]: number } + ~~~~~~~~~~~~~~~~~~~ +!!! error TS2413: Numeric index type 'string' is not assignable to string index type 'number'. + interface I16 extends TNX { [x: string]: number } + ~~~~~~~~~~~~~~~~~~~ +!!! error TS2411: Property 'a' of type '"hello"' is not assignable to string index type 'number'. + + type Identifiable = { _id: string } & T; + + interface I20 extends Partial { a: string } + ~~~ +!!! error TS2430: Interface 'I20' incorrectly extends interface 'Partial'. +!!! error TS2430: Types of property 'a' are incompatible. +!!! error TS2430: Type 'string' is not assignable to type 'number | undefined'. + interface I21 extends Readonly { a: string } + ~~~ +!!! error TS2430: Interface 'I21' incorrectly extends interface 'Readonly'. +!!! error TS2430: Types of property 'a' are incompatible. +!!! error TS2430: Type 'string' is not assignable to type 'number'. + interface I22 extends Identifiable { a: string } + ~~~ +!!! error TS2430: Interface 'I22' incorrectly extends interface 'Identifiable'. +!!! error TS2430: Type 'I22' is not assignable to type 'T1'. +!!! error TS2430: Types of property 'a' are incompatible. +!!! error TS2430: Type 'string' is not assignable to type 'number'. + interface I23 extends Identifiable { a: string } + ~~~ +!!! error TS2430: Interface 'I23' incorrectly extends interface 'Identifiable'. +!!! error TS2430: Type 'I23' is not assignable to type 'T1'. +!!! error TS2430: Types of property 'a' are incompatible. +!!! error TS2430: Type 'string' is not assignable to type 'number'. + + type U = { a: number } | { b: string }; + + interface I30 extends U { x: string } + ~ +!!! error TS2312: An interface may only extend a class or another interface. + interface I31 extends T { x: string } + ~ +!!! error TS2312: An interface may only extend a class or another interface. + \ No newline at end of file diff --git a/tests/baselines/reference/interfaceExtendsObjectIntersectionErrors.js b/tests/baselines/reference/interfaceExtendsObjectIntersectionErrors.js new file mode 100644 index 00000000000..61f84b2f7fe --- /dev/null +++ b/tests/baselines/reference/interfaceExtendsObjectIntersectionErrors.js @@ -0,0 +1,97 @@ +//// [interfaceExtendsObjectIntersectionErrors.ts] + +type T1 = { a: number }; +type T2 = T1 & { b: number }; +type T3 = number[]; +type T4 = [string, number]; +type T5 = { [P in 'a' | 'b' | 'c']: string }; + +interface I1 extends T1 { a: string } +interface I2 extends T2 { b: string } +interface I3 extends T3 { length: string } +interface I4 extends T4 { 0: number } +interface I5 extends T5 { c: number } + +type Constructor = new () => T; +declare function Constructor(): Constructor; + +class C1 extends Constructor() { a: string } +class C2 extends Constructor() { b: string } +class C3 extends Constructor() { length: string } +class C4 extends Constructor() { 0: number } +class C5 extends Constructor() { c: number } + +declare class CX { static a: string } +declare enum EX { A, B, C } +declare namespace NX { export const a = "hello" } + +type TCX = typeof CX; +type TEX = typeof EX; +type TNX = typeof NX; + +interface I10 extends TCX { a: number } +interface I11 extends TEX { C: string } +interface I12 extends TNX { a: number } +interface I14 extends TCX { [x: string]: number } +interface I15 extends TEX { [x: string]: number } +interface I16 extends TNX { [x: string]: number } + +type Identifiable = { _id: string } & T; + +interface I20 extends Partial { a: string } +interface I21 extends Readonly { a: string } +interface I22 extends Identifiable { a: string } +interface I23 extends Identifiable { a: string } + +type U = { a: number } | { b: string }; + +interface I30 extends U { x: string } +interface I31 extends T { x: string } + + +//// [interfaceExtendsObjectIntersectionErrors.js] +var __extends = (this && this.__extends) || (function () { + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var C1 = (function (_super) { + __extends(C1, _super); + function C1() { + return _super !== null && _super.apply(this, arguments) || this; + } + return C1; +}(Constructor())); +var C2 = (function (_super) { + __extends(C2, _super); + function C2() { + return _super !== null && _super.apply(this, arguments) || this; + } + return C2; +}(Constructor())); +var C3 = (function (_super) { + __extends(C3, _super); + function C3() { + return _super !== null && _super.apply(this, arguments) || this; + } + return C3; +}(Constructor())); +var C4 = (function (_super) { + __extends(C4, _super); + function C4() { + return _super !== null && _super.apply(this, arguments) || this; + } + return C4; +}(Constructor())); +var C5 = (function (_super) { + __extends(C5, _super); + function C5() { + return _super !== null && _super.apply(this, arguments) || this; + } + return C5; +}(Constructor())); diff --git a/tests/baselines/reference/intersectionThisTypes.js b/tests/baselines/reference/intersectionThisTypes.js new file mode 100644 index 00000000000..9c7be09eeb8 --- /dev/null +++ b/tests/baselines/reference/intersectionThisTypes.js @@ -0,0 +1,57 @@ +//// [intersectionThisTypes.ts] +interface Thing1 { + a: number; + self(): this; +} + +interface Thing2 { + b: number; + me(): this; +} + +type Thing3 = Thing1 & Thing2; +type Thing4 = Thing3 & string[]; + +function f1(t: Thing3) { + t = t.self(); + t = t.me().self().me(); +} + +interface Thing5 extends Thing4 { + c: string; +} + +function f2(t: Thing5) { + t = t.self(); + t = t.me().self().me(); +} + +interface Component { + extend(props: T): this & T; +} + +interface Label extends Component { + title: string; +} + +function test(label: Label) { + const extended = label.extend({ id: 67 }).extend({ tag: "hello" }); + extended.id; // Ok + extended.tag; // Ok +} + + +//// [intersectionThisTypes.js] +function f1(t) { + t = t.self(); + t = t.me().self().me(); +} +function f2(t) { + t = t.self(); + t = t.me().self().me(); +} +function test(label) { + var extended = label.extend({ id: 67 }).extend({ tag: "hello" }); + extended.id; // Ok + extended.tag; // Ok +} diff --git a/tests/baselines/reference/intersectionThisTypes.symbols b/tests/baselines/reference/intersectionThisTypes.symbols new file mode 100644 index 00000000000..8a8a6cd5496 --- /dev/null +++ b/tests/baselines/reference/intersectionThisTypes.symbols @@ -0,0 +1,127 @@ +=== tests/cases/conformance/types/intersection/intersectionThisTypes.ts === +interface Thing1 { +>Thing1 : Symbol(Thing1, Decl(intersectionThisTypes.ts, 0, 0)) + + a: number; +>a : Symbol(Thing1.a, Decl(intersectionThisTypes.ts, 0, 18)) + + self(): this; +>self : Symbol(Thing1.self, Decl(intersectionThisTypes.ts, 1, 14)) +} + +interface Thing2 { +>Thing2 : Symbol(Thing2, Decl(intersectionThisTypes.ts, 3, 1)) + + b: number; +>b : Symbol(Thing2.b, Decl(intersectionThisTypes.ts, 5, 18)) + + me(): this; +>me : Symbol(Thing2.me, Decl(intersectionThisTypes.ts, 6, 14)) +} + +type Thing3 = Thing1 & Thing2; +>Thing3 : Symbol(Thing3, Decl(intersectionThisTypes.ts, 8, 1)) +>Thing1 : Symbol(Thing1, Decl(intersectionThisTypes.ts, 0, 0)) +>Thing2 : Symbol(Thing2, Decl(intersectionThisTypes.ts, 3, 1)) + +type Thing4 = Thing3 & string[]; +>Thing4 : Symbol(Thing4, Decl(intersectionThisTypes.ts, 10, 30)) +>Thing3 : Symbol(Thing3, Decl(intersectionThisTypes.ts, 8, 1)) + +function f1(t: Thing3) { +>f1 : Symbol(f1, Decl(intersectionThisTypes.ts, 11, 32)) +>t : Symbol(t, Decl(intersectionThisTypes.ts, 13, 12)) +>Thing3 : Symbol(Thing3, Decl(intersectionThisTypes.ts, 8, 1)) + + t = t.self(); +>t : Symbol(t, Decl(intersectionThisTypes.ts, 13, 12)) +>t.self : Symbol(Thing1.self, Decl(intersectionThisTypes.ts, 1, 14)) +>t : Symbol(t, Decl(intersectionThisTypes.ts, 13, 12)) +>self : Symbol(Thing1.self, Decl(intersectionThisTypes.ts, 1, 14)) + + t = t.me().self().me(); +>t : Symbol(t, Decl(intersectionThisTypes.ts, 13, 12)) +>t.me().self().me : Symbol(Thing2.me, Decl(intersectionThisTypes.ts, 6, 14)) +>t.me().self : Symbol(Thing1.self, Decl(intersectionThisTypes.ts, 1, 14)) +>t.me : Symbol(Thing2.me, Decl(intersectionThisTypes.ts, 6, 14)) +>t : Symbol(t, Decl(intersectionThisTypes.ts, 13, 12)) +>me : Symbol(Thing2.me, Decl(intersectionThisTypes.ts, 6, 14)) +>self : Symbol(Thing1.self, Decl(intersectionThisTypes.ts, 1, 14)) +>me : Symbol(Thing2.me, Decl(intersectionThisTypes.ts, 6, 14)) +} + +interface Thing5 extends Thing4 { +>Thing5 : Symbol(Thing5, Decl(intersectionThisTypes.ts, 16, 1)) +>Thing4 : Symbol(Thing4, Decl(intersectionThisTypes.ts, 10, 30)) + + c: string; +>c : Symbol(Thing5.c, Decl(intersectionThisTypes.ts, 18, 33)) +} + +function f2(t: Thing5) { +>f2 : Symbol(f2, Decl(intersectionThisTypes.ts, 20, 1)) +>t : Symbol(t, Decl(intersectionThisTypes.ts, 22, 12)) +>Thing5 : Symbol(Thing5, Decl(intersectionThisTypes.ts, 16, 1)) + + t = t.self(); +>t : Symbol(t, Decl(intersectionThisTypes.ts, 22, 12)) +>t.self : Symbol(Thing1.self, Decl(intersectionThisTypes.ts, 1, 14)) +>t : Symbol(t, Decl(intersectionThisTypes.ts, 22, 12)) +>self : Symbol(Thing1.self, Decl(intersectionThisTypes.ts, 1, 14)) + + t = t.me().self().me(); +>t : Symbol(t, Decl(intersectionThisTypes.ts, 22, 12)) +>t.me().self().me : Symbol(Thing2.me, Decl(intersectionThisTypes.ts, 6, 14)) +>t.me().self : Symbol(Thing1.self, Decl(intersectionThisTypes.ts, 1, 14)) +>t.me : Symbol(Thing2.me, Decl(intersectionThisTypes.ts, 6, 14)) +>t : Symbol(t, Decl(intersectionThisTypes.ts, 22, 12)) +>me : Symbol(Thing2.me, Decl(intersectionThisTypes.ts, 6, 14)) +>self : Symbol(Thing1.self, Decl(intersectionThisTypes.ts, 1, 14)) +>me : Symbol(Thing2.me, Decl(intersectionThisTypes.ts, 6, 14)) +} + +interface Component { +>Component : Symbol(Component, Decl(intersectionThisTypes.ts, 25, 1)) + + extend(props: T): this & T; +>extend : Symbol(Component.extend, Decl(intersectionThisTypes.ts, 27, 21)) +>T : Symbol(T, Decl(intersectionThisTypes.ts, 28, 11)) +>props : Symbol(props, Decl(intersectionThisTypes.ts, 28, 14)) +>T : Symbol(T, Decl(intersectionThisTypes.ts, 28, 11)) +>T : Symbol(T, Decl(intersectionThisTypes.ts, 28, 11)) +} + +interface Label extends Component { +>Label : Symbol(Label, Decl(intersectionThisTypes.ts, 29, 1)) +>Component : Symbol(Component, Decl(intersectionThisTypes.ts, 25, 1)) + + title: string; +>title : Symbol(Label.title, Decl(intersectionThisTypes.ts, 31, 35)) +} + +function test(label: Label) { +>test : Symbol(test, Decl(intersectionThisTypes.ts, 33, 1)) +>label : Symbol(label, Decl(intersectionThisTypes.ts, 35, 14)) +>Label : Symbol(Label, Decl(intersectionThisTypes.ts, 29, 1)) + + const extended = label.extend({ id: 67 }).extend({ tag: "hello" }); +>extended : Symbol(extended, Decl(intersectionThisTypes.ts, 36, 9)) +>label.extend({ id: 67 }).extend : Symbol(Component.extend, Decl(intersectionThisTypes.ts, 27, 21)) +>label.extend : Symbol(Component.extend, Decl(intersectionThisTypes.ts, 27, 21)) +>label : Symbol(label, Decl(intersectionThisTypes.ts, 35, 14)) +>extend : Symbol(Component.extend, Decl(intersectionThisTypes.ts, 27, 21)) +>id : Symbol(id, Decl(intersectionThisTypes.ts, 36, 35)) +>extend : Symbol(Component.extend, Decl(intersectionThisTypes.ts, 27, 21)) +>tag : Symbol(tag, Decl(intersectionThisTypes.ts, 36, 54)) + + extended.id; // Ok +>extended.id : Symbol(id, Decl(intersectionThisTypes.ts, 36, 35)) +>extended : Symbol(extended, Decl(intersectionThisTypes.ts, 36, 9)) +>id : Symbol(id, Decl(intersectionThisTypes.ts, 36, 35)) + + extended.tag; // Ok +>extended.tag : Symbol(tag, Decl(intersectionThisTypes.ts, 36, 54)) +>extended : Symbol(extended, Decl(intersectionThisTypes.ts, 36, 9)) +>tag : Symbol(tag, Decl(intersectionThisTypes.ts, 36, 54)) +} + diff --git a/tests/baselines/reference/intersectionThisTypes.types b/tests/baselines/reference/intersectionThisTypes.types new file mode 100644 index 00000000000..285609cdfdc --- /dev/null +++ b/tests/baselines/reference/intersectionThisTypes.types @@ -0,0 +1,145 @@ +=== tests/cases/conformance/types/intersection/intersectionThisTypes.ts === +interface Thing1 { +>Thing1 : Thing1 + + a: number; +>a : number + + self(): this; +>self : () => this +} + +interface Thing2 { +>Thing2 : Thing2 + + b: number; +>b : number + + me(): this; +>me : () => this +} + +type Thing3 = Thing1 & Thing2; +>Thing3 : Thing3 +>Thing1 : Thing1 +>Thing2 : Thing2 + +type Thing4 = Thing3 & string[]; +>Thing4 : Thing4 +>Thing3 : Thing3 + +function f1(t: Thing3) { +>f1 : (t: Thing3) => void +>t : Thing3 +>Thing3 : Thing3 + + t = t.self(); +>t = t.self() : Thing3 +>t : Thing3 +>t.self() : Thing3 +>t.self : () => Thing3 +>t : Thing3 +>self : () => Thing3 + + t = t.me().self().me(); +>t = t.me().self().me() : Thing3 +>t : Thing3 +>t.me().self().me() : Thing3 +>t.me().self().me : () => Thing3 +>t.me().self() : Thing3 +>t.me().self : () => Thing3 +>t.me() : Thing3 +>t.me : () => Thing3 +>t : Thing3 +>me : () => Thing3 +>self : () => Thing3 +>me : () => Thing3 +} + +interface Thing5 extends Thing4 { +>Thing5 : Thing5 +>Thing4 : Thing4 + + c: string; +>c : string +} + +function f2(t: Thing5) { +>f2 : (t: Thing5) => void +>t : Thing5 +>Thing5 : Thing5 + + t = t.self(); +>t = t.self() : Thing5 +>t : Thing5 +>t.self() : Thing5 +>t.self : () => Thing5 +>t : Thing5 +>self : () => Thing5 + + t = t.me().self().me(); +>t = t.me().self().me() : Thing5 +>t : Thing5 +>t.me().self().me() : Thing5 +>t.me().self().me : () => Thing5 +>t.me().self() : Thing5 +>t.me().self : () => Thing5 +>t.me() : Thing5 +>t.me : () => Thing5 +>t : Thing5 +>me : () => Thing5 +>self : () => Thing5 +>me : () => Thing5 +} + +interface Component { +>Component : Component + + extend(props: T): this & T; +>extend : (props: T) => this & T +>T : T +>props : T +>T : T +>T : T +} + +interface Label extends Component { +>Label : Label +>Component : Component + + title: string; +>title : string +} + +function test(label: Label) { +>test : (label: Label) => void +>label : Label +>Label : Label + + const extended = label.extend({ id: 67 }).extend({ tag: "hello" }); +>extended : Label & { id: number; } & { tag: string; } +>label.extend({ id: 67 }).extend({ tag: "hello" }) : Label & { id: number; } & { tag: string; } +>label.extend({ id: 67 }).extend : (props: T) => Label & { id: number; } & T +>label.extend({ id: 67 }) : Label & { id: number; } +>label.extend : (props: T) => Label & T +>label : Label +>extend : (props: T) => Label & T +>{ id: 67 } : { id: number; } +>id : number +>67 : 67 +>extend : (props: T) => Label & { id: number; } & T +>{ tag: "hello" } : { tag: string; } +>tag : string +>"hello" : "hello" + + extended.id; // Ok +>extended.id : number +>extended : Label & { id: number; } & { tag: string; } +>id : number + + extended.tag; // Ok +>extended.tag : string +>extended : Label & { id: number; } & { tag: string; } +>tag : string +} + From 80e5f2f314b46e327567902a912b2d885e6a4e63 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 22 Jan 2017 11:53:18 -0800 Subject: [PATCH 25/63] Add regression test --- .../conformance/types/keyof/keyofAndIndexedAccess.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts b/tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts index a4088e65df4..04c26fbe8f7 100644 --- a/tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts +++ b/tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts @@ -505,3 +505,15 @@ function updateIds2( // Repro from #13514 declare function head>(list: T): T[0]; + +// Repro from #13604 + +class A { + props: T & { foo: string }; +} + +class B extends A<{ x: number}> { + f(p: this["props"]) { + p.x; + } +} From 6d6b19fd23e7795da5e73c4fe72517d898536b22 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 22 Jan 2017 11:54:39 -0800 Subject: [PATCH 26/63] Fix typo in intersection apparent type --- 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 60d109d7600..bd8ff7568f3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4871,7 +4871,7 @@ namespace ts { */ function getApparentType(type: Type): Type { const t = type.flags & TypeFlags.TypeVariable ? getBaseConstraintOfType(type) || emptyObjectType : type; - return t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(type) : + return t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(t) : t.flags & TypeFlags.StringLike ? globalStringType : t.flags & TypeFlags.NumberLike ? globalNumberType : t.flags & TypeFlags.BooleanLike ? globalBooleanType : From f0e90c0d8bcc0009dca5e4ffcbcbb9b529779f03 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 22 Jan 2017 11:59:40 -0800 Subject: [PATCH 27/63] Accept new baselines --- .../reference/keyofAndIndexedAccess.js | 38 +++++++++++++++++++ .../reference/keyofAndIndexedAccess.symbols | 28 ++++++++++++++ .../reference/keyofAndIndexedAccess.types | 28 ++++++++++++++ 3 files changed, 94 insertions(+) diff --git a/tests/baselines/reference/keyofAndIndexedAccess.js b/tests/baselines/reference/keyofAndIndexedAccess.js index a86184c8ff0..e7df8bbd5a1 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess.js +++ b/tests/baselines/reference/keyofAndIndexedAccess.js @@ -504,6 +504,18 @@ function updateIds2( // Repro from #13514 declare function head>(list: T): T[0]; + +// Repro from #13604 + +class A { + props: T & { foo: string }; +} + +class B extends A<{ x: number}> { + f(p: this["props"]) { + p.x; + } +} //// [keyofAndIndexedAccess.js] @@ -834,6 +846,22 @@ function updateIds2(obj, key, stringMap) { var x = obj[key]; stringMap[x]; // Should be OK. } +// Repro from #13604 +var A = (function () { + function A() { + } + return A; +}()); +var B = (function (_super) { + __extends(B, _super); + function B() { + return _super !== null && _super.apply(this, arguments) || this; + } + B.prototype.f = function (p) { + p.x; + }; + return B; +}(A)); //// [keyofAndIndexedAccess.d.ts] @@ -1066,3 +1094,13 @@ declare function updateIds2>(list: T): T[0]; +declare class A { + props: T & { + foo: string; + }; +} +declare class B extends A<{ + x: number; +}> { + f(p: this["props"]): void; +} diff --git a/tests/baselines/reference/keyofAndIndexedAccess.symbols b/tests/baselines/reference/keyofAndIndexedAccess.symbols index 4c12c6554c9..01501cd719c 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess.symbols +++ b/tests/baselines/reference/keyofAndIndexedAccess.symbols @@ -1816,3 +1816,31 @@ declare function head>(list: T): T[0]; >T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 504, 22)) >T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 504, 22)) +// Repro from #13604 + +class A { +>A : Symbol(A, Decl(keyofAndIndexedAccess.ts, 504, 59)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 508, 8)) + + props: T & { foo: string }; +>props : Symbol(A.props, Decl(keyofAndIndexedAccess.ts, 508, 12)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 508, 8)) +>foo : Symbol(foo, Decl(keyofAndIndexedAccess.ts, 509, 13)) +} + +class B extends A<{ x: number}> { +>B : Symbol(B, Decl(keyofAndIndexedAccess.ts, 510, 1)) +>A : Symbol(A, Decl(keyofAndIndexedAccess.ts, 504, 59)) +>x : Symbol(x, Decl(keyofAndIndexedAccess.ts, 512, 19)) + + f(p: this["props"]) { +>f : Symbol(B.f, Decl(keyofAndIndexedAccess.ts, 512, 33)) +>p : Symbol(p, Decl(keyofAndIndexedAccess.ts, 513, 3)) + + p.x; +>p.x : Symbol(x, Decl(keyofAndIndexedAccess.ts, 512, 19)) +>p : Symbol(p, Decl(keyofAndIndexedAccess.ts, 513, 3)) +>x : Symbol(x, Decl(keyofAndIndexedAccess.ts, 512, 19)) + } +} + diff --git a/tests/baselines/reference/keyofAndIndexedAccess.types b/tests/baselines/reference/keyofAndIndexedAccess.types index 3919d768151..21c9d645ce4 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess.types +++ b/tests/baselines/reference/keyofAndIndexedAccess.types @@ -2138,3 +2138,31 @@ declare function head>(list: T): T[0]; >T : T >T : T +// Repro from #13604 + +class A { +>A : A +>T : T + + props: T & { foo: string }; +>props : T & { foo: string; } +>T : T +>foo : string +} + +class B extends A<{ x: number}> { +>B : B +>A : A<{ x: number; }> +>x : number + + f(p: this["props"]) { +>f : (p: this["props"]) => void +>p : this["props"] + + p.x; +>p.x : number +>p : this["props"] +>x : number + } +} + From dd0ed44b9aaa7dcd24bb415a5a6a241cd2d6061f Mon Sep 17 00:00:00 2001 From: David Sheldrick Date: Mon, 23 Jan 2017 17:40:20 +0100 Subject: [PATCH 28/63] Add option to output .js files while preserving jsx This commit adds the ability to preserve jsx in source code, but also to output .js files rather than .jsx files. This is useful for react-native which does not support .jsx files. --- lib/protocol.d.ts | 5 +- src/compiler/commandLineParser.ts | 3 +- src/compiler/diagnosticMessages.json | 2 +- src/compiler/types.ts | 3 +- src/harness/unittests/commandLineParsing.ts | 2 +- .../convertCompilerOptionsFromJson.ts | 2 +- src/harness/unittests/matchFiles.ts | 54 ++++++++++++++++- src/server/protocol.ts | 9 +-- tests/cases/unittests/matchFiles.ts | 58 ++++++++++++++++++- 9 files changed, 125 insertions(+), 13 deletions(-) diff --git a/lib/protocol.d.ts b/lib/protocol.d.ts index d6c0246af34..66c2ef5c8db 100644 --- a/lib/protocol.d.ts +++ b/lib/protocol.d.ts @@ -1798,9 +1798,10 @@ declare namespace ts.server.protocol { namespace JsxEmit { type None = "None"; type Preserve = "Preserve"; + type PreserveWithJsExtension = "PreserveWithJsExtension"; type React = "React"; } - type JsxEmit = JsxEmit.None | JsxEmit.Preserve | JsxEmit.React; + type JsxEmit = JsxEmit.None | JsxEmit.Preserve | JsxEmit.React | JsxEmit.PreserveWithJsExtension; namespace ModuleKind { type None = "None"; type CommonJS = "CommonJS"; @@ -1880,4 +1881,4 @@ declare namespace ts { } import protocol = ts.server.protocol; export = protocol; -export as namespace protocol; \ No newline at end of file +export as namespace protocol; diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index b222df53630..7c69676d6f0 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -67,10 +67,11 @@ namespace ts { name: "jsx", type: createMapFromTemplate({ "preserve": JsxEmit.Preserve, + "preservewithjsextension": JsxEmit.PreserveWithJsExtension, "react": JsxEmit.React }), paramType: Diagnostics.KIND, - description: Diagnostics.Specify_JSX_code_generation_Colon_preserve_or_react, + description: Diagnostics.Specify_JSX_code_generation_Colon_preserve_preserveWithJsExtension_or_react, }, { name: "reactNamespace", diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 43bb7415c88..6646017e73d 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2713,7 +2713,7 @@ "category": "Message", "code": 6079 }, - "Specify JSX code generation: 'preserve' or 'react'": { + "Specify JSX code generation: 'preserve', 'preserveWithJsExtension', or 'react'": { "category": "Message", "code": 6080 }, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c16c199d3eb..9024b7c1b13 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3298,7 +3298,8 @@ export const enum JsxEmit { None = 0, Preserve = 1, - React = 2 + React = 2, + PreserveWithJsExtension = 3 } export const enum NewLineKind { diff --git a/src/harness/unittests/commandLineParsing.ts b/src/harness/unittests/commandLineParsing.ts index 8c691992043..34a096628f9 100644 --- a/src/harness/unittests/commandLineParsing.ts +++ b/src/harness/unittests/commandLineParsing.ts @@ -87,7 +87,7 @@ namespace ts { start: undefined, length: undefined, }, { - messageText: "Argument for '--jsx' option must be: 'preserve', 'react'", + messageText: "Argument for '--jsx' option must be: 'preserve', 'preservewithjsextension', 'react'", category: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.category, code: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.code, diff --git a/src/harness/unittests/convertCompilerOptionsFromJson.ts b/src/harness/unittests/convertCompilerOptionsFromJson.ts index f44dc259710..cbfa47180f3 100644 --- a/src/harness/unittests/convertCompilerOptionsFromJson.ts +++ b/src/harness/unittests/convertCompilerOptionsFromJson.ts @@ -94,7 +94,7 @@ namespace ts { file: undefined, start: 0, length: 0, - messageText: "Argument for '--jsx' option must be: 'preserve', 'react'", + messageText: "Argument for '--jsx' option must be: 'preserve', 'preservewithjsextension', 'react'", code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code, category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category }] diff --git a/src/harness/unittests/matchFiles.ts b/src/harness/unittests/matchFiles.ts index c562fcefe91..2b4bbfd4ee6 100644 --- a/src/harness/unittests/matchFiles.ts +++ b/src/harness/unittests/matchFiles.ts @@ -909,6 +909,31 @@ namespace ts { const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath); assertParsed(actual, expected); }); + it("with jsx=preserveWithJsExtension, allowJs=false", () => { + const json = { + compilerOptions: { + jsx: "preserveWithJsExtension", + allowJs: false + } + }; + const expected: ts.ParsedCommandLine = { + options: { + jsx: ts.JsxEmit.PreserveWithJsExtension, + allowJs: false + }, + errors: [], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/b.tsx", + "c:/dev/c.tsx", + ], + wildcardDirectories: { + "c:/dev": ts.WatchDirectoryFlags.Recursive + } + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath); + assertParsed(actual, expected); + }); it("with jsx=none, allowJs=true", () => { const json = { compilerOptions: { @@ -961,6 +986,33 @@ namespace ts { const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath); assertParsed(actual, expected); }); + it("with jsx=preserveWithJsExtension, allowJs=true", () => { + const json = { + compilerOptions: { + jsx: "preserveWithJsExtension", + allowJs: true + } + }; + const expected: ts.ParsedCommandLine = { + options: { + jsx: ts.JsxEmit.PreserveWithJsExtension, + allowJs: true + }, + errors: [], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/b.tsx", + "c:/dev/c.tsx", + "c:/dev/d.js", + "c:/dev/e.jsx", + ], + wildcardDirectories: { + "c:/dev": ts.WatchDirectoryFlags.Recursive + } + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath); + assertParsed(actual, expected); + }); it("exclude .min.js files using wildcards", () => { const json = { compilerOptions: { @@ -1306,4 +1358,4 @@ namespace ts { }); }); }); -} \ No newline at end of file +} diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 680b81dff99..b18c887126b 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -417,7 +417,7 @@ namespace ts.server.protocol { startOffset: number; /** - * Position (can be specified instead of line/offset pair) + * Position (can be specified instead of line/offset pair) */ /* @internal */ startPosition?: number; @@ -433,7 +433,7 @@ namespace ts.server.protocol { endOffset: number; /** - * Position (can be specified instead of line/offset pair) + * Position (can be specified instead of line/offset pair) */ /* @internal */ endPosition?: number; @@ -445,7 +445,7 @@ namespace ts.server.protocol { } /** - * Response for GetCodeFixes request. + * Response for GetCodeFixes request. */ export interface GetCodeFixesResponse extends Response { body?: CodeAction[]; @@ -2272,10 +2272,11 @@ namespace ts.server.protocol { export namespace JsxEmit { export type None = "None"; export type Preserve = "Preserve"; + export type PreserveWithJsExtension = "PreserveWithJsExtension"; export type React = "React"; } - export type JsxEmit = JsxEmit.None | JsxEmit.Preserve | JsxEmit.React; + export type JsxEmit = JsxEmit.None | JsxEmit.Preserve | JsxEmit.React | JsxEmit.PreserveWithJsExtension; export namespace ModuleKind { export type None = "None"; diff --git a/tests/cases/unittests/matchFiles.ts b/tests/cases/unittests/matchFiles.ts index 91be2de8747..ef982f5f2bb 100644 --- a/tests/cases/unittests/matchFiles.ts +++ b/tests/cases/unittests/matchFiles.ts @@ -898,6 +898,33 @@ namespace ts { assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); assert.deepEqual(actual.errors, expected.errors); }); + it("with jsx=preserveWithJsExtension, allowJs=false", () => { + const json = { + compilerOptions: { + jsx: "preserveWithJsExtension", + allowJs: false + } + }; + const expected: ts.ParsedCommandLine = { + options: { + jsx: ts.JsxEmit.PreserveWithJsExtension, + allowJs: false + }, + errors: [], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/b.tsx", + "c:/dev/c.tsx", + ], + wildcardDirectories: { + "c:/dev": ts.WatchDirectoryFlags.Recursive + } + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); it("with jsx=none, allowJs=true", () => { const json = { compilerOptions: { @@ -954,6 +981,35 @@ namespace ts { assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); assert.deepEqual(actual.errors, expected.errors); }); + it("with jsx=preserveWithJsExtension, allowJs=true", () => { + const json = { + compilerOptions: { + jsx: "preserveWithJsExtension", + allowJs: true + } + }; + const expected: ts.ParsedCommandLine = { + options: { + jsx: ts.JsxEmit.PreserveWithJsExtension, + allowJs: true + }, + errors: [], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/b.tsx", + "c:/dev/c.tsx", + "c:/dev/d.js", + "c:/dev/e.jsx", + ], + wildcardDirectories: { + "c:/dev": ts.WatchDirectoryFlags.Recursive + } + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); describe("with trailing recursive directory", () => { it("in includes", () => { const json = { @@ -1149,4 +1205,4 @@ namespace ts { }); }); }); -} \ No newline at end of file +} From 7879b22ea9b210934c50b8d87df418379dfcc435 Mon Sep 17 00:00:00 2001 From: David Sheldrick Date: Mon, 23 Jan 2017 19:30:24 +0100 Subject: [PATCH 29/63] Add test case for preserveWithJsExtension --- ...utTsxFile_PreserveWithJsExtension.baseline | 26 +++++++++++++++++++ ...itOutputTsxFile_PreserveWithJsExtension.ts | 22 ++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 tests/baselines/reference/getEmitOutputTsxFile_PreserveWithJsExtension.baseline create mode 100644 tests/cases/fourslash/getEmitOutputTsxFile_PreserveWithJsExtension.ts diff --git a/tests/baselines/reference/getEmitOutputTsxFile_PreserveWithJsExtension.baseline b/tests/baselines/reference/getEmitOutputTsxFile_PreserveWithJsExtension.baseline new file mode 100644 index 00000000000..88fb0f0daf6 --- /dev/null +++ b/tests/baselines/reference/getEmitOutputTsxFile_PreserveWithJsExtension.baseline @@ -0,0 +1,26 @@ +EmitSkipped: false +FileName : /tests/cases/fourslash/inputFile1.js.map +{"version":3,"file":"inputFile1.js","sourceRoot":"","sources":["inputFile1.ts"],"names":[],"mappings":"AAAA,kBAAkB;AACjB,IAAI,CAAC,GAAW,CAAC,CAAC;AAClB;IAAA;IAGA,CAAC;IAAD,UAAC;AAAD,CAAC,AAHD,IAGC"}FileName : /tests/cases/fourslash/inputFile1.js +// regular ts file +var t = 5; +var Bar = (function () { + function Bar() { + } + return Bar; +}()); +//# sourceMappingURL=inputFile1.js.mapFileName : /tests/cases/fourslash/inputFile1.d.ts +declare var t: number; +declare class Bar { + x: string; + y: number; +} + +EmitSkipped: false +FileName : /tests/cases/fourslash/inputFile2.js.map +{"version":3,"file":"inputFile2.js","sourceRoot":"","sources":["inputFile2.tsx"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,QAAQ,CAAC;AACjB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC,CAAC,CAAC,EAAG,CAAA"}FileName : /tests/cases/fourslash/inputFile2.js +var y = "my div"; +var x =
; +//# sourceMappingURL=inputFile2.js.mapFileName : /tests/cases/fourslash/inputFile2.d.ts +declare var y: string; +declare var x: any; + diff --git a/tests/cases/fourslash/getEmitOutputTsxFile_PreserveWithJsExtension.ts b/tests/cases/fourslash/getEmitOutputTsxFile_PreserveWithJsExtension.ts new file mode 100644 index 00000000000..a1e4ce2d984 --- /dev/null +++ b/tests/cases/fourslash/getEmitOutputTsxFile_PreserveWithJsExtension.ts @@ -0,0 +1,22 @@ +/// + +// @BaselineFile: getEmitOutputTsxFile_PreserveWithJsExtension.baseline +// @declaration: true +// @sourceMap: true +// @jsx: preserveWithJsExtension + +// @Filename: inputFile1.ts +// @emitThisFile: true +////// regular ts file +//// var t: number = 5; +//// class Bar { +//// x : string; +//// y : number +//// } + +// @Filename: inputFile2.tsx +// @emitThisFile: true +//// var y = "my div"; +//// var x =
+ +verify.baselineGetEmitOutput(); From a32914f6872b9c5764d77f77ea85c7160ff9ae28 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Mon, 23 Jan 2017 11:14:29 -0800 Subject: [PATCH 30/63] Combine `forEachExpectedEmitFile` and `forEachEmittedFile` --- src/compiler/declarationEmitter.ts | 4 ++-- src/compiler/emitter.ts | 2 +- src/compiler/program.ts | 2 +- src/compiler/utilities.ts | 24 ++++++++---------------- 4 files changed, 12 insertions(+), 20 deletions(-) diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index 2287de179e3..46df4fed689 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -32,7 +32,7 @@ namespace ts { export function getDeclarationDiagnostics(host: EmitHost, resolver: EmitResolver, targetSourceFile: SourceFile): Diagnostic[] { const declarationDiagnostics = createDiagnosticCollection(); - forEachExpectedEmitFile(host, getDeclarationDiagnosticsFromFile, targetSourceFile); + forEachEmittedFile(host, getDeclarationDiagnosticsFromFile, targetSourceFile); return declarationDiagnostics.getDiagnostics(targetSourceFile ? targetSourceFile.fileName : undefined); function getDeclarationDiagnosticsFromFile({ declarationFilePath }: EmitFileNames, sources: SourceFile[], isBundledEmit: boolean) { @@ -1788,7 +1788,7 @@ namespace ts { } else { // Get the declaration file path - forEachExpectedEmitFile(host, getDeclFileName, referencedFile, emitOnlyDtsFiles); + forEachEmittedFile(host, getDeclFileName, referencedFile, emitOnlyDtsFiles); } if (declFileName) { diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 1c4662fa587..cc006a06637 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -73,7 +73,7 @@ namespace ts { // Emit each output file performance.mark("beforePrint"); - forEachEmittedFile(host, transformed, emitFile, emitOnlyDtsFiles); + forEachEmittedFile(host, emitFile, transformed, emitOnlyDtsFiles); performance.measure("printTime", "beforePrint"); // Clean up emit nodes on parse tree diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 851e206d448..650711afc79 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1707,7 +1707,7 @@ namespace ts { if (!options.noEmit && !options.suppressOutputPathCheck) { const emitHost = getEmitHost(); const emitFilesSeen = createFileMap(!host.useCaseSensitiveFileNames() ? key => key.toLocaleLowerCase() : undefined); - forEachExpectedEmitFile(emitHost, (emitFileNames) => { + forEachEmittedFile(emitHost, (emitFileNames) => { verifyEmitFilePath(emitFileNames.jsFilePath, emitFilesSeen); verifyEmitFilePath(emitFileNames.declarationFilePath, emitFilesSeen); }); diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index f59d384e490..b7cc0f0de6d 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2590,27 +2590,20 @@ namespace ts { } /** - * Iterates over the source files that are expected to have an emit output. This function - * is used by the legacy emitter and the declaration emitter and should not be used by - * the tree transforming emitter. + * Iterates over the source files that are expected to have an emit output. * * @param host An EmitHost. * @param action The action to execute. - * @param targetSourceFile An optional target source file to emit. + * @param sourceFilesOrTargetSourceFile + * If an array, the full list of source files to emit. + * Else, calls `getSourceFilesToEmit` with the (optional) target source file to determine the list of source files to emit. */ - export function forEachExpectedEmitFile(host: EmitHost, - action: (emitFileNames: EmitFileNames, sourceFiles: SourceFile[], isBundledEmit: boolean, emitOnlyDtsFiles: boolean) => void, - targetSourceFile?: SourceFile, + export function forEachEmittedFile( + host: EmitHost, action: (emitFileNames: EmitFileNames, sourceFiles: SourceFile[], isBundledEmit: boolean, emitOnlyDtsFiles: boolean) => void, + sourceFilesOrTargetSourceFile?: SourceFile[] | SourceFile, emitOnlyDtsFiles?: boolean) { - forEachEmittedFile(host, getSourceFilesToEmit(host, targetSourceFile), action, emitOnlyDtsFiles); - } - /** - * Iterates over each source file to emit. - */ - export function forEachEmittedFile(host: EmitHost, sourceFiles: SourceFile[], - action: (emitFileNames: EmitFileNames, sourceFiles: SourceFile[], isBundledEmit: boolean, emitOnlyDtsFiles: boolean) => void, - emitOnlyDtsFiles?: boolean) { + const sourceFiles = isArray(sourceFilesOrTargetSourceFile) ? sourceFilesOrTargetSourceFile : getSourceFilesToEmit(host, sourceFilesOrTargetSourceFile); const options = host.getCompilerOptions(); if (options.outFile || options.out) { if (sourceFiles.length) { @@ -2622,7 +2615,6 @@ namespace ts { } else { for (const sourceFile of sourceFiles) { - const options = host.getCompilerOptions(); const jsFilePath = getOwnEmitOutputFilePath(sourceFile, host, getOutputExtension(sourceFile, options)); const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options); const declarationFilePath = !isSourceFileJavaScript(sourceFile) && (emitOnlyDtsFiles || options.declaration) ? getDeclarationEmitOutputFilePath(sourceFile, host) : undefined; From 8d590d51916e6491191634097b8fb04f40d7d964 Mon Sep 17 00:00:00 2001 From: David Sheldrick Date: Mon, 23 Jan 2017 21:42:39 +0100 Subject: [PATCH 31/63] rename preserveWithJsExtension to react-native --- lib/protocol.d.ts | 4 ++-- src/compiler/commandLineParser.ts | 4 ++-- src/compiler/diagnosticMessages.json | 2 +- src/compiler/types.ts | 2 +- src/harness/unittests/commandLineParsing.ts | 2 +- .../unittests/convertCompilerOptionsFromJson.ts | 2 +- src/harness/unittests/matchFiles.ts | 12 ++++++------ src/server/protocol.ts | 4 ++-- ...ine => getEmitOutputTsxFile_ReactNative.baseline} | 0 ...ension.ts => getEmitOutputTsxFile_ReactNative.ts} | 4 ++-- tests/cases/unittests/matchFiles.ts | 12 ++++++------ 11 files changed, 24 insertions(+), 24 deletions(-) rename tests/baselines/reference/{getEmitOutputTsxFile_PreserveWithJsExtension.baseline => getEmitOutputTsxFile_ReactNative.baseline} (100%) rename tests/cases/fourslash/{getEmitOutputTsxFile_PreserveWithJsExtension.ts => getEmitOutputTsxFile_ReactNative.ts} (75%) diff --git a/lib/protocol.d.ts b/lib/protocol.d.ts index 66c2ef5c8db..cd46ebcd366 100644 --- a/lib/protocol.d.ts +++ b/lib/protocol.d.ts @@ -1798,10 +1798,10 @@ declare namespace ts.server.protocol { namespace JsxEmit { type None = "None"; type Preserve = "Preserve"; - type PreserveWithJsExtension = "PreserveWithJsExtension"; + type ReactNative = "ReactNative"; type React = "React"; } - type JsxEmit = JsxEmit.None | JsxEmit.Preserve | JsxEmit.React | JsxEmit.PreserveWithJsExtension; + type JsxEmit = JsxEmit.None | JsxEmit.Preserve | JsxEmit.React | JsxEmit.ReactNative; namespace ModuleKind { type None = "None"; type CommonJS = "CommonJS"; diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 7c69676d6f0..248726693c9 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -67,11 +67,11 @@ namespace ts { name: "jsx", type: createMapFromTemplate({ "preserve": JsxEmit.Preserve, - "preservewithjsextension": JsxEmit.PreserveWithJsExtension, + "react-native": JsxEmit.ReactNative, "react": JsxEmit.React }), paramType: Diagnostics.KIND, - description: Diagnostics.Specify_JSX_code_generation_Colon_preserve_preserveWithJsExtension_or_react, + description: Diagnostics.Specify_JSX_code_generation_Colon_preserve_react_native_or_react, }, { name: "reactNamespace", diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 6646017e73d..4278784e9ab 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2713,7 +2713,7 @@ "category": "Message", "code": 6079 }, - "Specify JSX code generation: 'preserve', 'preserveWithJsExtension', or 'react'": { + "Specify JSX code generation: 'preserve', 'react-native', or 'react'": { "category": "Message", "code": 6080 }, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 9024b7c1b13..6ac7d573eda 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3299,7 +3299,7 @@ None = 0, Preserve = 1, React = 2, - PreserveWithJsExtension = 3 + ReactNative = 3 } export const enum NewLineKind { diff --git a/src/harness/unittests/commandLineParsing.ts b/src/harness/unittests/commandLineParsing.ts index 34a096628f9..1895fe2d60e 100644 --- a/src/harness/unittests/commandLineParsing.ts +++ b/src/harness/unittests/commandLineParsing.ts @@ -87,7 +87,7 @@ namespace ts { start: undefined, length: undefined, }, { - messageText: "Argument for '--jsx' option must be: 'preserve', 'preservewithjsextension', 'react'", + messageText: "Argument for '--jsx' option must be: 'preserve', 'react-native', 'react'", category: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.category, code: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.code, diff --git a/src/harness/unittests/convertCompilerOptionsFromJson.ts b/src/harness/unittests/convertCompilerOptionsFromJson.ts index cbfa47180f3..4e442173883 100644 --- a/src/harness/unittests/convertCompilerOptionsFromJson.ts +++ b/src/harness/unittests/convertCompilerOptionsFromJson.ts @@ -94,7 +94,7 @@ namespace ts { file: undefined, start: 0, length: 0, - messageText: "Argument for '--jsx' option must be: 'preserve', 'preservewithjsextension', 'react'", + messageText: "Argument for '--jsx' option must be: 'preserve', 'react-native', 'react'", code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code, category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category }] diff --git a/src/harness/unittests/matchFiles.ts b/src/harness/unittests/matchFiles.ts index 2b4bbfd4ee6..38e5c6c4393 100644 --- a/src/harness/unittests/matchFiles.ts +++ b/src/harness/unittests/matchFiles.ts @@ -909,16 +909,16 @@ namespace ts { const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath); assertParsed(actual, expected); }); - it("with jsx=preserveWithJsExtension, allowJs=false", () => { + it("with jsx=react-native, allowJs=false", () => { const json = { compilerOptions: { - jsx: "preserveWithJsExtension", + jsx: "react-native", allowJs: false } }; const expected: ts.ParsedCommandLine = { options: { - jsx: ts.JsxEmit.PreserveWithJsExtension, + jsx: ts.JsxEmit.ReactNative, allowJs: false }, errors: [], @@ -986,16 +986,16 @@ namespace ts { const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath); assertParsed(actual, expected); }); - it("with jsx=preserveWithJsExtension, allowJs=true", () => { + it("with jsx=react-native, allowJs=true", () => { const json = { compilerOptions: { - jsx: "preserveWithJsExtension", + jsx: "react-native", allowJs: true } }; const expected: ts.ParsedCommandLine = { options: { - jsx: ts.JsxEmit.PreserveWithJsExtension, + jsx: ts.JsxEmit.ReactNative, allowJs: true }, errors: [], diff --git a/src/server/protocol.ts b/src/server/protocol.ts index b18c887126b..e3fe17362d7 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -2272,11 +2272,11 @@ namespace ts.server.protocol { export namespace JsxEmit { export type None = "None"; export type Preserve = "Preserve"; - export type PreserveWithJsExtension = "PreserveWithJsExtension"; + export type ReactNative = "ReactNative"; export type React = "React"; } - export type JsxEmit = JsxEmit.None | JsxEmit.Preserve | JsxEmit.React | JsxEmit.PreserveWithJsExtension; + export type JsxEmit = JsxEmit.None | JsxEmit.Preserve | JsxEmit.React | JsxEmit.ReactNative; export namespace ModuleKind { export type None = "None"; diff --git a/tests/baselines/reference/getEmitOutputTsxFile_PreserveWithJsExtension.baseline b/tests/baselines/reference/getEmitOutputTsxFile_ReactNative.baseline similarity index 100% rename from tests/baselines/reference/getEmitOutputTsxFile_PreserveWithJsExtension.baseline rename to tests/baselines/reference/getEmitOutputTsxFile_ReactNative.baseline diff --git a/tests/cases/fourslash/getEmitOutputTsxFile_PreserveWithJsExtension.ts b/tests/cases/fourslash/getEmitOutputTsxFile_ReactNative.ts similarity index 75% rename from tests/cases/fourslash/getEmitOutputTsxFile_PreserveWithJsExtension.ts rename to tests/cases/fourslash/getEmitOutputTsxFile_ReactNative.ts index a1e4ce2d984..c2aac0e9d03 100644 --- a/tests/cases/fourslash/getEmitOutputTsxFile_PreserveWithJsExtension.ts +++ b/tests/cases/fourslash/getEmitOutputTsxFile_ReactNative.ts @@ -1,9 +1,9 @@ /// -// @BaselineFile: getEmitOutputTsxFile_PreserveWithJsExtension.baseline +// @BaselineFile: getEmitOutputTsxFile_ReactNative.baseline // @declaration: true // @sourceMap: true -// @jsx: preserveWithJsExtension +// @jsx: react-native // @Filename: inputFile1.ts // @emitThisFile: true diff --git a/tests/cases/unittests/matchFiles.ts b/tests/cases/unittests/matchFiles.ts index ef982f5f2bb..e3448136c08 100644 --- a/tests/cases/unittests/matchFiles.ts +++ b/tests/cases/unittests/matchFiles.ts @@ -898,16 +898,16 @@ namespace ts { assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); assert.deepEqual(actual.errors, expected.errors); }); - it("with jsx=preserveWithJsExtension, allowJs=false", () => { + it("with jsx=react-native, allowJs=false", () => { const json = { compilerOptions: { - jsx: "preserveWithJsExtension", + jsx: "react-native", allowJs: false } }; const expected: ts.ParsedCommandLine = { options: { - jsx: ts.JsxEmit.PreserveWithJsExtension, + jsx: ts.JsxEmit.ReactNative, allowJs: false }, errors: [], @@ -981,16 +981,16 @@ namespace ts { assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); assert.deepEqual(actual.errors, expected.errors); }); - it("with jsx=preserveWithJsExtension, allowJs=true", () => { + it("with jsx=react-native, allowJs=true", () => { const json = { compilerOptions: { - jsx: "preserveWithJsExtension", + jsx: "react-native", allowJs: true } }; const expected: ts.ParsedCommandLine = { options: { - jsx: ts.JsxEmit.PreserveWithJsExtension, + jsx: ts.JsxEmit.ReactNative, allowJs: true }, errors: [], From 7bf52ee1fde05154eb38042e63ac1ef95d0a415d Mon Sep 17 00:00:00 2001 From: David Sheldrick Date: Mon, 23 Jan 2017 22:08:39 +0100 Subject: [PATCH 32/63] add notifications and tests for jsx react-native es3 --- src/compiler/transformers/es5.ts | 4 ++-- tests/baselines/reference/es3-jsx-preserve.js | 11 +++++++++++ tests/baselines/reference/es3-jsx-preserve.symbols | 11 +++++++++++ tests/baselines/reference/es3-jsx-preserve.types | 13 +++++++++++++ tests/baselines/reference/es3-jsx-react-native.js | 11 +++++++++++ .../reference/es3-jsx-react-native.symbols | 11 +++++++++++ .../baselines/reference/es3-jsx-react-native.types | 13 +++++++++++++ tests/baselines/reference/es3-jsx-react.js | 11 +++++++++++ tests/baselines/reference/es3-jsx-react.symbols | 11 +++++++++++ tests/baselines/reference/es3-jsx-react.types | 13 +++++++++++++ tests/cases/compiler/es3-jsx-preserve.tsx | 9 +++++++++ tests/cases/compiler/es3-jsx-react-native.tsx | 9 +++++++++ tests/cases/compiler/es3-jsx-react.tsx | 9 +++++++++ 13 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/es3-jsx-preserve.js create mode 100644 tests/baselines/reference/es3-jsx-preserve.symbols create mode 100644 tests/baselines/reference/es3-jsx-preserve.types create mode 100644 tests/baselines/reference/es3-jsx-react-native.js create mode 100644 tests/baselines/reference/es3-jsx-react-native.symbols create mode 100644 tests/baselines/reference/es3-jsx-react-native.types create mode 100644 tests/baselines/reference/es3-jsx-react.js create mode 100644 tests/baselines/reference/es3-jsx-react.symbols create mode 100644 tests/baselines/reference/es3-jsx-react.types create mode 100644 tests/cases/compiler/es3-jsx-preserve.tsx create mode 100644 tests/cases/compiler/es3-jsx-react-native.tsx create mode 100644 tests/cases/compiler/es3-jsx-react.tsx diff --git a/src/compiler/transformers/es5.ts b/src/compiler/transformers/es5.ts index 6dd875965d9..972b9214f16 100644 --- a/src/compiler/transformers/es5.ts +++ b/src/compiler/transformers/es5.ts @@ -14,7 +14,7 @@ namespace ts { // enable emit notification only if using --jsx preserve let previousOnEmitNode: (emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void) => void; let noSubstitution: boolean[]; - if (compilerOptions.jsx === JsxEmit.Preserve) { + if (compilerOptions.jsx === JsxEmit.Preserve || compilerOptions.jsx === JsxEmit.ReactNative) { previousOnEmitNode = context.onEmitNode; context.onEmitNode = onEmitNode; context.enableEmitNotification(SyntaxKind.JsxOpeningElement); @@ -116,4 +116,4 @@ namespace ts { return undefined; } } -} \ No newline at end of file +} diff --git a/tests/baselines/reference/es3-jsx-preserve.js b/tests/baselines/reference/es3-jsx-preserve.js new file mode 100644 index 00000000000..cb1ba2a887d --- /dev/null +++ b/tests/baselines/reference/es3-jsx-preserve.js @@ -0,0 +1,11 @@ +//// [es3-jsx-preserve.tsx] + +const React: any = null; + +const elem =
; + + + +//// [es3-jsx-preserve.jsx] +var React = null; +var elem =
; diff --git a/tests/baselines/reference/es3-jsx-preserve.symbols b/tests/baselines/reference/es3-jsx-preserve.symbols new file mode 100644 index 00000000000..61c9260223f --- /dev/null +++ b/tests/baselines/reference/es3-jsx-preserve.symbols @@ -0,0 +1,11 @@ +=== tests/cases/compiler/es3-jsx-preserve.tsx === + +const React: any = null; +>React : Symbol(React, Decl(es3-jsx-preserve.tsx, 1, 5)) + +const elem =
; +>elem : Symbol(elem, Decl(es3-jsx-preserve.tsx, 3, 5)) +>div : Symbol(unknown) +>div : Symbol(unknown) + + diff --git a/tests/baselines/reference/es3-jsx-preserve.types b/tests/baselines/reference/es3-jsx-preserve.types new file mode 100644 index 00000000000..b37fe8af567 --- /dev/null +++ b/tests/baselines/reference/es3-jsx-preserve.types @@ -0,0 +1,13 @@ +=== tests/cases/compiler/es3-jsx-preserve.tsx === + +const React: any = null; +>React : any +>null : null + +const elem =
; +>elem : any +>
: any +>div : any +>div : any + + diff --git a/tests/baselines/reference/es3-jsx-react-native.js b/tests/baselines/reference/es3-jsx-react-native.js new file mode 100644 index 00000000000..08e6e25502b --- /dev/null +++ b/tests/baselines/reference/es3-jsx-react-native.js @@ -0,0 +1,11 @@ +//// [es3-jsx-react-native.tsx] + +const React: any = null; + +const elem =
; + + + +//// [es3-jsx-react-native.js] +var React = null; +var elem =
; diff --git a/tests/baselines/reference/es3-jsx-react-native.symbols b/tests/baselines/reference/es3-jsx-react-native.symbols new file mode 100644 index 00000000000..e7f010bd2ea --- /dev/null +++ b/tests/baselines/reference/es3-jsx-react-native.symbols @@ -0,0 +1,11 @@ +=== tests/cases/compiler/es3-jsx-react-native.tsx === + +const React: any = null; +>React : Symbol(React, Decl(es3-jsx-react-native.tsx, 1, 5)) + +const elem =
; +>elem : Symbol(elem, Decl(es3-jsx-react-native.tsx, 3, 5)) +>div : Symbol(unknown) +>div : Symbol(unknown) + + diff --git a/tests/baselines/reference/es3-jsx-react-native.types b/tests/baselines/reference/es3-jsx-react-native.types new file mode 100644 index 00000000000..1bf199606f2 --- /dev/null +++ b/tests/baselines/reference/es3-jsx-react-native.types @@ -0,0 +1,13 @@ +=== tests/cases/compiler/es3-jsx-react-native.tsx === + +const React: any = null; +>React : any +>null : null + +const elem =
; +>elem : any +>
: any +>div : any +>div : any + + diff --git a/tests/baselines/reference/es3-jsx-react.js b/tests/baselines/reference/es3-jsx-react.js new file mode 100644 index 00000000000..861dde74c86 --- /dev/null +++ b/tests/baselines/reference/es3-jsx-react.js @@ -0,0 +1,11 @@ +//// [es3-jsx-react.tsx] + +const React: any = null; + +const elem =
; + + + +//// [es3-jsx-react.js] +var React = null; +var elem = React.createElement("div", null); diff --git a/tests/baselines/reference/es3-jsx-react.symbols b/tests/baselines/reference/es3-jsx-react.symbols new file mode 100644 index 00000000000..465cfab7ea9 --- /dev/null +++ b/tests/baselines/reference/es3-jsx-react.symbols @@ -0,0 +1,11 @@ +=== tests/cases/compiler/es3-jsx-react.tsx === + +const React: any = null; +>React : Symbol(React, Decl(es3-jsx-react.tsx, 1, 5)) + +const elem =
; +>elem : Symbol(elem, Decl(es3-jsx-react.tsx, 3, 5)) +>div : Symbol(unknown) +>div : Symbol(unknown) + + diff --git a/tests/baselines/reference/es3-jsx-react.types b/tests/baselines/reference/es3-jsx-react.types new file mode 100644 index 00000000000..b7734ffc1f0 --- /dev/null +++ b/tests/baselines/reference/es3-jsx-react.types @@ -0,0 +1,13 @@ +=== tests/cases/compiler/es3-jsx-react.tsx === + +const React: any = null; +>React : any +>null : null + +const elem =
; +>elem : any +>
: any +>div : any +>div : any + + diff --git a/tests/cases/compiler/es3-jsx-preserve.tsx b/tests/cases/compiler/es3-jsx-preserve.tsx new file mode 100644 index 00000000000..f6092e692b4 --- /dev/null +++ b/tests/cases/compiler/es3-jsx-preserve.tsx @@ -0,0 +1,9 @@ +// @target: ES3 +// @sourcemap: false +// @declaration: false +// @jsx: preserve + +const React: any = null; + +const elem =
; + diff --git a/tests/cases/compiler/es3-jsx-react-native.tsx b/tests/cases/compiler/es3-jsx-react-native.tsx new file mode 100644 index 00000000000..9ed0f9e003d --- /dev/null +++ b/tests/cases/compiler/es3-jsx-react-native.tsx @@ -0,0 +1,9 @@ +// @target: ES3 +// @sourcemap: false +// @declaration: false +// @jsx: react-native + +const React: any = null; + +const elem =
; + diff --git a/tests/cases/compiler/es3-jsx-react.tsx b/tests/cases/compiler/es3-jsx-react.tsx new file mode 100644 index 00000000000..d47aea9613f --- /dev/null +++ b/tests/cases/compiler/es3-jsx-react.tsx @@ -0,0 +1,9 @@ +// @target: ES3 +// @sourcemap: false +// @declaration: false +// @jsx: react + +const React: any = null; + +const elem =
; + From 6fda5a1b3a3018623e3b3d49ab9520a9af24510c Mon Sep 17 00:00:00 2001 From: David Sheldrick Date: Mon, 23 Jan 2017 22:14:51 +0100 Subject: [PATCH 33/63] Update comment about jsx react-native in es5.ts --- src/compiler/transformers/es5.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/transformers/es5.ts b/src/compiler/transformers/es5.ts index 972b9214f16..c3b011fe36d 100644 --- a/src/compiler/transformers/es5.ts +++ b/src/compiler/transformers/es5.ts @@ -11,7 +11,7 @@ namespace ts { export function transformES5(context: TransformationContext) { const compilerOptions = context.getCompilerOptions(); - // enable emit notification only if using --jsx preserve + // enable emit notification only if using --jsx preserve or react-native let previousOnEmitNode: (emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void) => void; let noSubstitution: boolean[]; if (compilerOptions.jsx === JsxEmit.Preserve || compilerOptions.jsx === JsxEmit.ReactNative) { From 77a504bb6495c277d5c8742426cf58162edbd06a Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Fri, 20 Jan 2017 14:58:07 -0800 Subject: [PATCH 34/63] Clean up code in findAllReferences --- src/services/findAllReferences.ts | 217 ++++++++++++++++-------------- src/services/utilities.ts | 2 +- 2 files changed, 115 insertions(+), 104 deletions(-) diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index 82a5da453b7..3c38c4e7536 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -7,30 +7,9 @@ namespace ts.FindAllReferences { export function getReferencedSymbolsForNode(typeChecker: TypeChecker, cancellationToken: CancellationToken, node: Node, sourceFiles: SourceFile[], findInStrings: boolean, findInComments: boolean, implementations: boolean): ReferencedSymbol[] | undefined { if (!implementations) { - if (isTypeKeyword(node.kind)) { - return getAllReferencesForKeyword(sourceFiles, node.kind, cancellationToken); - } - - // Labels - if (isLabelName(node)) { - if (isJumpStatementTarget(node)) { - const labelDefinition = getTargetLabel((node.parent), (node).text); - // if we have a label definition, look within its statement for references, if not, then - // the label is undefined and we have no results.. - return labelDefinition && getLabelReferencesInNode(labelDefinition.parent, labelDefinition, cancellationToken); - } - else { - // it is a label definition and not a target, search within the parent labeledStatement - return getLabelReferencesInNode(node.parent, node, cancellationToken); - } - } - - if (isThis(node)) { - return getReferencesForThisKeyword(node, sourceFiles, typeChecker, cancellationToken); - } - - if (node.kind === SyntaxKind.SuperKeyword) { - return getReferencesForSuperKeyword(node, typeChecker, cancellationToken); + const special = getReferencedSymbolsSpecial(node, sourceFiles, typeChecker, cancellationToken); + if (special) { + return special; } } @@ -69,9 +48,8 @@ namespace ts.FindAllReferences { // Maps from a symbol ID to the ReferencedSymbol entry in 'result'. const symbolToIndex: number[] = []; - let result: ReferencedSymbol[]; + const result: ReferencedSymbol[] = []; if (scope) { - result = []; getReferencesInNode(scope, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result, symbolToIndex, implementations, typeChecker, cancellationToken); } else { @@ -79,7 +57,6 @@ namespace ts.FindAllReferences { for (const sourceFile of sourceFiles) { cancellationToken.throwIfCancellationRequested(); if (sourceFileHasName(sourceFile, internedName)) { - result = result || []; getReferencesInNode(sourceFile, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result, symbolToIndex, implementations, typeChecker, cancellationToken); } } @@ -88,6 +65,37 @@ namespace ts.FindAllReferences { return result; } + /** getReferencedSymbols for special node kinds. */ + function getReferencedSymbolsSpecial(node: Node, sourceFiles: SourceFile[], typeChecker: TypeChecker, cancellationToken: CancellationToken): ReferencedSymbol[] | undefined { + if (isTypeKeyword(node.kind)) { + return getAllReferencesForKeyword(sourceFiles, node.kind, cancellationToken); + } + + // Labels + if (isLabelName(node)) { + if (isJumpStatementTarget(node)) { + const labelDefinition = getTargetLabel((node.parent), (node).text); + // if we have a label definition, look within its statement for references, if not, then + // the label is undefined and we have no results.. + return labelDefinition && getLabelReferencesInNode(labelDefinition.parent, labelDefinition, cancellationToken); + } + else { + // it is a label definition and not a target, search within the parent labeledStatement + return getLabelReferencesInNode(node.parent, node, cancellationToken); + } + } + + if (isThis(node)) { + return getReferencesForThisKeyword(node, sourceFiles, typeChecker, cancellationToken); + } + + if (node.kind === SyntaxKind.SuperKeyword) { + return getReferencesForSuperKeyword(node, typeChecker, cancellationToken); + } + + return undefined; + } + function sourceFileHasName(sourceFile: SourceFile, name: string): boolean { return getNameTable(sourceFile).get(name) !== undefined; } @@ -166,7 +174,7 @@ namespace ts.FindAllReferences { // If this is an export or import specifier it could have been renamed using the 'as' syntax. // If so we want to search for whatever under the cursor. if (isImportOrExportSpecifierName(location)) { - return location.getText(); + return location.text; } // Try to get the local symbol if we're dealing with an 'export default' @@ -401,6 +409,9 @@ namespace ts.FindAllReferences { const inheritsFromCache: Map = createMap(); // Build the set of symbols to search for, initially it has only the current symbol const searchSymbols = populateSearchSymbolSet(searchSymbol, searchLocation, typeChecker, implementations); + function isSearchedFor(symbol: Symbol): boolean { + return contains(searchSymbols, symbol); + } for (const position of possiblePositions) { cancellationToken.throwIfCancellationRequested(); @@ -438,7 +449,7 @@ namespace ts.FindAllReferences { if (referenceSymbol) { const referenceSymbolDeclaration = referenceSymbol.valueDeclaration; const shorthandValueSymbol = typeChecker.getShorthandAssignmentValueSymbol(referenceSymbolDeclaration); - const relatedSymbol = getRelatedSymbol(searchSymbols, referenceSymbol, referenceLocation, + const relatedSymbol = getRelatedSymbol(isSearchedFor, referenceSymbol, referenceLocation, /*searchLocationIsConstructor*/ searchLocation.kind === SyntaxKind.ConstructorKeyword, parents, inheritsFromCache, typeChecker); if (relatedSymbol) { @@ -450,7 +461,7 @@ namespace ts.FindAllReferences { * the position in short-hand property assignment excluding property accessing. However, if we do findAllReference at the * position of property accessing, the referenceEntry of such position will be handled in the first case. */ - else if (!(referenceSymbol.flags & SymbolFlags.Transient) && searchSymbols.indexOf(shorthandValueSymbol) >= 0) { + else if (!(referenceSymbol.flags & SymbolFlags.Transient) && isSearchedFor(shorthandValueSymbol)) { addReferenceToRelatedSymbol(referenceSymbolDeclaration.name, shorthandValueSymbol); } else if (searchLocation.kind === SyntaxKind.ConstructorKeyword) { @@ -482,10 +493,6 @@ namespace ts.FindAllReferences { } } - function getPropertyAccessExpressionFromRightHandSide(node: Node): PropertyAccessExpression { - return isRightSideOfPropertyAccess(node) && node.parent; - } - /** Adds references when a constructor is used with `new this()` in its own class and `super()` calls in subclasses. */ function findAdditionalConstructorReferences(referenceSymbol: Symbol, referenceLocation: Node): void { Debug.assert(isClassLike(searchSymbol.valueDeclaration)); @@ -494,7 +501,7 @@ namespace ts.FindAllReferences { if (referenceSymbol === searchSymbol && isClassLike(referenceClass)) { Debug.assert(referenceClass.name === referenceLocation); // This is the class declaration containing the constructor. - addReferences(findOwnConstructorCalls(searchSymbol)); + addReferences(findOwnConstructorCalls(searchSymbol, sourceFile)); } else { // If this class appears in `extends C`, then the extending class' "super" calls are references. @@ -512,58 +519,6 @@ namespace ts.FindAllReferences { } } - /** `classSymbol` is the class where the constructor was defined. - * Reference the constructor and all calls to `new this()`. - */ - function findOwnConstructorCalls(classSymbol: Symbol): Node[] { - const result: Node[] = []; - - for (const decl of classSymbol.members.get("__constructor").declarations) { - const ctrKeyword = ts.findChildOfKind(decl, ts.SyntaxKind.ConstructorKeyword, sourceFile)! - Debug.assert(decl.kind === SyntaxKind.Constructor && !!ctrKeyword); - result.push(ctrKeyword); - } - - classSymbol.exports.forEach(member => { - const decl = member.valueDeclaration; - if (decl && decl.kind === SyntaxKind.MethodDeclaration) { - const body = (decl).body; - if (body) { - forEachDescendantOfKind(body, SyntaxKind.ThisKeyword, thisKeyword => { - if (isNewExpressionTarget(thisKeyword)) { - result.push(thisKeyword); - } - }); - } - } - }); - - return result; - } - - /** Find references to `super` in the constructor of an extending class. */ - function superConstructorAccesses(cls: ClassLikeDeclaration): Node[] { - const symbol = cls.symbol; - const ctr = symbol.members.get("__constructor"); - if (!ctr) { - return []; - } - - const result: Node[] = []; - for (const decl of ctr.declarations) { - Debug.assert(decl.kind === SyntaxKind.Constructor); - const body = (decl).body; - if (body) { - forEachDescendantOfKind(body, SyntaxKind.SuperKeyword, node => { - if (isCallExpressionTarget(node)) { - result.push(node); - } - }); - } - }; - return result; - } - function getReferencedSymbol(symbol: Symbol): ReferencedSymbol { const symbolId = getSymbolId(symbol); let index = symbolToIndex[symbolId]; @@ -591,6 +546,62 @@ namespace ts.FindAllReferences { } } + function getPropertyAccessExpressionFromRightHandSide(node: Node): PropertyAccessExpression { + return isRightSideOfPropertyAccess(node) && node.parent; + } + + /** `classSymbol` is the class where the constructor was defined. + * Reference the constructor and all calls to `new this()`. + */ + function findOwnConstructorCalls(classSymbol: Symbol, sourceFile: SourceFile): Node[] { + const result: Node[] = []; + + for (const decl of classSymbol.members.get("__constructor").declarations) { + const ctrKeyword = ts.findChildOfKind(decl, ts.SyntaxKind.ConstructorKeyword, sourceFile)! + Debug.assert(decl.kind === SyntaxKind.Constructor && !!ctrKeyword); + result.push(ctrKeyword); + } + + classSymbol.exports.forEach(member => { + const decl = member.valueDeclaration; + if (decl && decl.kind === SyntaxKind.MethodDeclaration) { + const body = (decl).body; + if (body) { + forEachDescendantOfKind(body, SyntaxKind.ThisKeyword, thisKeyword => { + if (isNewExpressionTarget(thisKeyword)) { + result.push(thisKeyword); + } + }); + } + } + }); + + return result; + } + + /** Find references to `super` in the constructor of an extending class. */ + function superConstructorAccesses(cls: ClassLikeDeclaration): Node[] { + const symbol = cls.symbol; + const ctr = symbol.members.get("__constructor"); + if (!ctr) { + return []; + } + + const result: Node[] = []; + for (const decl of ctr.declarations) { + Debug.assert(decl.kind === SyntaxKind.Constructor); + const body = (decl).body; + if (body) { + forEachDescendantOfKind(body, SyntaxKind.SuperKeyword, node => { + if (isCallExpressionTarget(node)) { + result.push(node); + } + }); + } + }; + return result; + } + function getImplementationReferenceEntryForNode(refNode: Node, result: ReferenceEntry[], typeChecker: TypeChecker): void { // Check if we found a function/propertyAssignment/method with an implementation or initializer if (isDeclarationName(refNode) && isImplementation(refNode.parent)) { @@ -805,13 +816,13 @@ namespace ts.FindAllReferences { const sourceFile = searchSpaceNode.getSourceFile(); const possiblePositions = getPossibleSymbolReferencePositions(sourceFile, "super", searchSpaceNode.getStart(), searchSpaceNode.getEnd(), cancellationToken); - forEach(possiblePositions, position => { + for (const position of possiblePositions) { cancellationToken.throwIfCancellationRequested(); const node = getTouchingWord(sourceFile, position); if (!node || node.kind !== SyntaxKind.SuperKeyword) { - return; + continue; } const container = getSuperContainer(node, /*stopOnFunctions*/ false); @@ -822,7 +833,7 @@ namespace ts.FindAllReferences { if (container && (ModifierFlags.Static & getModifierFlags(container)) === staticFlag && container.parent.symbol === searchSpaceNode.symbol) { references.push(getReferenceEntryFromNode(node)); } - }); + } const definition = getDefinition(searchSpaceNode.symbol, superKeyword, typeChecker); return [{ definition, references }]; @@ -1057,7 +1068,7 @@ namespace ts.FindAllReferences { // If this is a union property, add all the symbols from all its source symbols in all unioned types. // If the symbol is an instantiation from a another symbol (e.g. widened symbol) , add the root the list - forEach(typeChecker.getRootSymbols(symbol), rootSymbol => { + for (const rootSymbol of typeChecker.getRootSymbols(symbol)) { if (rootSymbol !== symbol) { result.push(rootSymbol); } @@ -1066,7 +1077,7 @@ namespace ts.FindAllReferences { if (!implementations && rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, /*previousIterationSymbolsCache*/ createMap(), typeChecker); } - }); + } return result; } @@ -1130,17 +1141,17 @@ namespace ts.FindAllReferences { } } - function getRelatedSymbol(searchSymbols: Symbol[], referenceSymbol: Symbol, referenceLocation: Node, searchLocationIsConstructor: boolean, parents: Symbol[] | undefined, cache: Map, typeChecker: TypeChecker): Symbol { - if (contains(searchSymbols, referenceSymbol)) { + function getRelatedSymbol(isSearchedFor: (symbol: Symbol) => boolean, referenceSymbol: Symbol, referenceLocation: Node, searchLocationIsConstructor: boolean, parents: Symbol[] | undefined, cache: Map, typeChecker: TypeChecker): Symbol | undefined { + if (isSearchedFor(referenceSymbol)) { // If we are searching for constructor uses, they must be 'new' expressions. - return (!searchLocationIsConstructor || isNewExpressionTarget(referenceLocation)) && referenceSymbol; + return (!searchLocationIsConstructor || isNewExpressionTarget(referenceLocation)) ? referenceSymbol : undefined; } // If the reference symbol is an alias, check if what it is aliasing is one of the search // symbols but by looking up for related symbol of this alias so it can handle multiple level of indirectness. const aliasSymbol = getAliasSymbolForPropertyNameSymbol(referenceSymbol, referenceLocation, typeChecker); if (aliasSymbol) { - return getRelatedSymbol(searchSymbols, aliasSymbol, referenceLocation, searchLocationIsConstructor, parents, cache, typeChecker); + return getRelatedSymbol(isSearchedFor, aliasSymbol, referenceLocation, searchLocationIsConstructor, parents, cache, typeChecker); } // If the reference location is in an object literal, try to get the contextual type for the @@ -1148,9 +1159,8 @@ namespace ts.FindAllReferences { // compare to our searchSymbol const containingObjectLiteralElement = getContainingObjectLiteralElement(referenceLocation); if (containingObjectLiteralElement) { - const contextualSymbol = forEach(getPropertySymbolsFromContextualType(containingObjectLiteralElement, typeChecker), contextualSymbol => { - return forEach(typeChecker.getRootSymbols(contextualSymbol), s => searchSymbols.indexOf(s) >= 0 ? s : undefined); - }); + const contextualSymbol = forEach(getPropertySymbolsFromContextualType(containingObjectLiteralElement, typeChecker), contextualSymbol => + find(typeChecker.getRootSymbols(contextualSymbol), isSearchedFor)); if (contextualSymbol) { return contextualSymbol; @@ -1161,7 +1171,7 @@ namespace ts.FindAllReferences { // In below eg. get 'property' from type of elems iterating type // for ( { property: p2 } of elems) { } const propertySymbol = getPropertySymbolOfDestructuringAssignment(referenceLocation, typeChecker); - if (propertySymbol && searchSymbols.indexOf(propertySymbol) >= 0) { + if (propertySymbol && isSearchedFor(propertySymbol)) { return propertySymbol; } } @@ -1170,7 +1180,7 @@ namespace ts.FindAllReferences { // then include the binding element in the related symbols // let { a } : { a }; const bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName(referenceSymbol, typeChecker); - if (bindingElementPropertySymbol && searchSymbols.indexOf(bindingElementPropertySymbol) >= 0) { + if (bindingElementPropertySymbol && isSearchedFor(bindingElementPropertySymbol)) { return bindingElementPropertySymbol; } @@ -1178,7 +1188,7 @@ namespace ts.FindAllReferences { // Or a union property, use its underlying unioned symbols return forEach(typeChecker.getRootSymbols(referenceSymbol), rootSymbol => { // if it is in the list, then we are done - if (searchSymbols.indexOf(rootSymbol) >= 0) { + if (isSearchedFor(rootSymbol)) { return rootSymbol; } @@ -1195,7 +1205,7 @@ namespace ts.FindAllReferences { const result: Symbol[] = []; getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, /*previousIterationSymbolsCache*/ createMap(), typeChecker); - return forEach(result, s => searchSymbols.indexOf(s) >= 0 ? s : undefined); + return find(result, isSearchedFor); } return undefined; @@ -1214,6 +1224,7 @@ namespace ts.FindAllReferences { return (node.name).text; } + /** Gets all symbols for one property. Does not get symbols for every property. */ function getPropertySymbolsFromContextualType(node: ObjectLiteralElement, typeChecker: TypeChecker): Symbol[] { const objectLiteral = node.parent; const contextualType = typeChecker.getContextualType(objectLiteral); diff --git a/src/services/utilities.ts b/src/services/utilities.ts index a1680da69c3..f83f9ef8231 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -1319,7 +1319,7 @@ namespace ts { return name; } - export function isImportOrExportSpecifierName(location: Node): boolean { + export function isImportOrExportSpecifierName(location: Node): location is Identifier { return location.parent && (location.parent.kind === SyntaxKind.ImportSpecifier || location.parent.kind === SyntaxKind.ExportSpecifier) && (location.parent).propertyName === location; From 0ca4cb25d68f370ac6bc5013f71f43b96b6f1e7a Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Mon, 23 Jan 2017 13:23:26 -0800 Subject: [PATCH 35/63] Support find-all-references for default exports --- src/compiler/utilities.ts | 8 +- src/services/findAllReferences.ts | 114 ++++++++++-------- .../fourslash/findAllRefsForDefaultExport.ts | 11 ++ 3 files changed, 82 insertions(+), 51 deletions(-) create mode 100644 tests/cases/fourslash/findAllRefsForDefaultExport.ts diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index b7cc0f0de6d..5c63d8bb60c 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -395,7 +395,7 @@ namespace ts { function isShorthandAmbientModule(node: Node): boolean { // The only kind of module that can be missing a body is a shorthand ambient module. - return node.kind === SyntaxKind.ModuleDeclaration && (!(node).body); + return node && node.kind === SyntaxKind.ModuleDeclaration && (!(node).body); } export function isBlockScopedContainerTopLevel(node: Node): boolean { @@ -3104,7 +3104,11 @@ namespace ts { } export function getLocalSymbolForExportDefault(symbol: Symbol) { - return symbol && symbol.valueDeclaration && hasModifier(symbol.valueDeclaration, ModifierFlags.Default) ? symbol.valueDeclaration.localSymbol : undefined; + return isExportDefaultSymbol(symbol) ? symbol.valueDeclaration.localSymbol : undefined; + } + + export function isExportDefaultSymbol(symbol: Symbol): boolean { + return symbol && symbol.valueDeclaration && hasModifier(symbol.valueDeclaration, ModifierFlags.Default); } /** Return ".ts", ".d.ts", or ".tsx", if that is the extension. */ diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index 3c38c4e7536..83006c66d77 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -15,14 +15,13 @@ namespace ts.FindAllReferences { // `getSymbolAtLocation` normally returns the symbol of the class when given the constructor keyword, // so we have to specify that we want the constructor symbol. - const symbol = typeChecker.getSymbolAtLocation(node); - - if (!implementations && !symbol && node.kind === SyntaxKind.StringLiteral) { - return getReferencesForStringLiteral(node, sourceFiles, typeChecker, cancellationToken); - } + let symbol = typeChecker.getSymbolAtLocation(node); // Could not find a symbol e.g. unknown identifier if (!symbol) { + if (!implementations && node.kind === SyntaxKind.StringLiteral) { + return getReferencesForStringLiteral(node, sourceFiles, typeChecker, cancellationToken); + } // Can't have references to something that we have no symbol for. return undefined; } @@ -34,9 +33,27 @@ namespace ts.FindAllReferences { return undefined; } + const aliasedSymbol = followAliasIfNecessary(symbol, node, typeChecker); + const isShorthandModule = ts.isShorthandAmbientModuleSymbol(aliasedSymbol); + // Don't follow alias for shorthand modules because we lose information that way. + if (!isShorthandModule) { + symbol = aliasedSymbol; + } + // Compute the meaning from the location and the symbol it references const searchMeaning = getIntersectingMeaningFromDeclarations(getMeaningFromLocation(node), declarations); + const result: ReferencedSymbol[] = []; + // Maps from a symbol ID to the ReferencedSymbol entry in 'result'. + const symbolToIndex: number[] = []; + const inheritsFromCache: Map = createMap(); + + // Build the set of symbols to search for, initially it has only the current symbol + const searchSymbols = populateSearchSymbolSet(symbol, node, typeChecker, implementations, isShorthandModule ? aliasedSymbol : undefined); + function isSearchedFor(symbol: Symbol): boolean { + return contains(searchSymbols, symbol); + } + // Get the text to search for. // Note: if this is an external module symbol, the name doesn't include quotes. const declaredName = stripQuotes(getDeclaredName(typeChecker, symbol, node)); @@ -44,25 +61,28 @@ namespace ts.FindAllReferences { // Try to get the smallest valid scope that we can limit our search to; // otherwise we'll need to search globally (i.e. include each file). const scope = getSymbolScope(symbol); - - // Maps from a symbol ID to the ReferencedSymbol entry in 'result'. - const symbolToIndex: number[] = []; - - const result: ReferencedSymbol[] = []; if (scope) { - getReferencesInNode(scope, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result, symbolToIndex, implementations, typeChecker, cancellationToken); + getRefs(scope, declaredName); } else { - const internedName = getInternedName(symbol, node); + const isDefault = isExportDefaultSymbol(symbol); + const internedName = isDefault ? symbol.valueDeclaration.localSymbol.name : getInternedName(symbol, node); for (const sourceFile of sourceFiles) { cancellationToken.throwIfCancellationRequested(); - if (sourceFileHasName(sourceFile, internedName)) { - getReferencesInNode(sourceFile, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result, symbolToIndex, implementations, typeChecker, cancellationToken); + const searchName = (isDefault ? getDefaultImportName(symbol, sourceFile, typeChecker) : undefined) || + (sourceFileHasName(sourceFile, internedName) ? declaredName : undefined); + if (searchName !== undefined) { + getRefs(sourceFile, searchName); } } } return result; + + function getRefs(scope: ts.Node, searchName: string): void { + getReferencesInNode(scope, symbol, searchName, node, searchMeaning, findInStrings, findInComments, result, + symbolToIndex, implementations, typeChecker, cancellationToken, isSearchedFor, inheritsFromCache); + } } /** getReferencedSymbols for special node kinds. */ @@ -100,6 +120,23 @@ namespace ts.FindAllReferences { return getNameTable(sourceFile).get(name) !== undefined; } + /** + * Given a symbol, see if any of the imports in a source file reference it. + * Only call this if `symbol` is a default export. + */ + function getDefaultImportName(symbol: Symbol, sourceFile: SourceFile, checker: ts.TypeChecker): string | undefined { + for (const importSpecifier of sourceFile.imports) { + const importDecl = importSpecifier.parent as ts.ImportDeclaration; + Debug.assert(importDecl.moduleSpecifier === importSpecifier); + const defaultName = importDecl.importClause.name; + const defaultReferencedSymbol = checker.getAliasedSymbol(checker.getSymbolAtLocation(defaultName)); + if (symbol === defaultReferencedSymbol) { + return defaultName.text; + } + } + return undefined; + } + function getDefinition(symbol: Symbol, node: Node, typeChecker: TypeChecker): ReferencedSymbolDefinitionInfo { const { displayParts, symbolKind } = SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker, symbol, node.getSourceFile(), getContainerNode(node), node); const name = displayParts.map(p => p.text).join(""); @@ -177,11 +214,6 @@ namespace ts.FindAllReferences { return location.text; } - // Try to get the local symbol if we're dealing with an 'export default' - // since that symbol has the "true" name. - const localExportDefaultSymbol = getLocalSymbolForExportDefault(symbol); - symbol = localExportDefaultSymbol || symbol; - return stripQuotes(symbol.name); } @@ -398,7 +430,9 @@ namespace ts.FindAllReferences { symbolToIndex: number[], implementations: boolean, typeChecker: TypeChecker, - cancellationToken: CancellationToken): void { + cancellationToken: CancellationToken, + isSearchedFor: (symbol: Symbol) => boolean, + inheritsFromCache: Map): void { const sourceFile = container.getSourceFile(); @@ -406,12 +440,6 @@ namespace ts.FindAllReferences { const possiblePositions = getPossibleSymbolReferencePositions(sourceFile, searchText, start, container.getEnd(), cancellationToken); const parents = getParentSymbolsOfPropertyAccess(); - const inheritsFromCache: Map = createMap(); - // Build the set of symbols to search for, initially it has only the current symbol - const searchSymbols = populateSearchSymbolSet(searchSymbol, searchLocation, typeChecker, implementations); - function isSearchedFor(symbol: Symbol): boolean { - return contains(searchSymbols, symbol); - } for (const position of possiblePositions) { cancellationToken.throwIfCancellationRequested(); @@ -456,11 +484,11 @@ namespace ts.FindAllReferences { addReferenceToRelatedSymbol(referenceLocation, relatedSymbol); } /* Because in short-hand property assignment, an identifier which stored as name of the short-hand property assignment - * has two meaning : property name and property value. Therefore when we do findAllReference at the position where - * an identifier is declared, the language service should return the position of the variable declaration as well as - * the position in short-hand property assignment excluding property accessing. However, if we do findAllReference at the - * position of property accessing, the referenceEntry of such position will be handled in the first case. - */ + * has two meanings: property name and property value. Therefore when we do findAllReference at the position where + * an identifier is declared, the language service should return the position of the variable declaration as well as + * the position in short-hand property assignment excluding property accessing. However, if we do findAllReference at the + * position of property accessing, the referenceEntry of such position will be handled in the first case. + */ else if (!(referenceSymbol.flags & SymbolFlags.Transient) && isSearchedFor(shorthandValueSymbol)) { addReferenceToRelatedSymbol(referenceSymbolDeclaration.name, shorthandValueSymbol); } @@ -472,10 +500,10 @@ namespace ts.FindAllReferences { return; /* If we are just looking for implementations and this is a property access expression, we need to get the - * symbol of the local type of the symbol the property is being accessed on. This is because our search - * symbol may have a different parent symbol if the local type's symbol does not declare the property - * being accessed (i.e. it is declared in some parent class or interface) - */ + * symbol of the local type of the symbol the property is being accessed on. This is because our search + * symbol may have a different parent symbol if the local type's symbol does not declare the property + * being accessed (i.e. it is declared in some parent class or interface) + */ function getParentSymbolsOfPropertyAccess(): Symbol[] | undefined { if (implementations) { const propertyAccessExpression = getPropertyAccessExpressionFromRightHandSide(searchLocation); @@ -994,7 +1022,7 @@ namespace ts.FindAllReferences { } } - function populateSearchSymbolSet(symbol: Symbol, location: Node, typeChecker: TypeChecker, implementations: boolean): Symbol[] { + function populateSearchSymbolSet(symbol: Symbol, location: Node, typeChecker: TypeChecker, implementations: boolean, aliasSymbol?: Symbol): Symbol[] { // The search set contains at least the current symbol let result = [symbol]; @@ -1009,18 +1037,6 @@ namespace ts.FindAllReferences { } } - // If the symbol is an alias, add what it aliases to the list - // import {a} from "mod"; - // export {a} - // If the symbol is an alias to default declaration, add what it aliases to the list - // declare "mod" { export default class B { } } - // import B from "mod"; - //// For export specifiers, the exported name can be referring to a local symbol, e.g.: - //// import {a} from "mod"; - //// export {a as somethingElse} - //// We want the *local* declaration of 'a' as declared in the import, - //// *not* as declared within "mod" (or farther) - const aliasSymbol = getAliasSymbolForPropertyNameSymbol(symbol, location, typeChecker); if (aliasSymbol) { result = result.concat(populateSearchSymbolSet(aliasSymbol, location, typeChecker, implementations)); } @@ -1225,7 +1241,7 @@ namespace ts.FindAllReferences { } /** Gets all symbols for one property. Does not get symbols for every property. */ - function getPropertySymbolsFromContextualType(node: ObjectLiteralElement, typeChecker: TypeChecker): Symbol[] { + function getPropertySymbolsFromContextualType(node: ObjectLiteralElement, typeChecker: TypeChecker): Symbol[] | undefined { const objectLiteral = node.parent; const contextualType = typeChecker.getContextualType(objectLiteral); const name = getNameFromObjectLiteralElement(node); diff --git a/tests/cases/fourslash/findAllRefsForDefaultExport.ts b/tests/cases/fourslash/findAllRefsForDefaultExport.ts new file mode 100644 index 00000000000..a27227b907a --- /dev/null +++ b/tests/cases/fourslash/findAllRefsForDefaultExport.ts @@ -0,0 +1,11 @@ +/// + +// @Filename: a.ts +////export default function /*def*/[|f|]() {} + +// @Filename: b.ts +////import [|g|] from "./a"; +/////*ref*/[|g|](); + +verify.rangesReferenceEachOther(); +verify.goToDefinition("ref", "def"); From da05ced2e5b8807af3698963515bc71da0997a0d Mon Sep 17 00:00:00 2001 From: falsandtru Date: Wed, 18 Jan 2017 12:05:25 +0900 Subject: [PATCH 36/63] Fix Symbol.valueOf method signature --- src/lib/es2015.symbol.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/es2015.symbol.d.ts b/src/lib/es2015.symbol.d.ts index cd7e45595f0..d7ea4fa0328 100644 --- a/src/lib/es2015.symbol.d.ts +++ b/src/lib/es2015.symbol.d.ts @@ -3,7 +3,7 @@ interface Symbol { toString(): string; /** Returns the primitive value of the specified object. */ - valueOf(): Object; + valueOf(): symbol; } interface SymbolConstructor { From 053b3cd893d00b63dda48085c744844128aaba43 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 23 Jan 2017 16:01:29 -0800 Subject: [PATCH 37/63] getFirstToken skips JSDoc Fixes #13519. This is a better fix than #13599. Also fixes broken tests associated with #13599. --- src/harness/unittests/jsDocParsing.ts | 13 +++++++++---- src/services/services.ts | 8 +++----- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/harness/unittests/jsDocParsing.ts b/src/harness/unittests/jsDocParsing.ts index 3cafc9d49ae..98c32c77778 100644 --- a/src/harness/unittests/jsDocParsing.ts +++ b/src/harness/unittests/jsDocParsing.ts @@ -290,16 +290,21 @@ namespace ts { }); describe("getFirstToken", () => { it("gets jsdoc", () => { - const first = ts.createSourceFile("foo.ts", "/** comment */var a = true;", ts.ScriptTarget.ES5, /*setParentNodes*/ true); + const root = ts.createSourceFile("foo.ts", "/** comment */var a = true;", ts.ScriptTarget.ES5, /*setParentNodes*/ true); + assert.isDefined(root); + assert.equal(root.kind, ts.SyntaxKind.SourceFile); + const first = root.getFirstToken(); assert.isDefined(first); - assert.equal(first.kind, 263); + assert.equal(first.kind, ts.SyntaxKind.VarKeyword); }); }); describe("getLastToken", () => { it("gets jsdoc", () => { - const last = ts.createSourceFile("foo.ts", "var a = true;/** comment */", ts.ScriptTarget.ES5, /*setParentNodes*/ true); + const root = ts.createSourceFile("foo.ts", "var a = true;/** comment */", ts.ScriptTarget.ES5, /*setParentNodes*/ true); + assert.isDefined(root); + const last = root.getLastToken(); assert.isDefined(last); - assert.equal(last.kind, 263); + assert.equal(last.kind, ts.SyntaxKind.EndOfFileToken); }); }); }); diff --git a/src/services/services.ts b/src/services/services.ts index cb38b1d500e..208e1031cd2 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -193,8 +193,8 @@ namespace ts { return undefined; } - const child = children[0]; - return child.kind < SyntaxKind.FirstNode || SyntaxKind.FirstJSDocNode <= child.kind && child.kind <= SyntaxKind.LastJSDocNode ? + const child = ts.find(children, kid => kid.kind < SyntaxKind.FirstJSDocNode || kid.kind > SyntaxKind.LastJSDocNode); + return child.kind < SyntaxKind.FirstNode ? child : child.getFirstToken(sourceFile); } @@ -207,9 +207,7 @@ namespace ts { return undefined; } - return child.kind < SyntaxKind.FirstNode || SyntaxKind.FirstJSDocNode <= child.kind && child.kind <= SyntaxKind.LastJSDocNode ? - child : - child.getLastToken(sourceFile); + return child.kind < SyntaxKind.FirstNode ? child : child.getLastToken(sourceFile); } } From 24bb21c55a1842393d523d8b4a26f5f230d24e10 Mon Sep 17 00:00:00 2001 From: Herrington Darkholme Date: Tue, 24 Jan 2017 11:24:30 +0800 Subject: [PATCH 38/63] address code review --- src/compiler/checker.ts | 11 +++++++---- tests/baselines/reference/objectSpread.js | 5 ++--- tests/baselines/reference/objectSpread.symbols | 5 ++--- tests/baselines/reference/objectSpread.types | 7 +++---- .../reference/objectSpreadNegative.errors.txt | 4 ++-- tests/cases/conformance/types/spread/objectSpread.ts | 3 +-- 6 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 97ca01bc086..1a1cea4633f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6291,6 +6291,9 @@ namespace ts { if (right.flags & TypeFlags.Union) { return mapType(right, t => getSpreadType(left, t)); } + if (right.flags & TypeFlags.NonPrimitive) { + return emptyObjectType; + } const members = createMap(); const skippedPrivateMembers = createMap(); @@ -15719,12 +15722,12 @@ namespace ts { } } - /** + /** * Static members being set on a constructor function may conflict with built-in properties - * of Function. Esp. in ECMAScript 5 there are non-configurable and non-writable - * built-in properties. This check issues a transpile error when a class has a static + * of Function. Esp. in ECMAScript 5 there are non-configurable and non-writable + * built-in properties. This check issues a transpile error when a class has a static * member with the same name as a non-writable built-in property. - * + * * @see http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.3 * @see http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.5 * @see http://www.ecma-international.org/ecma-262/6.0/#sec-properties-of-the-function-constructor diff --git a/tests/baselines/reference/objectSpread.js b/tests/baselines/reference/objectSpread.js index 259b86628a5..2bc3b9e11bd 100644 --- a/tests/baselines/reference/objectSpread.js +++ b/tests/baselines/reference/objectSpread.js @@ -79,8 +79,7 @@ let computedAfter: { a: number, b: string, "at the end": number } = let a = 12; let shortCutted: { a: number, b: string } = { ...o, a } // non primitive -let spreadNonPrimitve = { ...{}} - +let spreadNonPrimitive = { ...{}}; //// [objectSpread.js] @@ -151,5 +150,5 @@ var computedAfter = __assign({}, o, (_c = { b: 'yeah' }, _c['at the end'] = 14, var a = 12; var shortCutted = __assign({}, o, { a: a }); // non primitive -var spreadNonPrimitve = __assign({}, {}); +var spreadNonPrimitive = __assign({}, {}); var _a, _b, _c; diff --git a/tests/baselines/reference/objectSpread.symbols b/tests/baselines/reference/objectSpread.symbols index 69c9ed34341..1ec2520e166 100644 --- a/tests/baselines/reference/objectSpread.symbols +++ b/tests/baselines/reference/objectSpread.symbols @@ -317,7 +317,6 @@ let shortCutted: { a: number, b: string } = { ...o, a } >a : Symbol(a, Decl(objectSpread.ts, 78, 51)) // non primitive -let spreadNonPrimitve = { ...{}} ->spreadNonPrimitve : Symbol(spreadNonPrimitve, Decl(objectSpread.ts, 80, 3)) - +let spreadNonPrimitive = { ...{}}; +>spreadNonPrimitive : Symbol(spreadNonPrimitive, Decl(objectSpread.ts, 80, 3)) diff --git a/tests/baselines/reference/objectSpread.types b/tests/baselines/reference/objectSpread.types index 8a8df1a497f..950dab43465 100644 --- a/tests/baselines/reference/objectSpread.types +++ b/tests/baselines/reference/objectSpread.types @@ -408,10 +408,9 @@ let shortCutted: { a: number, b: string } = { ...o, a } >a : number // non primitive -let spreadNonPrimitve = { ...{}} ->spreadNonPrimitve : { constructor: Function; toString(): string; toLocaleString(): string; valueOf(): Object; hasOwnProperty(v: string): boolean; isPrototypeOf(v: Object): boolean; propertyIsEnumerable(v: string): boolean; } ->{ ...{}} : { constructor: Function; toString(): string; toLocaleString(): string; valueOf(): Object; hasOwnProperty(v: string): boolean; isPrototypeOf(v: Object): boolean; propertyIsEnumerable(v: string): boolean; } +let spreadNonPrimitive = { ...{}}; +>spreadNonPrimitive : {} +>{ ...{}} : {} >{} : object >{} : {} - diff --git a/tests/baselines/reference/objectSpreadNegative.errors.txt b/tests/baselines/reference/objectSpreadNegative.errors.txt index 2b0960996ff..d9106d651a3 100644 --- a/tests/baselines/reference/objectSpreadNegative.errors.txt +++ b/tests/baselines/reference/objectSpreadNegative.errors.txt @@ -14,7 +14,7 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(37,19): error TS269 tests/cases/conformance/types/spread/objectSpreadNegative.ts(42,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures. tests/cases/conformance/types/spread/objectSpreadNegative.ts(46,12): error TS2339: Property 'b' does not exist on type '{}'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(52,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(57,11): error TS2339: Property 'a' does not exist on type '{ constructor: Function; toString(): string; toLocaleString(): string; valueOf(): Object; hasOwnProperty(v: string): boolean; isPrototypeOf(v: Object): boolean; propertyIsEnumerable(v: string): boolean; }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(57,11): error TS2339: Property 'a' does not exist on type '{}'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(61,14): error TS2698: Spread types may only be created from object types. tests/cases/conformance/types/spread/objectSpreadNegative.ts(64,14): error TS2698: Spread types may only be created from object types. @@ -107,7 +107,7 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(64,14): error TS269 let spreadObj = { ...obj }; spreadObj.a; // error 'a' is not in {} ~ -!!! error TS2339: Property 'a' does not exist on type '{ constructor: Function; toString(): string; toLocaleString(): string; valueOf(): Object; hasOwnProperty(v: string): boolean; isPrototypeOf(v: Object): boolean; propertyIsEnumerable(v: string): boolean; }'. +!!! error TS2339: Property 'a' does not exist on type '{}'. // generics function f(t: T, u: U) { diff --git a/tests/cases/conformance/types/spread/objectSpread.ts b/tests/cases/conformance/types/spread/objectSpread.ts index c4562e6f196..59b93bdd9e4 100644 --- a/tests/cases/conformance/types/spread/objectSpread.ts +++ b/tests/cases/conformance/types/spread/objectSpread.ts @@ -79,5 +79,4 @@ let computedAfter: { a: number, b: string, "at the end": number } = let a = 12; let shortCutted: { a: number, b: string } = { ...o, a } // non primitive -let spreadNonPrimitve = { ...{}} - +let spreadNonPrimitive = { ...{}}; From ebb666a9c2e01a5ae1358252e0dde6a3e83f11f1 Mon Sep 17 00:00:00 2001 From: David Sheldrick Date: Tue, 24 Jan 2017 05:09:30 +0100 Subject: [PATCH 39/63] delete fourslash testcase for --jsx react-native --- .../getEmitOutputTsxFile_ReactNative.baseline | 26 ------------------- .../getEmitOutputTsxFile_ReactNative.ts | 22 ---------------- 2 files changed, 48 deletions(-) delete mode 100644 tests/baselines/reference/getEmitOutputTsxFile_ReactNative.baseline delete mode 100644 tests/cases/fourslash/getEmitOutputTsxFile_ReactNative.ts diff --git a/tests/baselines/reference/getEmitOutputTsxFile_ReactNative.baseline b/tests/baselines/reference/getEmitOutputTsxFile_ReactNative.baseline deleted file mode 100644 index 88fb0f0daf6..00000000000 --- a/tests/baselines/reference/getEmitOutputTsxFile_ReactNative.baseline +++ /dev/null @@ -1,26 +0,0 @@ -EmitSkipped: false -FileName : /tests/cases/fourslash/inputFile1.js.map -{"version":3,"file":"inputFile1.js","sourceRoot":"","sources":["inputFile1.ts"],"names":[],"mappings":"AAAA,kBAAkB;AACjB,IAAI,CAAC,GAAW,CAAC,CAAC;AAClB;IAAA;IAGA,CAAC;IAAD,UAAC;AAAD,CAAC,AAHD,IAGC"}FileName : /tests/cases/fourslash/inputFile1.js -// regular ts file -var t = 5; -var Bar = (function () { - function Bar() { - } - return Bar; -}()); -//# sourceMappingURL=inputFile1.js.mapFileName : /tests/cases/fourslash/inputFile1.d.ts -declare var t: number; -declare class Bar { - x: string; - y: number; -} - -EmitSkipped: false -FileName : /tests/cases/fourslash/inputFile2.js.map -{"version":3,"file":"inputFile2.js","sourceRoot":"","sources":["inputFile2.tsx"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,QAAQ,CAAC;AACjB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC,CAAC,CAAC,EAAG,CAAA"}FileName : /tests/cases/fourslash/inputFile2.js -var y = "my div"; -var x =
; -//# sourceMappingURL=inputFile2.js.mapFileName : /tests/cases/fourslash/inputFile2.d.ts -declare var y: string; -declare var x: any; - diff --git a/tests/cases/fourslash/getEmitOutputTsxFile_ReactNative.ts b/tests/cases/fourslash/getEmitOutputTsxFile_ReactNative.ts deleted file mode 100644 index c2aac0e9d03..00000000000 --- a/tests/cases/fourslash/getEmitOutputTsxFile_ReactNative.ts +++ /dev/null @@ -1,22 +0,0 @@ -/// - -// @BaselineFile: getEmitOutputTsxFile_ReactNative.baseline -// @declaration: true -// @sourceMap: true -// @jsx: react-native - -// @Filename: inputFile1.ts -// @emitThisFile: true -////// regular ts file -//// var t: number = 5; -//// class Bar { -//// x : string; -//// y : number -//// } - -// @Filename: inputFile2.tsx -// @emitThisFile: true -//// var y = "my div"; -//// var x =
- -verify.baselineGetEmitOutput(); From 0a4632fe79c0390db616812ee9a5d2dd1fc1cff6 Mon Sep 17 00:00:00 2001 From: David Sheldrick Date: Tue, 24 Jan 2017 07:16:15 +0100 Subject: [PATCH 40/63] revert change to lib/protocol.d.ts --- lib/protocol.d.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/protocol.d.ts b/lib/protocol.d.ts index cd46ebcd366..d6c0246af34 100644 --- a/lib/protocol.d.ts +++ b/lib/protocol.d.ts @@ -1798,10 +1798,9 @@ declare namespace ts.server.protocol { namespace JsxEmit { type None = "None"; type Preserve = "Preserve"; - type ReactNative = "ReactNative"; type React = "React"; } - type JsxEmit = JsxEmit.None | JsxEmit.Preserve | JsxEmit.React | JsxEmit.ReactNative; + type JsxEmit = JsxEmit.None | JsxEmit.Preserve | JsxEmit.React; namespace ModuleKind { type None = "None"; type CommonJS = "CommonJS"; @@ -1881,4 +1880,4 @@ declare namespace ts { } import protocol = ts.server.protocol; export = protocol; -export as namespace protocol; +export as namespace protocol; \ No newline at end of file From 0d21c241b2954a1ba8b23f98c6a3f083de22d3bd Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Tue, 24 Jan 2017 09:06:46 -0800 Subject: [PATCH 41/63] Support find-all-references on mapped types. * Need to put a 'mappedTypeOrigin' property in SymbolLinks --- src/compiler/checker.ts | 15 ++++++++++++--- src/compiler/types.ts | 1 + tests/cases/fourslash/findAllRefsForMappedType.ts | 9 +++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 tests/cases/fourslash/findAllRefsForMappedType.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bd8ff7568f3..878e7d47273 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4618,12 +4618,14 @@ namespace ts { const typeParameter = getTypeParameterFromMappedType(type); const constraintType = getConstraintTypeFromMappedType(type); const templateType = getTemplateTypeFromMappedType(type); - const modifiersType = getApparentType(getModifiersTypeFromMappedType(type)); + const modifiersType = getApparentType(getModifiersTypeFromMappedType(type)); // The 'T' in 'keyof T' const templateReadonly = !!type.declaration.readonlyToken; const templateOptional = !!type.declaration.questionToken; if (type.declaration.typeParameter.constraint.kind === SyntaxKind.TypeOperator) { // We have a { [P in keyof T]: X } - forEachType(getLiteralTypeFromPropertyNames(modifiersType), addMemberForKeyType); + for (const propertySymbol of getPropertiesOfType(modifiersType)) { + addMemberForKeyType(getLiteralTypeFromPropertyName(propertySymbol), propertySymbol); + } if (getIndexInfoOfType(modifiersType, IndexKind.String)) { addMemberForKeyType(stringType); } @@ -4638,7 +4640,7 @@ namespace ts { } setStructuredTypeMembers(type, members, emptyArray, emptyArray, stringIndexInfo, undefined); - function addMemberForKeyType(t: Type) { + function addMemberForKeyType(t: Type, propertySymbol?: Symbol) { // Create a mapper from T to the current iteration type constituent. Then, if the // mapped type is itself an instantiated type, combine the iteration mapper with the // instantiation mapper. @@ -4654,6 +4656,9 @@ namespace ts { const prop = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | (isOptional ? SymbolFlags.Optional : 0), propName); prop.type = propType; prop.isReadonly = templateReadonly || modifiersProp && isReadonlySymbol(modifiersProp); + if (propertySymbol) { + prop.mappedTypeOrigin = propertySymbol; + } members.set(propName, prop); } else if (t.flags & TypeFlags.String) { @@ -20230,6 +20235,10 @@ namespace ts { const links = symbol as SymbolLinks; return [links.leftSpread, links.rightSpread]; } + if ((symbol as SymbolLinks).mappedTypeOrigin) { + return getRootSymbols((symbol as SymbolLinks).mappedTypeOrigin); + } + let target: Symbol; let next = symbol; while (next = getSymbolLinks(next).target) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 6ac7d573eda..8b49af402cf 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2712,6 +2712,7 @@ containingType?: UnionOrIntersectionType; // Containing union or intersection type for synthetic property leftSpread?: Symbol; // Left source for synthetic spread property rightSpread?: Symbol; // Right source for synthetic spread property + mappedTypeOrigin?: Symbol; // For a property on a mapped type, points back to the orignal 'T' from 'keyof T'. hasNonUniformType?: boolean; // True if constituents have non-uniform types isPartial?: boolean; // True if syntheric property of union type occurs in some but not all constituents isDiscriminantProperty?: boolean; // True if discriminant synthetic property diff --git a/tests/cases/fourslash/findAllRefsForMappedType.ts b/tests/cases/fourslash/findAllRefsForMappedType.ts new file mode 100644 index 00000000000..620eae0815c --- /dev/null +++ b/tests/cases/fourslash/findAllRefsForMappedType.ts @@ -0,0 +1,9 @@ +/// + +////interface T { [|a|]: number }; +////type U { [K in keyof T]: string }; +////type V = { [K in keyof U]: boolean }; +////const u: U = { [|a|]: "" } +////const v: V = { [|a|]: true } + +verify.rangesReferenceEachOther(); From e8c3d548eb66c020b02cfa135b492f9480ef639c Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Tue, 24 Jan 2017 12:56:21 -0800 Subject: [PATCH 42/63] Fix tests --- src/services/documentHighlights.ts | 2 +- src/services/findAllReferences.ts | 109 +++++++++++------- src/services/goToImplementation.ts | 2 +- src/services/services.ts | 10 +- tests/cases/fourslash/renameDefaultImport.ts | 17 ++- .../renameDefaultImportDifferentName.ts | 14 ++- .../cases/fourslash/renameImportAndExport.ts | 4 +- 7 files changed, 104 insertions(+), 54 deletions(-) diff --git a/src/services/documentHighlights.ts b/src/services/documentHighlights.ts index 778a007ded5..ff2b819ec26 100644 --- a/src/services/documentHighlights.ts +++ b/src/services/documentHighlights.ts @@ -17,7 +17,7 @@ namespace ts.DocumentHighlights { } function getSemanticDocumentHighlights(node: Node, typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFilesToSearch: SourceFile[]): DocumentHighlights[] { - const referencedSymbols = FindAllReferences.getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFilesToSearch, /*findInStrings*/false, /*findInComments*/false, /*implementations*/false); + const referencedSymbols = FindAllReferences.getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFilesToSearch); return referencedSymbols && convertReferencedSymbols(referencedSymbols); } diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index 83006c66d77..df568f6df3e 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -1,11 +1,11 @@ /* @internal */ namespace ts.FindAllReferences { - export function findReferencedSymbols(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFiles: SourceFile[], sourceFile: SourceFile, position: number, findInStrings: boolean, findInComments: boolean): ReferencedSymbol[] | undefined { + export function findReferencedSymbols(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFiles: SourceFile[], sourceFile: SourceFile, position: number, findInStrings: boolean, findInComments: boolean, isForRename: boolean): ReferencedSymbol[] | undefined { const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true); - return getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFiles, findInStrings, findInComments, /*implementations*/false); + return getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFiles, findInStrings, findInComments, isForRename); } - export function getReferencedSymbolsForNode(typeChecker: TypeChecker, cancellationToken: CancellationToken, node: Node, sourceFiles: SourceFile[], findInStrings: boolean, findInComments: boolean, implementations: boolean): ReferencedSymbol[] | undefined { + export function getReferencedSymbolsForNode(typeChecker: TypeChecker, cancellationToken: CancellationToken, node: Node, sourceFiles: SourceFile[], findInStrings?: boolean, findInComments?: boolean, isForRename?: boolean, implementations?: boolean): ReferencedSymbol[] | undefined { if (!implementations) { const special = getReferencedSymbolsSpecial(node, sourceFiles, typeChecker, cancellationToken); if (special) { @@ -33,11 +33,16 @@ namespace ts.FindAllReferences { return undefined; } - const aliasedSymbol = followAliasIfNecessary(symbol, node, typeChecker); - const isShorthandModule = ts.isShorthandAmbientModuleSymbol(aliasedSymbol); - // Don't follow alias for shorthand modules because we lose information that way. - if (!isShorthandModule) { - symbol = aliasedSymbol; + const { symbol: aliasedSymbol, shorthandModuleSymbol } = followAliases(symbol, node, typeChecker, isForRename); + symbol = aliasedSymbol; + + // Build the set of symbols to search for, initially it has only the current symbol + const searchSymbols = populateSearchSymbolSet(symbol, node, typeChecker, implementations); + if (shorthandModuleSymbol) { + searchSymbols.push(shorthandModuleSymbol); + } + function isSearchedFor(symbol: Symbol): boolean { + return contains(searchSymbols, symbol); } // Compute the meaning from the location and the symbol it references @@ -48,12 +53,6 @@ namespace ts.FindAllReferences { const symbolToIndex: number[] = []; const inheritsFromCache: Map = createMap(); - // Build the set of symbols to search for, initially it has only the current symbol - const searchSymbols = populateSearchSymbolSet(symbol, node, typeChecker, implementations, isShorthandModule ? aliasedSymbol : undefined); - function isSearchedFor(symbol: Symbol): boolean { - return contains(searchSymbols, symbol); - } - // Get the text to search for. // Note: if this is an external module symbol, the name doesn't include quotes. const declaredName = stripQuotes(getDeclaredName(typeChecker, symbol, node)); @@ -116,6 +115,31 @@ namespace ts.FindAllReferences { return undefined; } + /** + * Follows aliases to get to the original declaration of a symbol. + * For a shorthand ambient module, we don't follow the alias to it, but we will need to add it to the set of search symbols. + */ + function followAliases(symbol: Symbol, node: Node, typeChecker: TypeChecker, isForRename: boolean): { symbol: Symbol, shorthandModuleSymbol?: Symbol } { + while (true) { + // When renaming a default import, only rename in the current file + if (isForRename && isImportDefaultSymbol(symbol)) { + return { symbol }; + } + + const aliasedSymbol = getAliasSymbolForPropertyNameSymbol(symbol, node, typeChecker); + // Don't follow alias if it goes to unknown symbol. This can happen if it points to an untyped module. + if (!aliasedSymbol || !aliasedSymbol.declarations) { + return { symbol }; + } + + if (ts.isShorthandAmbientModuleSymbol(aliasedSymbol)) { + return { symbol, shorthandModuleSymbol: aliasedSymbol }; + } + + symbol = aliasedSymbol; + } + } + function sourceFileHasName(sourceFile: SourceFile, name: string): boolean { return getNameTable(sourceFile).get(name) !== undefined; } @@ -157,29 +181,30 @@ namespace ts.FindAllReferences { } function getAliasSymbolForPropertyNameSymbol(symbol: Symbol, location: Node, typeChecker: TypeChecker): Symbol | undefined { - if (symbol.flags & SymbolFlags.Alias) { - // Default import get alias - const defaultImport = getDeclarationOfKind(symbol, SyntaxKind.ImportClause); - if (defaultImport) { - return typeChecker.getAliasedSymbol(symbol); - } + if (!(symbol.flags & SymbolFlags.Alias)) { + return undefined; + } - const importOrExportSpecifier = forEach(symbol.declarations, - declaration => (declaration.kind === SyntaxKind.ImportSpecifier || - declaration.kind === SyntaxKind.ExportSpecifier) ? declaration : undefined); - if (importOrExportSpecifier && - // export { a } - (!importOrExportSpecifier.propertyName || - // export {a as class } where a is location - importOrExportSpecifier.propertyName === location)) { - // If Import specifier -> get alias - // else Export specifier -> get local target - return importOrExportSpecifier.kind === SyntaxKind.ImportSpecifier ? - typeChecker.getAliasedSymbol(symbol) : - typeChecker.getExportSpecifierLocalTargetSymbol(importOrExportSpecifier); - } + // Default import get alias + const defaultImport = getDeclarationOfKind(symbol, SyntaxKind.ImportClause); + if (defaultImport) { + return typeChecker.getAliasedSymbol(symbol); + } + + const importOrExportSpecifier = forEach(symbol.declarations, + declaration => (declaration.kind === SyntaxKind.ImportSpecifier || + declaration.kind === SyntaxKind.ExportSpecifier) ? declaration : undefined); + if (importOrExportSpecifier && + // export { a } + (!importOrExportSpecifier.propertyName || + // export {a as class } where a is location + importOrExportSpecifier.propertyName === location)) { + // If Import specifier -> get alias + // else Export specifier -> get local target + return importOrExportSpecifier.kind === SyntaxKind.ImportSpecifier ? + typeChecker.getAliasedSymbol(symbol) : + typeChecker.getExportSpecifierLocalTargetSymbol(importOrExportSpecifier); } - return undefined; } function followAliasIfNecessary(symbol: Symbol, location: Node, typeChecker: TypeChecker): Symbol { @@ -1022,9 +1047,9 @@ namespace ts.FindAllReferences { } } - function populateSearchSymbolSet(symbol: Symbol, location: Node, typeChecker: TypeChecker, implementations: boolean, aliasSymbol?: Symbol): Symbol[] { + function populateSearchSymbolSet(symbol: Symbol, location: Node, typeChecker: TypeChecker, implementations: boolean): Symbol[] { // The search set contains at least the current symbol - let result = [symbol]; + const result = [symbol]; // If the location is name of property symbol from object literal destructuring pattern // Search the property symbol @@ -1037,10 +1062,6 @@ namespace ts.FindAllReferences { } } - if (aliasSymbol) { - result = result.concat(populateSearchSymbolSet(aliasSymbol, location, typeChecker, implementations)); - } - // If the location is in a context sensitive location (i.e. in an object literal) try // to get a contextual type for it, and add the property symbol from the contextual // type to the search set @@ -1072,7 +1093,7 @@ namespace ts.FindAllReferences { // Property Declaration symbol is a member of the class, so the symbol is stored in its class Declaration.symbol.members if (symbol.valueDeclaration && symbol.valueDeclaration.kind === SyntaxKind.Parameter && isParameterPropertyDeclaration(symbol.valueDeclaration)) { - result = result.concat(typeChecker.getSymbolsOfParameterPropertyDeclaration(symbol.valueDeclaration, symbol.name)); + addRange(result, typeChecker.getSymbolsOfParameterPropertyDeclaration(symbol.valueDeclaration, symbol.name)); } // If this is symbol of binding element without propertyName declaration in Object binding pattern @@ -1447,4 +1468,8 @@ namespace ts.FindAllReferences { return false; } + + function isImportDefaultSymbol(symbol: Symbol): boolean { + return symbol.declarations[0].kind === SyntaxKind.ImportClause; + } } diff --git a/src/services/goToImplementation.ts b/src/services/goToImplementation.ts index 123d29630ad..9135e1fe0f0 100644 --- a/src/services/goToImplementation.ts +++ b/src/services/goToImplementation.ts @@ -17,7 +17,7 @@ namespace ts.GoToImplementation { else { // Perform "Find all References" and retrieve only those that are implementations const referencedSymbols = FindAllReferences.getReferencedSymbolsForNode(typeChecker, cancellationToken, - node, sourceFiles, /*findInStrings*/false, /*findInComments*/false, /*implementations*/true); + node, sourceFiles, /*findInStrings*/false, /*findInComments*/false, /*isForRename*/false, /*implementations*/true); const result = flatMap(referencedSymbols, symbol => map(symbol.references, ({ textSpan, fileName }) => ({ textSpan, fileName }))); diff --git a/src/services/services.ts b/src/services/services.ts index cb38b1d500e..00a8c9a9f2e 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1406,25 +1406,25 @@ namespace ts { } function findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): RenameLocation[] { - const referencedSymbols = findReferencedSymbols(fileName, position, findInStrings, findInComments); + const referencedSymbols = findReferencedSymbols(fileName, position, findInStrings, findInComments, /*isForRename*/true); return FindAllReferences.convertReferences(referencedSymbols); } function getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[] { - const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false); + const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false, /*isForRename*/false); return FindAllReferences.convertReferences(referencedSymbols); } function findReferences(fileName: string, position: number): ReferencedSymbol[] { - const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false); + const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false, /*isForRename*/false); // Only include referenced symbols that have a valid definition. return filter(referencedSymbols, rs => !!rs.definition); } - function findReferencedSymbols(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): ReferencedSymbol[] { + function findReferencedSymbols(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, isForRename: boolean): ReferencedSymbol[] { synchronizeHostData(); - return FindAllReferences.findReferencedSymbols(program.getTypeChecker(), cancellationToken, program.getSourceFiles(), getValidSourceFile(fileName), position, findInStrings, findInComments); + return FindAllReferences.findReferencedSymbols(program.getTypeChecker(), cancellationToken, program.getSourceFiles(), getValidSourceFile(fileName), position, findInStrings, findInComments, isForRename); } /// NavigateTo diff --git a/tests/cases/fourslash/renameDefaultImport.ts b/tests/cases/fourslash/renameDefaultImport.ts index 8d9b65d78d6..ff297ffa147 100644 --- a/tests/cases/fourslash/renameDefaultImport.ts +++ b/tests/cases/fourslash/renameDefaultImport.ts @@ -1,7 +1,7 @@ /// // @Filename: B.ts -////export default class [|B|] { +////export default class /*1*/[|B|] { //// test() { //// } ////} @@ -11,4 +11,17 @@ ////let b = new [|B|](); ////b.test(); -verify.rangesAreRenameLocations(); +goTo.marker("1"); +verify.occurrencesAtPositionCount(1); + +const [C, B0, B1] = test.ranges(); +verify.rangesReferenceEachOther(); + +goTo.rangeStart(C); +verify.renameLocations(false, false, [C, B0, B1]); + +const rangesInB = [B0, B1]; +for (const r of rangesInB) { + goTo.rangeStart(r); + verify.renameLocations(false, false, rangesInB); +} diff --git a/tests/cases/fourslash/renameDefaultImportDifferentName.ts b/tests/cases/fourslash/renameDefaultImportDifferentName.ts index aec699aadda..be968c9b883 100644 --- a/tests/cases/fourslash/renameDefaultImportDifferentName.ts +++ b/tests/cases/fourslash/renameDefaultImportDifferentName.ts @@ -1,7 +1,7 @@ /// // @Filename: B.ts -////export default class /*1*/C { +////export default class /*1*/[|C|] { //// test() { //// } ////} @@ -14,4 +14,14 @@ goTo.marker("1"); verify.occurrencesAtPositionCount(1); -verify.rangesAreRenameLocations(); +const [C, B0, B1] = test.ranges(); +verify.rangesReferenceEachOther(); + +goTo.rangeStart(C); +verify.renameLocations(false, false, [C, B0, B1]); + +const rangesInB = [B0, B1]; +for (const r of rangesInB) { + goTo.rangeStart(r); + verify.renameLocations(false, false, rangesInB); +} diff --git a/tests/cases/fourslash/renameImportAndExport.ts b/tests/cases/fourslash/renameImportAndExport.ts index fe8bce4b208..4545277c564 100644 --- a/tests/cases/fourslash/renameImportAndExport.ts +++ b/tests/cases/fourslash/renameImportAndExport.ts @@ -3,4 +3,6 @@ ////import [|a|] from "module"; ////export { [|a|] }; -verify.rangesAreRenameLocations(); +const [r0, r1] = test.ranges(); +verify.referencesOf(r1, [r0, r1]); +//verify.rangesAreRenameLocations(); From b48a2811f67b66a14cd4584999a7d7ab2e723b56 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Tue, 24 Jan 2017 13:03:16 -0800 Subject: [PATCH 43/63] Update baselines --- tests/baselines/reference/mappedTypes1.js | 2 +- tests/baselines/reference/mappedTypes1.types | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/baselines/reference/mappedTypes1.js b/tests/baselines/reference/mappedTypes1.js index 1998ad5ab6b..4dd8f172179 100644 --- a/tests/baselines/reference/mappedTypes1.js +++ b/tests/baselines/reference/mappedTypes1.js @@ -139,9 +139,9 @@ declare let x2: string; declare let x3: number; declare let x4: { toString: void; - valueOf: void; toFixed: void; toExponential: void; toPrecision: void; + valueOf: void; toLocaleString: void; }; diff --git a/tests/baselines/reference/mappedTypes1.types b/tests/baselines/reference/mappedTypes1.types index 35d13143bab..a9a7f53a899 100644 --- a/tests/baselines/reference/mappedTypes1.types +++ b/tests/baselines/reference/mappedTypes1.types @@ -165,7 +165,7 @@ let x3 = f3(); >f3 : () => { [P in keyof T1]: void; } let x4 = f4(); ->x4 : { toString: void; valueOf: void; toFixed: void; toExponential: void; toPrecision: void; toLocaleString: void; } ->f4() : { toString: void; valueOf: void; toFixed: void; toExponential: void; toPrecision: void; toLocaleString: void; } +>x4 : { toString: void; toFixed: void; toExponential: void; toPrecision: void; valueOf: void; toLocaleString: void; } +>f4() : { toString: void; toFixed: void; toExponential: void; toPrecision: void; valueOf: void; toLocaleString: void; } >f4 : () => { [P in keyof T1]: void; } From 20249e5c4a66e5abef595c52e87be5b1eabff468 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Tue, 24 Jan 2017 13:42:05 -0800 Subject: [PATCH 44/63] More exhaustive needsDotDotForPropertyAccess --- src/compiler/emitter.ts | 6 ++- src/compiler/utilities.ts | 42 +++++++++++++++++-- .../propertyAccessNumericLiterals.es6.js | 14 +++++++ .../propertyAccessNumericLiterals.es6.symbols | 21 ++++++++++ .../propertyAccessNumericLiterals.es6.types | 31 ++++++++++++++ .../propertyAccessNumericLiterals.js | 15 +++++++ .../propertyAccessNumericLiterals.symbols | 25 +++++++++++ .../propertyAccessNumericLiterals.types | 37 ++++++++++++++++ .../propertyAccessNumericLiterals.es6.ts | 6 +++ .../propertyAccessNumericLiterals.ts | 7 ++++ 10 files changed, 199 insertions(+), 5 deletions(-) create mode 100644 tests/baselines/reference/propertyAccessNumericLiterals.es6.js create mode 100644 tests/baselines/reference/propertyAccessNumericLiterals.es6.symbols create mode 100644 tests/baselines/reference/propertyAccessNumericLiterals.es6.types create mode 100644 tests/baselines/reference/propertyAccessNumericLiterals.js create mode 100644 tests/baselines/reference/propertyAccessNumericLiterals.symbols create mode 100644 tests/baselines/reference/propertyAccessNumericLiterals.types create mode 100644 tests/cases/conformance/es6/propertyAccess/propertyAccessNumericLiterals.es6.ts create mode 100644 tests/cases/conformance/expressions/propertyAccess/propertyAccessNumericLiterals.ts diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index cc006a06637..27285a4c2dc 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1054,9 +1054,11 @@ namespace ts { // Also emit a dot if expression is a integer const enum value - it will appear in generated code as numeric literal function needsDotDotForPropertyAccess(expression: Expression) { if (expression.kind === SyntaxKind.NumericLiteral) { - // check if numeric literal was originally written with a dot + // check if numeric literal is a decimal literal that was originally written with a dot const text = getLiteralTextOfNode(expression); - return text.indexOf(tokenToString(SyntaxKind.DotToken)) < 0; + return getNumericLiteralFlags(text, /*hint*/ NumericLiteralFlags.All) === NumericLiteralFlags.None + && !(expression).isOctalLiteral + && text.indexOf(tokenToString(SyntaxKind.DotToken)) < 0; } else if (isPropertyAccessExpression(expression) || isElementAccessExpression(expression)) { // check if constant enum value is integer diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index b7cc0f0de6d..b1d2ba0854c 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -341,16 +341,52 @@ namespace ts { } export function isBinaryOrOctalIntegerLiteral(node: LiteralLikeNode, text: string) { - if (node.kind === SyntaxKind.NumericLiteral && text.length > 1) { + return node.kind === SyntaxKind.NumericLiteral + && (getNumericLiteralFlags(text, /*hint*/ NumericLiteralFlags.BinaryOrOctal) & NumericLiteralFlags.BinaryOrOctal) !== 0; + } + + export const enum NumericLiteralFlags { + None = 0, + Hexadecimal = 1 << 0, + Binary = 1 << 1, + Octal = 1 << 2, + Scientific = 1 << 3, + + BinaryOrOctal = Binary | Octal, + BinaryOrOctalOrHexadecimal = BinaryOrOctal | Hexadecimal, + All = Hexadecimal | Binary | Octal | Scientific, + } + + /** + * Scans a numeric literal string to determine the form of the number. + * @param text Numeric literal text + * @param hint If `Scientific` or `All` is specified, performs a more expensive check to scan for scientific notation. + */ + export function getNumericLiteralFlags(text: string, hint?: NumericLiteralFlags) { + if (text.length > 1) { switch (text.charCodeAt(1)) { case CharacterCodes.b: case CharacterCodes.B: + return NumericLiteralFlags.Binary; case CharacterCodes.o: case CharacterCodes.O: - return true; + return NumericLiteralFlags.Octal; + case CharacterCodes.x: + case CharacterCodes.X: + return NumericLiteralFlags.Hexadecimal; + } + + if (hint & NumericLiteralFlags.Scientific) { + for (let i = text.length - 1; i >= 0; i--) { + switch (text.charCodeAt(i)) { + case CharacterCodes.e: + case CharacterCodes.E: + return NumericLiteralFlags.Scientific; + } + } } } - return false; + return NumericLiteralFlags.None; } function getQuotedEscapedLiteralText(leftQuote: string, text: string, rightQuote: string) { diff --git a/tests/baselines/reference/propertyAccessNumericLiterals.es6.js b/tests/baselines/reference/propertyAccessNumericLiterals.es6.js new file mode 100644 index 00000000000..66ac4178155 --- /dev/null +++ b/tests/baselines/reference/propertyAccessNumericLiterals.es6.js @@ -0,0 +1,14 @@ +//// [propertyAccessNumericLiterals.es6.ts] +0xffffffff.toString(); +0o01234.toString(); +0b01101101.toString(); +1234..toString(); +1e0.toString(); + + +//// [propertyAccessNumericLiterals.es6.js] +0xffffffff.toString(); +0o01234.toString(); +0b01101101.toString(); +1234..toString(); +1e0.toString(); diff --git a/tests/baselines/reference/propertyAccessNumericLiterals.es6.symbols b/tests/baselines/reference/propertyAccessNumericLiterals.es6.symbols new file mode 100644 index 00000000000..dc0be21d84f --- /dev/null +++ b/tests/baselines/reference/propertyAccessNumericLiterals.es6.symbols @@ -0,0 +1,21 @@ +=== tests/cases/conformance/es6/propertyAccess/propertyAccessNumericLiterals.es6.ts === +0xffffffff.toString(); +>0xffffffff.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + +0o01234.toString(); +>0o01234.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + +0b01101101.toString(); +>0b01101101.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + +1234..toString(); +>1234..toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + +1e0.toString(); +>1e0.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + diff --git a/tests/baselines/reference/propertyAccessNumericLiterals.es6.types b/tests/baselines/reference/propertyAccessNumericLiterals.es6.types new file mode 100644 index 00000000000..9d32cc5b6e8 --- /dev/null +++ b/tests/baselines/reference/propertyAccessNumericLiterals.es6.types @@ -0,0 +1,31 @@ +=== tests/cases/conformance/es6/propertyAccess/propertyAccessNumericLiterals.es6.ts === +0xffffffff.toString(); +>0xffffffff.toString() : string +>0xffffffff.toString : (radix?: number) => string +>0xffffffff : 4294967295 +>toString : (radix?: number) => string + +0o01234.toString(); +>0o01234.toString() : string +>0o01234.toString : (radix?: number) => string +>0o01234 : 668 +>toString : (radix?: number) => string + +0b01101101.toString(); +>0b01101101.toString() : string +>0b01101101.toString : (radix?: number) => string +>0b01101101 : 109 +>toString : (radix?: number) => string + +1234..toString(); +>1234..toString() : string +>1234..toString : (radix?: number) => string +>1234. : 1234 +>toString : (radix?: number) => string + +1e0.toString(); +>1e0.toString() : string +>1e0.toString : (radix?: number) => string +>1e0 : 1 +>toString : (radix?: number) => string + diff --git a/tests/baselines/reference/propertyAccessNumericLiterals.js b/tests/baselines/reference/propertyAccessNumericLiterals.js new file mode 100644 index 00000000000..1a7eb6c0a21 --- /dev/null +++ b/tests/baselines/reference/propertyAccessNumericLiterals.js @@ -0,0 +1,15 @@ +//// [propertyAccessNumericLiterals.ts] +0xffffffff.toString(); +0o01234.toString(); +0b01101101.toString(); +1234..toString(); +1e0.toString(); +000.toString(); + +//// [propertyAccessNumericLiterals.js] +0xffffffff.toString(); +668..toString(); +109..toString(); +1234..toString(); +1e0.toString(); +000.toString(); diff --git a/tests/baselines/reference/propertyAccessNumericLiterals.symbols b/tests/baselines/reference/propertyAccessNumericLiterals.symbols new file mode 100644 index 00000000000..5be13615e90 --- /dev/null +++ b/tests/baselines/reference/propertyAccessNumericLiterals.symbols @@ -0,0 +1,25 @@ +=== tests/cases/conformance/expressions/propertyAccess/propertyAccessNumericLiterals.ts === +0xffffffff.toString(); +>0xffffffff.toString : Symbol(Number.toString, Decl(lib.d.ts, --, --)) +>toString : Symbol(Number.toString, Decl(lib.d.ts, --, --)) + +0o01234.toString(); +>0o01234.toString : Symbol(Number.toString, Decl(lib.d.ts, --, --)) +>toString : Symbol(Number.toString, Decl(lib.d.ts, --, --)) + +0b01101101.toString(); +>0b01101101.toString : Symbol(Number.toString, Decl(lib.d.ts, --, --)) +>toString : Symbol(Number.toString, Decl(lib.d.ts, --, --)) + +1234..toString(); +>1234..toString : Symbol(Number.toString, Decl(lib.d.ts, --, --)) +>toString : Symbol(Number.toString, Decl(lib.d.ts, --, --)) + +1e0.toString(); +>1e0.toString : Symbol(Number.toString, Decl(lib.d.ts, --, --)) +>toString : Symbol(Number.toString, Decl(lib.d.ts, --, --)) + +000.toString(); +>000.toString : Symbol(Number.toString, Decl(lib.d.ts, --, --)) +>toString : Symbol(Number.toString, Decl(lib.d.ts, --, --)) + diff --git a/tests/baselines/reference/propertyAccessNumericLiterals.types b/tests/baselines/reference/propertyAccessNumericLiterals.types new file mode 100644 index 00000000000..a2567ff2537 --- /dev/null +++ b/tests/baselines/reference/propertyAccessNumericLiterals.types @@ -0,0 +1,37 @@ +=== tests/cases/conformance/expressions/propertyAccess/propertyAccessNumericLiterals.ts === +0xffffffff.toString(); +>0xffffffff.toString() : string +>0xffffffff.toString : (radix?: number) => string +>0xffffffff : 4294967295 +>toString : (radix?: number) => string + +0o01234.toString(); +>0o01234.toString() : string +>0o01234.toString : (radix?: number) => string +>0o01234 : 668 +>toString : (radix?: number) => string + +0b01101101.toString(); +>0b01101101.toString() : string +>0b01101101.toString : (radix?: number) => string +>0b01101101 : 109 +>toString : (radix?: number) => string + +1234..toString(); +>1234..toString() : string +>1234..toString : (radix?: number) => string +>1234. : 1234 +>toString : (radix?: number) => string + +1e0.toString(); +>1e0.toString() : string +>1e0.toString : (radix?: number) => string +>1e0 : 1 +>toString : (radix?: number) => string + +000.toString(); +>000.toString() : string +>000.toString : (radix?: number) => string +>000 : 0 +>toString : (radix?: number) => string + diff --git a/tests/cases/conformance/es6/propertyAccess/propertyAccessNumericLiterals.es6.ts b/tests/cases/conformance/es6/propertyAccess/propertyAccessNumericLiterals.es6.ts new file mode 100644 index 00000000000..81e39965a6a --- /dev/null +++ b/tests/cases/conformance/es6/propertyAccess/propertyAccessNumericLiterals.es6.ts @@ -0,0 +1,6 @@ +// @target: es6 +0xffffffff.toString(); +0o01234.toString(); +0b01101101.toString(); +1234..toString(); +1e0.toString(); diff --git a/tests/cases/conformance/expressions/propertyAccess/propertyAccessNumericLiterals.ts b/tests/cases/conformance/expressions/propertyAccess/propertyAccessNumericLiterals.ts new file mode 100644 index 00000000000..318b05fc0b5 --- /dev/null +++ b/tests/cases/conformance/expressions/propertyAccess/propertyAccessNumericLiterals.ts @@ -0,0 +1,7 @@ +// @target: es3 +0xffffffff.toString(); +0o01234.toString(); +0b01101101.toString(); +1234..toString(); +1e0.toString(); +000.toString(); \ No newline at end of file From a478bfddd2233d3579a2b037fc0df32807cb0ebe Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Tue, 24 Jan 2017 13:44:36 -0800 Subject: [PATCH 45/63] Simplify code in 'rename' --- src/services/rename.ts | 172 ++++++++++++++++++++--------------------- 1 file changed, 84 insertions(+), 88 deletions(-) diff --git a/src/services/rename.ts b/src/services/rename.ts index 6f28e505f79..afb16618b03 100644 --- a/src/services/rename.ts +++ b/src/services/rename.ts @@ -1,98 +1,94 @@ /* @internal */ namespace ts.Rename { export function getRenameInfo(typeChecker: TypeChecker, defaultLibFileName: string, getCanonicalFileName: (fileName: string) => string, sourceFile: SourceFile, position: number): RenameInfo { - const canonicalDefaultLibName = getCanonicalFileName(ts.normalizePath(defaultLibFileName)); - const node = getTouchingWord(sourceFile, position, /*includeJsDocComment*/ true); + const renameInfo = node && nodeIsEligibleForRename(node) + ? getRenameInfoForNode(node, typeChecker, sourceFile, getIsDefinedInLibraryFile(defaultLibFileName, getCanonicalFileName)) + : undefined; + return renameInfo || getRenameInfoError(Diagnostics.You_cannot_rename_this_element); + } - if (node) { - if (node.kind === SyntaxKind.Identifier || - node.kind === SyntaxKind.StringLiteral || - isLiteralNameOfPropertyDeclarationOrIndexAccess(node) || - isThis(node)) { - const symbol = typeChecker.getSymbolAtLocation(node); - - // Only allow a symbol to be renamed if it actually has at least one declaration. - if (symbol) { - const declarations = symbol.getDeclarations(); - if (declarations && declarations.length > 0) { - // Disallow rename for elements that are defined in the standard TypeScript library. - if (forEach(declarations, isDefinedInLibraryFile)) { - return getRenameInfoError(getLocaleSpecificMessage(Diagnostics.You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library)); - } - - const displayName = stripQuotes(getDeclaredName(typeChecker, symbol, node)); - const kind = SymbolDisplay.getSymbolKind(typeChecker, symbol, node); - if (kind) { - return { - canRename: true, - kind, - displayName, - localizedErrorMessage: undefined, - fullDisplayName: typeChecker.getFullyQualifiedName(symbol), - kindModifiers: SymbolDisplay.getSymbolModifiers(symbol), - triggerSpan: createTriggerSpanForNode(node, sourceFile) - }; - } - } - } - else if (node.kind === SyntaxKind.StringLiteral) { - const type = getStringLiteralTypeForNode(node, typeChecker); - if (type) { - if (isDefinedInLibraryFile(node)) { - return getRenameInfoError(getLocaleSpecificMessage(Diagnostics.You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library)); - } - else { - const displayName = stripQuotes(type.text); - return { - canRename: true, - kind: ScriptElementKind.variableElement, - displayName, - localizedErrorMessage: undefined, - fullDisplayName: displayName, - kindModifiers: ScriptElementKindModifier.none, - triggerSpan: createTriggerSpanForNode(node, sourceFile) - }; - } - } - } - } + function getIsDefinedInLibraryFile(defaultLibFileName: string, getCanonicalFileName: (fileName: string) => string): (declaration: Node) => boolean { + if (!defaultLibFileName) { + return () => false; } - return getRenameInfoError(getLocaleSpecificMessage(Diagnostics.You_cannot_rename_this_element)); - - function getRenameInfoError(localizedErrorMessage: string): RenameInfo { - return { - canRename: false, - localizedErrorMessage: localizedErrorMessage, - displayName: undefined, - fullDisplayName: undefined, - kind: undefined, - kindModifiers: undefined, - triggerSpan: undefined - }; - } - - function isDefinedInLibraryFile(declaration: Node) { - if (defaultLibFileName) { - const sourceFile = declaration.getSourceFile(); - const canonicalName = getCanonicalFileName(ts.normalizePath(sourceFile.fileName)); - if (canonicalName === canonicalDefaultLibName) { - return true; - } - } - return false; - } - - function createTriggerSpanForNode(node: Node, sourceFile: SourceFile) { - let start = node.getStart(sourceFile); - let width = node.getWidth(sourceFile); - if (node.kind === SyntaxKind.StringLiteral) { - // Exclude the quotes - start += 1; - width -= 2; - } - return createTextSpan(start, width); + const canonicalDefaultLibName = getCanonicalFileName(ts.normalizePath(defaultLibFileName)); + return declaration => { + const sourceFile = declaration.getSourceFile(); + const canonicalName = getCanonicalFileName(ts.normalizePath(sourceFile.fileName)); + return canonicalName === canonicalDefaultLibName; } } + + function getRenameInfoForNode(node: Node, typeChecker: TypeChecker, sourceFile: SourceFile, isDefinedInLibraryFile: (declaration: Node) => boolean): RenameInfo | undefined { + const symbol = typeChecker.getSymbolAtLocation(node); + + // Only allow a symbol to be renamed if it actually has at least one declaration. + if (symbol) { + const declarations = symbol.getDeclarations(); + if (declarations && declarations.length > 0) { + // Disallow rename for elements that are defined in the standard TypeScript library. + if (some(declarations, isDefinedInLibraryFile)) { + return getRenameInfoError(Diagnostics.You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library); + } + + const displayName = stripQuotes(getDeclaredName(typeChecker, symbol, node)); + const kind = SymbolDisplay.getSymbolKind(typeChecker, symbol, node); + return kind ? getRenameInfoSuccess(displayName, typeChecker.getFullyQualifiedName(symbol), kind, SymbolDisplay.getSymbolModifiers(symbol), node, sourceFile) : undefined; + } + } + else if (node.kind === SyntaxKind.StringLiteral) { + const type = getStringLiteralTypeForNode(node, typeChecker); + if (type) { + if (isDefinedInLibraryFile(node)) { + return getRenameInfoError(Diagnostics.You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library); + } + + const displayName = stripQuotes(type.text); + return getRenameInfoSuccess(displayName, displayName, ScriptElementKind.variableElement, ScriptElementKindModifier.none, node, sourceFile); + } + } + } + + function getRenameInfoSuccess(displayName: string, fullDisplayName: string, kind: string, kindModifiers: string, node: Node, sourceFile: SourceFile): RenameInfo { + return { + canRename: true, + kind, + displayName, + localizedErrorMessage: undefined, + fullDisplayName, + kindModifiers, + triggerSpan: createTriggerSpanForNode(node, sourceFile) + }; + } + + function getRenameInfoError(diagnostic: DiagnosticMessage): RenameInfo { + return { + canRename: false, + localizedErrorMessage: getLocaleSpecificMessage(diagnostic), + displayName: undefined, + fullDisplayName: undefined, + kind: undefined, + kindModifiers: undefined, + triggerSpan: undefined + }; + } + + function createTriggerSpanForNode(node: Node, sourceFile: SourceFile) { + let start = node.getStart(sourceFile); + let width = node.getWidth(sourceFile); + if (node.kind === SyntaxKind.StringLiteral) { + // Exclude the quotes + start += 1; + width -= 2; + } + return createTextSpan(start, width); + } + + function nodeIsEligibleForRename(node: Node) { + return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.StringLiteral || + isLiteralNameOfPropertyDeclarationOrIndexAccess(node) || + isThis(node); + } } From 50442b5a23148a9dd818e716748b48be00776a8a Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Tue, 24 Jan 2017 13:57:42 -0800 Subject: [PATCH 46/63] Undo change to test --- tests/cases/fourslash/renameImportAndExport.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/cases/fourslash/renameImportAndExport.ts b/tests/cases/fourslash/renameImportAndExport.ts index 4545277c564..fe8bce4b208 100644 --- a/tests/cases/fourslash/renameImportAndExport.ts +++ b/tests/cases/fourslash/renameImportAndExport.ts @@ -3,6 +3,4 @@ ////import [|a|] from "module"; ////export { [|a|] }; -const [r0, r1] = test.ranges(); -verify.referencesOf(r1, [r0, r1]); -//verify.rangesAreRenameLocations(); +verify.rangesAreRenameLocations(); From 33b8677cb52eb54a3d4d8365fb3e6b7eba2c0dec Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Tue, 24 Jan 2017 14:32:39 -0800 Subject: [PATCH 47/63] Change "getIsDefinedInLibraryFile" back to just "isDefinedInLibraryFile" --- src/services/rename.ts | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/services/rename.ts b/src/services/rename.ts index afb16618b03..2e9396888ef 100644 --- a/src/services/rename.ts +++ b/src/services/rename.ts @@ -1,23 +1,21 @@ /* @internal */ namespace ts.Rename { export function getRenameInfo(typeChecker: TypeChecker, defaultLibFileName: string, getCanonicalFileName: (fileName: string) => string, sourceFile: SourceFile, position: number): RenameInfo { + const getCanonicalDefaultLibName = memoize(() => getCanonicalFileName(ts.normalizePath(defaultLibFileName))); const node = getTouchingWord(sourceFile, position, /*includeJsDocComment*/ true); const renameInfo = node && nodeIsEligibleForRename(node) - ? getRenameInfoForNode(node, typeChecker, sourceFile, getIsDefinedInLibraryFile(defaultLibFileName, getCanonicalFileName)) + ? getRenameInfoForNode(node, typeChecker, sourceFile, isDefinedInLibraryFile) : undefined; return renameInfo || getRenameInfoError(Diagnostics.You_cannot_rename_this_element); - } - function getIsDefinedInLibraryFile(defaultLibFileName: string, getCanonicalFileName: (fileName: string) => string): (declaration: Node) => boolean { - if (!defaultLibFileName) { - return () => false; - } + function isDefinedInLibraryFile(declaration: Node) { + if (!defaultLibFileName) { + return false; + } - const canonicalDefaultLibName = getCanonicalFileName(ts.normalizePath(defaultLibFileName)); - return declaration => { const sourceFile = declaration.getSourceFile(); const canonicalName = getCanonicalFileName(ts.normalizePath(sourceFile.fileName)); - return canonicalName === canonicalDefaultLibName; + return canonicalName === getCanonicalDefaultLibName(); } } From 9be46006e60c6ce218086dec27534c8e17651816 Mon Sep 17 00:00:00 2001 From: Anatoly Ressin Date: Wed, 25 Jan 2017 15:41:46 +0200 Subject: [PATCH 48/63] fixes #13674 --- tests/webTestServer.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/webTestServer.ts b/tests/webTestServer.ts index 67bbce2a472..abfd71a8fff 100644 --- a/tests/webTestServer.ts +++ b/tests/webTestServer.ts @@ -315,7 +315,6 @@ if (browser === "chrome") { let defaultChromePath = ""; switch (os.platform()) { case "win32": - case "win64": defaultChromePath = "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe"; break; case "darwin": From 128b84d1db7359119fa211c3a222d43f5fb99a8b Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Wed, 25 Jan 2017 09:13:00 -0800 Subject: [PATCH 49/63] Add "workers" option in gulpfile. This allows e.g. `gulp runtests-parallel --w 3`. --- Gulpfile.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Gulpfile.ts b/Gulpfile.ts index bf5a074ef06..4f205bfb0ff 100644 --- a/Gulpfile.ts +++ b/Gulpfile.ts @@ -50,7 +50,8 @@ const cmdLineOptions = minimist(process.argv.slice(2), { r: "reporter", color: "colors", f: "files", - file: "files" + file: "files", + w: "workers", }, default: { soft: false, @@ -63,6 +64,7 @@ const cmdLineOptions = minimist(process.argv.slice(2), { reporter: process.env.reporter || process.env.r, lint: process.env.lint || true, files: process.env.f || process.env.file || process.env.files || "", + workers: process.env.workerCount || os.cpus().length, } }); @@ -604,7 +606,7 @@ function runConsoleTests(defaultReporter: string, runInParallel: boolean, done: } while (fs.existsSync(taskConfigsFolder)); fs.mkdirSync(taskConfigsFolder); - workerCount = process.env.workerCount || os.cpus().length; + workerCount = cmdLineOptions["workers"]; } if (tests || light || taskConfigsFolder) { @@ -1017,7 +1019,7 @@ gulp.task("lint", "Runs tslint on the compiler sources. Optional arguments are: cb(); }, (cb) => { files = files.filter(file => fileMatcher.test(file.path)).sort((filea, fileb) => filea.stat.size - fileb.stat.size); - const workerCount = (process.env.workerCount && +process.env.workerCount) || os.cpus().length; + const workerCount = cmdLineOptions["workers"]; for (let i = 0; i < workerCount; i++) { spawnLintWorker(files, finished); } From abc30b26c75247d839d2a2ecf5ee2b80ff5864ac Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Wed, 25 Jan 2017 09:53:34 -0800 Subject: [PATCH 50/63] handle cases when body of for-of statement is expanded after loop conversion (#13677) --- src/compiler/transformers/es2015.ts | 2 +- .../nestedLoopWithOnlyInnerLetCaptured.js | 18 +++++++++++++++++ ...nestedLoopWithOnlyInnerLetCaptured.symbols | 15 ++++++++++++++ .../nestedLoopWithOnlyInnerLetCaptured.types | 20 +++++++++++++++++++ .../nestedLoopWithOnlyInnerLetCaptured.ts | 6 ++++++ 5 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/nestedLoopWithOnlyInnerLetCaptured.js create mode 100644 tests/baselines/reference/nestedLoopWithOnlyInnerLetCaptured.symbols create mode 100644 tests/baselines/reference/nestedLoopWithOnlyInnerLetCaptured.types create mode 100644 tests/cases/compiler/nestedLoopWithOnlyInnerLetCaptured.ts diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index d1dab8eeb7a..3b8b4524aab 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -2316,7 +2316,7 @@ namespace ts { addRange(statements, convertedLoopBodyStatements); } else { - const statement = visitNode(node.statement, visitor, isStatement); + const statement = visitNode(node.statement, visitor, isStatement, /*optional*/ false, liftToBlock); if (isBlock(statement)) { addRange(statements, statement.statements); bodyLocation = statement; diff --git a/tests/baselines/reference/nestedLoopWithOnlyInnerLetCaptured.js b/tests/baselines/reference/nestedLoopWithOnlyInnerLetCaptured.js new file mode 100644 index 00000000000..ee17bb53eec --- /dev/null +++ b/tests/baselines/reference/nestedLoopWithOnlyInnerLetCaptured.js @@ -0,0 +1,18 @@ +//// [nestedLoopWithOnlyInnerLetCaptured.ts] +declare let doSomething; + +for (let a1 of []) + for (let a2 of a1.someArray) + doSomething(() => a2); + +//// [nestedLoopWithOnlyInnerLetCaptured.js] +for (var _i = 0, _a = []; _i < _a.length; _i++) { + var a1 = _a[_i]; + var _loop_1 = function (a2) { + doSomething(function () { return a2; }); + }; + for (var _b = 0, _c = a1.someArray; _b < _c.length; _b++) { + var a2 = _c[_b]; + _loop_1(a2); + } +} diff --git a/tests/baselines/reference/nestedLoopWithOnlyInnerLetCaptured.symbols b/tests/baselines/reference/nestedLoopWithOnlyInnerLetCaptured.symbols new file mode 100644 index 00000000000..f134dcbffa9 --- /dev/null +++ b/tests/baselines/reference/nestedLoopWithOnlyInnerLetCaptured.symbols @@ -0,0 +1,15 @@ +=== tests/cases/compiler/nestedLoopWithOnlyInnerLetCaptured.ts === +declare let doSomething; +>doSomething : Symbol(doSomething, Decl(nestedLoopWithOnlyInnerLetCaptured.ts, 0, 11)) + +for (let a1 of []) +>a1 : Symbol(a1, Decl(nestedLoopWithOnlyInnerLetCaptured.ts, 2, 8)) + + for (let a2 of a1.someArray) +>a2 : Symbol(a2, Decl(nestedLoopWithOnlyInnerLetCaptured.ts, 3, 12)) +>a1 : Symbol(a1, Decl(nestedLoopWithOnlyInnerLetCaptured.ts, 2, 8)) + + doSomething(() => a2); +>doSomething : Symbol(doSomething, Decl(nestedLoopWithOnlyInnerLetCaptured.ts, 0, 11)) +>a2 : Symbol(a2, Decl(nestedLoopWithOnlyInnerLetCaptured.ts, 3, 12)) + diff --git a/tests/baselines/reference/nestedLoopWithOnlyInnerLetCaptured.types b/tests/baselines/reference/nestedLoopWithOnlyInnerLetCaptured.types new file mode 100644 index 00000000000..6be9dbf6abf --- /dev/null +++ b/tests/baselines/reference/nestedLoopWithOnlyInnerLetCaptured.types @@ -0,0 +1,20 @@ +=== tests/cases/compiler/nestedLoopWithOnlyInnerLetCaptured.ts === +declare let doSomething; +>doSomething : any + +for (let a1 of []) +>a1 : any +>[] : undefined[] + + for (let a2 of a1.someArray) +>a2 : any +>a1.someArray : any +>a1 : any +>someArray : any + + doSomething(() => a2); +>doSomething(() => a2) : any +>doSomething : any +>() => a2 : () => any +>a2 : any + diff --git a/tests/cases/compiler/nestedLoopWithOnlyInnerLetCaptured.ts b/tests/cases/compiler/nestedLoopWithOnlyInnerLetCaptured.ts new file mode 100644 index 00000000000..210465b13da --- /dev/null +++ b/tests/cases/compiler/nestedLoopWithOnlyInnerLetCaptured.ts @@ -0,0 +1,6 @@ +// @target: es5 +declare let doSomething; + +for (let a1 of []) + for (let a2 of a1.someArray) + doSomething(() => a2); \ No newline at end of file From 76b1e95c3d89fa2ca762eda75c9bd182612ee85a Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Wed, 25 Jan 2017 10:40:59 -0800 Subject: [PATCH 51/63] Always call `checkExpression` on JSX attribute values Fixes #13676 --- src/compiler/checker.ts | 19 ++--- .../baselines/reference/reactImportDropped.js | 48 ++++++++++++ .../reference/reactImportDropped.symbols | 65 ++++++++++++++++ .../reference/reactImportDropped.types | 74 +++++++++++++++++++ tests/cases/compiler/reactImportDropped.ts | 42 +++++++++++ 5 files changed, 239 insertions(+), 9 deletions(-) create mode 100644 tests/baselines/reference/reactImportDropped.js create mode 100644 tests/baselines/reference/reactImportDropped.symbols create mode 100644 tests/baselines/reference/reactImportDropped.types create mode 100644 tests/cases/compiler/reactImportDropped.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a09b63d46fd..7c8a0b7337f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11879,6 +11879,16 @@ namespace ts { function checkJsxAttribute(node: JsxAttribute, elementAttributesType: Type, nameTable: Map) { let correspondingPropType: Type = undefined; + // We need to unconditionally get the expression type + let exprType: Type; + if (node.initializer) { + exprType = checkExpression(node.initializer); + } + else { + // is sugar for + exprType = booleanType; + } + // Look up the corresponding property for this attribute if (elementAttributesType === emptyObjectType && isUnhyphenatedJsxName(node.name.text)) { // If there is no 'props' property, you may not have non-"data-" attributes @@ -11902,15 +11912,6 @@ namespace ts { } } - let exprType: Type; - if (node.initializer) { - exprType = checkExpression(node.initializer); - } - else { - // is sugar for - exprType = booleanType; - } - if (correspondingPropType) { checkTypeAssignableTo(exprType, correspondingPropType, node); } diff --git a/tests/baselines/reference/reactImportDropped.js b/tests/baselines/reference/reactImportDropped.js new file mode 100644 index 00000000000..7ada76b42f4 --- /dev/null +++ b/tests/baselines/reference/reactImportDropped.js @@ -0,0 +1,48 @@ +//// [tests/cases/compiler/reactImportDropped.ts] //// + +//// [react.d.ts] + +export = React; +export as namespace React; + +declare namespace React { + + function createClass(spec: any): ClassicComponentClass; + + interface ClassicComponentClass { + new (props?: any): ClassicComponentClass; + } +} + +declare global { + namespace JSX { + interface ElementAttributesProperty { } + } +} + + +//// [TabBar.js] +export default React.createClass({ + render() { + return ( + null + ); + } +}); + +//// [NavigationView.js] +import TabBar from '../../components/TabBar'; +import {layout} from '../../utils/theme'; // <- DO NOT DROP this import +const x = ; + + +//// [TabBar.js] +export default React.createClass({ + render() { + return (null); + } +}); +//// [NavigationView.js] +import TabBar from '../../components/TabBar'; +import { layout } from '../../utils/theme'; // <- DO NOT DROP this import +const x = React.createElement(TabBar, { height: layout.footerHeight }); diff --git a/tests/baselines/reference/reactImportDropped.symbols b/tests/baselines/reference/reactImportDropped.symbols new file mode 100644 index 00000000000..d7374df044e --- /dev/null +++ b/tests/baselines/reference/reactImportDropped.symbols @@ -0,0 +1,65 @@ +=== tests/cases/compiler/react.d.ts === + +export = React; +>React : Symbol(React, Decl(react.d.ts, 2, 26)) + +export as namespace React; +>React : Symbol(React, Decl(react.d.ts, 1, 15)) + +declare namespace React { +>React : Symbol(React, Decl(react.d.ts, 2, 26)) + + function createClass(spec: any): ClassicComponentClass; +>createClass : Symbol(createClass, Decl(react.d.ts, 4, 25)) +>spec : Symbol(spec, Decl(react.d.ts, 6, 25)) +>ClassicComponentClass : Symbol(ClassicComponentClass, Decl(react.d.ts, 6, 59)) + + interface ClassicComponentClass { +>ClassicComponentClass : Symbol(ClassicComponentClass, Decl(react.d.ts, 6, 59)) + + new (props?: any): ClassicComponentClass; +>props : Symbol(props, Decl(react.d.ts, 9, 13)) +>ClassicComponentClass : Symbol(ClassicComponentClass, Decl(react.d.ts, 6, 59)) + } +} + +declare global { +>global : Symbol(global, Decl(react.d.ts, 11, 1)) + + namespace JSX { +>JSX : Symbol(JSX, Decl(react.d.ts, 13, 16)) + + interface ElementAttributesProperty { } +>ElementAttributesProperty : Symbol(ElementAttributesProperty, Decl(react.d.ts, 14, 19)) + } +} + + +=== tests/cases/compiler/src/components/TabBar.js === +export default React.createClass({ +>React.createClass : Symbol(React.createClass, Decl(react.d.ts, 4, 25)) +>React : Symbol(React, Decl(react.d.ts, 1, 15)) +>createClass : Symbol(React.createClass, Decl(react.d.ts, 4, 25)) + + render() { +>render : Symbol(render, Decl(TabBar.js, 0, 34)) + + return ( + null + ); + } +}); + +=== tests/cases/compiler/src/modules/navigation/NavigationView.js === +import TabBar from '../../components/TabBar'; +>TabBar : Symbol(TabBar, Decl(NavigationView.js, 0, 6)) + +import {layout} from '../../utils/theme'; // <- DO NOT DROP this import +>layout : Symbol(layout, Decl(NavigationView.js, 1, 8)) + +const x = ; +>x : Symbol(x, Decl(NavigationView.js, 2, 5)) +>TabBar : Symbol(TabBar, Decl(NavigationView.js, 0, 6)) +>height : Symbol(layout) +>layout : Symbol(layout, Decl(NavigationView.js, 1, 8)) + diff --git a/tests/baselines/reference/reactImportDropped.types b/tests/baselines/reference/reactImportDropped.types new file mode 100644 index 00000000000..36f1a6a4779 --- /dev/null +++ b/tests/baselines/reference/reactImportDropped.types @@ -0,0 +1,74 @@ +=== tests/cases/compiler/react.d.ts === + +export = React; +>React : typeof React + +export as namespace React; +>React : typeof React + +declare namespace React { +>React : typeof React + + function createClass(spec: any): ClassicComponentClass; +>createClass : (spec: any) => ClassicComponentClass +>spec : any +>ClassicComponentClass : ClassicComponentClass + + interface ClassicComponentClass { +>ClassicComponentClass : ClassicComponentClass + + new (props?: any): ClassicComponentClass; +>props : any +>ClassicComponentClass : ClassicComponentClass + } +} + +declare global { +>global : any + + namespace JSX { +>JSX : any + + interface ElementAttributesProperty { } +>ElementAttributesProperty : ElementAttributesProperty + } +} + + +=== tests/cases/compiler/src/components/TabBar.js === +export default React.createClass({ +>React.createClass({ render() { return ( null ); }}) : React.ClassicComponentClass +>React.createClass : (spec: any) => React.ClassicComponentClass +>React : typeof React +>createClass : (spec: any) => React.ClassicComponentClass +>{ render() { return ( null ); }} : { render(): any; } + + render() { +>render : () => any + + return ( +>( null ) : null + + null +>null : null + + ); + } +}); + +=== tests/cases/compiler/src/modules/navigation/NavigationView.js === +import TabBar from '../../components/TabBar'; +>TabBar : React.ClassicComponentClass + +import {layout} from '../../utils/theme'; // <- DO NOT DROP this import +>layout : any + +const x = ; +>x : any +> : any +>TabBar : React.ClassicComponentClass +>height : any +>layout.footerHeight : any +>layout : any +>footerHeight : any + diff --git a/tests/cases/compiler/reactImportDropped.ts b/tests/cases/compiler/reactImportDropped.ts new file mode 100644 index 00000000000..a345e7c74fd --- /dev/null +++ b/tests/cases/compiler/reactImportDropped.ts @@ -0,0 +1,42 @@ +//@module: es6 +//@moduleResolution: node +//@target: es6 +//@noImplicitAny: false +//@allowSyntheticDefaultImports: true +//@allowJs: true +//@jsx: react +//@outDir: "build" + +//@filename: react.d.ts +export = React; +export as namespace React; + +declare namespace React { + + function createClass(spec: any): ClassicComponentClass; + + interface ClassicComponentClass { + new (props?: any): ClassicComponentClass; + } +} + +declare global { + namespace JSX { + interface ElementAttributesProperty { } + } +} + + +//@filename: src/components/TabBar.js +export default React.createClass({ + render() { + return ( + null + ); + } +}); + +//@filename: src/modules/navigation/NavigationView.js +import TabBar from '../../components/TabBar'; +import {layout} from '../../utils/theme'; // <- DO NOT DROP this import +const x = ; From 16bdaaa0a6db70a3594d3e847545e6ce370ce620 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Wed, 25 Jan 2017 11:04:23 -0800 Subject: [PATCH 52/63] Fix positionToLineOffset conversion for getImplementation --- src/server/session.ts | 16 +++++++++------- .../goToImplementation_inDifferentFiles.ts | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+), 7 deletions(-) create mode 100644 tests/cases/fourslash/server/goToImplementation_inDifferentFiles.ts diff --git a/src/server/session.ts b/src/server/session.ts index 1fa3986f66f..825ad8506d7 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -484,18 +484,20 @@ namespace ts.server { private getImplementation(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.FileSpan[] | ImplementationLocation[] { const { file, project } = this.getFileAndProject(args); - const scriptInfo = project.getScriptInfoForNormalizedPath(file); - const position = this.getPosition(args, scriptInfo); + const position = this.getPosition(args, project.getScriptInfoForNormalizedPath(file)); const implementations = project.getLanguageService().getImplementationAtPosition(file, position); if (!implementations) { return []; } if (simplifiedResult) { - return implementations.map(impl => ({ - file: impl.fileName, - start: scriptInfo.positionToLineOffset(impl.textSpan.start), - end: scriptInfo.positionToLineOffset(ts.textSpanEnd(impl.textSpan)) - })); + return implementations.map(({ fileName, textSpan }) => { + const scriptInfo = project.getScriptInfo(fileName); + return { + file: fileName, + start: scriptInfo.positionToLineOffset(textSpan.start), + end: scriptInfo.positionToLineOffset(ts.textSpanEnd(textSpan)) + }; + }); } else { return implementations; diff --git a/tests/cases/fourslash/server/goToImplementation_inDifferentFiles.ts b/tests/cases/fourslash/server/goToImplementation_inDifferentFiles.ts new file mode 100644 index 00000000000..e4289b83102 --- /dev/null +++ b/tests/cases/fourslash/server/goToImplementation_inDifferentFiles.ts @@ -0,0 +1,19 @@ +/// + +// @Filename: /bar.ts +////import {Foo} from './foo' +//// +////[|class A implements Foo { +//// func() {} +////}|] +//// +////[|class B implements Foo { +//// func() {} +////}|] + +// @Filename: /foo.ts +////export interface /**/Foo { +//// func(); +////} + +verify.allRangesAppearInImplementationList(""); From 916e67a92c0c9d348ac74f8f3e78374d55964d78 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Wed, 25 Jan 2017 08:32:08 -0800 Subject: [PATCH 53/63] For goToDefinition, verify that tryGetSignatureDeclaration returns a signature declaration and not a FunctionType. --- src/services/goToDefinition.ts | 17 +++++++++++++++-- .../fourslash/goToDefinitionFunctionType.ts | 17 +++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 tests/cases/fourslash/goToDefinitionFunctionType.ts diff --git a/src/services/goToDefinition.ts b/src/services/goToDefinition.ts index ab35a17fcef..73cf06d31ef 100644 --- a/src/services/goToDefinition.ts +++ b/src/services/goToDefinition.ts @@ -187,7 +187,15 @@ namespace ts.GoToDefinition { } function isSignatureDeclaration(node: Node): boolean { - return node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature + switch (node.kind) { + case ts.SyntaxKind.Constructor: + case ts.SyntaxKind.FunctionDeclaration: + case ts.SyntaxKind.MethodDeclaration: + case ts.SyntaxKind.MethodSignature: + return true; + default: + return false; + } } /** Creates a DefinitionInfo from a Declaration, using the declaration's name if possible. */ @@ -254,6 +262,11 @@ namespace ts.GoToDefinition { function tryGetSignatureDeclaration(typeChecker: TypeChecker, node: Node): SignatureDeclaration | undefined { const callLike = getAncestorCallLikeExpression(node); - return callLike && typeChecker.getResolvedSignature(callLike).declaration; + const decl = callLike && typeChecker.getResolvedSignature(callLike).declaration; + if (decl && isSignatureDeclaration(decl)) { + return decl; + } + // Don't go to a function type, go to the value having that type. + return undefined; } } diff --git a/tests/cases/fourslash/goToDefinitionFunctionType.ts b/tests/cases/fourslash/goToDefinitionFunctionType.ts new file mode 100644 index 00000000000..1b50de3af6d --- /dev/null +++ b/tests/cases/fourslash/goToDefinitionFunctionType.ts @@ -0,0 +1,17 @@ +/// + +// Tests that goToDefinition does not go to a function type; it goes to the value. + +////const /*constDefinition*/c: () => void; +/////*constReference*/c(); +////function test(/*cbDefinition*/cb: () => void) { +//// /*cbReference*/cb(); +////} +////class C { +//// /*propDefinition*/prop: () => void; +//// m() { +//// this./*propReference*/prop(); +//// } +////} + +verify.goToDefinitionForMarkers("const", "cb", "prop"); From 97e964a08f242eb806962d9d53e1d92f7d764fc8 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Wed, 25 Jan 2017 14:15:06 -0800 Subject: [PATCH 54/63] Fix typo --- tests/cases/fourslash/findAllRefsForMappedType.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cases/fourslash/findAllRefsForMappedType.ts b/tests/cases/fourslash/findAllRefsForMappedType.ts index 620eae0815c..38fb3a226c6 100644 --- a/tests/cases/fourslash/findAllRefsForMappedType.ts +++ b/tests/cases/fourslash/findAllRefsForMappedType.ts @@ -1,7 +1,7 @@ /// ////interface T { [|a|]: number }; -////type U { [K in keyof T]: string }; +////type U = { [K in keyof T]: string }; ////type V = { [K in keyof U]: boolean }; ////const u: U = { [|a|]: "" } ////const v: V = { [|a|]: true } From 5bf9b30c5d596037a10bdf78213b711fac20efbf Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Thu, 26 Jan 2017 09:50:38 -0800 Subject: [PATCH 55/63] Replace `isSearchedFor` with directly passing `searchSymbols` --- src/services/findAllReferences.ts | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index df568f6df3e..28474839cf3 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -41,9 +41,6 @@ namespace ts.FindAllReferences { if (shorthandModuleSymbol) { searchSymbols.push(shorthandModuleSymbol); } - function isSearchedFor(symbol: Symbol): boolean { - return contains(searchSymbols, symbol); - } // Compute the meaning from the location and the symbol it references const searchMeaning = getIntersectingMeaningFromDeclarations(getMeaningFromLocation(node), declarations); @@ -80,7 +77,7 @@ namespace ts.FindAllReferences { function getRefs(scope: ts.Node, searchName: string): void { getReferencesInNode(scope, symbol, searchName, node, searchMeaning, findInStrings, findInComments, result, - symbolToIndex, implementations, typeChecker, cancellationToken, isSearchedFor, inheritsFromCache); + symbolToIndex, implementations, typeChecker, cancellationToken, searchSymbols, inheritsFromCache); } } @@ -456,7 +453,7 @@ namespace ts.FindAllReferences { implementations: boolean, typeChecker: TypeChecker, cancellationToken: CancellationToken, - isSearchedFor: (symbol: Symbol) => boolean, + searchSymbols: Symbol[], inheritsFromCache: Map): void { const sourceFile = container.getSourceFile(); @@ -502,7 +499,7 @@ namespace ts.FindAllReferences { if (referenceSymbol) { const referenceSymbolDeclaration = referenceSymbol.valueDeclaration; const shorthandValueSymbol = typeChecker.getShorthandAssignmentValueSymbol(referenceSymbolDeclaration); - const relatedSymbol = getRelatedSymbol(isSearchedFor, referenceSymbol, referenceLocation, + const relatedSymbol = getRelatedSymbol(searchSymbols, referenceSymbol, referenceLocation, /*searchLocationIsConstructor*/ searchLocation.kind === SyntaxKind.ConstructorKeyword, parents, inheritsFromCache, typeChecker); if (relatedSymbol) { @@ -514,7 +511,7 @@ namespace ts.FindAllReferences { * the position in short-hand property assignment excluding property accessing. However, if we do findAllReference at the * position of property accessing, the referenceEntry of such position will be handled in the first case. */ - else if (!(referenceSymbol.flags & SymbolFlags.Transient) && isSearchedFor(shorthandValueSymbol)) { + else if (!(referenceSymbol.flags & SymbolFlags.Transient) && contains(searchSymbols, shorthandValueSymbol)) { addReferenceToRelatedSymbol(referenceSymbolDeclaration.name, shorthandValueSymbol); } else if (searchLocation.kind === SyntaxKind.ConstructorKeyword) { @@ -1178,8 +1175,8 @@ namespace ts.FindAllReferences { } } - function getRelatedSymbol(isSearchedFor: (symbol: Symbol) => boolean, referenceSymbol: Symbol, referenceLocation: Node, searchLocationIsConstructor: boolean, parents: Symbol[] | undefined, cache: Map, typeChecker: TypeChecker): Symbol | undefined { - if (isSearchedFor(referenceSymbol)) { + function getRelatedSymbol(searchSymbols: Symbol[], referenceSymbol: Symbol, referenceLocation: Node, searchLocationIsConstructor: boolean, parents: Symbol[] | undefined, cache: Map, typeChecker: TypeChecker): Symbol | undefined { + if (contains(searchSymbols, referenceSymbol)) { // If we are searching for constructor uses, they must be 'new' expressions. return (!searchLocationIsConstructor || isNewExpressionTarget(referenceLocation)) ? referenceSymbol : undefined; } @@ -1188,7 +1185,7 @@ namespace ts.FindAllReferences { // symbols but by looking up for related symbol of this alias so it can handle multiple level of indirectness. const aliasSymbol = getAliasSymbolForPropertyNameSymbol(referenceSymbol, referenceLocation, typeChecker); if (aliasSymbol) { - return getRelatedSymbol(isSearchedFor, aliasSymbol, referenceLocation, searchLocationIsConstructor, parents, cache, typeChecker); + return getRelatedSymbol(searchSymbols, aliasSymbol, referenceLocation, searchLocationIsConstructor, parents, cache, typeChecker); } // If the reference location is in an object literal, try to get the contextual type for the @@ -1197,7 +1194,7 @@ namespace ts.FindAllReferences { const containingObjectLiteralElement = getContainingObjectLiteralElement(referenceLocation); if (containingObjectLiteralElement) { const contextualSymbol = forEach(getPropertySymbolsFromContextualType(containingObjectLiteralElement, typeChecker), contextualSymbol => - find(typeChecker.getRootSymbols(contextualSymbol), isSearchedFor)); + find(typeChecker.getRootSymbols(contextualSymbol), symbol => contains(searchSymbols, symbol))); if (contextualSymbol) { return contextualSymbol; @@ -1208,7 +1205,7 @@ namespace ts.FindAllReferences { // In below eg. get 'property' from type of elems iterating type // for ( { property: p2 } of elems) { } const propertySymbol = getPropertySymbolOfDestructuringAssignment(referenceLocation, typeChecker); - if (propertySymbol && isSearchedFor(propertySymbol)) { + if (propertySymbol && contains(searchSymbols, propertySymbol)) { return propertySymbol; } } @@ -1217,7 +1214,7 @@ namespace ts.FindAllReferences { // then include the binding element in the related symbols // let { a } : { a }; const bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName(referenceSymbol, typeChecker); - if (bindingElementPropertySymbol && isSearchedFor(bindingElementPropertySymbol)) { + if (bindingElementPropertySymbol && contains(searchSymbols, bindingElementPropertySymbol)) { return bindingElementPropertySymbol; } @@ -1225,7 +1222,7 @@ namespace ts.FindAllReferences { // Or a union property, use its underlying unioned symbols return forEach(typeChecker.getRootSymbols(referenceSymbol), rootSymbol => { // if it is in the list, then we are done - if (isSearchedFor(rootSymbol)) { + if (contains(searchSymbols, rootSymbol)) { return rootSymbol; } @@ -1242,7 +1239,7 @@ namespace ts.FindAllReferences { const result: Symbol[] = []; getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, /*previousIterationSymbolsCache*/ createMap(), typeChecker); - return find(result, isSearchedFor); + return find(result, symbol => contains(searchSymbols, symbol)); } return undefined; From 71d1a3f051c0990c07a510dc811dfc4be4b3b6d7 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Thu, 26 Jan 2017 11:38:50 -0800 Subject: [PATCH 56/63] property handle misspelled namepath in @typedef tag (#13702) --- src/compiler/parser.ts | 9 ++++++-- .../misspelledJsDocTypedefTags.symbols | 8 +++++++ .../misspelledJsDocTypedefTags.types | 22 +++++++++++++++++++ .../compiler/misspelledJsDocTypedefTags.ts | 9 ++++++++ 4 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/misspelledJsDocTypedefTags.symbols create mode 100644 tests/baselines/reference/misspelledJsDocTypedefTags.types create mode 100644 tests/cases/compiler/misspelledJsDocTypedefTags.ts diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index c795cab14a3..c5439aa051b 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -6693,10 +6693,15 @@ namespace ts { typedefTag.fullName = parseJSDocTypeNameWithNamespace(/*flags*/ 0); if (typedefTag.fullName) { let rightNode = typedefTag.fullName; - while (rightNode.kind !== SyntaxKind.Identifier) { + while (true) { + if (rightNode.kind === SyntaxKind.Identifier || !rightNode.body) { + // if node is identifier - use it as name + // otherwise use name of the rightmost part that we were able to parse + typedefTag.name = rightNode.kind === SyntaxKind.Identifier ? rightNode : rightNode.name; + break; + } rightNode = rightNode.body; } - typedefTag.name = rightNode; } typedefTag.typeExpression = typeExpression; skipWhitespace(); diff --git a/tests/baselines/reference/misspelledJsDocTypedefTags.symbols b/tests/baselines/reference/misspelledJsDocTypedefTags.symbols new file mode 100644 index 00000000000..bf3f6e7fab0 --- /dev/null +++ b/tests/baselines/reference/misspelledJsDocTypedefTags.symbols @@ -0,0 +1,8 @@ +=== tests/cases/compiler/a.js === + +No type information for this code./** @typedef {{ endTime: number, screenshots: number}} A.*/ +No type information for this code.Animation.AnimationModel.ScreenshotCapture.Request; +No type information for this code. +No type information for this code./** @typedef {{ endTime: number, screenshots: !B.}} */ +No type information for this code.Animation.AnimationModel.ScreenshotCapture.Request; +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/misspelledJsDocTypedefTags.types b/tests/baselines/reference/misspelledJsDocTypedefTags.types new file mode 100644 index 00000000000..70cc011ea69 --- /dev/null +++ b/tests/baselines/reference/misspelledJsDocTypedefTags.types @@ -0,0 +1,22 @@ +=== tests/cases/compiler/a.js === + +/** @typedef {{ endTime: number, screenshots: number}} A.*/ +Animation.AnimationModel.ScreenshotCapture.Request; +>Animation.AnimationModel.ScreenshotCapture.Request : any +>Animation.AnimationModel.ScreenshotCapture : any +>Animation.AnimationModel : any +>Animation : any +>AnimationModel : any +>ScreenshotCapture : any +>Request : any + +/** @typedef {{ endTime: number, screenshots: !B.}} */ +Animation.AnimationModel.ScreenshotCapture.Request; +>Animation.AnimationModel.ScreenshotCapture.Request : any +>Animation.AnimationModel.ScreenshotCapture : any +>Animation.AnimationModel : any +>Animation : any +>AnimationModel : any +>ScreenshotCapture : any +>Request : any + diff --git a/tests/cases/compiler/misspelledJsDocTypedefTags.ts b/tests/cases/compiler/misspelledJsDocTypedefTags.ts new file mode 100644 index 00000000000..3f3221020bd --- /dev/null +++ b/tests/cases/compiler/misspelledJsDocTypedefTags.ts @@ -0,0 +1,9 @@ +// @allowJs: true +// @noEmit: true + +// @filename: a.js +/** @typedef {{ endTime: number, screenshots: number}} A.*/ +Animation.AnimationModel.ScreenshotCapture.Request; + +/** @typedef {{ endTime: number, screenshots: !B.}} */ +Animation.AnimationModel.ScreenshotCapture.Request; \ No newline at end of file From cabcaaadcbd505f264dc396aad97cee427459171 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 26 Jan 2017 16:04:58 -0800 Subject: [PATCH 57/63] Property assignment is not an assignment target In a destructuring assignment, a property assignment is not an assignment target. Its initialiser is. For example: ```ts ({ source: target} = o); ``` Here, `target` is the assignment target. `source` is not. Previously, both were assignment targets. --- src/compiler/utilities.ts | 11 +++++--- ...ertyAssignmentNameIsNotAssignmentTarget.js | 17 +++++++++++++ ...ssignmentNameIsNotAssignmentTarget.symbols | 21 ++++++++++++++++ ...yAssignmentNameIsNotAssignmentTarget.types | 25 +++++++++++++++++++ ...ertyAssignmentNameIsNotAssignmentTarget.ts | 7 ++++++ 5 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 tests/baselines/reference/destructuringPropertyAssignmentNameIsNotAssignmentTarget.js create mode 100644 tests/baselines/reference/destructuringPropertyAssignmentNameIsNotAssignmentTarget.symbols create mode 100644 tests/baselines/reference/destructuringPropertyAssignmentNameIsNotAssignmentTarget.types create mode 100644 tests/cases/compiler/destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 5c63d8bb60c..17e9fe8e1d7 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1662,11 +1662,15 @@ namespace ts { node = parent; break; case SyntaxKind.ShorthandPropertyAssignment: - if ((parent).name !== node) { + if ((parent as ShorthandPropertyAssignment).name !== node) { return AssignmentKind.None; } - // Fall through + node = parent.parent; + break; case SyntaxKind.PropertyAssignment: + if ((parent as ShorthandPropertyAssignment).name === node) { + return AssignmentKind.None; + } node = parent.parent; break; default: @@ -1678,7 +1682,8 @@ namespace ts { // A node is an assignment target if it is on the left hand side of an '=' token, if it is parented by a property // assignment in an object literal that is an assignment target, or if it is parented by an array literal that is - // an assignment target. Examples include 'a = xxx', '{ p: a } = xxx', '[{ p: a}] = xxx'. + // an assignment target. Examples include 'a = xxx', '{ p: a } = xxx', '[{ a }] = xxx'. + // (Note that `p` is not a target in the above examples, only `a`.) export function isAssignmentTarget(node: Node): boolean { return getAssignmentTargetKind(node) !== AssignmentKind.None; } diff --git a/tests/baselines/reference/destructuringPropertyAssignmentNameIsNotAssignmentTarget.js b/tests/baselines/reference/destructuringPropertyAssignmentNameIsNotAssignmentTarget.js new file mode 100644 index 00000000000..b2ba970ef51 --- /dev/null +++ b/tests/baselines/reference/destructuringPropertyAssignmentNameIsNotAssignmentTarget.js @@ -0,0 +1,17 @@ +//// [destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts] +// test for #10668 +function qux(bar: { value: number }) { + let foo: number; + ({ value: foo } = bar); + let x = () => bar; +} + + + +//// [destructuringPropertyAssignmentNameIsNotAssignmentTarget.js] +// test for #10668 +function qux(bar) { + var foo; + (foo = bar.value); + var x = function () { return bar; }; +} diff --git a/tests/baselines/reference/destructuringPropertyAssignmentNameIsNotAssignmentTarget.symbols b/tests/baselines/reference/destructuringPropertyAssignmentNameIsNotAssignmentTarget.symbols new file mode 100644 index 00000000000..b9ebe219f65 --- /dev/null +++ b/tests/baselines/reference/destructuringPropertyAssignmentNameIsNotAssignmentTarget.symbols @@ -0,0 +1,21 @@ +=== tests/cases/compiler/destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts === +// test for #10668 +function qux(bar: { value: number }) { +>qux : Symbol(qux, Decl(destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts, 0, 0)) +>bar : Symbol(bar, Decl(destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts, 1, 13)) +>value : Symbol(value, Decl(destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts, 1, 19)) + + let foo: number; +>foo : Symbol(foo, Decl(destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts, 2, 7)) + + ({ value: foo } = bar); +>value : Symbol(value, Decl(destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts, 3, 6)) +>foo : Symbol(foo, Decl(destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts, 2, 7)) +>bar : Symbol(bar, Decl(destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts, 1, 13)) + + let x = () => bar; +>x : Symbol(x, Decl(destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts, 4, 7)) +>bar : Symbol(bar, Decl(destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts, 1, 13)) +} + + diff --git a/tests/baselines/reference/destructuringPropertyAssignmentNameIsNotAssignmentTarget.types b/tests/baselines/reference/destructuringPropertyAssignmentNameIsNotAssignmentTarget.types new file mode 100644 index 00000000000..e0428fc959f --- /dev/null +++ b/tests/baselines/reference/destructuringPropertyAssignmentNameIsNotAssignmentTarget.types @@ -0,0 +1,25 @@ +=== tests/cases/compiler/destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts === +// test for #10668 +function qux(bar: { value: number }) { +>qux : (bar: { value: number; }) => void +>bar : { value: number; } +>value : number + + let foo: number; +>foo : number + + ({ value: foo } = bar); +>({ value: foo } = bar) : { value: number; } +>{ value: foo } = bar : { value: number; } +>{ value: foo } : { value: number; } +>value : number +>foo : number +>bar : { value: number; } + + let x = () => bar; +>x : () => { value: number; } +>() => bar : () => { value: number; } +>bar : { value: number; } +} + + diff --git a/tests/cases/compiler/destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts b/tests/cases/compiler/destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts new file mode 100644 index 00000000000..c0002f3e80a --- /dev/null +++ b/tests/cases/compiler/destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts @@ -0,0 +1,7 @@ +// test for #10668 +function qux(bar: { value: number }) { + let foo: number; + ({ value: foo } = bar); + let x = () => bar; +} + From 4d67b0c2b6f4cb99b74db702eda6eb62c1cda7f4 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 27 Jan 2017 09:53:57 -0800 Subject: [PATCH 58/63] Allow super to access method signatures Previously, super was only allowed to access method *declarations*. But method signatures can come from interfaces that merge with classes, and should also be accessible as methods on super. --- src/compiler/checker.ts | 13 ++++--- .../superHasMethodsFromMergedInterface.js | 37 +++++++++++++++++++ ...superHasMethodsFromMergedInterface.symbols | 23 ++++++++++++ .../superHasMethodsFromMergedInterface.types | 24 ++++++++++++ .../superHasMethodsFromMergedInterface.ts | 7 ++++ 5 files changed, 99 insertions(+), 5 deletions(-) create mode 100644 tests/baselines/reference/superHasMethodsFromMergedInterface.js create mode 100644 tests/baselines/reference/superHasMethodsFromMergedInterface.symbols create mode 100644 tests/baselines/reference/superHasMethodsFromMergedInterface.types create mode 100644 tests/cases/compiler/superHasMethodsFromMergedInterface.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7c8a0b7337f..7d0f2cb0bbb 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12337,12 +12337,15 @@ namespace ts { // - 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 (languageVersion < ScriptTarget.ES2015 && getDeclarationKindFromSymbol(prop) !== SyntaxKind.MethodDeclaration) { - // `prop` refers to a *property* declared in the super class - // rather than a *method*, so it does not satisfy the above criteria. + if (languageVersion < ScriptTarget.ES2015) { + const propKind = getDeclarationKindFromSymbol(prop); + if (propKind !== SyntaxKind.MethodDeclaration && propKind !== SyntaxKind.MethodSignature) { + // `prop` refers to a *property* declared in the super class + // rather than a *method*, so it does not satisfy the above criteria. - error(errorNode, Diagnostics.Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword); - return false; + error(errorNode, Diagnostics.Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword); + return false; + } } if (flags & ModifierFlags.Abstract) { diff --git a/tests/baselines/reference/superHasMethodsFromMergedInterface.js b/tests/baselines/reference/superHasMethodsFromMergedInterface.js new file mode 100644 index 00000000000..e7086106210 --- /dev/null +++ b/tests/baselines/reference/superHasMethodsFromMergedInterface.js @@ -0,0 +1,37 @@ +//// [superHasMethodsFromMergedInterface.ts] +class C { m1() { } } +interface C { m2(): void } +class Sub extends C { + m3() { + super.m2(); + } +} + + +//// [superHasMethodsFromMergedInterface.js] +var __extends = (this && this.__extends) || (function () { + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var C = (function () { + function C() { + } + C.prototype.m1 = function () { }; + return C; +}()); +var Sub = (function (_super) { + __extends(Sub, _super); + function Sub() { + return _super !== null && _super.apply(this, arguments) || this; + } + Sub.prototype.m3 = function () { + _super.prototype.m2.call(this); + }; + return Sub; +}(C)); diff --git a/tests/baselines/reference/superHasMethodsFromMergedInterface.symbols b/tests/baselines/reference/superHasMethodsFromMergedInterface.symbols new file mode 100644 index 00000000000..ec0af8064ed --- /dev/null +++ b/tests/baselines/reference/superHasMethodsFromMergedInterface.symbols @@ -0,0 +1,23 @@ +=== tests/cases/compiler/superHasMethodsFromMergedInterface.ts === +class C { m1() { } } +>C : Symbol(C, Decl(superHasMethodsFromMergedInterface.ts, 0, 0), Decl(superHasMethodsFromMergedInterface.ts, 0, 20)) +>m1 : Symbol(C.m1, Decl(superHasMethodsFromMergedInterface.ts, 0, 9)) + +interface C { m2(): void } +>C : Symbol(C, Decl(superHasMethodsFromMergedInterface.ts, 0, 0), Decl(superHasMethodsFromMergedInterface.ts, 0, 20)) +>m2 : Symbol(C.m2, Decl(superHasMethodsFromMergedInterface.ts, 1, 13)) + +class Sub extends C { +>Sub : Symbol(Sub, Decl(superHasMethodsFromMergedInterface.ts, 1, 26)) +>C : Symbol(C, Decl(superHasMethodsFromMergedInterface.ts, 0, 0), Decl(superHasMethodsFromMergedInterface.ts, 0, 20)) + + m3() { +>m3 : Symbol(Sub.m3, Decl(superHasMethodsFromMergedInterface.ts, 2, 21)) + + super.m2(); +>super.m2 : Symbol(C.m2, Decl(superHasMethodsFromMergedInterface.ts, 1, 13)) +>super : Symbol(C, Decl(superHasMethodsFromMergedInterface.ts, 0, 0), Decl(superHasMethodsFromMergedInterface.ts, 0, 20)) +>m2 : Symbol(C.m2, Decl(superHasMethodsFromMergedInterface.ts, 1, 13)) + } +} + diff --git a/tests/baselines/reference/superHasMethodsFromMergedInterface.types b/tests/baselines/reference/superHasMethodsFromMergedInterface.types new file mode 100644 index 00000000000..7f314d90bed --- /dev/null +++ b/tests/baselines/reference/superHasMethodsFromMergedInterface.types @@ -0,0 +1,24 @@ +=== tests/cases/compiler/superHasMethodsFromMergedInterface.ts === +class C { m1() { } } +>C : C +>m1 : () => void + +interface C { m2(): void } +>C : C +>m2 : () => void + +class Sub extends C { +>Sub : Sub +>C : C + + m3() { +>m3 : () => void + + super.m2(); +>super.m2() : void +>super.m2 : () => void +>super : C +>m2 : () => void + } +} + diff --git a/tests/cases/compiler/superHasMethodsFromMergedInterface.ts b/tests/cases/compiler/superHasMethodsFromMergedInterface.ts new file mode 100644 index 00000000000..cdca6ae65bf --- /dev/null +++ b/tests/cases/compiler/superHasMethodsFromMergedInterface.ts @@ -0,0 +1,7 @@ +class C { m1() { } } +interface C { m2(): void } +class Sub extends C { + m3() { + super.m2(); + } +} From 5282a8d0f5c1ddcf104eb44b36923f7f8d26a240 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 30 Jan 2017 08:55:32 -0800 Subject: [PATCH 59/63] ES6 target uses Object.assign for emitting spread Also omits the __assign helper --- src/compiler/transformers/esnext.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 0a529a8e871..ee92ec7c613 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -402,6 +402,11 @@ namespace ts { }; export function createAssignHelper(context: TransformationContext, attributesSegments: Expression[]) { + if (context.getCompilerOptions().target === ScriptTarget.ES2015) { + return createCall(createPropertyAccess(createIdentifier("Object"), "assign"), + /*typeArguments*/ undefined, + attributesSegments); + } context.requestEmitHelper(assignHelper); return createCall( getHelperName("__assign"), From a67a7493317d2ceff8037a0da5f1cebb356e2960 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 30 Jan 2017 10:42:11 -0800 Subject: [PATCH 60/63] Emit Object.assign for spread for targets >= ES6 --- src/compiler/transformers/esnext.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index ee92ec7c613..8b5a095a17e 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -402,7 +402,7 @@ namespace ts { }; export function createAssignHelper(context: TransformationContext, attributesSegments: Expression[]) { - if (context.getCompilerOptions().target === ScriptTarget.ES2015) { + if (context.getCompilerOptions().target >= ScriptTarget.ES2015) { return createCall(createPropertyAccess(createIdentifier("Object"), "assign"), /*typeArguments*/ undefined, attributesSegments); From 46cdac1ec73a58fd8b0350e517d314395b9f0f0e Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 30 Jan 2017 10:42:39 -0800 Subject: [PATCH 61/63] Update baselines --- tests/baselines/reference/objectRest2.js | 10 +--------- tests/baselines/reference/objectRestForOf.js | 10 +--------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/tests/baselines/reference/objectRest2.js b/tests/baselines/reference/objectRest2.js index 6abff9e56a1..e46d22db80a 100644 --- a/tests/baselines/reference/objectRest2.js +++ b/tests/baselines/reference/objectRest2.js @@ -15,14 +15,6 @@ rootConnection('test'); //// [objectRest2.js] -var __assign = (this && this.__assign) || Object.assign || function(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) - t[p] = s[p]; - } - return t; -}; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } @@ -35,7 +27,7 @@ function rootConnection(name) { return { resolve: (context, args) => __awaiter(this, void 0, void 0, function* () { const { objects } = yield { objects: 12 }; - return __assign({}, connectionFromArray(objects, args)); + return Object.assign({}, connectionFromArray(objects, args)); }) }; } diff --git a/tests/baselines/reference/objectRestForOf.js b/tests/baselines/reference/objectRestForOf.js index fd81f77512e..f8a88fe2868 100644 --- a/tests/baselines/reference/objectRestForOf.js +++ b/tests/baselines/reference/objectRestForOf.js @@ -15,14 +15,6 @@ for (const norest of array.map(a => ({ ...a, x: 'a string' }))) { //// [objectRestForOf.js] -var __assign = (this && this.__assign) || Object.assign || function(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) - t[p] = s[p]; - } - return t; -}; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) @@ -43,6 +35,6 @@ for (let _b of array) { ({ x: xx } = _b, rrestOff = __rest(_b, ["x"])); [xx, rrestOff]; } -for (const norest of array.map(a => (__assign({}, a, { x: 'a string' })))) { +for (const norest of array.map(a => (Object.assign({}, a, { x: 'a string' })))) { [norest.x, norest.y]; } From cca68adf877f5c91fcb8dd00842e985cecfdaa63 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 30 Jan 2017 12:42:19 -0800 Subject: [PATCH 62/63] Import helpers skips __assign when target >= ES6 Instead, Object.assign is emitted. --- src/compiler/checker.ts | 2 +- tests/baselines/reference/importHelpersES6.js | 6 +++++- .../baselines/reference/importHelpersES6.symbols | 13 ++++++++----- tests/baselines/reference/importHelpersES6.types | 16 +++++++++++----- tests/cases/compiler/importHelpersES6.ts | 4 +++- 5 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7d0f2cb0bbb..95dff83cd94 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11721,7 +11721,7 @@ namespace ts { member = prop; } else if (memberDecl.kind === SyntaxKind.SpreadAssignment) { - if (languageVersion < ScriptTarget.ESNext) { + if (languageVersion < ScriptTarget.ES2015) { checkExternalEmitHelpers(memberDecl, ExternalEmitHelpers.Assign); } if (propertiesArray.length > 0) { diff --git a/tests/baselines/reference/importHelpersES6.js b/tests/baselines/reference/importHelpersES6.js index 209f3c34588..bc17939e2cc 100644 --- a/tests/baselines/reference/importHelpersES6.js +++ b/tests/baselines/reference/importHelpersES6.js @@ -5,10 +5,12 @@ declare var dec: any; @dec export class A { } + +const o = { a: 1 }; +const y = { ...o }; //// [tslib.d.ts] export declare function __extends(d: Function, b: Function): void; -export declare function __assign(t: any, ...sources: any[]): any; export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any; export declare function __param(paramIndex: number, decorator: Function): Function; export declare function __metadata(metadataKey: any, metadataValue: any): Function; @@ -23,3 +25,5 @@ A = tslib_1.__decorate([ dec ], A); export { A }; +const o = { a: 1 }; +const y = Object.assign({}, o); diff --git a/tests/baselines/reference/importHelpersES6.symbols b/tests/baselines/reference/importHelpersES6.symbols index 284a2251a6b..66a8b131aec 100644 --- a/tests/baselines/reference/importHelpersES6.symbols +++ b/tests/baselines/reference/importHelpersES6.symbols @@ -8,6 +8,14 @@ declare var dec: any; } +const o = { a: 1 }; +>o : Symbol(o, Decl(a.ts, 5, 5)) +>a : Symbol(a, Decl(a.ts, 5, 11)) + +const y = { ...o }; +>y : Symbol(y, Decl(a.ts, 6, 5)) +>o : Symbol(o, Decl(a.ts, 5, 5)) + === tests/cases/compiler/tslib.d.ts === export declare function __extends(d: Function, b: Function): void; >__extends : Symbol(__extends, Decl(tslib.d.ts, --, --)) @@ -16,11 +24,6 @@ export declare function __extends(d: Function, b: Function): void; >b : Symbol(b, Decl(tslib.d.ts, --, --)) >Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) -export declare function __assign(t: any, ...sources: any[]): any; ->__assign : Symbol(__assign, Decl(tslib.d.ts, --, --)) ->t : Symbol(t, Decl(tslib.d.ts, --, --)) ->sources : Symbol(sources, Decl(tslib.d.ts, --, --)) - export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any; >__decorate : Symbol(__decorate, Decl(tslib.d.ts, --, --)) >decorators : Symbol(decorators, Decl(tslib.d.ts, --, --)) diff --git a/tests/baselines/reference/importHelpersES6.types b/tests/baselines/reference/importHelpersES6.types index ebfd5a5a2a5..26f30e32e58 100644 --- a/tests/baselines/reference/importHelpersES6.types +++ b/tests/baselines/reference/importHelpersES6.types @@ -8,6 +8,17 @@ declare var dec: any; } +const o = { a: 1 }; +>o : { a: number; } +>{ a: 1 } : { a: number; } +>a : number +>1 : 1 + +const y = { ...o }; +>y : { a: number; } +>{ ...o } : { a: number; } +>o : { a: number; } + === tests/cases/compiler/tslib.d.ts === export declare function __extends(d: Function, b: Function): void; >__extends : (d: Function, b: Function) => void @@ -16,11 +27,6 @@ export declare function __extends(d: Function, b: Function): void; >b : Function >Function : Function -export declare function __assign(t: any, ...sources: any[]): any; ->__assign : (t: any, ...sources: any[]) => any ->t : any ->sources : any[] - export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any; >__decorate : (decorators: Function[], target: any, key?: string | symbol, desc?: any) => any >decorators : Function[] diff --git a/tests/cases/compiler/importHelpersES6.ts b/tests/cases/compiler/importHelpersES6.ts index 9be680a88d6..0267156cf7e 100644 --- a/tests/cases/compiler/importHelpersES6.ts +++ b/tests/cases/compiler/importHelpersES6.ts @@ -7,9 +7,11 @@ declare var dec: any; } +const o = { a: 1 }; +const y = { ...o }; + // @filename: tslib.d.ts export declare function __extends(d: Function, b: Function): void; -export declare function __assign(t: any, ...sources: any[]): any; export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any; export declare function __param(paramIndex: number, decorator: Function): Function; export declare function __metadata(metadataKey: any, metadataValue: any): Function; From 9b6f9305d99ed4424ac473f85955a9b10314d805 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Mon, 30 Jan 2017 13:19:44 -0800 Subject: [PATCH 63/63] support untyped imports in shims (#13758) --- src/services/shims.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/services/shims.ts b/src/services/shims.ts index cf6bceb816c..487947ee458 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -385,7 +385,10 @@ namespace ts { if (settingsJson == null || settingsJson == "") { throw Error("LanguageServiceShimHostAdapter.getCompilationSettings: empty compilationSettings"); } - return JSON.parse(settingsJson); + const compilerOptions = JSON.parse(settingsJson); + // permit language service to handle all files (filtering should be performed on the host side) + compilerOptions.allowNonTsExtensions = true; + return compilerOptions; } public getScriptFileNames(): string[] { @@ -1061,12 +1064,6 @@ namespace ts { const compilerOptions = JSON.parse(compilerOptionsJson); const result = resolveModuleName(moduleName, normalizeSlashes(fileName), compilerOptions, this.host); const resolvedFileName = result.resolvedModule ? result.resolvedModule.resolvedFileName : undefined; - if (resolvedFileName && !compilerOptions.allowJs && fileExtensionIs(resolvedFileName, ".js")) { - return { - resolvedFileName: undefined, - failedLookupLocations: [] - }; - } return { resolvedFileName, failedLookupLocations: result.failedLookupLocations