From d0282b75a112a211b7f5d92c62ebf0720bf9c16a Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 13 Jun 2019 14:22:37 -0700 Subject: [PATCH 001/140] Add test to verify when source changes --- .../unittests/tsserver/projectReferences.ts | 75 ++++++++++++++++++- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/src/testRunner/unittests/tsserver/projectReferences.ts b/src/testRunner/unittests/tsserver/projectReferences.ts index 1b2e90bcd4f..eb3d83e2b98 100644 --- a/src/testRunner/unittests/tsserver/projectReferences.ts +++ b/src/testRunner/unittests/tsserver/projectReferences.ts @@ -169,6 +169,8 @@ fn5(); expectedResponse: Response; expectedResponseNoMap?: Response; expectedResponseNoDts?: Response; + requestDependencyChange?: Partial; + expectedResponseDependencyChange: Response; } function gotoDefintinionFromMainTs(fn: number): SessionAction { const textSpan = usageSpan(fn); @@ -200,6 +202,11 @@ fn5(); // To import declaration definitions: [{ file: mainTs.path, ...importSpan(fn) }], textSpan + }, + expectedResponseDependencyChange: { + // Definition on fn + 1 line + definitions: [{ file: dependencyTs.path, ...declarationSpan(fn + 1) }], + textSpan } }; } @@ -227,6 +234,8 @@ fn5(); function renameFromDependencyTs(fn: number): SessionAction { const defSpan = declarationSpan(fn); const { contextStart: _, contextEnd: _1, ...triggerSpan } = defSpan; + const defSpanPlusOne = declarationSpan(fn + 1); + const { contextStart: _2, contextEnd: _3, ...triggerSpanPlusOne } = defSpanPlusOne; return { reqName: "rename", request: { @@ -246,12 +255,30 @@ fn5(); locs: [ { file: dependencyTs.path, locs: [defSpan] } ] + }, + requestDependencyChange: { + command: protocol.CommandTypes.Rename, + arguments: { file: dependencyTs.path, ...triggerSpanPlusOne.start } + }, + expectedResponseDependencyChange: { + info: { + canRename: true, + fileToRename: undefined, + displayName: `fn${fn}`, + fullDisplayName: `"${dependecyLocation}/FnS".fn${fn}`, + kind: ScriptElementKind.functionElement, + kindModifiers: "export", + triggerSpan: triggerSpanPlusOne + }, + locs: [ + { file: dependencyTs.path, locs: [defSpanPlusOne] } + ] } }; } function renameFromDependencyTsWithBothProjectsOpen(fn: number): SessionAction { - const { reqName, request, expectedResponse } = renameFromDependencyTs(fn); + const { reqName, request, expectedResponse, expectedResponseDependencyChange, requestDependencyChange } = renameFromDependencyTs(fn); const { info, locs } = expectedResponse; return { reqName, @@ -271,7 +298,21 @@ fn5(); }, // Only dependency result expectedResponseNoMap: expectedResponse, - expectedResponseNoDts: expectedResponse + expectedResponseNoDts: expectedResponse, + requestDependencyChange, + expectedResponseDependencyChange: { + info: expectedResponseDependencyChange.info, + locs: [ + expectedResponseDependencyChange.locs[0], + { + file: mainTs.path, + locs: [ + importSpan(fn), + usageSpan(fn) + ] + } + ] + } }; } @@ -633,6 +674,36 @@ fn5(); verifyMainScenarioAndScriptInfoCollectionWithNoDts, /*noDts*/ true ); + + it("when defining project source changes", () => { + const { host, session } = openTsFile(); + + // First action + firstAction(session); + + // Make change, without rebuild of solution + if (contains(openInfos, dependencyTs.path)) { + session.executeCommandSeq({ + command: protocol.CommandTypes.Change, + arguments: { + file: dependencyTs.path, line: 1, offset: 1, endLine: 1, endOffset: 1, insertString: `function fooBar() { } +`} + }); + } + else { + host.writeFile(dependencyTs.path, `function fooBar() { } +${dependencyTs.content}`); + } + host.runQueuedTimeoutCallbacks(); + + for (const actionGetter of actionGetters) { + for (let fn = 1; fn <= 5; fn++) { + const { reqName, request, requestDependencyChange, expectedResponseDependencyChange } = actionGetter(fn); + const { response } = session.executeCommandSeq(requestDependencyChange || request); + assert.deepEqual(response, expectedResponseDependencyChange, `Failed on ${reqName}`); + } + } + }); } const usageVerifier: DocumentPositionMapperVerifier = { From 0adab8934aad26fb3a5883b64f1198943700c0f2 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 21 Jun 2019 13:11:39 -0700 Subject: [PATCH 002/140] Use source files instead of .d.ts files from project references --- src/compiler/program.ts | 86 +++++++++++++++---- src/compiler/types.ts | 9 ++ src/server/editorServices.ts | 4 +- src/server/project.ts | 26 ++++++ src/services/services.ts | 6 ++ src/services/types.ts | 4 + .../reference/api/tsserverlibrary.d.ts | 2 + 7 files changed, 119 insertions(+), 18 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 2b62da72d24..27bd1fd3d3b 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -813,6 +813,8 @@ namespace ts { let resolvedProjectReferences: ReadonlyArray | undefined; let projectReferenceRedirects: Map | undefined; let mapFromFileToProjectReferenceRedirects: Map | undefined; + let mapFromToProjectReferenceRedirectSource: Map | undefined; + const useSourceOfReference = host.useSourceInsteadOfReferenceRedirect && host.useSourceInsteadOfReferenceRedirect(); const shouldCreateNewSourceFile = shouldProgramCreateNewSourceFiles(oldProgram, options); const structuralIsReused = tryReuseStructureFromOldProgram(); @@ -824,17 +826,29 @@ namespace ts { if (!resolvedProjectReferences) { resolvedProjectReferences = projectReferences.map(parseProjectReferenceConfigFile); } + if (host.setGetSourceOfProjectReferenceRedirect) { + host.setGetSourceOfProjectReferenceRedirect(getSourceOfProjectReferenceRedirect); + } if (rootNames.length) { for (const parsedRef of resolvedProjectReferences) { if (!parsedRef) continue; const out = parsedRef.commandLine.options.outFile || parsedRef.commandLine.options.out; - if (out) { - processSourceFile(changeExtension(out, ".d.ts"), /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined); + if (useSourceOfReference) { + if (out || getEmitModuleKind(parsedRef.commandLine.options) === ModuleKind.None) { + for (const fileName of parsedRef.commandLine.fileNames) { + processSourceFile(fileName, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined); + } + } } - else if (getEmitModuleKind(parsedRef.commandLine.options) === ModuleKind.None) { - for (const fileName of parsedRef.commandLine.fileNames) { - if (!fileExtensionIs(fileName, Extension.Dts) && hasTSFileExtension(fileName)) { - processSourceFile(getOutputDeclarationFileName(fileName, parsedRef.commandLine, !host.useCaseSensitiveFileNames()), /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined); + else { + if (out) { + processSourceFile(changeExtension(out, ".d.ts"), /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined); + } + else if (getEmitModuleKind(parsedRef.commandLine.options) === ModuleKind.None) { + for (const fileName of parsedRef.commandLine.fileNames) { + if (!fileExtensionIs(fileName, Extension.Dts) && hasTSFileExtension(fileName)) { + processSourceFile(getOutputDeclarationFileName(fileName, parsedRef.commandLine, !host.useCaseSensitiveFileNames()), /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined); + } } } } @@ -1212,6 +1226,9 @@ namespace ts { } if (projectReferences) { resolvedProjectReferences = projectReferences.map(parseProjectReferenceConfigFile); + if (host.setGetSourceOfProjectReferenceRedirect) { + host.setGetSourceOfProjectReferenceRedirect(getSourceOfProjectReferenceRedirect); + } } // check if program source files has changed in the way that can affect structure of the program @@ -2220,6 +2237,14 @@ namespace ts { // Get source file from normalized fileName function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, refFile: SourceFile, refPos: number, refEnd: number, packageId: PackageId | undefined): SourceFile | undefined { + if (useSourceOfReference) { + const source = getSourceOfProjectReferenceRedirect(fileName); + if (source) { + return isString(source) ? + findSourceFile(source, toPath(source), isDefaultLib, ignoreNoDefaultLib, refFile, refPos, refEnd, packageId) : + undefined; + } + } const originalFileName = fileName; if (filesByName.has(path)) { const file = filesByName.get(path); @@ -2267,7 +2292,7 @@ namespace ts { } let redirectedPath: Path | undefined; - if (refFile) { + if (refFile && !useSourceOfReference) { const redirectProject = getProjectReferenceRedirectProject(fileName); if (redirectProject) { if (redirectProject.commandLine.options.outFile || redirectProject.commandLine.options.out) { @@ -2286,15 +2311,20 @@ namespace ts { } // We haven't looked for this file, do so now and cache result - const file = host.getSourceFile(fileName, options.target!, hostErrorMessage => { // TODO: GH#18217 - if (refFile !== undefined && refPos !== undefined && refEnd !== undefined) { - fileProcessingDiagnostics.add(createFileDiagnostic(refFile, refPos, refEnd - refPos, - Diagnostics.Cannot_read_file_0_Colon_1, fileName, hostErrorMessage)); - } - else { - fileProcessingDiagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, fileName, hostErrorMessage)); - } - }, shouldCreateNewSourceFile); + const file = host.getSourceFile( + fileName, + options.target!, + hostErrorMessage => { // TODO: GH#18217 + if (refFile !== undefined && refPos !== undefined && refEnd !== undefined) { + fileProcessingDiagnostics.add(createFileDiagnostic(refFile, refPos, refEnd - refPos, + Diagnostics.Cannot_read_file_0_Colon_1, fileName, hostErrorMessage)); + } + else { + fileProcessingDiagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, fileName, hostErrorMessage)); + } + }, + shouldCreateNewSourceFile + ); if (packageId) { const packageIdKey = packageIdToString(packageId); @@ -2424,6 +2454,30 @@ namespace ts { }); } + function getSourceOfProjectReferenceRedirect(file: string) { + if (!isDeclarationFileName(file)) return undefined; + if (mapFromToProjectReferenceRedirectSource === undefined) { + mapFromToProjectReferenceRedirectSource = createMap(); + forEachResolvedProjectReference(resolvedRef => { + if (resolvedRef) { + const out = resolvedRef.commandLine.options.outFile || resolvedRef.commandLine.options.out; + if (out) { + // Dont know which source file it means so return true? + const outputDts = changeExtension(out, Extension.Dts); + mapFromToProjectReferenceRedirectSource!.set(toPath(outputDts), true); + } + else { + forEach(resolvedRef.commandLine.fileNames, fileName => { + const outputDts = getOutputDeclarationFileName(fileName, resolvedRef.commandLine, host.useCaseSensitiveFileNames()); + mapFromToProjectReferenceRedirectSource!.set(toPath(outputDts), fileName); + }); + } + } + }); + } + return mapFromToProjectReferenceRedirectSource.get(toPath(file)); + } + function forEachProjectReference( projectReferences: ReadonlyArray | undefined, resolvedProjectReferences: ReadonlyArray | undefined, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ec46da039d9..fc24088e0fa 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5166,11 +5166,20 @@ namespace ts { /* @internal */ hasChangedAutomaticTypeDirectiveNames?: boolean; createHash?(data: string): string; getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined; + /* @internal */ setGetSourceOfProjectReferenceRedirect?(getSource: GetSourceOfProjectReferenceRedirect): void; + /* @internal */ useSourceInsteadOfReferenceRedirect?(): boolean; // TODO: later handle this in better way in builder host instead once the api for tsbuild finalizes and doesn't use compilerHost as base /*@internal*/createDirectory?(directory: string): void; } + /** true if --out otherwise source file name */ + /*@internal*/ + export type SourceOfProjectReferenceRedirect = string | true ; + + /*@internal*/ + export type GetSourceOfProjectReferenceRedirect = (fileName: string) => SourceOfProjectReferenceRedirect | undefined; + /* @internal */ export const enum TransformFlags { None = 0, diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 4e5435feaba..f7fb537f543 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -1798,7 +1798,7 @@ namespace ts.server { let scriptInfo: ScriptInfo | NormalizedPath; let path: Path; // Use the project's fileExists so that it can use caching instead of reaching to disk for the query - if (!isDynamic && !project.fileExists(newRootFile)) { + if (!isDynamic && !project.fileExistsWithCache(newRootFile)) { path = normalizedPathToPath(normalizedPath, this.currentDirectory, this.toCanonicalFileName); const existingValue = projectRootFilesMap.get(path)!; if (isScriptInfo(existingValue)) { @@ -1831,7 +1831,7 @@ namespace ts.server { projectRootFilesMap.forEach((value, path) => { if (!newRootScriptInfoMap.has(path)) { if (isScriptInfo(value)) { - project.removeFile(value, project.fileExists(path), /*detachFromProject*/ true); + project.removeFile(value, project.fileExistsWithCache(path), /*detachFromProject*/ true); } else { projectRootFilesMap.delete(path); diff --git a/src/server/project.ts b/src/server/project.ts index d1605e22d1d..3e69a785516 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -381,6 +381,11 @@ namespace ts.server { } fileExists(file: string): boolean { + return this.fileExistsWithCache(file); + } + + /* @internal */ + fileExistsWithCache(file: string): boolean { // As an optimization, don't hit the disks for files we already know don't exist // (because we're watching for their creation). const path = this.toPath(file); @@ -1369,6 +1374,7 @@ namespace ts.server { configFileWatcher: FileWatcher | undefined; private directoriesWatchedForWildcards: Map | undefined; readonly canonicalConfigFilePath: NormalizedPath; + private getSourceOfProjectReferenceRedirect: GetSourceOfProjectReferenceRedirect | undefined; /* @internal */ pendingReload: ConfigFileProgramReloadLevel | undefined; @@ -1414,6 +1420,25 @@ namespace ts.server { this.canonicalConfigFilePath = asNormalizedPath(projectService.toCanonicalFileName(configFileName)); } + /* @internal */ + setGetSourceOfProjectReferenceRedirect(getSource: GetSourceOfProjectReferenceRedirect) { + this.getSourceOfProjectReferenceRedirect = getSource; + } + + /* @internal */ + useSourceInsteadOfReferenceRedirect() { + return true; + } + + fileExists(file: string): boolean { + // Project references go to source file instead of .d.ts file + if (this.getSourceOfProjectReferenceRedirect) { + const source = this.getSourceOfProjectReferenceRedirect(file); + if (source) return isString(source) ? super.fileExists(source) : true; + } + return super.fileExists(file); + } + /** * If the project has reload from disk pending, it reloads (and then updates graph as part of that) instead of just updating the graph * @returns: true if set of files in the project stays the same and false - otherwise. @@ -1436,6 +1461,7 @@ namespace ts.server { default: result = super.updateGraph(); } + this.getSourceOfProjectReferenceRedirect = undefined; this.projectService.sendProjectLoadingFinishEvent(this); this.projectService.sendProjectTelemetry(this); return result; diff --git a/src/services/services.ts b/src/services/services.ts index fab6f88b779..a8b05402e76 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1245,6 +1245,12 @@ namespace ts { return host.resolveTypeReferenceDirectives!(typeReferenceDirectiveNames, containingFile, redirectedReference); }; } + if (host.setGetSourceOfProjectReferenceRedirect) { + compilerHost.setGetSourceOfProjectReferenceRedirect = getSource => host.setGetSourceOfProjectReferenceRedirect!(getSource); + } + if (host.useSourceInsteadOfReferenceRedirect) { + compilerHost.useSourceInsteadOfReferenceRedirect = () => host.useSourceInsteadOfReferenceRedirect!(); + } const documentRegistryBucketKey = documentRegistry.getKeyForCompilationSettings(newSettings); const options: CreateProgramOptions = { diff --git a/src/services/types.ts b/src/services/types.ts index b97125734f7..3c9509ca5e9 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -236,6 +236,10 @@ namespace ts { getDocumentPositionMapper?(generatedFileName: string, sourceFileName?: string): DocumentPositionMapper | undefined; /* @internal */ getSourceFileLike?(fileName: string): SourceFileLike | undefined; + /* @internal */ + setGetSourceOfProjectReferenceRedirect?(getSource: GetSourceOfProjectReferenceRedirect): void; + /* @internal */ + useSourceInsteadOfReferenceRedirect?(): boolean; } /* @internal */ diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 82ab70b6e6f..53459d993cf 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -8546,11 +8546,13 @@ declare namespace ts.server { private typeAcquisition; private directoriesWatchedForWildcards; readonly canonicalConfigFilePath: NormalizedPath; + private getSourceOfProjectReferenceRedirect; /** Ref count to the project when opened from external project */ private externalProjectRefCount; private projectErrors; private projectReferences; protected isInitialLoadPending: () => boolean; + fileExists(file: string): boolean; /** * If the project has reload from disk pending, it reloads (and then updates graph as part of that) instead of just updating the graph * @returns: true if set of files in the project stays the same and false - otherwise. From c97be16fa192e4c6ce04e5867b0a9e042cfdb392 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 21 Jun 2019 13:54:06 -0700 Subject: [PATCH 003/140] Log the config of the project --- src/server/editorServices.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index f7fb537f543..1b2666d4cba 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -1757,6 +1757,12 @@ namespace ts.server { configFileErrors.push(...parsedCommandLine.errors); } + this.logger.info(`Config: ${configFilename} : ${JSON.stringify({ + rootNames: parsedCommandLine.fileNames, + options: parsedCommandLine.options, + projectReferences: parsedCommandLine.projectReferences + }, /*replacer*/ undefined, " ")}`); + Debug.assert(!!parsedCommandLine.fileNames); const compilerOptions = parsedCommandLine.options; From 746b01e5772d5eda7f71a72265c5fee3a3a6ba8e Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 21 Jun 2019 14:16:40 -0700 Subject: [PATCH 004/140] Check only for .d.ts files --- src/compiler/program.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 27bd1fd3d3b..6fee35d2448 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -2468,8 +2468,10 @@ namespace ts { } else { forEach(resolvedRef.commandLine.fileNames, fileName => { - const outputDts = getOutputDeclarationFileName(fileName, resolvedRef.commandLine, host.useCaseSensitiveFileNames()); - mapFromToProjectReferenceRedirectSource!.set(toPath(outputDts), fileName); + if (!fileExtensionIs(fileName, Extension.Dts) && hasTSFileExtension(fileName)) { + const outputDts = getOutputDeclarationFileName(fileName, resolvedRef.commandLine, host.useCaseSensitiveFileNames()); + mapFromToProjectReferenceRedirectSource!.set(toPath(outputDts), fileName); + } }); } } From ecf875112b7a7faea715a60ac1ee4da8c201bb38 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 21 Jun 2019 14:22:11 -0700 Subject: [PATCH 005/140] Check for language serivice enabled when including source files --- src/server/project.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/server/project.ts b/src/server/project.ts index 3e69a785516..3b721c14b58 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -1427,12 +1427,12 @@ namespace ts.server { /* @internal */ useSourceInsteadOfReferenceRedirect() { - return true; + return !!this.languageServiceEnabled; } fileExists(file: string): boolean { // Project references go to source file instead of .d.ts file - if (this.getSourceOfProjectReferenceRedirect) { + if (this.languageServiceEnabled && this.getSourceOfProjectReferenceRedirect) { const source = this.getSourceOfProjectReferenceRedirect(file); if (source) return isString(source) ? super.fileExists(source) : true; } From 181028821ba5600324b13b645f93b098747f6d5a Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 21 Jun 2019 14:54:38 -0700 Subject: [PATCH 006/140] Fix tests --- src/testRunner/unittests/tsserver/projectReferences.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/testRunner/unittests/tsserver/projectReferences.ts b/src/testRunner/unittests/tsserver/projectReferences.ts index eb3d83e2b98..d5a67252824 100644 --- a/src/testRunner/unittests/tsserver/projectReferences.ts +++ b/src/testRunner/unittests/tsserver/projectReferences.ts @@ -85,8 +85,8 @@ namespace ts.projectSystem { }); const { file: _, ...renameTextOfMyConstInLib } = locationOfMyConstInLib; assert.deepEqual(response.locs, [ - { file: myConstFile, locs: [{ start: myConstStart, end: myConstEnd }] }, - { file: locationOfMyConstInLib.file, locs: [renameTextOfMyConstInLib] } + { file: locationOfMyConstInLib.file, locs: [renameTextOfMyConstInLib] }, + { file: myConstFile, locs: [{ start: myConstStart, end: myConstEnd }] } ]); }); }); From f4728682b7f6a8275b034fb9be5a2f64b84e0aea Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 25 Jun 2019 12:15:04 -0700 Subject: [PATCH 007/140] Watch generated file if it doesnt exist when trying to translate it to to source generated position --- src/server/editorServices.ts | 8 +- src/server/project.ts | 100 +++++++++ src/server/utilities.ts | 1 + .../unittests/tsserver/projectReferences.ts | 200 ++++++++++-------- .../reference/api/tsserverlibrary.d.ts | 4 + 5 files changed, 229 insertions(+), 84 deletions(-) diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 1b2666d4cba..8c7462d857b 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -2240,7 +2240,13 @@ namespace ts.server { getDocumentPositionMapper(project: Project, generatedFileName: string, sourceFileName?: string): DocumentPositionMapper | undefined { // Since declaration info and map file watches arent updating project's directory structure host (which can cache file structure) use host const declarationInfo = this.getOrCreateScriptInfoNotOpenedByClient(generatedFileName, project.currentDirectory, this.host); - if (!declarationInfo) return undefined; + if (!declarationInfo) { + if (sourceFileName) { + // Project contains source file and it generates the generated file name + project.addGeneratedFileWatch(generatedFileName, sourceFileName); + } + return undefined; + } // Try to get from cache declarationInfo.getSnapshot(); // Ensure synchronized diff --git a/src/server/project.ts b/src/server/project.ts index 3b721c14b58..8f8e6e5da8e 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -109,12 +109,22 @@ namespace ts.server { return value instanceof ScriptInfo; } + interface GeneratedFileWatcher { + generatedFilePath: Path; + watcher: FileWatcher; + } + type GeneratedFileWatcherMap = GeneratedFileWatcher | Map; + function isGeneratedFileWatcher(watch: GeneratedFileWatcherMap): watch is GeneratedFileWatcher { + return (watch as GeneratedFileWatcher).generatedFilePath !== undefined; + } + export abstract class Project implements LanguageServiceHost, ModuleResolutionHost { private rootFiles: ScriptInfo[] = []; private rootFilesMap: Map = createMap(); private program: Program | undefined; private externalFiles: SortedReadonlyArray | undefined; private missingFilesMap: Map | undefined; + private generatedFilesMap: GeneratedFileWatcherMap | undefined; private plugins: PluginModuleWithName[] = []; /*@internal*/ @@ -573,6 +583,7 @@ namespace ts.server { this.lastFileExceededProgramSize = lastFileExceededProgramSize; this.builderState = undefined; this.resolutionCache.closeTypeRootsWatch(); + this.clearGeneratedFileWatch(); this.projectService.onUpdateLanguageServiceStateForProject(this, /*languageServiceEnabled*/ false); } @@ -654,6 +665,7 @@ namespace ts.server { clearMap(this.missingFilesMap, closeFileWatcher); this.missingFilesMap = undefined!; } + this.clearGeneratedFileWatch(); // signal language service to release source files acquired from document registry this.languageService.dispose(); @@ -947,6 +959,39 @@ namespace ts.server { missingFilePath => this.addMissingFileWatcher(missingFilePath) ); + if (this.generatedFilesMap) { + const outPath = this.compilerOptions.outFile && this.compilerOptions.out; + if (isGeneratedFileWatcher(this.generatedFilesMap)) { + // --out + if (!outPath || !this.isValidGeneratedFileWatcher( + removeFileExtension(outPath) + Extension.Dts, + this.generatedFilesMap, + )) { + this.clearGeneratedFileWatch(); + } + } + else { + // MultiFile + if (outPath) { + this.clearGeneratedFileWatch(); + } + else { + this.generatedFilesMap.forEach((watcher, source) => { + const sourceFile = this.program!.getSourceFileByPath(source as Path); + if (!sourceFile || + sourceFile.resolvedPath !== source || + !this.isValidGeneratedFileWatcher( + getDeclarationEmitOutputFilePathWorker(sourceFile.fileName, this.compilerOptions, this.currentDirectory, this.program!.getCommonSourceDirectory(), this.getCanonicalFileName), + watcher + )) { + closeFileWatcherOf(watcher); + (this.generatedFilesMap as Map).delete(source); + } + }); + } + } + } + // Watch the type locations that would be added to program as part of automatic type resolutions if (this.languageServiceEnabled) { this.resolutionCache.updateTypeRootsWatch(); @@ -1011,6 +1056,61 @@ namespace ts.server { return !!this.missingFilesMap && this.missingFilesMap.has(path); } + /* @internal */ + addGeneratedFileWatch(generatedFile: string, sourceFile: string) { + if (this.compilerOptions.outFile || this.compilerOptions.out) { + // Single watcher + if (!this.generatedFilesMap) { + this.generatedFilesMap = this.createGeneratedFileWatcher(generatedFile); + } + } + else { + // Map + const path = this.toPath(sourceFile); + if (this.generatedFilesMap) { + if (isGeneratedFileWatcher(this.generatedFilesMap)) { + Debug.fail(`${this.projectName} Expected not to have --out watcher for generated file with options: ${JSON.stringify(this.compilerOptions)}`); + return; + } + if (this.generatedFilesMap.has(path)) return; + } + else { + this.generatedFilesMap = createMap(); + } + this.generatedFilesMap.set(path, this.createGeneratedFileWatcher(generatedFile)); + } + } + + private createGeneratedFileWatcher(generatedFile: string): GeneratedFileWatcher { + return { + generatedFilePath: this.toPath(generatedFile), + watcher: this.projectService.watchFactory.watchFile( + this.projectService.host, + generatedFile, + () => this.projectService.delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(this), + PollingInterval.High, + WatchType.MissingGeneratedFile, + this + ) + }; + } + + private isValidGeneratedFileWatcher(generateFile: string, watcher: GeneratedFileWatcher) { + return this.toPath(generateFile) === watcher.generatedFilePath; + } + + private clearGeneratedFileWatch() { + if (this.generatedFilesMap) { + if (isGeneratedFileWatcher(this.generatedFilesMap)) { + closeFileWatcherOf(this.generatedFilesMap); + } + else { + clearMap(this.generatedFilesMap, closeFileWatcherOf); + } + this.generatedFilesMap = undefined; + } + } + getScriptInfoForNormalizedPath(fileName: NormalizedPath): ScriptInfo | undefined { const scriptInfo = this.projectService.getScriptInfoForPath(this.toPath(fileName)); if (scriptInfo && !scriptInfo.isAttached(this)) { diff --git a/src/server/utilities.ts b/src/server/utilities.ts index 91880ccfdbe..fd38c6a4326 100644 --- a/src/server/utilities.ts +++ b/src/server/utilities.ts @@ -227,5 +227,6 @@ namespace ts { NodeModulesForClosedScriptInfo = "node_modules for closed script infos in them", MissingSourceMapFile = "Missing source map file", NoopConfigFileForInferredRoot = "Noop Config file for the inferred project root", + MissingGeneratedFile = "Missing generated file" } } diff --git a/src/testRunner/unittests/tsserver/projectReferences.ts b/src/testRunner/unittests/tsserver/projectReferences.ts index d5a67252824..9c02b670bb7 100644 --- a/src/testRunner/unittests/tsserver/projectReferences.ts +++ b/src/testRunner/unittests/tsserver/projectReferences.ts @@ -94,6 +94,7 @@ namespace ts.projectSystem { describe("with main and depedency project", () => { const projectLocation = "/user/username/projects/myproject"; const dependecyLocation = `${projectLocation}/dependency`; + const dependecyDeclsLocation = `${projectLocation}/decls`; const mainLocation = `${projectLocation}/main`; const dependencyTs: File = { path: `${dependecyLocation}/FnS.ts`, @@ -106,7 +107,7 @@ export function fn5() { } }; const dependencyConfig: File = { path: `${dependecyLocation}/tsconfig.json`, - content: JSON.stringify({ compilerOptions: { composite: true, declarationMap: true } }) + content: JSON.stringify({ compilerOptions: { composite: true, declarationMap: true, declarationDir: "../decls" } }) }; const mainTs: File = { @@ -117,7 +118,7 @@ export function fn5() { } fn3, fn4, fn5 -} from '../dependency/fns' +} from '../decls/fns' fn1(); fn2(); @@ -142,9 +143,9 @@ fn5(); path: `${projectLocation}/random/tsconfig.json`, content: "{}" }; - const dtsLocation = `${dependecyLocation}/FnS.d.ts`; + const dtsLocation = `${dependecyDeclsLocation}/FnS.d.ts`; const dtsPath = dtsLocation.toLowerCase() as Path; - const dtsMapLocation = `${dtsLocation}.map`; + const dtsMapLocation = `${dependecyDeclsLocation}/FnS.d.ts.map`; const dtsMapPath = dtsMapLocation.toLowerCase() as Path; const files = [dependencyTs, dependencyConfig, mainTs, mainConfig, libFile, randomFile, randomConfig]; @@ -224,7 +225,7 @@ fn5(); start: { line: fn + 1, offset: 5 }, end: { line: fn + 1, offset: 8 }, contextStart: { line: 1, offset: 1 }, - contextEnd: { line: 7, offset: 27 } + contextEnd: { line: 7, offset: 22 } }; } function usageSpan(fn: number): protocol.TextSpan { @@ -328,19 +329,25 @@ fn5(); function verifyDocumentPositionMapperUpdates( mainScenario: string, verifier: ReadonlyArray, - closedInfos: ReadonlyArray) { + closedInfos: ReadonlyArray, + withRefs: boolean) { const openFiles = verifier.map(v => v.openFile); const expectedProjectActualFiles = verifier.map(v => v.expectedProjectActualFiles); - const actionGetters = verifier.map(v => v.actionGetter); const openFileLastLines = verifier.map(v => v.openFileLastLine); const configFiles = openFiles.map(openFile => `${getDirectoryPath(openFile.path)}/tsconfig.json`); const openInfos = openFiles.map(f => f.path); // When usage and dependency are used, dependency config is part of closedInfo so ignore - const otherWatchedFiles = verifier.length > 1 ? [configFiles[0]] : configFiles; + const otherWatchedFiles = withRefs && verifier.length > 1 ? [configFiles[0]] : configFiles; function openTsFile(onHostCreate?: (host: TestServerHost) => void) { const host = createHost(files, [mainConfig.path]); + if (!withRefs) { + // Erase project reference + host.writeFile(mainConfig.path, JSON.stringify({ + compilerOptions: { composite: true, declarationMap: true } + })); + } if (onHostCreate) { onHostCreate(host); } @@ -377,7 +384,7 @@ fn5(); ); } - function verifyInfosWhenNoDtsFile(session: TestSession, host: TestServerHost, dependencyTsAndMapOk?: true) { + function verifyInfosWhenNoDtsFile(session: TestSession, host: TestServerHost, watchDts: boolean, dependencyTsAndMapOk?: true) { const dtsMapClosedInfo = firstDefined(closedInfos, f => f.toLowerCase() === dtsMapPath ? f : undefined); const dtsClosedInfo = firstDefined(closedInfos, f => f.toLowerCase() === dtsPath ? f : undefined); verifyInfosWithRandom( @@ -385,8 +392,7 @@ fn5(); host, openInfos, closedInfos.filter(f => (dependencyTsAndMapOk || f !== dtsMapClosedInfo) && f !== dtsClosedInfo && (dependencyTsAndMapOk || f !== dependencyTs.path)), - // When project actual file contains dts, it needs to be watched - dtsClosedInfo && expectedProjectActualFiles.some(expectedProjectActualFiles => expectedProjectActualFiles.some(f => f.toLowerCase() === dtsPath)) ? + dtsClosedInfo && watchDts ? otherWatchedFiles.concat(dtsClosedInfo) : otherWatchedFiles ); @@ -402,22 +408,22 @@ fn5(); } } - function action(actionGetter: SessionActionGetter, fn: number, session: TestSession) { - const { reqName, request, expectedResponse, expectedResponseNoMap, expectedResponseNoDts } = actionGetter(fn); + function action(verifier: DocumentPositionMapperVerifier, fn: number, session: TestSession) { + const { reqName, request, expectedResponse, expectedResponseNoMap, expectedResponseNoDts } = verifier.actionGetter(fn); const { response } = session.executeCommandSeq(request); - return { reqName, response, expectedResponse, expectedResponseNoMap, expectedResponseNoDts }; + return { reqName, response, expectedResponse, expectedResponseNoMap, expectedResponseNoDts, verifier }; } function firstAction(session: TestSession) { - actionGetters.forEach(actionGetter => action(actionGetter, 1, session)); + verifier.forEach(v => action(v, 1, session)); } function verifyAllFnActionWorker(session: TestSession, verifyAction: (result: ReturnType, dtsInfo: server.ScriptInfo | undefined, isFirst: boolean) => void, dtsAbsent?: true) { // action let isFirst = true; - for (const actionGetter of actionGetters) { + for (const v of verifier) { for (let fn = 1; fn <= 5; fn++) { - const result = action(actionGetter, fn, session); + const result = action(v, fn, session); const dtsInfo = session.getProjectService().filenameToScriptInfo.get(dtsPath); if (dtsAbsent) { assert.isUndefined(dtsInfo); @@ -490,9 +496,17 @@ fn5(); dependencyTsAndMapOk?: true ) { // action - verifyAllFnActionWorker(session, ({ reqName, response, expectedResponse, expectedResponseNoDts }) => { + verifyAllFnActionWorker(session, ({ reqName, response, expectedResponse, expectedResponseNoDts, verifier }) => { assert.deepEqual(response, expectedResponseNoDts || expectedResponse, `Failed on ${reqName}`); - verifyInfosWhenNoDtsFile(session, host, dependencyTsAndMapOk); + verifyInfosWhenNoDtsFile( + session, + host, + // Even when project actual file contains dts, its not watched because the dts is in another folder and module resolution just fails + // instead of succeeding to source file and then mapping using project reference (When using usage location) + // But watched if sourcemapper is in source project since we need to keep track of dts to update the source mapper for any potential usages + verifier.expectedProjectActualFiles.every(f => f.toLowerCase() !== dtsPath), + dependencyTsAndMapOk, + ); }, /*dtsAbsent*/ true); } @@ -576,7 +590,11 @@ fn5(); // Collecting at this point retains dependency.d.ts and map watcher closeFilesForSession([randomFile], session); openFilesForSession([randomFile], session); - verifyInfosWhenNoDtsFile(session, host); + verifyInfosWhenNoDtsFile( + session, + host, + !!forEach(verifier, v => v.expectedProjectActualFiles.every(f => f.toLowerCase() !== dtsPath)) + ); // Closing open file, removes dependencies too closeFilesForSession([...openFiles, randomFile], session); @@ -657,7 +675,7 @@ fn5(); "when dependency file's map changes", host => host.writeFile( dtsMapLocation, - `{"version":3,"file":"FnS.d.ts","sourceRoot":"","sources":["FnS.ts"],"names":[],"mappings":"AAAA,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,eAAO,MAAM,CAAC,KAAK,CAAC"}` + `{"version":3,"file":"FnS.d.ts","sourceRoot":"","sources":["../dependency/FnS.ts"],"names":[],"mappings":"AAAA,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,eAAO,MAAM,CAAC,KAAK,CAAC"}` ), /*afterActionDocumentPositionMapperNotEquals*/ true ); @@ -675,75 +693,91 @@ fn5(); /*noDts*/ true ); - it("when defining project source changes", () => { - const { host, session } = openTsFile(); + if (withRefs) { + it("when defining project source changes", () => { + const { host, session } = openTsFile(); - // First action - firstAction(session); + // First action + firstAction(session); - // Make change, without rebuild of solution - if (contains(openInfos, dependencyTs.path)) { - session.executeCommandSeq({ - command: protocol.CommandTypes.Change, - arguments: { - file: dependencyTs.path, line: 1, offset: 1, endLine: 1, endOffset: 1, insertString: `function fooBar() { } + // Make change, without rebuild of solution + if (contains(openInfos, dependencyTs.path)) { + session.executeCommandSeq({ + command: protocol.CommandTypes.Change, + arguments: { + file: dependencyTs.path, line: 1, offset: 1, endLine: 1, endOffset: 1, insertString: `function fooBar() { } `} - }); - } - else { - host.writeFile(dependencyTs.path, `function fooBar() { } -${dependencyTs.content}`); - } - host.runQueuedTimeoutCallbacks(); - - for (const actionGetter of actionGetters) { - for (let fn = 1; fn <= 5; fn++) { - const { reqName, request, requestDependencyChange, expectedResponseDependencyChange } = actionGetter(fn); - const { response } = session.executeCommandSeq(requestDependencyChange || request); - assert.deepEqual(response, expectedResponseDependencyChange, `Failed on ${reqName}`); + }); } - } + else { + host.writeFile(dependencyTs.path, `function fooBar() { } +${dependencyTs.content}`); + } + host.runQueuedTimeoutCallbacks(); + + for (const v of verifier) { + for (let fn = 1; fn <= 5; fn++) { + const { reqName, request, requestDependencyChange, expectedResponseDependencyChange } = v.actionGetter(fn); + const { response } = session.executeCommandSeq(requestDependencyChange || request); + assert.deepEqual(response, expectedResponseDependencyChange, `Failed on ${reqName}`); + } + } + }); + } + } + + function verifyScenarios(withRefs: boolean) { + describe(withRefs ? "when main tsconfig has project reference" : "when main tsconfig doesnt have project reference", () => { + const usageVerifier: DocumentPositionMapperVerifier = { + openFile: mainTs, + expectedProjectActualFiles: [mainTs.path, libFile.path, mainConfig.path, dtsPath], + actionGetter: gotoDefintinionFromMainTs, + openFileLastLine: 14 + }; + describe("from project that uses dependency", () => { + const closedInfos = withRefs ? + [dependencyTs.path, dependencyConfig.path, libFile.path, dtsPath, dtsMapLocation] : + [dependencyTs.path, libFile.path, dtsPath, dtsMapLocation]; + verifyDocumentPositionMapperUpdates( + "can go to definition correctly", + [usageVerifier], + closedInfos, + withRefs + ); + }); + + const definingVerifier: DocumentPositionMapperVerifier = { + openFile: dependencyTs, + expectedProjectActualFiles: [dependencyTs.path, libFile.path, dependencyConfig.path], + actionGetter: renameFromDependencyTs, + openFileLastLine: 6, + }; + describe("from defining project", () => { + const closedInfos = [libFile.path, dtsLocation, dtsMapLocation]; + verifyDocumentPositionMapperUpdates( + "rename locations from dependency", + [definingVerifier], + closedInfos, + withRefs + ); + }); + + describe("when opening depedency and usage project", () => { + const closedInfos = withRefs ? + [libFile.path, dtsPath, dtsMapLocation, dependencyConfig.path] : + [libFile.path, dtsPath, dtsMapLocation]; + verifyDocumentPositionMapperUpdates( + "goto Definition in usage and rename locations from defining project", + [usageVerifier, { ...definingVerifier, actionGetter: renameFromDependencyTsWithBothProjectsOpen }], + closedInfos, + withRefs + ); + }); }); } - const usageVerifier: DocumentPositionMapperVerifier = { - openFile: mainTs, - expectedProjectActualFiles: [mainTs.path, libFile.path, mainConfig.path, dtsPath], - actionGetter: gotoDefintinionFromMainTs, - openFileLastLine: 14 - }; - describe("from project that uses dependency", () => { - const closedInfos = [dependencyTs.path, dependencyConfig.path, libFile.path, dtsPath, dtsMapLocation]; - verifyDocumentPositionMapperUpdates( - "can go to definition correctly", - [usageVerifier], - closedInfos - ); - }); - - const definingVerifier: DocumentPositionMapperVerifier = { - openFile: dependencyTs, - expectedProjectActualFiles: [dependencyTs.path, libFile.path, dependencyConfig.path], - actionGetter: renameFromDependencyTs, - openFileLastLine: 6 - }; - describe("from defining project", () => { - const closedInfos = [libFile.path, dtsLocation, dtsMapLocation]; - verifyDocumentPositionMapperUpdates( - "rename locations from dependency", - [definingVerifier], - closedInfos - ); - }); - - describe("when opening depedency and usage project", () => { - const closedInfos = [libFile.path, dtsPath, dtsMapLocation, dependencyConfig.path]; - verifyDocumentPositionMapperUpdates( - "goto Definition in usage and rename locations from defining project", - [usageVerifier, { ...definingVerifier, actionGetter: renameFromDependencyTsWithBothProjectsOpen }], - closedInfos - ); - }); + verifyScenarios(/*withRefs*/ false); + verifyScenarios(/*withRefs*/ true); }); }); } diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 53459d993cf..286516f37af 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -8397,6 +8397,7 @@ declare namespace ts.server { private program; private externalFiles; private missingFilesMap; + private generatedFilesMap; private plugins; private lastFileExceededProgramSize; protected languageService: LanguageService; @@ -8509,6 +8510,9 @@ declare namespace ts.server { private detachScriptInfoFromProject; private addMissingFileWatcher; private isWatchedMissingFile; + private createGeneratedFileWatcher; + private isValidGeneratedFileWatcher; + private clearGeneratedFileWatch; getScriptInfoForNormalizedPath(fileName: NormalizedPath): ScriptInfo | undefined; getScriptInfo(uncheckedFileName: string): ScriptInfo | undefined; filesToString(writeProjectFileNames: boolean): string; From 012ecdacde36330ecd1eab532dbe1d83624d87be Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Wed, 26 Jun 2019 13:41:46 -0700 Subject: [PATCH 008/140] Add sourceOf project reference redirect to filesByName list for redirect path so that module symbol is correctly resolved --- src/compiler/program.ts | 11 +- src/services/services.ts | 9 +- src/services/sourcemaps.ts | 6 + .../unittests/tsserver/projectReferences.ts | 158 +++++++++--------- 4 files changed, 103 insertions(+), 81 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 6fee35d2448..9a4e26a2903 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1411,6 +1411,13 @@ namespace ts { for (const newSourceFile of newSourceFiles) { const filePath = newSourceFile.path; addFileToFilesByName(newSourceFile, filePath, newSourceFile.resolvedPath); + if (useSourceOfReference) { + const redirectProject = getProjectReferenceRedirectProject(newSourceFile.fileName); + if (redirectProject && !(redirectProject.commandLine.options.outFile || redirectProject.commandLine.options.out)) { + const redirect = getProjectReferenceOutputName(redirectProject, newSourceFile.fileName); + addFileToFilesByName(newSourceFile, toPath(redirect), /*redirectedPath*/ undefined); + } + } // Set the file as found during node modules search if it was found that way in old progra, if (oldProgram.isSourceFileFromExternalLibrary(oldProgram.getSourceFileByPath(filePath)!)) { sourceFilesFoundSearchingNodeModules.set(filePath, true); @@ -2240,9 +2247,11 @@ namespace ts { if (useSourceOfReference) { const source = getSourceOfProjectReferenceRedirect(fileName); if (source) { - return isString(source) ? + const file = isString(source) ? findSourceFile(source, toPath(source), isDefaultLib, ignoreNoDefaultLib, refFile, refPos, refEnd, packageId) : undefined; + if (file) addFileToFilesByName(file, path, /*redirectedPath*/ undefined); + return file; } } const originalFileName = fileName; diff --git a/src/services/services.ts b/src/services/services.ts index a8b05402e76..aa6ea119225 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1148,10 +1148,11 @@ namespace ts { useCaseSensitiveFileNames: () => useCaseSensitiveFileNames, getCurrentDirectory: () => currentDirectory, getProgram, - fileExists: host.fileExists && (f => host.fileExists!(f)), - readFile: host.readFile && ((f, encoding) => host.readFile!(f, encoding)), - getDocumentPositionMapper: host.getDocumentPositionMapper && ((generatedFileName, sourceFileName) => host.getDocumentPositionMapper!(generatedFileName, sourceFileName)), - getSourceFileLike: host.getSourceFileLike && (f => host.getSourceFileLike!(f)), + fileExists: maybeBind(host, host.fileExists), + readFile: maybeBind(host, host.readFile), + getDocumentPositionMapper: maybeBind(host, host.getDocumentPositionMapper), + useSourceInsteadOfReferenceRedirect: maybeBind(host, host.useSourceInsteadOfReferenceRedirect), + getSourceFileLike: maybeBind(host, host.getSourceFileLike), log }); diff --git a/src/services/sourcemaps.ts b/src/services/sourcemaps.ts index d07c21a9f43..de590d4e5b4 100644 --- a/src/services/sourcemaps.ts +++ b/src/services/sourcemaps.ts @@ -17,6 +17,7 @@ namespace ts { readFile?(path: string, encoding?: string): string | undefined; getSourceFileLike?(fileName: string): SourceFileLike | undefined; getDocumentPositionMapper?(generatedFileName: string, sourceFileName?: string): DocumentPositionMapper | undefined; + /* @internal */ useSourceInsteadOfReferenceRedirect?(): boolean; log(s: string): void; } @@ -70,6 +71,11 @@ namespace ts { if (!sourceFile) return undefined; const program = host.getProgram()!; + // If this is source file of project reference source (instead of redirect) there is no generated position + if (host.useSourceInsteadOfReferenceRedirect && + host.useSourceInsteadOfReferenceRedirect() && + program.getResolvedProjectReferenceToRedirect(sourceFile.fileName)) return undefined; + const options = program.getCompilerOptions(); const outPath = options.outFile || options.out; diff --git a/src/testRunner/unittests/tsserver/projectReferences.ts b/src/testRunner/unittests/tsserver/projectReferences.ts index 9c02b670bb7..5320cfe13bc 100644 --- a/src/testRunner/unittests/tsserver/projectReferences.ts +++ b/src/testRunner/unittests/tsserver/projectReferences.ts @@ -373,7 +373,7 @@ fn5(); verifyInfosWithRandom(session, host, openInfos, closedInfos, otherWatchedFiles); } - function verifyInfosWhenNoMapFile(session: TestSession, host: TestServerHost, dependencyTsOK?: true) { + function verifyInfosWhenNoMapFile(session: TestSession, host: TestServerHost, dependencyTsOK?: boolean) { const dtsMapClosedInfo = firstDefined(closedInfos, f => f.toLowerCase() === dtsMapPath ? f : undefined); verifyInfosWithRandom( session, @@ -384,46 +384,48 @@ fn5(); ); } - function verifyInfosWhenNoDtsFile(session: TestSession, host: TestServerHost, watchDts: boolean, dependencyTsAndMapOk?: true) { + function verifyInfosWhenNoDtsFile(session: TestSession, host: TestServerHost, watchDts: boolean, dependencyTsOk?: boolean, depedencyMapOk?: boolean) { const dtsMapClosedInfo = firstDefined(closedInfos, f => f.toLowerCase() === dtsMapPath ? f : undefined); const dtsClosedInfo = firstDefined(closedInfos, f => f.toLowerCase() === dtsPath ? f : undefined); verifyInfosWithRandom( session, host, openInfos, - closedInfos.filter(f => (dependencyTsAndMapOk || f !== dtsMapClosedInfo) && f !== dtsClosedInfo && (dependencyTsAndMapOk || f !== dependencyTs.path)), + closedInfos.filter(f => (depedencyMapOk || f !== dtsMapClosedInfo) && f !== dtsClosedInfo && (dependencyTsOk || f !== dependencyTs.path)), dtsClosedInfo && watchDts ? otherWatchedFiles.concat(dtsClosedInfo) : otherWatchedFiles ); } - function verifyDocumentPositionMapper(session: TestSession, dependencyMap: server.ScriptInfo, documentPositionMapper: server.ScriptInfo["documentPositionMapper"], notEqual?: true) { + function verifyDocumentPositionMapper(session: TestSession, dependencyMap: server.ScriptInfo | undefined, documentPositionMapper: server.ScriptInfo["documentPositionMapper"], notEqual?: true) { assert.strictEqual(session.getProjectService().filenameToScriptInfo.get(dtsMapPath), dependencyMap); - if (notEqual) { - assert.notStrictEqual(dependencyMap.documentPositionMapper, documentPositionMapper); - } - else { - assert.strictEqual(dependencyMap.documentPositionMapper, documentPositionMapper); + if (dependencyMap) { + if (notEqual) { + assert.notStrictEqual(dependencyMap.documentPositionMapper, documentPositionMapper); + } + else { + assert.strictEqual(dependencyMap.documentPositionMapper, documentPositionMapper); + } } } - function action(verifier: DocumentPositionMapperVerifier, fn: number, session: TestSession) { - const { reqName, request, expectedResponse, expectedResponseNoMap, expectedResponseNoDts } = verifier.actionGetter(fn); - const { response } = session.executeCommandSeq(request); - return { reqName, response, expectedResponse, expectedResponseNoMap, expectedResponseNoDts, verifier }; + function action(verifier: DocumentPositionMapperVerifier, fn: number, session: TestSession, useDependencyChange?: boolean) { + const { reqName, request, expectedResponse, expectedResponseNoMap, expectedResponseNoDts, requestDependencyChange, expectedResponseDependencyChange } = verifier.actionGetter(fn); + const { response } = session.executeCommandSeq(useDependencyChange ? requestDependencyChange || request : request); + return { reqName, response, expectedResponse, expectedResponseNoMap, expectedResponseNoDts, expectedResponseDependencyChange, verifier }; } function firstAction(session: TestSession) { verifier.forEach(v => action(v, 1, session)); } - function verifyAllFnActionWorker(session: TestSession, verifyAction: (result: ReturnType, dtsInfo: server.ScriptInfo | undefined, isFirst: boolean) => void, dtsAbsent?: true) { + function verifyAllFnActionWorker(session: TestSession, verifyAction: (result: ReturnType, dtsInfo: server.ScriptInfo | undefined, isFirst: boolean) => void, dtsAbsent?: boolean, useDependencyChange?: boolean) { // action let isFirst = true; for (const v of verifier) { for (let fn = 1; fn <= 5; fn++) { - const result = action(v, fn, session); + const result = action(v, fn, session, useDependencyChange); const dtsInfo = session.getProjectService().filenameToScriptInfo.get(dtsPath); if (dtsAbsent) { assert.isUndefined(dtsInfo); @@ -437,33 +439,38 @@ fn5(); } } + function dtsAbsent() { + return withRefs && !contains(closedInfos, dtsPath, (a, b) => a.toLowerCase() === b.toLowerCase()); + } + function verifyAllFnAction( session: TestSession, host: TestServerHost, firstDocumentPositionMapperNotEquals?: true, dependencyMap?: server.ScriptInfo, - documentPositionMapper?: server.ScriptInfo["documentPositionMapper"] + documentPositionMapper?: server.ScriptInfo["documentPositionMapper"], + useDependencyChange?: boolean ) { // action - verifyAllFnActionWorker(session, ({ reqName, response, expectedResponse }, dtsInfo, isFirst) => { - assert.deepEqual(response, expectedResponse, `Failed on ${reqName}`); + verifyAllFnActionWorker(session, ({ reqName, response, expectedResponse, expectedResponseDependencyChange }, dtsInfo, isFirst) => { + assert.deepEqual(response, useDependencyChange ? expectedResponseDependencyChange || expectedResponse : expectedResponse, `Failed on ${reqName}`); verifyInfos(session, host); - assert.equal(dtsInfo!.sourceMapFilePath, dtsMapPath); + if (dtsInfo) assert.equal(dtsInfo.sourceMapFilePath, dtsMapPath); if (isFirst) { if (dependencyMap) { verifyDocumentPositionMapper(session, dependencyMap, documentPositionMapper, firstDocumentPositionMapperNotEquals); documentPositionMapper = dependencyMap.documentPositionMapper; } else { - dependencyMap = session.getProjectService().filenameToScriptInfo.get(dtsMapPath)!; - documentPositionMapper = dependencyMap.documentPositionMapper; + dependencyMap = session.getProjectService().filenameToScriptInfo.get(dtsMapPath); + documentPositionMapper = dependencyMap && dependencyMap.documentPositionMapper; } } else { - verifyDocumentPositionMapper(session, dependencyMap!, documentPositionMapper); + verifyDocumentPositionMapper(session, dependencyMap, documentPositionMapper); } - }); - return { dependencyMap: dependencyMap!, documentPositionMapper }; + }, dtsAbsent(), useDependencyChange); + return { dependencyMap, documentPositionMapper }; } function verifyAllFnActionWithNoMap( @@ -474,19 +481,21 @@ fn5(); let sourceMapFilePath: server.ScriptInfo["sourceMapFilePath"]; // action verifyAllFnActionWorker(session, ({ reqName, response, expectedResponse, expectedResponseNoMap }, dtsInfo, isFirst) => { - assert.deepEqual(response, expectedResponseNoMap || expectedResponse, `Failed on ${reqName}`); + assert.deepEqual(response, withRefs ? expectedResponse : expectedResponseNoMap || expectedResponse, `Failed on ${reqName}`); verifyInfosWhenNoMapFile(session, host, dependencyTsOK); assert.isUndefined(session.getProjectService().filenameToScriptInfo.get(dtsMapPath)); - if (isFirst) { - assert.isNotString(dtsInfo!.sourceMapFilePath); - assert.isNotFalse(dtsInfo!.sourceMapFilePath); - assert.isDefined(dtsInfo!.sourceMapFilePath); - sourceMapFilePath = dtsInfo!.sourceMapFilePath; + if (!withRefs) { + if (isFirst) { + assert.isNotString(dtsInfo!.sourceMapFilePath); + assert.isNotFalse(dtsInfo!.sourceMapFilePath); + assert.isDefined(dtsInfo!.sourceMapFilePath); + sourceMapFilePath = dtsInfo!.sourceMapFilePath; + } + else { + assert.equal(dtsInfo!.sourceMapFilePath, sourceMapFilePath); + } } - else { - assert.equal(dtsInfo!.sourceMapFilePath, sourceMapFilePath); - } - }); + }, dtsAbsent()); return sourceMapFilePath; } @@ -497,7 +506,7 @@ fn5(); ) { // action verifyAllFnActionWorker(session, ({ reqName, response, expectedResponse, expectedResponseNoDts, verifier }) => { - assert.deepEqual(response, expectedResponseNoDts || expectedResponse, `Failed on ${reqName}`); + assert.deepEqual(response, withRefs ? expectedResponse : expectedResponseNoDts || expectedResponse, `Failed on ${reqName}`); verifyInfosWhenNoDtsFile( session, host, @@ -505,7 +514,8 @@ fn5(); // instead of succeeding to source file and then mapping using project reference (When using usage location) // But watched if sourcemapper is in source project since we need to keep track of dts to update the source mapper for any potential usages verifier.expectedProjectActualFiles.every(f => f.toLowerCase() !== dtsPath), - dependencyTsAndMapOk, + /*dependencyTsOk*/ withRefs || dependencyTsAndMapOk, + /*dependencyMapOk*/ dependencyTsAndMapOk ); }, /*dtsAbsent*/ true); } @@ -513,14 +523,15 @@ fn5(); function verifyScenarioWithChangesWorker( change: (host: TestServerHost, session: TestSession) => void, afterActionDocumentPositionMapperNotEquals: true | undefined, - timeoutBeforeAction: boolean + timeoutBeforeAction: boolean, + useDependencyChange?: boolean ) { const { host, session } = openTsFile(); // Create DocumentPositionMapper firstAction(session); - const dependencyMap = session.getProjectService().filenameToScriptInfo.get(dtsMapPath)!; - const documentPositionMapper = dependencyMap.documentPositionMapper; + const dependencyMap = session.getProjectService().filenameToScriptInfo.get(dtsMapPath); + const documentPositionMapper = dependencyMap && dependencyMap.documentPositionMapper; // change change(host, session); @@ -531,21 +542,22 @@ fn5(); } // action - verifyAllFnAction(session, host, afterActionDocumentPositionMapperNotEquals, dependencyMap, documentPositionMapper); + verifyAllFnAction(session, host, afterActionDocumentPositionMapperNotEquals, dependencyMap, documentPositionMapper, useDependencyChange); } function verifyScenarioWithChanges( scenarioName: string, change: (host: TestServerHost, session: TestSession) => void, - afterActionDocumentPositionMapperNotEquals?: true + afterActionDocumentPositionMapperNotEquals?: true, + useDependencyChange?: boolean ) { describe(scenarioName, () => { it("when timeout occurs before request", () => { - verifyScenarioWithChangesWorker(change, afterActionDocumentPositionMapperNotEquals, /*timeoutBeforeAction*/ true); + verifyScenarioWithChangesWorker(change, afterActionDocumentPositionMapperNotEquals, /*timeoutBeforeAction*/ true, useDependencyChange); }); it("when timeout does not occur before request", () => { - verifyScenarioWithChangesWorker(change, afterActionDocumentPositionMapperNotEquals, /*timeoutBeforeAction*/ false); + verifyScenarioWithChangesWorker(change, afterActionDocumentPositionMapperNotEquals, /*timeoutBeforeAction*/ false, useDependencyChange); }); }); } @@ -570,12 +582,12 @@ fn5(); function verifyMainScenarioAndScriptInfoCollectionWithNoMap(session: TestSession, host: TestServerHost, dependencyTsOKInScenario?: true) { // Main scenario action - verifyAllFnActionWithNoMap(session, host, dependencyTsOKInScenario); + verifyAllFnActionWithNoMap(session, host, withRefs || dependencyTsOKInScenario); // Collecting at this point retains dependency.d.ts and map watcher closeFilesForSession([randomFile], session); openFilesForSession([randomFile], session); - verifyInfosWhenNoMapFile(session, host); + verifyInfosWhenNoMapFile(session, host, withRefs); // Closing open file, removes dependencies too closeFilesForSession([...openFiles, randomFile], session); @@ -593,7 +605,8 @@ fn5(); verifyInfosWhenNoDtsFile( session, host, - !!forEach(verifier, v => v.expectedProjectActualFiles.every(f => f.toLowerCase() !== dtsPath)) + !!forEach(verifier, v => v.expectedProjectActualFiles.every(f => f.toLowerCase() !== dtsPath)), + /*dependencyTsOk*/ withRefs ); // Closing open file, removes dependencies too @@ -694,35 +707,26 @@ fn5(); ); if (withRefs) { - it("when defining project source changes", () => { - const { host, session } = openTsFile(); - - // First action - firstAction(session); - - // Make change, without rebuild of solution - if (contains(openInfos, dependencyTs.path)) { - session.executeCommandSeq({ - command: protocol.CommandTypes.Change, - arguments: { - file: dependencyTs.path, line: 1, offset: 1, endLine: 1, endOffset: 1, insertString: `function fooBar() { } + verifyScenarioWithChanges( + "when defining project source changes", + (host, session) => { + // Make change, without rebuild of solution + if (contains(openInfos, dependencyTs.path)) { + session.executeCommandSeq({ + command: protocol.CommandTypes.Change, + arguments: { + file: dependencyTs.path, line: 1, offset: 1, endLine: 1, endOffset: 1, insertString: `function fooBar() { } `} - }); - } - else { - host.writeFile(dependencyTs.path, `function fooBar() { } -${dependencyTs.content}`); - } - host.runQueuedTimeoutCallbacks(); - - for (const v of verifier) { - for (let fn = 1; fn <= 5; fn++) { - const { reqName, request, requestDependencyChange, expectedResponseDependencyChange } = v.actionGetter(fn); - const { response } = session.executeCommandSeq(requestDependencyChange || request); - assert.deepEqual(response, expectedResponseDependencyChange, `Failed on ${reqName}`); + }); } - } - }); + else { + host.writeFile(dependencyTs.path, `function fooBar() { } +${dependencyTs.content}`); + } + }, + /*afterActionDocumentPositionMapperNotEquals*/ undefined, + /*useDepedencyChange*/ true + ); } } @@ -730,13 +734,15 @@ ${dependencyTs.content}`); describe(withRefs ? "when main tsconfig has project reference" : "when main tsconfig doesnt have project reference", () => { const usageVerifier: DocumentPositionMapperVerifier = { openFile: mainTs, - expectedProjectActualFiles: [mainTs.path, libFile.path, mainConfig.path, dtsPath], + expectedProjectActualFiles: withRefs ? + [mainTs.path, libFile.path, mainConfig.path, dependencyTs.path] : + [mainTs.path, libFile.path, mainConfig.path, dtsPath], actionGetter: gotoDefintinionFromMainTs, openFileLastLine: 14 }; describe("from project that uses dependency", () => { const closedInfos = withRefs ? - [dependencyTs.path, dependencyConfig.path, libFile.path, dtsPath, dtsMapLocation] : + [dependencyTs.path, dependencyConfig.path, libFile.path] : [dependencyTs.path, libFile.path, dtsPath, dtsMapLocation]; verifyDocumentPositionMapperUpdates( "can go to definition correctly", @@ -764,7 +770,7 @@ ${dependencyTs.content}`); describe("when opening depedency and usage project", () => { const closedInfos = withRefs ? - [libFile.path, dtsPath, dtsMapLocation, dependencyConfig.path] : + [libFile.path, dependencyConfig.path] : [libFile.path, dtsPath, dtsMapLocation]; verifyDocumentPositionMapperUpdates( "goto Definition in usage and rename locations from defining project", From 2f30add809bbc5988d817896f85ecb93dfec61c4 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Wed, 26 Jun 2019 15:29:35 -0700 Subject: [PATCH 009/140] More tests --- .../unittests/tsserver/declarationFileMaps.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/testRunner/unittests/tsserver/declarationFileMaps.ts b/src/testRunner/unittests/tsserver/declarationFileMaps.ts index 0f8af3c414e..b060790939f 100644 --- a/src/testRunner/unittests/tsserver/declarationFileMaps.ts +++ b/src/testRunner/unittests/tsserver/declarationFileMaps.ts @@ -199,7 +199,7 @@ namespace ts.projectSystem { } function verifyUserTsConfigProject(session: TestSession) { - checkProjectActualFiles(session.getProjectService().configuredProjects.get(userTsconfig.path)!, [userTs.path, aDts.path, userTsconfig.path]); + checkProjectActualFiles(session.getProjectService().configuredProjects.get(userTsconfig.path)!, [userTs.path, aTs.path, userTsconfig.path]); } it("goToDefinition", () => { @@ -470,6 +470,13 @@ namespace ts.projectSystem { name: "function f(): void", }, references: [ + makeReferenceEntry({ + file: aTs, + text: "f", + options: { index: 1 }, + contextText: "function f() {}", + isDefinition: true + }), { fileName: bTs.path, isDefinition: false, @@ -477,13 +484,6 @@ namespace ts.projectSystem { isWriteAccess: false, textSpan: { start: 0, length: 1 }, }, - makeReferenceEntry({ - file: aTs, - text: "f", - options: { index: 1 }, - contextText: "function f() {}", - isDefinition: true - }) ], } ]); From da9260c01305bc4f91193f787c868f0def6c0f48 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Wed, 26 Jun 2019 15:57:22 -0700 Subject: [PATCH 010/140] Create original project when location is in source of project reference redirect --- src/compiler/program.ts | 2 +- src/compiler/utilities.ts | 4 ++++ src/server/editorServices.ts | 7 +++++-- src/server/project.ts | 18 +++++++++++++++--- src/server/session.ts | 6 ++++-- src/services/sourcemaps.ts | 7 ++++--- .../tsserver/events/projectLoading.ts | 2 +- 7 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 9a4e26a2903..2ddf191a327 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -814,7 +814,7 @@ namespace ts { let projectReferenceRedirects: Map | undefined; let mapFromFileToProjectReferenceRedirects: Map | undefined; let mapFromToProjectReferenceRedirectSource: Map | undefined; - const useSourceOfReference = host.useSourceInsteadOfReferenceRedirect && host.useSourceInsteadOfReferenceRedirect(); + const useSourceOfReference = useSourceInsteadOfReferenceRedirect(host); const shouldCreateNewSourceFile = shouldProgramCreateNewSourceFiles(oldProgram, options); const structuralIsReused = tryReuseStructureFromOldProgram(); diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 0e2488a0233..ecf7d431a2e 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -4614,6 +4614,10 @@ namespace ts { return false; } } + + export function useSourceInsteadOfReferenceRedirect(host: { useSourceInsteadOfReferenceRedirect?(): boolean; }) { + return host.useSourceInsteadOfReferenceRedirect && host.useSourceInsteadOfReferenceRedirect(); + } } namespace ts { diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 8c7462d857b..e379d1fda2c 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -2570,7 +2570,9 @@ namespace ts.server { /*@internal*/ getOriginalLocationEnsuringConfiguredProject(project: Project, location: DocumentPosition): DocumentPosition | undefined { - const originalLocation = project.getSourceMapper().tryGetSourcePosition(location); + const originalLocation = useSourceInsteadOfReferenceRedirect(project) && project.getResolvedProjectReferenceToRedirect(location.fileName) ? + location : + project.getSourceMapper().tryGetSourcePosition(location); if (!originalLocation) return undefined; const { fileName } = originalLocation; @@ -2581,7 +2583,8 @@ namespace ts.server { if (!configFileName) return undefined; const configuredProject = this.findConfiguredProjectByProjectName(configFileName) || - this.createAndLoadConfiguredProject(configFileName, `Creating project for original file: ${originalFileInfo.fileName} for location: ${location.fileName}`); + this.createAndLoadConfiguredProject(configFileName, `Creating project for original file: ${originalFileInfo.fileName}${location !== originalLocation ? " for location " + location.fileName : ""}`); + if (configuredProject === project) return originalLocation; updateProjectIfDirty(configuredProject); // Keep this configured project as referenced from project addOriginalConfiguredProject(configuredProject); diff --git a/src/server/project.ts b/src/server/project.ts index 8f8e6e5da8e..c6c8ab84b20 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -196,6 +196,14 @@ namespace ts.server { /*@internal*/ originalConfiguredProjects: Map | undefined; + /*@internal*/ + useSourceInsteadOfReferenceRedirect?: () => boolean; + + /*@internal*/ + getResolvedProjectReferenceToRedirect(_fileName: string): ResolvedProjectReference | undefined { + return undefined; + } + private readonly cancellationToken: ThrottledCancellationToken; public isNonTsProject() { @@ -1526,9 +1534,7 @@ namespace ts.server { } /* @internal */ - useSourceInsteadOfReferenceRedirect() { - return !!this.languageServiceEnabled; - } + useSourceInsteadOfReferenceRedirect = () => !!this.languageServiceEnabled; fileExists(file: string): boolean { // Project references go to source file instead of .d.ts file @@ -1590,6 +1596,12 @@ namespace ts.server { return program && program.forEachResolvedProjectReference(cb); } + /*@internal*/ + getResolvedProjectReferenceToRedirect(fileName: string): ResolvedProjectReference | undefined { + const program = this.getCurrentProgram(); + return program && program.getResolvedProjectReferenceToRedirect(fileName); + } + /*@internal*/ enablePluginsWithOptions(options: CompilerOptions, pluginConfigOverrides: Map | undefined) { const host = this.projectService.host; diff --git a/src/server/session.ts b/src/server/session.ts index 5064b529560..792ec2cbce9 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -443,7 +443,9 @@ namespace ts.server { function getDefinitionInProject(definition: DocumentPosition | undefined, definingProject: Project, project: Project): DocumentPosition | undefined { if (!definition || project.containsFile(toNormalizedPath(definition.fileName))) return definition; - const mappedDefinition = definingProject.getLanguageService().getSourceMapper().tryGetGeneratedPosition(definition); + const mappedDefinition = useSourceInsteadOfReferenceRedirect(definingProject) && definingProject.getResolvedProjectReferenceToRedirect(definition.fileName) ? + definition : + definingProject.getLanguageService().getSourceMapper().tryGetGeneratedPosition(definition); return mappedDefinition && project.containsFile(toNormalizedPath(mappedDefinition.fileName)) ? mappedDefinition : undefined; } @@ -472,7 +474,7 @@ namespace ts.server { for (const symlinkedProject of symlinkedProjects) addToTodo({ project: symlinkedProject, location: originalLocation as TLocation }, toDo!, seenProjects); }); } - return originalLocation; + return originalLocation === location ? undefined : originalLocation; }); return toDo; } diff --git a/src/services/sourcemaps.ts b/src/services/sourcemaps.ts index de590d4e5b4..c4c14e58686 100644 --- a/src/services/sourcemaps.ts +++ b/src/services/sourcemaps.ts @@ -72,9 +72,10 @@ namespace ts { const program = host.getProgram()!; // If this is source file of project reference source (instead of redirect) there is no generated position - if (host.useSourceInsteadOfReferenceRedirect && - host.useSourceInsteadOfReferenceRedirect() && - program.getResolvedProjectReferenceToRedirect(sourceFile.fileName)) return undefined; + if (useSourceInsteadOfReferenceRedirect(host) && + program.getResolvedProjectReferenceToRedirect(sourceFile.fileName)) { + return undefined; + } const options = program.getCompilerOptions(); const outPath = options.outFile || options.out; diff --git a/src/testRunner/unittests/tsserver/events/projectLoading.ts b/src/testRunner/unittests/tsserver/events/projectLoading.ts index 7a881ff1380..53fe28240f8 100644 --- a/src/testRunner/unittests/tsserver/events/projectLoading.ts +++ b/src/testRunner/unittests/tsserver/events/projectLoading.ts @@ -110,7 +110,7 @@ namespace ts.projectSystem { checkNumberOfProjects(service, { configuredProjects: 2 }); const project = service.configuredProjects.get(configA.path)!; assert.isDefined(project); - verifyEvent(project, `Creating project for original file: ${aTs.path} for location: ${aDTs.path}`); + verifyEvent(project, `Creating project for original file: ${aTs.path}`); }); describe("with external projects and config files ", () => { From 75bd3cd9be28686c492d7028ed828fce7f9bcef9 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 27 Jun 2019 12:12:02 -0700 Subject: [PATCH 011/140] Fix more tests --- src/testRunner/unittests/tsbuildWatchMode.ts | 191 +++++++++++-------- 1 file changed, 108 insertions(+), 83 deletions(-) diff --git a/src/testRunner/unittests/tsbuildWatchMode.ts b/src/testRunner/unittests/tsbuildWatchMode.ts index a630e28f1d8..6a577888c7e 100644 --- a/src/testRunner/unittests/tsbuildWatchMode.ts +++ b/src/testRunner/unittests/tsbuildWatchMode.ts @@ -681,9 +681,9 @@ let x: string = 10;`); const coreIndexDts = projectFileName(SubProject.core, "index.d.ts"); const coreAnotherModuleDts = projectFileName(SubProject.core, "anotherModule.d.ts"); const logicIndexDts = projectFileName(SubProject.logic, "index.d.ts"); - const expectedWatchedFiles = [core[0], logic[0], ...tests, libFile].map(f => f.path).concat([coreIndexDts, coreAnotherModuleDts, logicIndexDts].map(f => f.toLowerCase())); const expectedWatchedDirectoriesRecursive = projectSystem.getTypeRootsFromLocation(projectPath(SubProject.tests)); const expectedProgramFiles = [tests[1].path, libFile.path, coreIndexDts, coreAnotherModuleDts, logicIndexDts]; + const expectedProjectFiles = [libFile, ...tests, ...logic.slice(1), ...core.slice(1, core.length - 1)].map(f => f.path); function createSolutionAndWatchMode() { return createSolutionAndWatchModeOfProject(allFiles, projectsLocation, `${project}/${SubProject.tests}`, tests[0].path, getOutputFileStamps); @@ -694,12 +694,19 @@ let x: string = 10;`); } function verifyWatches(host: TsBuildWatchSystem, withTsserver?: boolean) { - verifyWatchesOfProject(host, withTsserver ? expectedWatchedFiles.filter(f => f !== tests[1].path.toLowerCase()) : expectedWatchedFiles, expectedWatchedDirectoriesRecursive); + verifyWatchesOfProject( + host, + withTsserver ? + [...core.slice(0, core.length - 1), ...logic, tests[0], libFile].map(f => f.path.toLowerCase()) : + [core[0], logic[0], ...tests, libFile].map(f => f.path).concat([coreIndexDts, coreAnotherModuleDts, logicIndexDts].map(f => f.toLowerCase())), + expectedWatchedDirectoriesRecursive + ); } function verifyScenario( edit: (host: TsBuildWatchSystem, solutionBuilder: SolutionBuilder) => void, - expectedFilesAfterEdit: ReadonlyArray + expectedProgramFilesAfterEdit: ReadonlyArray, + expectedProjectFilesAfterEdit: ReadonlyArray ) { it("with tsc-watch", () => { const { host, solutionBuilder, watch } = createSolutionAndWatchMode(); @@ -708,7 +715,7 @@ let x: string = 10;`); host.checkTimeoutQueueLengthAndRun(1); checkOutputErrorsIncremental(host, emptyArray); - checkProgramActualFiles(watch(), expectedFilesAfterEdit); + checkProgramActualFiles(watch(), expectedProgramFilesAfterEdit); }); @@ -718,7 +725,7 @@ let x: string = 10;`); edit(host, solutionBuilder); host.checkTimeoutQueueLengthAndRun(2); - checkProjectActualFiles(service, tests[0].path, [tests[0].path, ...expectedFilesAfterEdit]); + checkProjectActualFiles(service, tests[0].path, [...expectedProjectFilesAfterEdit]); }); } @@ -748,7 +755,7 @@ function foo() { // not ideal, but currently because of d.ts but no new file is written // There will be timeout queued even though file contents are same - }, expectedProgramFiles); + }, expectedProgramFiles, expectedProjectFiles); }); describe("non local edit in ts file, rebuilds in watch compilation", () => { @@ -758,7 +765,7 @@ export function gfoo() { }`); solutionBuilder.invalidateProject(logic[0].path.toLowerCase() as ResolvedConfigFilePath); solutionBuilder.buildNextInvalidatedProject(); - }, expectedProgramFiles); + }, expectedProgramFiles, expectedProjectFiles); }); describe("change in project reference config file builds correctly", () => { @@ -769,7 +776,7 @@ export function gfoo() { })); solutionBuilder.invalidateProject(logic[0].path.toLowerCase() as ResolvedConfigFilePath, ConfigFileProgramReloadLevel.Full); solutionBuilder.buildNextInvalidatedProject(); - }, [tests[1].path, libFile.path, coreIndexDts, coreAnotherModuleDts, projectFilePath(SubProject.logic, "decls/index.d.ts")]); + }, [tests[1].path, libFile.path, coreIndexDts, coreAnotherModuleDts, projectFilePath(SubProject.logic, "decls/index.d.ts")], expectedProjectFiles); }); }); @@ -859,7 +866,9 @@ export function gfoo() { const aDts = dtsFile(multiFolder ? "a/index" : "a"), bDts = dtsFile(multiFolder ? "b/index" : "b"); const expectedFiles = [jsFile(multiFolder ? "a/index" : "a"), aDts, jsFile(multiFolder ? "b/index" : "b"), bDts, jsFile(multiFolder ? "c/index" : "c")]; const expectedProgramFiles = [cTs.path, libFile.path, aDts, refs.path, bDts]; + const expectedProjectFiles = [cTs.path, libFile.path, aTs.path, refs.path, bTs.path]; const expectedWatchedFiles = expectedProgramFiles.concat(cTsconfig.path, bTsconfig.path, aTsconfig.path).map(s => s.toLowerCase()); + const expectedProjectWatchedFiles = expectedProjectFiles.concat(cTsconfig.path, bTsconfig.path, aTsconfig.path).map(s => s.toLowerCase()); const expectedWatchedDirectories = multiFolder ? [ getProjectPath(project).toLowerCase() // watches for directories created for resolution of b ] : emptyArray; @@ -897,22 +906,29 @@ export function gfoo() { } function verifyProject(host: TsBuildWatchSystem, service: projectSystem.TestProjectService, orphanInfos?: ReadonlyArray) { - verifyServerState(host, service, expectedProgramFiles, expectedWatchedFiles, expectedWatchedDirectoriesRecursive, orphanInfos); + verifyServerState({ host, service, expectedProjectFiles, expectedProjectWatchedFiles, expectedWatchedDirectoriesRecursive, orphanInfos }); } - function verifyServerState( - host: TsBuildWatchSystem, - service: projectSystem.TestProjectService, - expectedProgramFiles: ReadonlyArray, - expectedWatchedFiles: ReadonlyArray, - expectedWatchedDirectoriesRecursive: ReadonlyArray, - orphanInfos?: ReadonlyArray) { - checkProjectActualFiles(service, cTsconfig.path, expectedProgramFiles.concat(cTsconfig.path)); - const watchedFiles = expectedWatchedFiles.filter(f => f !== cTs.path.toLowerCase()); - if (orphanInfos) { + interface VerifyServerState { + host: TsBuildWatchSystem; + service: projectSystem.TestProjectService; + expectedProjectFiles: ReadonlyArray; + expectedProjectWatchedFiles: ReadonlyArray; + expectedWatchedDirectoriesRecursive: ReadonlyArray; + orphanInfos?: ReadonlyArray; + } + function verifyServerState({ host, service, expectedProjectFiles, expectedProjectWatchedFiles, expectedWatchedDirectoriesRecursive, orphanInfos }: VerifyServerState) { + checkProjectActualFiles(service, cTsconfig.path, expectedProjectFiles.concat(cTsconfig.path)); + const watchedFiles = expectedProjectWatchedFiles.filter(f => f !== cTs.path.toLowerCase()); + const actualOrphan = arrayFrom(mapDefinedIterator( + service.filenameToScriptInfo.values(), + v => v.containingProjects.length === 0 ? v.fileName : undefined + )); + assert.equal(actualOrphan.length, orphanInfos ? orphanInfos.length : 0, `Orphans found: ${JSON.stringify(actualOrphan, /*replacer*/ undefined, " ")}`); + if (orphanInfos && orphanInfos.length) { for (const orphan of orphanInfos) { const info = service.getScriptInfoForPath(orphan as Path); - assert.isDefined(info); + assert.isDefined(info, `${orphan} expected to be present. Actual: ${JSON.stringify(actualOrphan, /*replacer*/ undefined, " ")}`); assert.equal(info!.containingProjects.length, 0); watchedFiles.push(orphan); } @@ -920,16 +936,20 @@ export function gfoo() { verifyWatchesOfProject(host, watchedFiles, expectedWatchedDirectoriesRecursive, expectedWatchedDirectories); } - function verifyScenario( - edit: (host: TsBuildWatchSystem, solutionBuilder: SolutionBuilder) => void, - expectedEditErrors: ReadonlyArray, - expectedProgramFiles: ReadonlyArray, - expectedWatchedFiles: ReadonlyArray, - expectedWatchedDirectoriesRecursive: ReadonlyArray, - dependencies: ReadonlyArray<[string, ReadonlyArray]>, - revert?: (host: TsBuildWatchSystem) => void, - orphanInfosAfterEdit?: ReadonlyArray, - orphanInfosAfterRevert?: ReadonlyArray) { + interface VerifyScenario { + edit: (host: TsBuildWatchSystem, solutionBuilder: SolutionBuilder) => void; + expectedEditErrors: ReadonlyArray; + expectedProgramFiles: ReadonlyArray; + expectedProjectFiles: ReadonlyArray; + expectedWatchedFiles: ReadonlyArray; + expectedProjectWatchedFiles: ReadonlyArray; + expectedWatchedDirectoriesRecursive: ReadonlyArray; + dependencies: ReadonlyArray<[string, ReadonlyArray]>; + revert?: (host: TsBuildWatchSystem) => void; + orphanInfosAfterEdit?: ReadonlyArray; + orphanInfosAfterRevert?: ReadonlyArray; + } + function verifyScenario({ edit, expectedEditErrors, expectedProgramFiles, expectedProjectFiles, expectedWatchedFiles, expectedProjectWatchedFiles, expectedWatchedDirectoriesRecursive, dependencies, revert, orphanInfosAfterEdit, orphanInfosAfterRevert }: VerifyScenario) { it("with tsc-watch", () => { const { host, solutionBuilder, watch } = createSolutionAndWatchMode(); @@ -956,7 +976,7 @@ export function gfoo() { edit(host, solutionBuilder); host.checkTimeoutQueueLengthAndRun(2); - verifyServerState(host, service, expectedProgramFiles, expectedWatchedFiles, expectedWatchedDirectoriesRecursive, orphanInfosAfterEdit); + verifyServerState({ host, service, expectedProjectFiles, expectedProjectWatchedFiles, expectedWatchedDirectoriesRecursive, orphanInfos: orphanInfosAfterEdit }); if (revert) { revert(host); @@ -981,20 +1001,21 @@ export function gfoo() { }); describe("non local edit updates the program and watch correctly", () => { - verifyScenario( - (host, solutionBuilder) => { + verifyScenario({ + edit: (host, solutionBuilder) => { // edit - host.writeFile(bTs.path, `${bTs.content} -export function gfoo() { -}`); - solutionBuilder.invalidateProject(bTsconfig.path.toLowerCase() as ResolvedConfigFilePath); + host.writeFile(bTs.path, `${bTs.content}\nexport function gfoo() {\n}`); + solutionBuilder.invalidateProject((bTsconfig.path.toLowerCase() as ResolvedConfigFilePath)); solutionBuilder.buildNextInvalidatedProject(); }, - emptyArray, + expectedEditErrors: emptyArray, expectedProgramFiles, + expectedProjectFiles, expectedWatchedFiles, + expectedProjectWatchedFiles, expectedWatchedDirectoriesRecursive, - defaultDependencies); + dependencies: defaultDependencies + }); }); describe("edit on config file", () => { @@ -1003,30 +1024,32 @@ export function gfoo() { path: getFilePathInProject(project, "nrefs/a.d.ts"), content: refs.content }; - verifyScenario( - host => { + verifyScenario({ + edit: host => { const cTsConfigJson = JSON.parse(cTsconfig.content); host.ensureFileOrFolder(nrefs); cTsConfigJson.compilerOptions.paths = { "@ref/*": nrefsPath }; host.writeFile(cTsconfig.path, JSON.stringify(cTsConfigJson)); }, - emptyArray, - expectedProgramFiles.map(nrefReplacer), - expectedWatchedFiles.map(nrefReplacer), - expectedWatchedDirectoriesRecursive.map(nrefReplacer), - [ + expectedEditErrors: emptyArray, + expectedProgramFiles: expectedProgramFiles.map(nrefReplacer), + expectedProjectFiles: expectedProjectFiles.map(nrefReplacer), + expectedWatchedFiles: expectedWatchedFiles.map(nrefReplacer), + expectedProjectWatchedFiles: expectedProjectWatchedFiles.map(nrefReplacer), + expectedWatchedDirectoriesRecursive: expectedWatchedDirectoriesRecursive.map(nrefReplacer), + dependencies: [ [aDts, [aDts]], [bDts, [bDts, aDts]], [nrefs.path, [nrefs.path]], [cTs.path, [cTs.path, nrefs.path, bDts]] ], // revert the update - host => host.writeFile(cTsconfig.path, cTsconfig.content), + revert: host => host.writeFile(cTsconfig.path, cTsconfig.content), // AfterEdit:: Extra watched files on server since the script infos arent deleted till next file open - [refs.path.toLowerCase()], + orphanInfosAfterEdit: [refs.path.toLowerCase()], // AfterRevert:: Extra watched files on server since the script infos arent deleted till next file open - [nrefs.path.toLowerCase()] - ); + orphanInfosAfterRevert: [nrefs.path.toLowerCase()] + }); }); describe("edit in referenced config file", () => { @@ -1035,82 +1058,84 @@ export function gfoo() { content: "export declare class A {}" }; const expectedProgramFiles = [cTs.path, bDts, nrefs.path, refs.path, libFile.path]; + const expectedProjectFiles = [cTs.path, bTs.path, nrefs.path, refs.path, libFile.path]; const [, ...expectedWatchedDirectoriesRecursiveWithoutA] = expectedWatchedDirectoriesRecursive; // Not looking in a folder for resolution in multi folder scenario - verifyScenario( - host => { + verifyScenario({ + edit: host => { const bTsConfigJson = JSON.parse(bTsconfig.content); host.ensureFileOrFolder(nrefs); bTsConfigJson.compilerOptions.paths = { "@ref/*": nrefsPath }; host.writeFile(bTsconfig.path, JSON.stringify(bTsConfigJson)); }, - emptyArray, + expectedEditErrors: emptyArray, expectedProgramFiles, - expectedProgramFiles.concat(cTsconfig.path, bTsconfig.path, aTsconfig.path).map(s => s.toLowerCase()), - (multiFolder ? expectedWatchedDirectoriesRecursiveWithoutA : expectedWatchedDirectoriesRecursive).concat(getFilePathInProject(project, "nrefs").toLowerCase()), - [ + expectedProjectFiles, + expectedWatchedFiles: expectedProgramFiles.concat(cTsconfig.path, bTsconfig.path, aTsconfig.path).map(s => s.toLowerCase()), + expectedProjectWatchedFiles: expectedProjectFiles.concat(cTsconfig.path, bTsconfig.path, aTsconfig.path).map(s => s.toLowerCase()), + expectedWatchedDirectoriesRecursive: (multiFolder ? expectedWatchedDirectoriesRecursiveWithoutA : expectedWatchedDirectoriesRecursive).concat(getFilePathInProject(project, "nrefs").toLowerCase()), + dependencies: [ [nrefs.path, [nrefs.path]], [bDts, [bDts, nrefs.path]], [refs.path, [refs.path]], [cTs.path, [cTs.path, refs.path, bDts]], ], // revert the update - host => host.writeFile(bTsconfig.path, bTsconfig.content), + revert: host => host.writeFile(bTsconfig.path, bTsconfig.content), // AfterEdit:: Extra watched files on server since the script infos arent deleted till next file open - [aDts.toLowerCase()], + orphanInfosAfterEdit: [aTs.path.toLowerCase()], // AfterRevert:: Extra watched files on server since the script infos arent deleted till next file open - [nrefs.path.toLowerCase()] - ); + orphanInfosAfterRevert: [nrefs.path.toLowerCase()] + }); }); describe("deleting referenced config file", () => { const expectedProgramFiles = [cTs.path, bTs.path, refs.path, libFile.path]; + const expectedWatchedFiles = expectedProgramFiles.concat(cTsconfig.path, bTsconfig.path).map(s => s.toLowerCase()); const [, ...expectedWatchedDirectoriesRecursiveWithoutA] = expectedWatchedDirectoriesRecursive; // Not looking in a folder for resolution in multi folder scenario // Resolutions should change now // Should map to b.ts instead with options from our own config - verifyScenario( - host => host.deleteFile(bTsconfig.path), - [ + verifyScenario({ + edit: host => host.deleteFile(bTsconfig.path), + expectedEditErrors: [ `${multiFolder ? "c/tsconfig.json" : "tsconfig.c.json"}(9,21): error TS6053: File '/user/username/projects/transitiveReferences/${multiFolder ? "b" : "tsconfig.b.json"}' not found.\n` ], expectedProgramFiles, - expectedProgramFiles.concat(cTsconfig.path, bTsconfig.path).map(s => s.toLowerCase()), - multiFolder ? expectedWatchedDirectoriesRecursiveWithoutA : expectedWatchedDirectoriesRecursive, - [ + expectedProjectFiles: expectedProgramFiles, + expectedWatchedFiles, + expectedProjectWatchedFiles: expectedWatchedFiles, + expectedWatchedDirectoriesRecursive: multiFolder ? expectedWatchedDirectoriesRecursiveWithoutA : expectedWatchedDirectoriesRecursive, + dependencies: [ [bTs.path, [bTs.path, refs.path]], [refs.path, [refs.path]], [cTs.path, [cTs.path, refs.path, bTs.path]], ], // revert the update - host => host.writeFile(bTsconfig.path, bTsconfig.content), + revert: host => host.writeFile(bTsconfig.path, bTsconfig.content), // AfterEdit:: Extra watched files on server since the script infos arent deleted till next file open - [bDts.toLowerCase(), aDts.toLowerCase(), aTsconfig.path.toLowerCase()], - // AfterRevert:: Extra watched files on server since the script infos arent deleted till next file open - [bTs.path.toLowerCase()] - ); + orphanInfosAfterEdit: [aTs.path.toLowerCase(), aTsconfig.path.toLowerCase()], + }); }); describe("deleting transitively referenced config file", () => { - verifyScenario( - host => host.deleteFile(aTsconfig.path), - [ + verifyScenario({ + edit: host => host.deleteFile(aTsconfig.path), + expectedEditErrors: [ `${multiFolder ? "b/tsconfig.json" : "tsconfig.b.json"}(10,21): error TS6053: File '/user/username/projects/transitiveReferences/${multiFolder ? "a" : "tsconfig.a.json"}' not found.\n` ], - expectedProgramFiles.map(s => s.replace(aDts, aTs.path)), - expectedWatchedFiles.map(s => s.replace(aDts.toLowerCase(), aTs.path.toLocaleLowerCase())), + expectedProgramFiles: expectedProgramFiles.map(s => s.replace(aDts, aTs.path)), + expectedProjectFiles, + expectedWatchedFiles: expectedWatchedFiles.map(s => s.replace(aDts.toLowerCase(), aTs.path.toLocaleLowerCase())), + expectedProjectWatchedFiles, expectedWatchedDirectoriesRecursive, - [ + dependencies: [ [aTs.path, [aTs.path]], [bDts, [bDts, aTs.path]], [refs.path, [refs.path]], [cTs.path, [cTs.path, refs.path, bDts]], ], // revert the update - host => host.writeFile(aTsconfig.path, aTsconfig.content), - // AfterEdit:: Extra watched files on server since the script infos arent deleted till next file open - [aDts.toLowerCase()], - // AfterRevert:: Extra watched files on server since the script infos arent deleted till next file open - [aTs.path.toLowerCase()] - ); + revert: host => host.writeFile(aTsconfig.path, aTsconfig.content), + }); }); } From f72af3be60688fa30a2e918e8dc86c1fad882b8a Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 28 Jun 2019 15:49:48 -0700 Subject: [PATCH 012/140] Verify the scenarios when d.ts directory of dependency doesnt exist --- src/compiler/program.ts | 14 ++++-- src/compiler/types.ts | 9 ++-- src/server/project.ts | 45 ++++++++++++++++--- src/services/services.ts | 4 +- src/services/types.ts | 2 +- .../unittests/tsserver/projectReferences.ts | 30 +++++++++++++ 6 files changed, 88 insertions(+), 16 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 27f5d25c847..37c2d6a9c83 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -826,8 +826,11 @@ namespace ts { if (!resolvedProjectReferences) { resolvedProjectReferences = projectReferences.map(parseProjectReferenceConfigFile); } - if (host.setGetSourceOfProjectReferenceRedirect) { - host.setGetSourceOfProjectReferenceRedirect(getSourceOfProjectReferenceRedirect); + if (host.setResolvedProjectReferenceCallbacks) { + host.setResolvedProjectReferenceCallbacks({ + getSourceOfProjectReferenceRedirect, + forEachResolvedProjectReference + }); } if (rootNames.length) { for (const parsedRef of resolvedProjectReferences) { @@ -1226,8 +1229,11 @@ namespace ts { } if (projectReferences) { resolvedProjectReferences = projectReferences.map(parseProjectReferenceConfigFile); - if (host.setGetSourceOfProjectReferenceRedirect) { - host.setGetSourceOfProjectReferenceRedirect(getSourceOfProjectReferenceRedirect); + if (host.setResolvedProjectReferenceCallbacks) { + host.setResolvedProjectReferenceCallbacks({ + getSourceOfProjectReferenceRedirect, + forEachResolvedProjectReference + }); } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 79a92cfa31d..3cf506b0d58 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5166,7 +5166,7 @@ namespace ts { /* @internal */ hasChangedAutomaticTypeDirectiveNames?: boolean; createHash?(data: string): string; getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined; - /* @internal */ setGetSourceOfProjectReferenceRedirect?(getSource: GetSourceOfProjectReferenceRedirect): void; + /* @internal */ setResolvedProjectReferenceCallbacks?(callbacks: ResolvedProjectReferenceCallbacks): void; /* @internal */ useSourceInsteadOfReferenceRedirect?(): boolean; // TODO: later handle this in better way in builder host instead once the api for tsbuild finalizes and doesn't use compilerHost as base @@ -5175,10 +5175,13 @@ namespace ts { /** true if --out otherwise source file name */ /*@internal*/ - export type SourceOfProjectReferenceRedirect = string | true ; + export type SourceOfProjectReferenceRedirect = string | true; /*@internal*/ - export type GetSourceOfProjectReferenceRedirect = (fileName: string) => SourceOfProjectReferenceRedirect | undefined; + interface ResolvedProjectReferenceCallbacks { + getSourceOfProjectReferenceRedirect(fileName: string): SourceOfProjectReferenceRedirect | undefined; + forEachResolvedProjectReference(cb: (resolvedProjectReference: ResolvedProjectReference | undefined, resolvedProjectReferencePath: Path) => T | undefined): T | undefined; + } /* @internal */ export const enum TransformFlags { diff --git a/src/server/project.ts b/src/server/project.ts index c6c8ab84b20..04a5b91531a 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -1482,7 +1482,8 @@ namespace ts.server { configFileWatcher: FileWatcher | undefined; private directoriesWatchedForWildcards: Map | undefined; readonly canonicalConfigFilePath: NormalizedPath; - private getSourceOfProjectReferenceRedirect: GetSourceOfProjectReferenceRedirect | undefined; + private projectReferenceCallbacks: ResolvedProjectReferenceCallbacks | undefined; + private mapOfDeclarationDirectories: Map | undefined; /* @internal */ pendingReload: ConfigFileProgramReloadLevel | undefined; @@ -1529,8 +1530,8 @@ namespace ts.server { } /* @internal */ - setGetSourceOfProjectReferenceRedirect(getSource: GetSourceOfProjectReferenceRedirect) { - this.getSourceOfProjectReferenceRedirect = getSource; + setResolvedProjectReferenceCallbacks(projectReferenceCallbacks: ResolvedProjectReferenceCallbacks) { + this.projectReferenceCallbacks = projectReferenceCallbacks; } /* @internal */ @@ -1538,13 +1539,42 @@ namespace ts.server { fileExists(file: string): boolean { // Project references go to source file instead of .d.ts file - if (this.languageServiceEnabled && this.getSourceOfProjectReferenceRedirect) { - const source = this.getSourceOfProjectReferenceRedirect(file); + if (this.useSourceInsteadOfReferenceRedirect() && this.projectReferenceCallbacks) { + const source = this.projectReferenceCallbacks.getSourceOfProjectReferenceRedirect(file); if (source) return isString(source) ? super.fileExists(source) : true; } return super.fileExists(file); } + directoryExists(path: string): boolean { + if (super.directoryExists(path)) return true; + if (!this.useSourceInsteadOfReferenceRedirect() || !this.projectReferenceCallbacks) return false; + + if (!this.mapOfDeclarationDirectories) { + this.mapOfDeclarationDirectories = createMap(); + this.projectReferenceCallbacks.forEachResolvedProjectReference(ref => { + if (!ref) return; + const out = ref.commandLine.options.outFile || ref.commandLine.options.outDir; + if (out) { + this.mapOfDeclarationDirectories!.set(getDirectoryPath(this.toPath(out)), true); + } + else { + // Set declaration's in different locations only, if they are next to source the directory present doesnt change + const declarationDir = ref.commandLine.options.declarationDir || ref.commandLine.options.outDir; + if (declarationDir) { + this.mapOfDeclarationDirectories!.set(this.toPath(declarationDir), true); + } + } + }); + } + const dirPath = this.toPath(path); + const dirPathWithTrailingDirectorySeparator = `${dirPath}${directorySeparator}`; + return !!forEachKey( + this.mapOfDeclarationDirectories, + declDirPath => dirPath === declDirPath || startsWith(declDirPath, dirPathWithTrailingDirectorySeparator) + ); + } + /** * If the project has reload from disk pending, it reloads (and then updates graph as part of that) instead of just updating the graph * @returns: true if set of files in the project stays the same and false - otherwise. @@ -1553,6 +1583,8 @@ namespace ts.server { this.isInitialLoadPending = returnFalse; const reloadLevel = this.pendingReload; this.pendingReload = ConfigFileProgramReloadLevel.None; + this.projectReferenceCallbacks = undefined; + this.mapOfDeclarationDirectories = undefined; let result: boolean; switch (reloadLevel) { case ConfigFileProgramReloadLevel.Partial: @@ -1567,7 +1599,6 @@ namespace ts.server { default: result = super.updateGraph(); } - this.getSourceOfProjectReferenceRedirect = undefined; this.projectService.sendProjectLoadingFinishEvent(this); this.projectService.sendProjectTelemetry(this); return result; @@ -1684,6 +1715,8 @@ namespace ts.server { this.stopWatchingWildCards(); this.projectErrors = undefined; this.configFileSpecs = undefined; + this.projectReferenceCallbacks = undefined; + this.mapOfDeclarationDirectories = undefined; super.close(); } diff --git a/src/services/services.ts b/src/services/services.ts index aa6ea119225..7de7934653e 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1246,8 +1246,8 @@ namespace ts { return host.resolveTypeReferenceDirectives!(typeReferenceDirectiveNames, containingFile, redirectedReference); }; } - if (host.setGetSourceOfProjectReferenceRedirect) { - compilerHost.setGetSourceOfProjectReferenceRedirect = getSource => host.setGetSourceOfProjectReferenceRedirect!(getSource); + if (host.setResolvedProjectReferenceCallbacks) { + compilerHost.setResolvedProjectReferenceCallbacks = callbacks => host.setResolvedProjectReferenceCallbacks!(callbacks); } if (host.useSourceInsteadOfReferenceRedirect) { compilerHost.useSourceInsteadOfReferenceRedirect = () => host.useSourceInsteadOfReferenceRedirect!(); diff --git a/src/services/types.ts b/src/services/types.ts index 3c9509ca5e9..b4fc25e587f 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -237,7 +237,7 @@ namespace ts { /* @internal */ getSourceFileLike?(fileName: string): SourceFileLike | undefined; /* @internal */ - setGetSourceOfProjectReferenceRedirect?(getSource: GetSourceOfProjectReferenceRedirect): void; + setResolvedProjectReferenceCallbacks?(callbacks: ResolvedProjectReferenceCallbacks): void; /* @internal */ useSourceInsteadOfReferenceRedirect?(): boolean; } diff --git a/src/testRunner/unittests/tsserver/projectReferences.ts b/src/testRunner/unittests/tsserver/projectReferences.ts index 5320cfe13bc..0b8b074f8e2 100644 --- a/src/testRunner/unittests/tsserver/projectReferences.ts +++ b/src/testRunner/unittests/tsserver/projectReferences.ts @@ -727,6 +727,36 @@ ${dependencyTs.content}`); /*afterActionDocumentPositionMapperNotEquals*/ undefined, /*useDepedencyChange*/ true ); + + it("when d.ts file is not generated", () => { + const host = createServerHost(files); + const session = createSession(host); + openFilesForSession([...openFiles, randomFile], session); + + const expectedClosedInfos = closedInfos.filter(f => f.toLowerCase() !== dtsPath && f.toLowerCase() !== dtsMapPath); + // If closed infos includes dts and dtsMap, watch dts since its not present + const expectedWatchedFiles = closedInfos.length === expectedClosedInfos.length ? + otherWatchedFiles : + otherWatchedFiles.concat(dtsPath); + // Main scenario action + verifyAllFnActionWorker(session, ({ reqName, response, expectedResponse }) => { + assert.deepEqual(response, expectedResponse, `Failed on ${reqName}`); + verifyInfosWithRandom(session, host, openInfos, expectedClosedInfos, expectedWatchedFiles); + verifyDocumentPositionMapper(session, /*dependencyMap*/ undefined, /*documentPositionMapper*/ undefined); + }, /*dtsAbsent*/ true); + checkProject(session); + + // Collecting at this point retains dependency.d.ts and map + closeFilesForSession([randomFile], session); + openFilesForSession([randomFile], session); + verifyInfosWithRandom(session, host, openInfos, expectedClosedInfos, expectedWatchedFiles); + verifyDocumentPositionMapper(session, /*dependencyMap*/ undefined, /*documentPositionMapper*/ undefined); + + // Closing open file, removes dependencies too + closeFilesForSession([...openFiles, randomFile], session); + openFilesForSession([randomFile], session); + verifyOnlyRandomInfos(session, host); + }); } } From f9e4b91203a0bcbddcca2acee442bb4f5ca0a869 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Mon, 1 Jul 2019 13:37:35 -0700 Subject: [PATCH 013/140] Fix incorrectly exported type --- src/compiler/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 3cf506b0d58..ff0aba6acad 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5178,7 +5178,7 @@ namespace ts { export type SourceOfProjectReferenceRedirect = string | true; /*@internal*/ - interface ResolvedProjectReferenceCallbacks { + export interface ResolvedProjectReferenceCallbacks { getSourceOfProjectReferenceRedirect(fileName: string): SourceOfProjectReferenceRedirect | undefined; forEachResolvedProjectReference(cb: (resolvedProjectReference: ResolvedProjectReference | undefined, resolvedProjectReferencePath: Path) => T | undefined): T | undefined; } From f7ea0bab60d4198c04f81de624ea61b6d75bcc9c Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Mon, 1 Jul 2019 14:29:32 -0700 Subject: [PATCH 014/140] Refactoring --- src/compiler/program.ts | 7 ++++++- src/compiler/types.ts | 2 ++ src/compiler/utilities.ts | 4 ---- src/server/editorServices.ts | 2 +- src/server/project.ts | 8 +++++--- src/server/session.ts | 2 +- src/services/services.ts | 1 - src/services/sourcemaps.ts | 4 +--- 8 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 9da4b2efe06..78e5f314879 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -814,7 +814,7 @@ namespace ts { let projectReferenceRedirects: Map | undefined; let mapFromFileToProjectReferenceRedirects: Map | undefined; let mapFromToProjectReferenceRedirectSource: Map | undefined; - const useSourceOfReference = useSourceInsteadOfReferenceRedirect(host); + const useSourceOfReference = !!host.useSourceInsteadOfReferenceRedirect && host.useSourceInsteadOfReferenceRedirect(); const shouldCreateNewSourceFile = shouldProgramCreateNewSourceFiles(oldProgram, options); const structuralIsReused = tryReuseStructureFromOldProgram(); @@ -964,6 +964,7 @@ namespace ts { getResolvedProjectReferenceToRedirect, getResolvedProjectReferenceByPath, forEachResolvedProjectReference, + isSourceOfProjectReferenceRedirect, emitBuildInfo }; @@ -2496,6 +2497,10 @@ namespace ts { return mapFromToProjectReferenceRedirectSource.get(toPath(file)); } + function isSourceOfProjectReferenceRedirect(fileName: string) { + return useSourceOfReference && !!getResolvedProjectReferenceToRedirect(fileName); + } + function forEachProjectReference( projectReferences: ReadonlyArray | undefined, resolvedProjectReferences: ReadonlyArray | undefined, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ff0aba6acad..16ea47beecc 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2993,6 +2993,7 @@ namespace ts { /*@internal*/ getResolvedProjectReferenceToRedirect(fileName: string): ResolvedProjectReference | undefined; /*@internal*/ forEachResolvedProjectReference(cb: (resolvedProjectReference: ResolvedProjectReference | undefined, resolvedProjectReferencePath: Path) => T | undefined): T | undefined; /*@internal*/ getResolvedProjectReferenceByPath(projectReferencePath: Path): ResolvedProjectReference | undefined; + /*@internal*/ isSourceOfProjectReferenceRedirect(fileName: string): boolean; /*@internal*/ getProgramBuildInfo?(): ProgramBuildInfo | undefined; /*@internal*/ emitBuildInfo(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult; } @@ -3090,6 +3091,7 @@ namespace ts { getSourceFile(fileName: string): SourceFile | undefined; getResolvedTypeReferenceDirectives(): ReadonlyMap; getProjectReferenceRedirect(fileName: string): string | undefined; + isSourceOfProjectReferenceRedirect(fileName: string): boolean; readonly redirectTargetsMap: RedirectTargetsMap; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 47877e1b27f..562d066b64e 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -4616,10 +4616,6 @@ namespace ts { return false; } } - - export function useSourceInsteadOfReferenceRedirect(host: { useSourceInsteadOfReferenceRedirect?(): boolean; }) { - return host.useSourceInsteadOfReferenceRedirect && host.useSourceInsteadOfReferenceRedirect(); - } } namespace ts { diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index e379d1fda2c..6fea0bc4171 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -2570,7 +2570,7 @@ namespace ts.server { /*@internal*/ getOriginalLocationEnsuringConfiguredProject(project: Project, location: DocumentPosition): DocumentPosition | undefined { - const originalLocation = useSourceInsteadOfReferenceRedirect(project) && project.getResolvedProjectReferenceToRedirect(location.fileName) ? + const originalLocation = project.isSourceOfProjectReferenceRedirect(location.fileName) ? location : project.getSourceMapper().tryGetSourcePosition(location); if (!originalLocation) return undefined; diff --git a/src/server/project.ts b/src/server/project.ts index 4e038b94773..cd5a3fec855 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -196,9 +196,6 @@ namespace ts.server { /*@internal*/ originalConfiguredProjects: Map | undefined; - /*@internal*/ - useSourceInsteadOfReferenceRedirect?: () => boolean; - /*@internal*/ getResolvedProjectReferenceToRedirect(_fileName: string): ResolvedProjectReference | undefined { return undefined; @@ -1231,6 +1228,11 @@ namespace ts.server { this.rootFilesMap.delete(info.path); } + /*@internal*/ + isSourceOfProjectReferenceRedirect(fileName: string) { + return !!this.program && this.program.isSourceOfProjectReferenceRedirect(fileName); + } + protected enableGlobalPlugins(options: CompilerOptions, pluginConfigOverrides: Map | undefined) { const host = this.projectService.host; diff --git a/src/server/session.ts b/src/server/session.ts index 088a3a1a249..ff339b06a81 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -443,7 +443,7 @@ namespace ts.server { function getDefinitionInProject(definition: DocumentPosition | undefined, definingProject: Project, project: Project): DocumentPosition | undefined { if (!definition || project.containsFile(toNormalizedPath(definition.fileName))) return definition; - const mappedDefinition = useSourceInsteadOfReferenceRedirect(definingProject) && definingProject.getResolvedProjectReferenceToRedirect(definition.fileName) ? + const mappedDefinition = definingProject.isSourceOfProjectReferenceRedirect(definition.fileName) ? definition : definingProject.getLanguageService().getSourceMapper().tryGetGeneratedPosition(definition); return mappedDefinition && project.containsFile(toNormalizedPath(mappedDefinition.fileName)) ? mappedDefinition : undefined; diff --git a/src/services/services.ts b/src/services/services.ts index 7de7934653e..2f9ba6eec94 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1151,7 +1151,6 @@ namespace ts { fileExists: maybeBind(host, host.fileExists), readFile: maybeBind(host, host.readFile), getDocumentPositionMapper: maybeBind(host, host.getDocumentPositionMapper), - useSourceInsteadOfReferenceRedirect: maybeBind(host, host.useSourceInsteadOfReferenceRedirect), getSourceFileLike: maybeBind(host, host.getSourceFileLike), log }); diff --git a/src/services/sourcemaps.ts b/src/services/sourcemaps.ts index c4c14e58686..6ab656b4236 100644 --- a/src/services/sourcemaps.ts +++ b/src/services/sourcemaps.ts @@ -17,7 +17,6 @@ namespace ts { readFile?(path: string, encoding?: string): string | undefined; getSourceFileLike?(fileName: string): SourceFileLike | undefined; getDocumentPositionMapper?(generatedFileName: string, sourceFileName?: string): DocumentPositionMapper | undefined; - /* @internal */ useSourceInsteadOfReferenceRedirect?(): boolean; log(s: string): void; } @@ -72,8 +71,7 @@ namespace ts { const program = host.getProgram()!; // If this is source file of project reference source (instead of redirect) there is no generated position - if (useSourceInsteadOfReferenceRedirect(host) && - program.getResolvedProjectReferenceToRedirect(sourceFile.fileName)) { + if (program.isSourceOfProjectReferenceRedirect(sourceFile.fileName)) { return undefined; } From b5737fc535701caff9b197b3cba6dd4c832e745f Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 2 Jul 2019 16:29:09 -0700 Subject: [PATCH 015/140] Refactor tests so its easy to edit and reason about them --- src/harness/virtualFileSystemWithWatch.ts | 4 +- src/testRunner/unittests/tsserver/helpers.ts | 4 +- .../unittests/tsserver/projectReferences.ts | 1321 +++++++++++------ 3 files changed, 835 insertions(+), 494 deletions(-) diff --git a/src/harness/virtualFileSystemWithWatch.ts b/src/harness/virtualFileSystemWithWatch.ts index f49f15cadc2..9e615a02638 100644 --- a/src/harness/virtualFileSystemWithWatch.ts +++ b/src/harness/virtualFileSystemWithWatch.ts @@ -196,8 +196,8 @@ interface Array {}` } } - export function checkWatchedFiles(host: TestServerHost, expectedFiles: string[]) { - checkMapKeys("watchedFiles", host.watchedFiles, expectedFiles); + export function checkWatchedFiles(host: TestServerHost, expectedFiles: string[], additionalInfo?: string) { + checkMapKeys(`watchedFiles:: ${additionalInfo || ""}::`, host.watchedFiles, expectedFiles); } export function checkWatchedFilesDetailed(host: TestServerHost, expectedFiles: ReadonlyMap): void; diff --git a/src/testRunner/unittests/tsserver/helpers.ts b/src/testRunner/unittests/tsserver/helpers.ts index 1c2383ab004..1c6bd4e9f59 100644 --- a/src/testRunner/unittests/tsserver/helpers.ts +++ b/src/testRunner/unittests/tsserver/helpers.ts @@ -488,8 +488,8 @@ namespace ts.projectSystem { checkArray("Open files", arrayFrom(projectService.openFiles.keys(), path => projectService.getScriptInfoForPath(path as Path)!.fileName), expectedFiles.map(file => file.path)); } - export function checkScriptInfos(projectService: server.ProjectService, expectedFiles: ReadonlyArray) { - checkArray("ScriptInfos files", arrayFrom(projectService.filenameToScriptInfo.values(), info => info.fileName), expectedFiles); + export function checkScriptInfos(projectService: server.ProjectService, expectedFiles: ReadonlyArray, additionInfo?: string) { + checkArray(`ScriptInfos files: ${additionInfo || ""}`, arrayFrom(projectService.filenameToScriptInfo.values(), info => info.fileName), expectedFiles); } export function protocolLocationFromSubstring(str: string, substring: string): protocol.Location { diff --git a/src/testRunner/unittests/tsserver/projectReferences.ts b/src/testRunner/unittests/tsserver/projectReferences.ts index 1eb7e8ecd18..c5712df2e1a 100644 --- a/src/testRunner/unittests/tsserver/projectReferences.ts +++ b/src/testRunner/unittests/tsserver/projectReferences.ts @@ -150,66 +150,17 @@ fn5(); const files = [dependencyTs, dependencyConfig, mainTs, mainConfig, libFile, randomFile, randomConfig]; - function verifyScriptInfos(session: TestSession, host: TestServerHost, openInfos: ReadonlyArray, closedInfos: ReadonlyArray, otherWatchedFiles: ReadonlyArray) { - checkScriptInfos(session.getProjectService(), openInfos.concat(closedInfos)); - checkWatchedFiles(host, closedInfos.concat(otherWatchedFiles).map(f => f.toLowerCase())); + function verifyScriptInfos(session: TestSession, host: TestServerHost, openInfos: ReadonlyArray, closedInfos: ReadonlyArray, otherWatchedFiles: ReadonlyArray, additionalInfo: string) { + checkScriptInfos(session.getProjectService(), openInfos.concat(closedInfos), additionalInfo); + checkWatchedFiles(host, closedInfos.concat(otherWatchedFiles).map(f => f.toLowerCase()), additionalInfo); } - function verifyInfosWithRandom(session: TestSession, host: TestServerHost, openInfos: ReadonlyArray, closedInfos: ReadonlyArray, otherWatchedFiles: ReadonlyArray) { - verifyScriptInfos(session, host, openInfos.concat(randomFile.path), closedInfos, otherWatchedFiles.concat(randomConfig.path)); + function verifyInfosWithRandom(session: TestSession, host: TestServerHost, openInfos: ReadonlyArray, closedInfos: ReadonlyArray, otherWatchedFiles: ReadonlyArray, reqName: string) { + verifyScriptInfos(session, host, openInfos.concat(randomFile.path), closedInfos, otherWatchedFiles.concat(randomConfig.path), reqName); } function verifyOnlyRandomInfos(session: TestSession, host: TestServerHost) { - verifyScriptInfos(session, host, [randomFile.path], [libFile.path], [randomConfig.path]); - } - - // Returns request and expected Response, expected response when no map file - interface SessionAction { - reqName: string; - request: Partial; - expectedResponse: Response; - expectedResponseNoMap?: Response; - expectedResponseNoDts?: Response; - requestDependencyChange?: Partial; - expectedResponseDependencyChange: Response; - } - function gotoDefintinionFromMainTs(fn: number): SessionAction { - const textSpan = usageSpan(fn); - const definition: protocol.FileSpan = { file: dependencyTs.path, ...declarationSpan(fn) }; - const declareSpaceLength = "declare ".length; - return { - reqName: "goToDef", - request: { - command: protocol.CommandTypes.DefinitionAndBoundSpan, - arguments: { file: mainTs.path, ...textSpan.start } - }, - expectedResponse: { - // To dependency - definitions: [definition], - textSpan - }, - expectedResponseNoMap: { - // To the dts - definitions: [{ - file: dtsPath, - start: { line: fn, offset: definition.start.offset + declareSpaceLength }, - end: { line: fn, offset: definition.end.offset + declareSpaceLength }, - contextStart: { line: fn, offset: 1 }, - contextEnd: { line: fn, offset: 37 } - }], - textSpan - }, - expectedResponseNoDts: { - // To import declaration - definitions: [{ file: mainTs.path, ...importSpan(fn) }], - textSpan - }, - expectedResponseDependencyChange: { - // Definition on fn + 1 line - definitions: [{ file: dependencyTs.path, ...declarationSpan(fn + 1) }], - textSpan - } - }; + verifyScriptInfos(session, host, [randomFile.path], [libFile.path], [randomConfig.path], "Random"); } function declarationSpan(fn: number): protocol.TextSpanWithContext { @@ -232,11 +183,93 @@ fn5(); return { start: { line: fn + 8, offset: 1 }, end: { line: fn + 8, offset: 4 } }; } - function renameFromDependencyTs(fn: number): SessionAction { + function goToDefFromMainTs(fn: number): Action { + const textSpan = usageSpan(fn); + const definition: protocol.FileSpan = { file: dependencyTs.path, ...declarationSpan(fn) }; + return { + reqName: "goToDef", + request: { + command: protocol.CommandTypes.DefinitionAndBoundSpan, + arguments: { file: mainTs.path, ...textSpan.start } + }, + expectedResponse: { + // To dependency + definitions: [definition], + textSpan + } + }; + } + + function goToDefFromMainTsWithNoMap(fn: number): Action { + const textSpan = usageSpan(fn); + const definition = declarationSpan(fn); + const declareSpaceLength = "declare ".length; + return { + reqName: "goToDef", + request: { + command: protocol.CommandTypes.DefinitionAndBoundSpan, + arguments: { file: mainTs.path, ...textSpan.start } + }, + expectedResponse: { + // To the dts + definitions: [{ + file: dtsPath, + start: { line: fn, offset: definition.start.offset + declareSpaceLength }, + end: { line: fn, offset: definition.end.offset + declareSpaceLength }, + contextStart: { line: fn, offset: 1 }, + contextEnd: { line: fn, offset: 37 } + }], + textSpan + } + }; + } + + function goToDefFromMainTsWithNoDts(fn: number): Action { + const textSpan = usageSpan(fn); + return { + reqName: "goToDef", + request: { + command: protocol.CommandTypes.DefinitionAndBoundSpan, + arguments: { file: mainTs.path, ...textSpan.start } + }, + expectedResponse: { + // To import declaration + definitions: [{ file: mainTs.path, ...importSpan(fn) }], + textSpan + } + }; + } + + function goToDefFromMainTsWithDependencyChange(fn: number): Action { + const textSpan = usageSpan(fn); + return { + reqName: "goToDef", + request: { + command: protocol.CommandTypes.DefinitionAndBoundSpan, + arguments: { file: mainTs.path, ...textSpan.start } + }, + expectedResponse: { + // Definition on fn + 1 line + definitions: [{ file: dependencyTs.path, ...declarationSpan(fn + 1) }], + textSpan + } + }; + } + + function goToDefFromMainTsProjectInfoVerifier(withRefs: boolean): ProjectInfoVerifier { + return { + openFile: mainTs, + openFileLastLine: 14, + configFile: mainConfig, + expectedProjectActualFiles: withRefs ? + [mainTs.path, libFile.path, mainConfig.path, dependencyTs.path] : + [mainTs.path, libFile.path, mainConfig.path, dtsPath] + }; + } + + function renameFromDependencyTs(fn: number): Action { const defSpan = declarationSpan(fn); const { contextStart: _, contextEnd: _1, ...triggerSpan } = defSpan; - const defSpanPlusOne = declarationSpan(fn + 1); - const { contextStart: _2, contextEnd: _3, ...triggerSpanPlusOne } = defSpanPlusOne; return { reqName: "rename", request: { @@ -256,30 +289,37 @@ fn5(); locs: [ { file: dependencyTs.path, locs: [defSpan] } ] - }, - requestDependencyChange: { - command: protocol.CommandTypes.Rename, - arguments: { file: dependencyTs.path, ...triggerSpanPlusOne.start } - }, - expectedResponseDependencyChange: { - info: { - canRename: true, - fileToRename: undefined, - displayName: `fn${fn}`, - fullDisplayName: `"${dependecyLocation}/FnS".fn${fn}`, - kind: ScriptElementKind.functionElement, - kindModifiers: "export", - triggerSpan: triggerSpanPlusOne - }, - locs: [ - { file: dependencyTs.path, locs: [defSpanPlusOne] } - ] } }; } - function renameFromDependencyTsWithBothProjectsOpen(fn: number): SessionAction { - const { reqName, request, expectedResponse, expectedResponseDependencyChange, requestDependencyChange } = renameFromDependencyTs(fn); + function renameFromDependencyTsWithDependencyChange(fn: number): Action { + const { expectedResponse: { info, locs }, ...rest } = renameFromDependencyTs(fn + 1); + + return { + ...rest, + expectedResponse: { + info: { + ...info as protocol.RenameInfoSuccess, + displayName: `fn${fn}`, + fullDisplayName: `"${dependecyLocation}/FnS".fn${fn}`, + }, + locs + } + }; + } + + function renameFromDependencyTsProjectInfoVerifier(): ProjectInfoVerifier { + return { + openFile: dependencyTs, + openFileLastLine: 6, + configFile: dependencyConfig, + expectedProjectActualFiles: [dependencyTs.path, libFile.path, dependencyConfig.path] + }; + } + + function renameFromDependencyTsWithBothProjectsOpen(fn: number): Action { + const { reqName, request, expectedResponse } = renameFromDependencyTs(fn); const { info, locs } = expectedResponse; return { reqName, @@ -296,15 +336,20 @@ fn5(); ] } ] - }, - // Only dependency result - expectedResponseNoMap: expectedResponse, - expectedResponseNoDts: expectedResponse, - requestDependencyChange, - expectedResponseDependencyChange: { - info: expectedResponseDependencyChange.info, + } + }; + } + + function renameFromDependencyTsWithBothProjectsOpenWithDependencyChange(fn: number): Action { + const { reqName, request, expectedResponse, } = renameFromDependencyTsWithDependencyChange(fn); + const { info, locs } = expectedResponse; + return { + reqName, + request, + expectedResponse: { + info, locs: [ - expectedResponseDependencyChange.locs[0], + locs[0], { file: mainTs.path, locs: [ @@ -317,401 +362,453 @@ fn5(); }; } - // Returns request and expected Response - type SessionActionGetter = (fn: number) => SessionAction; - // Open File, expectedProjectActualFiles, actionGetter, openFileLastLine - interface DocumentPositionMapperVerifier { + interface Action { + reqName: string; + request: Partial; + expectedResponse: Response; + } + interface ActionInfo { + action: (fn: number) => Action; + closedInfos: () => readonly string[]; + otherWatchedFiles: () => readonly string[]; + expectsDts: boolean; + expectsMap: boolean; + } + type ActionKey = keyof ActionInfoVerifier; + type ActionInfoGetterFn = () => ActionInfo; + type ActionInfoGetter = ActionInfoGetterFn | ActionKey; + interface ProjectInfoVerifier { openFile: File; - expectedProjectActualFiles: ReadonlyArray; - actionGetter: SessionActionGetter; openFileLastLine: number; + configFile: File; + expectedProjectActualFiles: readonly string[]; + } + interface ActionInfoVerifier { + main: ActionInfoGetter; + noMap: ActionInfoGetter; + mapFileCreated: ActionInfoGetter; + mapFileDeleted: ActionInfoGetter; + noDts: ActionInfoGetter; + dtsFileCreated: ActionInfoGetter; + dtsFileDeleted: ActionInfoGetter; + dependencyChange: ActionInfoGetter; + noBuild: ActionInfoGetter; + } + interface DocumentPositionMapperVerifier extends ProjectInfoVerifier, ActionInfoVerifier { } - function verifyDocumentPositionMapperUpdates( - mainScenario: string, - verifier: ReadonlyArray, - closedInfos: ReadonlyArray, - withRefs: boolean) { - const openFiles = verifier.map(v => v.openFile); - const expectedProjectActualFiles = verifier.map(v => v.expectedProjectActualFiles); - const openFileLastLines = verifier.map(v => v.openFileLastLine); + interface VerifierAndWithRefs { + withRefs: boolean; + verifier: (withRefs: boolean) => readonly DocumentPositionMapperVerifier[]; + } - const configFiles = openFiles.map(openFile => `${getDirectoryPath(openFile.path)}/tsconfig.json`); - const openInfos = openFiles.map(f => f.path); - // When usage and dependency are used, dependency config is part of closedInfo so ignore - const otherWatchedFiles = withRefs && verifier.length > 1 ? [configFiles[0]] : configFiles; - function openTsFile(onHostCreate?: (host: TestServerHost) => void) { - const host = createHost(files, [mainConfig.path]); - if (!withRefs) { - // Erase project reference - host.writeFile(mainConfig.path, JSON.stringify({ - compilerOptions: { composite: true, declarationMap: true } - })); - } - if (onHostCreate) { - onHostCreate(host); - } - const session = createSession(host); - openFilesForSession([...openFiles, randomFile], session); - return { host, session }; + function openFiles(verifiers: readonly DocumentPositionMapperVerifier[]) { + return verifiers.map(v => v.openFile); + } + interface OpenTsFile extends VerifierAndWithRefs { + onHostCreate?: (host: TestServerHost) => void; + } + function openTsFile({ withRefs, verifier, onHostCreate }: OpenTsFile) { + const host = createHost(files, [mainConfig.path]); + if (!withRefs) { + // Erase project reference + host.writeFile(mainConfig.path, JSON.stringify({ + compilerOptions: { composite: true, declarationMap: true } + })); } - - function checkProject(session: TestSession, noDts?: true) { - const service = session.getProjectService(); - checkNumberOfProjects(service, { configuredProjects: 1 + verifier.length }); - configFiles.forEach((configFile, index) => { - checkProjectActualFiles( - service.configuredProjects.get(configFile)!, - noDts ? - expectedProjectActualFiles[index].filter(f => f.toLowerCase() !== dtsPath) : - expectedProjectActualFiles[index] - ); - }); + if (onHostCreate) { + onHostCreate(host); } + const session = createSession(host); + const verifiers = verifier(withRefs); + openFilesForSession([...openFiles(verifiers), randomFile], session); + return { host, session, verifiers }; + } - function verifyInfos(session: TestSession, host: TestServerHost) { - verifyInfosWithRandom(session, host, openInfos, closedInfos, otherWatchedFiles); - } - - function verifyInfosWhenNoMapFile(session: TestSession, host: TestServerHost, dependencyTsOK?: boolean) { - const dtsMapClosedInfo = firstDefined(closedInfos, f => f.toLowerCase() === dtsMapPath ? f : undefined); - verifyInfosWithRandom( - session, - host, - openInfos, - closedInfos.filter(f => f !== dtsMapClosedInfo && (dependencyTsOK || f !== dependencyTs.path)), - dtsMapClosedInfo ? otherWatchedFiles.concat(dtsMapClosedInfo) : otherWatchedFiles + function checkProject(session: TestSession, verifiers: readonly DocumentPositionMapperVerifier[], noDts?: true) { + const service = session.getProjectService(); + checkNumberOfProjects(service, { configuredProjects: 1 + verifiers.length }); + verifiers.forEach(({ configFile, expectedProjectActualFiles }) => { + checkProjectActualFiles( + service.configuredProjects.get(configFile.path.toLowerCase())!, + noDts ? + expectedProjectActualFiles.filter(f => f.toLowerCase() !== dtsPath) : + expectedProjectActualFiles ); - } + }); + } - function verifyInfosWhenNoDtsFile(session: TestSession, host: TestServerHost, watchDts: boolean, dependencyTsOk?: boolean, depedencyMapOk?: boolean) { - const dtsMapClosedInfo = firstDefined(closedInfos, f => f.toLowerCase() === dtsMapPath ? f : undefined); - const dtsClosedInfo = firstDefined(closedInfos, f => f.toLowerCase() === dtsPath ? f : undefined); - verifyInfosWithRandom( - session, - host, - openInfos, - closedInfos.filter(f => (depedencyMapOk || f !== dtsMapClosedInfo) && f !== dtsClosedInfo && (dependencyTsOk || f !== dependencyTs.path)), - dtsClosedInfo && watchDts ? - otherWatchedFiles.concat(dtsClosedInfo) : - otherWatchedFiles - ); + function firstAction(session: TestSession, verifiers: readonly DocumentPositionMapperVerifier[]) { + for (const { action } of getActionInfo(verifiers, "main")) { + const { request } = action(1); + session.executeCommandSeq(request); } + } - function verifyDocumentPositionMapper(session: TestSession, dependencyMap: server.ScriptInfo | undefined, documentPositionMapper: server.ScriptInfo["documentPositionMapper"], notEqual?: true) { - assert.strictEqual(session.getProjectService().filenameToScriptInfo.get(dtsMapPath), dependencyMap); - if (dependencyMap) { - if (notEqual) { - assert.notStrictEqual(dependencyMap.documentPositionMapper, documentPositionMapper); - } - else { - assert.strictEqual(dependencyMap.documentPositionMapper, documentPositionMapper); - } + function verifyAction(session: TestSession, { reqName, request, expectedResponse }: Action) { + const { response } = session.executeCommandSeq(request); + assert.deepEqual(response, expectedResponse, `Failed Request: ${reqName}`); + } + + function verifyScriptInfoPresence(session: TestSession, path: string, expectedToBePresent: boolean, reqName: string) { + const info = session.getProjectService().filenameToScriptInfo.get(path); + if (expectedToBePresent) { + assert.isDefined(info, `${reqName}:: ${path} expected to be present`); + } + else { + assert.isUndefined(info, `${reqName}:: ${path} expected to be not present`); + } + return info; + } + + function verifyDocumentPositionMapper(session: TestSession, dependencyMap: server.ScriptInfo | undefined, documentPositionMapper: server.ScriptInfo["documentPositionMapper"], equal: boolean) { + assert.strictEqual(session.getProjectService().filenameToScriptInfo.get(dtsMapPath), dependencyMap); + if (dependencyMap) { + if (equal) { + assert.strictEqual(dependencyMap.documentPositionMapper, documentPositionMapper); + } + else { + assert.notStrictEqual(dependencyMap.documentPositionMapper, documentPositionMapper); } } + } - function action(verifier: DocumentPositionMapperVerifier, fn: number, session: TestSession, useDependencyChange?: boolean) { - const { reqName, request, expectedResponse, expectedResponseNoMap, expectedResponseNoDts, requestDependencyChange, expectedResponseDependencyChange } = verifier.actionGetter(fn); - const { response } = session.executeCommandSeq(useDependencyChange ? requestDependencyChange || request : request); - return { reqName, response, expectedResponse, expectedResponseNoMap, expectedResponseNoDts, expectedResponseDependencyChange, verifier }; - } - - function firstAction(session: TestSession) { - verifier.forEach(v => action(v, 1, session)); - } - - function verifyAllFnActionWorker(session: TestSession, verifyAction: (result: ReturnType, dtsInfo: server.ScriptInfo | undefined, isFirst: boolean) => void, dtsAbsent?: boolean, useDependencyChange?: boolean) { - // action - let isFirst = true; - for (const v of verifier) { - for (let fn = 1; fn <= 5; fn++) { - const result = action(v, fn, session, useDependencyChange); - const dtsInfo = session.getProjectService().filenameToScriptInfo.get(dtsPath); - if (dtsAbsent) { - assert.isUndefined(dtsInfo); - } - else { - assert.isDefined(dtsInfo); - } - verifyAction(result, dtsInfo, isFirst); - isFirst = false; - } + function getActionInfo(verifiers: readonly DocumentPositionMapperVerifier[], actionKey: ActionKey): ActionInfo[] { + return verifiers.map(v => { + let actionInfoGetter = v[actionKey]; + while (isString(actionInfoGetter)) { + actionInfoGetter = v[actionInfoGetter]; } - } + return actionInfoGetter(); + }); + } - function dtsAbsent() { - return withRefs && !contains(closedInfos, dtsPath, (a, b) => a.toLowerCase() === b.toLowerCase()); - } - - function verifyAllFnAction( - session: TestSession, - host: TestServerHost, - firstDocumentPositionMapperNotEquals?: true, - dependencyMap?: server.ScriptInfo, - documentPositionMapper?: server.ScriptInfo["documentPositionMapper"], - useDependencyChange?: boolean - ) { - // action - verifyAllFnActionWorker(session, ({ reqName, response, expectedResponse, expectedResponseDependencyChange }, dtsInfo, isFirst) => { - assert.deepEqual(response, useDependencyChange ? expectedResponseDependencyChange || expectedResponse : expectedResponse, `Failed on ${reqName}`); - verifyInfos(session, host); - if (dtsInfo) assert.equal(dtsInfo.sourceMapFilePath, dtsMapPath); - if (isFirst) { - if (dependencyMap) { - verifyDocumentPositionMapper(session, dependencyMap, documentPositionMapper, firstDocumentPositionMapperNotEquals); - documentPositionMapper = dependencyMap.documentPositionMapper; - } - else { - dependencyMap = session.getProjectService().filenameToScriptInfo.get(dtsMapPath); - documentPositionMapper = dependencyMap && dependencyMap.documentPositionMapper; - } - } - else { - verifyDocumentPositionMapper(session, dependencyMap, documentPositionMapper); - } - }, dtsAbsent(), useDependencyChange); - return { dependencyMap, documentPositionMapper }; - } - - function verifyAllFnActionWithNoMap( - session: TestSession, - host: TestServerHost, - dependencyTsOK?: true - ) { - let sourceMapFilePath: server.ScriptInfo["sourceMapFilePath"]; - // action - verifyAllFnActionWorker(session, ({ reqName, response, expectedResponse, expectedResponseNoMap }, dtsInfo, isFirst) => { - assert.deepEqual(response, withRefs ? expectedResponse : expectedResponseNoMap || expectedResponse, `Failed on ${reqName}`); - verifyInfosWhenNoMapFile(session, host, dependencyTsOK); - assert.isUndefined(session.getProjectService().filenameToScriptInfo.get(dtsMapPath)); - if (!withRefs) { - if (isFirst) { - assert.isNotString(dtsInfo!.sourceMapFilePath); - assert.isNotFalse(dtsInfo!.sourceMapFilePath); - assert.isDefined(dtsInfo!.sourceMapFilePath); - sourceMapFilePath = dtsInfo!.sourceMapFilePath; - } - else { - assert.equal(dtsInfo!.sourceMapFilePath, sourceMapFilePath); - } - } - }, dtsAbsent()); - return sourceMapFilePath; - } - - function verifyAllFnActionWithNoDts( - session: TestSession, - host: TestServerHost, - dependencyTsAndMapOk?: true - ) { - // action - verifyAllFnActionWorker(session, ({ reqName, response, expectedResponse, expectedResponseNoDts, verifier }) => { - assert.deepEqual(response, withRefs ? expectedResponse : expectedResponseNoDts || expectedResponse, `Failed on ${reqName}`); - verifyInfosWhenNoDtsFile( + interface VerifyAllFnAction { + session: TestSession; + host: TestServerHost; + verifiers: readonly DocumentPositionMapperVerifier[]; + actionKey: ActionKey; + sourceMapPath?: server.ScriptInfo["sourceMapFilePath"]; + dependencyMap?: server.ScriptInfo | undefined; + documentPositionMapper?: server.ScriptInfo["documentPositionMapper"]; + firstEquals?: boolean; + } + interface VerifyAllFnActionResult { + actionInfos: readonly ActionInfo[]; + actionKey: ActionKey; + dependencyMap: server.ScriptInfo | undefined; + documentPositionMapper: server.ScriptInfo["documentPositionMapper"] | undefined; + } + function verifyAllFnAction({ + session, + host, + verifiers, + actionKey, + dependencyMap, + documentPositionMapper, + firstEquals + }: VerifyAllFnAction): VerifyAllFnActionResult { + const actionInfos = getActionInfo(verifiers, actionKey); + let sourceMapPath: server.ScriptInfo["sourceMapFilePath"] | undefined; + // action + let first = true; + for (const { action, closedInfos, otherWatchedFiles, expectsDts, expectsMap } of actionInfos) { + for (let fn = 1; fn <= 5; fn++) { + const fnAction = action(fn); + verifyAction(session, fnAction); + const dtsInfo = verifyScriptInfoPresence(session, dtsPath, expectsDts, fnAction.reqName); + const dtsMapInfo = verifyScriptInfoPresence(session, dtsMapPath, expectsMap, fnAction.reqName); + verifyInfosWithRandom( session, host, - // Even when project actual file contains dts, its not watched because the dts is in another folder and module resolution just fails - // instead of succeeding to source file and then mapping using project reference (When using usage location) - // But watched if sourcemapper is in source project since we need to keep track of dts to update the source mapper for any potential usages - verifier.expectedProjectActualFiles.every(f => f.toLowerCase() !== dtsPath), - /*dependencyTsOk*/ withRefs || dependencyTsAndMapOk, - /*dependencyMapOk*/ dependencyTsAndMapOk + openFiles(verifiers).map(f => f.path), + closedInfos(), + otherWatchedFiles(), + `${actionKey}:: ${fnAction.reqName}` ); - }, /*dtsAbsent*/ true); + + if (dtsInfo) { + if (first) { + if (dtsMapInfo) { + assert.equal(dtsInfo.sourceMapFilePath, dtsMapPath, `${actionKey}:: ${fnAction.reqName}`); + } + else { + assert.isNotString(dtsInfo.sourceMapFilePath); + assert.isNotFalse(dtsInfo.sourceMapFilePath); + assert.isDefined(dtsInfo.sourceMapFilePath); + } + } + else { + assert.equal(dtsInfo.sourceMapFilePath, sourceMapPath, `${actionKey}:: ${fnAction.reqName}`); + } + } + if (!first || firstEquals !== undefined) { + verifyDocumentPositionMapper(session, dependencyMap, documentPositionMapper, !first || !!firstEquals); + } + sourceMapPath = dtsInfo && dtsInfo.sourceMapFilePath; + dependencyMap = dtsMapInfo; + documentPositionMapper = dependencyMap && dependencyMap.documentPositionMapper; + first = false; + } } - function verifyScenarioWithChangesWorker( - change: (host: TestServerHost, session: TestSession) => void, - afterActionDocumentPositionMapperNotEquals: true | undefined, - timeoutBeforeAction: boolean, - useDependencyChange?: boolean - ) { - const { host, session } = openTsFile(); + return { actionInfos, actionKey, dependencyMap, documentPositionMapper }; + } + + function verifyScriptInfoCollection( + session: TestSession, + host: TestServerHost, + verifiers: readonly DocumentPositionMapperVerifier[], + { dependencyMap, documentPositionMapper, actionInfos, actionKey }: VerifyAllFnActionResult + ) { + // Collecting at this point retains dependency.d.ts and map + closeFilesForSession([randomFile], session); + openFilesForSession([randomFile], session); + + const { closedInfos, otherWatchedFiles } = last(actionInfos); + verifyInfosWithRandom( + session, + host, + openFiles(verifiers).map(f => f.path), + closedInfos(), + otherWatchedFiles(), + `${actionKey} Collection` + ); + verifyDocumentPositionMapper(session, dependencyMap, documentPositionMapper, /*equal*/ true); + + // Closing open file, removes dependencies too + closeFilesForSession([...openFiles(verifiers), randomFile], session); + openFilesForSession([randomFile], session); + verifyOnlyRandomInfos(session, host); + } + + function verifyScenarioAndScriptInfoCollection( + session: TestSession, + host: TestServerHost, + verifiers: readonly DocumentPositionMapperVerifier[], + actionKey: ActionKey, + noDts?: true + ) { + // Main scenario action + const result = verifyAllFnAction({ session, host, verifiers, actionKey }); + checkProject(session, verifiers, noDts); + verifyScriptInfoCollection(session, host, verifiers, result); + } + + function verifyScenarioWithChangesWorker( + { + scenarioName, + verifier, + withRefs, + change, + afterActionDocumentPositionMapperNotEquals, + afterChangeActionKey + }: VerifyScenarioWithChanges, + timeoutBeforeAction: boolean, + ) { + it(scenarioName, () => { + const { host, session, verifiers } = openTsFile({ verifier, withRefs }); // Create DocumentPositionMapper - firstAction(session); + firstAction(session, verifiers); const dependencyMap = session.getProjectService().filenameToScriptInfo.get(dtsMapPath); const documentPositionMapper = dependencyMap && dependencyMap.documentPositionMapper; // change - change(host, session); + change(host, session, verifiers); if (timeoutBeforeAction) { host.runQueuedTimeoutCallbacks(); - checkProject(session); - verifyDocumentPositionMapper(session, dependencyMap, documentPositionMapper); + checkProject(session, verifiers); + verifyDocumentPositionMapper(session, dependencyMap, documentPositionMapper, /*equal*/ true); } // action - verifyAllFnAction(session, host, afterActionDocumentPositionMapperNotEquals, dependencyMap, documentPositionMapper, useDependencyChange); - } - - function verifyScenarioWithChanges( - scenarioName: string, - change: (host: TestServerHost, session: TestSession) => void, - afterActionDocumentPositionMapperNotEquals?: true, - useDependencyChange?: boolean - ) { - describe(scenarioName, () => { - it("when timeout occurs before request", () => { - verifyScenarioWithChangesWorker(change, afterActionDocumentPositionMapperNotEquals, /*timeoutBeforeAction*/ true, useDependencyChange); - }); - - it("when timeout does not occur before request", () => { - verifyScenarioWithChangesWorker(change, afterActionDocumentPositionMapperNotEquals, /*timeoutBeforeAction*/ false, useDependencyChange); - }); - }); - } - - function verifyMainScenarioAndScriptInfoCollection(session: TestSession, host: TestServerHost) { - // Main scenario action - const { dependencyMap, documentPositionMapper } = verifyAllFnAction(session, host); - checkProject(session); - verifyInfos(session, host); - - // Collecting at this point retains dependency.d.ts and map - closeFilesForSession([randomFile], session); - openFilesForSession([randomFile], session); - verifyInfos(session, host); - verifyDocumentPositionMapper(session, dependencyMap, documentPositionMapper); - - // Closing open file, removes dependencies too - closeFilesForSession([...openFiles, randomFile], session); - openFilesForSession([randomFile], session); - verifyOnlyRandomInfos(session, host); - } - - function verifyMainScenarioAndScriptInfoCollectionWithNoMap(session: TestSession, host: TestServerHost, dependencyTsOKInScenario?: true) { - // Main scenario action - verifyAllFnActionWithNoMap(session, host, withRefs || dependencyTsOKInScenario); - - // Collecting at this point retains dependency.d.ts and map watcher - closeFilesForSession([randomFile], session); - openFilesForSession([randomFile], session); - verifyInfosWhenNoMapFile(session, host, withRefs); - - // Closing open file, removes dependencies too - closeFilesForSession([...openFiles, randomFile], session); - openFilesForSession([randomFile], session); - verifyOnlyRandomInfos(session, host); - } - - function verifyMainScenarioAndScriptInfoCollectionWithNoDts(session: TestSession, host: TestServerHost, dependencyTsAndMapOk?: true) { - // Main scenario action - verifyAllFnActionWithNoDts(session, host, dependencyTsAndMapOk); - - // Collecting at this point retains dependency.d.ts and map watcher - closeFilesForSession([randomFile], session); - openFilesForSession([randomFile], session); - verifyInfosWhenNoDtsFile( + verifyAllFnAction({ session, host, - !!forEach(verifier, v => v.expectedProjectActualFiles.every(f => f.toLowerCase() !== dtsPath)), - /*dependencyTsOk*/ withRefs - ); + verifiers, + actionKey: afterChangeActionKey, + dependencyMap, + documentPositionMapper, + firstEquals: !afterActionDocumentPositionMapperNotEquals + }); + }); + } - // Closing open file, removes dependencies too - closeFilesForSession([...openFiles, randomFile], session); - openFilesForSession([randomFile], session); - verifyOnlyRandomInfos(session, host); - } + interface VerifyScenarioWithChanges extends VerifierAndWithRefs { + scenarioName: string; + change: (host: TestServerHost, session: TestSession, verifiers: readonly DocumentPositionMapperVerifier[]) => void; + afterActionDocumentPositionMapperNotEquals?: true; + afterChangeActionKey: ActionKey; + } + function verifyScenarioWithChanges(verify: VerifyScenarioWithChanges) { + describe("when timeout occurs before request", () => { + verifyScenarioWithChangesWorker(verify, /*timeoutBeforeAction*/ true); + }); - function verifyScenarioWhenFileNotPresent( - scenarioName: string, - fileLocation: string, - verifyScenarioAndScriptInfoCollection: (session: TestSession, host: TestServerHost, dependencyTsOk?: true) => void, - noDts?: true - ) { - describe(scenarioName, () => { - it(mainScenario, () => { - const { host, session } = openTsFile(host => host.deleteFile(fileLocation)); - checkProject(session, noDts); + describe("when timeout does not occur before request", () => { + verifyScenarioWithChangesWorker(verify, /*timeoutBeforeAction*/ false); + }); + } - verifyScenarioAndScriptInfoCollection(session, host); + interface VerifyScenarioWhenFileNotPresent extends VerifierAndWithRefs { + scenarioName: string; + fileLocation: string; + fileNotPresentKey: ActionKey; + fileCreatedKey: ActionKey; + fileDeletedKey: ActionKey; + noDts?: true; + } + function verifyScenarioWhenFileNotPresent({ + scenarioName, + verifier, + withRefs, + fileLocation, + fileNotPresentKey, + fileCreatedKey, + fileDeletedKey, + noDts + }: VerifyScenarioWhenFileNotPresent) { + describe(scenarioName, () => { + it("when file is not present", () => { + const { host, session, verifiers } = openTsFile({ + verifier, + withRefs, + onHostCreate: host => host.deleteFile(fileLocation) }); + checkProject(session, verifiers, noDts); - it("when file is created", () => { - let fileContents: string | undefined; - const { host, session } = openTsFile(host => { + verifyScenarioAndScriptInfoCollection(session, host, verifiers, fileNotPresentKey, noDts); + }); + + it("when file is created after actions on projects", () => { + let fileContents: string | undefined; + const { host, session, verifiers } = openTsFile({ + verifier, + withRefs, + onHostCreate: host => { fileContents = host.readFile(fileLocation); host.deleteFile(fileLocation); - }); - firstAction(session); - - host.writeFile(fileLocation, fileContents!); - verifyMainScenarioAndScriptInfoCollection(session, host); + } }); + firstAction(session, verifiers); - it("when file is deleted", () => { - const { host, session } = openTsFile(); - firstAction(session); - - // The dependency file is deleted when orphan files are collected - host.deleteFile(fileLocation); - verifyScenarioAndScriptInfoCollection(session, host, /*dependencyTsOk*/ true); - }); + host.writeFile(fileLocation, fileContents!); + verifyScenarioAndScriptInfoCollection(session, host, verifiers, fileCreatedKey); }); - } + it("when file is deleted after actions on the projects", () => { + const { host, session, verifiers } = openTsFile({ verifier, withRefs }); + firstAction(session, verifiers); + + // The dependency file is deleted when orphan files are collected + host.deleteFile(fileLocation); + // Verify with deleted action key + const result = verifyAllFnAction({ session, host, verifiers, actionKey: fileDeletedKey }); + checkProject(session, verifiers, noDts); + + // Script info collection should behave as fileNotPresentKey + verifyScriptInfoCollection( + session, + host, + verifiers, + { + actionInfos: getActionInfo(verifiers, fileNotPresentKey), + actionKey: result.actionKey, + dependencyMap: undefined, + documentPositionMapper: undefined + } + ); + }); + }); + } + + function verifyScenarioWorker({ mainScenario, verifier }: VerifyScenario, withRefs: boolean) { it(mainScenario, () => { - const { host, session } = openTsFile(); - checkProject(session); - - verifyMainScenarioAndScriptInfoCollection(session, host); + const { host, session, verifiers } = openTsFile({ withRefs, verifier }); + checkProject(session, verifiers); + verifyScenarioAndScriptInfoCollection(session, host, verifiers, "main"); }); // Edit - verifyScenarioWithChanges( - "when usage file changes, document position mapper doesnt change", - (_host, session) => openFiles.forEach( - (openFile, index) => session.executeCommandSeq({ + verifyScenarioWithChanges({ + scenarioName: "when usage file changes, document position mapper doesnt change", + verifier, + withRefs, + change: (_host, session, verifiers) => verifiers.forEach( + verifier => session.executeCommandSeq({ command: protocol.CommandTypes.Change, - arguments: { file: openFile.path, line: openFileLastLines[index], offset: 1, endLine: openFileLastLines[index], endOffset: 1, insertString: "const x = 10;" } + arguments: { + file: verifier.openFile.path, + line: verifier.openFileLastLine, + offset: 1, + endLine: verifier.openFileLastLine, + endOffset: 1, + insertString: "const x = 10;" + } }) - ) - ); + ), + afterChangeActionKey: "main" + }); // Edit dts to add new fn - verifyScenarioWithChanges( - "when dependency .d.ts changes, document position mapper doesnt change", - host => host.writeFile( + verifyScenarioWithChanges({ + scenarioName: "when dependency .d.ts changes, document position mapper doesnt change", + verifier, + withRefs, + change: host => host.writeFile( dtsLocation, host.readFile(dtsLocation)!.replace( "//# sourceMappingURL=FnS.d.ts.map", `export declare function fn6(): void; //# sourceMappingURL=FnS.d.ts.map` ) - ) - ); + ), + afterChangeActionKey: "main" + }); // Edit map file to represent added new line - verifyScenarioWithChanges( - "when dependency file's map changes", - host => host.writeFile( + verifyScenarioWithChanges({ + scenarioName: "when dependency file's map changes", + verifier, + withRefs, + change: host => host.writeFile( dtsMapLocation, `{"version":3,"file":"FnS.d.ts","sourceRoot":"","sources":["../dependency/FnS.ts"],"names":[],"mappings":"AAAA,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,eAAO,MAAM,CAAC,KAAK,CAAC"}` ), - /*afterActionDocumentPositionMapperNotEquals*/ true - ); + afterChangeActionKey: "main", + afterActionDocumentPositionMapperNotEquals: true + }); - verifyScenarioWhenFileNotPresent( - "when map file is not present", - dtsMapLocation, - verifyMainScenarioAndScriptInfoCollectionWithNoMap - ); + verifyScenarioWhenFileNotPresent({ + scenarioName: "with depedency files map file", + verifier, + withRefs, + fileLocation: dtsMapLocation, + fileNotPresentKey: "noMap", + fileCreatedKey: "mapFileCreated", + fileDeletedKey: "mapFileDeleted" + }); - verifyScenarioWhenFileNotPresent( - "when .d.ts file is not present", - dtsLocation, - verifyMainScenarioAndScriptInfoCollectionWithNoDts, - /*noDts*/ true - ); + verifyScenarioWhenFileNotPresent({ + scenarioName: "with depedency .d.ts file", + verifier, + withRefs, + fileLocation: dtsLocation, + fileNotPresentKey: "noDts", + fileCreatedKey: "dtsFileCreated", + fileDeletedKey: "dtsFileDeleted", + noDts: true + }); if (withRefs) { - verifyScenarioWithChanges( - "when defining project source changes", - (host, session) => { + verifyScenarioWithChanges({ + scenarioName: "when defining project source changes", + verifier, + withRefs, + change: (host, session, verifiers) => { // Make change, without rebuild of solution - if (contains(openInfos, dependencyTs.path)) { + if (contains(openFiles(verifiers), dependencyTs)) { session.executeCommandSeq({ command: protocol.CommandTypes.Change, arguments: { @@ -724,96 +821,340 @@ fn5(); ${dependencyTs.content}`); } }, - /*afterActionDocumentPositionMapperNotEquals*/ undefined, - /*useDepedencyChange*/ true - ); + afterChangeActionKey: "dependencyChange" + }); it("when d.ts file is not generated", () => { const host = createServerHost(files); const session = createSession(host); - openFilesForSession([...openFiles, randomFile], session); - - const expectedClosedInfos = closedInfos.filter(f => f.toLowerCase() !== dtsPath && f.toLowerCase() !== dtsMapPath); - // If closed infos includes dts and dtsMap, watch dts since its not present - const expectedWatchedFiles = closedInfos.length === expectedClosedInfos.length ? - otherWatchedFiles : - otherWatchedFiles.concat(dtsPath); - // Main scenario action - verifyAllFnActionWorker(session, ({ reqName, response, expectedResponse }) => { - assert.deepEqual(response, expectedResponse, `Failed on ${reqName}`); - verifyInfosWithRandom(session, host, openInfos, expectedClosedInfos, expectedWatchedFiles); - verifyDocumentPositionMapper(session, /*dependencyMap*/ undefined, /*documentPositionMapper*/ undefined); - }, /*dtsAbsent*/ true); - checkProject(session); - - // Collecting at this point retains dependency.d.ts and map - closeFilesForSession([randomFile], session); - openFilesForSession([randomFile], session); - verifyInfosWithRandom(session, host, openInfos, expectedClosedInfos, expectedWatchedFiles); - verifyDocumentPositionMapper(session, /*dependencyMap*/ undefined, /*documentPositionMapper*/ undefined); - - // Closing open file, removes dependencies too - closeFilesForSession([...openFiles, randomFile], session); - openFilesForSession([randomFile], session); - verifyOnlyRandomInfos(session, host); + const verifiers = verifier(withRefs); + openFilesForSession([...openFiles(verifiers), randomFile], session); + verifyScenarioAndScriptInfoCollection(session, host, verifiers, "noBuild"); }); } } - function verifyScenarios(withRefs: boolean) { - describe(withRefs ? "when main tsconfig has project reference" : "when main tsconfig doesnt have project reference", () => { - const usageVerifier: DocumentPositionMapperVerifier = { - openFile: mainTs, - expectedProjectActualFiles: withRefs ? - [mainTs.path, libFile.path, mainConfig.path, dependencyTs.path] : - [mainTs.path, libFile.path, mainConfig.path, dtsPath], - actionGetter: gotoDefintinionFromMainTs, - openFileLastLine: 14 - }; - describe("from project that uses dependency", () => { - const closedInfos = withRefs ? - [dependencyTs.path, dependencyConfig.path, libFile.path] : - [dependencyTs.path, libFile.path, dtsPath, dtsMapLocation]; - verifyDocumentPositionMapperUpdates( - "can go to definition correctly", - [usageVerifier], - closedInfos, - withRefs - ); - }); - - const definingVerifier: DocumentPositionMapperVerifier = { - openFile: dependencyTs, - expectedProjectActualFiles: [dependencyTs.path, libFile.path, dependencyConfig.path], - actionGetter: renameFromDependencyTs, - openFileLastLine: 6, - }; - describe("from defining project", () => { - const closedInfos = [libFile.path, dtsLocation, dtsMapLocation]; - verifyDocumentPositionMapperUpdates( - "rename locations from dependency", - [definingVerifier], - closedInfos, - withRefs - ); - }); - - describe("when opening depedency and usage project", () => { - const closedInfos = withRefs ? - [libFile.path, dependencyConfig.path] : - [libFile.path, dtsPath, dtsMapLocation]; - verifyDocumentPositionMapperUpdates( - "goto Definition in usage and rename locations from defining project", - [usageVerifier, { ...definingVerifier, actionGetter: renameFromDependencyTsWithBothProjectsOpen }], - closedInfos, - withRefs - ); - }); + interface VerifyScenario { + mainScenario: string; + verifier: (withRefs: boolean) => readonly DocumentPositionMapperVerifier[]; + } + function verifyScenario(scenario: VerifyScenario) { + describe("when main tsconfig doesnt have project reference", () => { + verifyScenarioWorker(scenario, /*withRefs*/ false); + }); + describe("when main tsconfig has project reference", () => { + verifyScenarioWorker(scenario, /*withRefs*/ true); }); } - verifyScenarios(/*withRefs*/ false); - verifyScenarios(/*withRefs*/ true); + describe("from project that uses dependency", () => { + function goToDefActionInfo(withRefs: boolean): ActionInfo { + return { + action: goToDefFromMainTs, + closedInfos: () => withRefs ? + [dependencyTs.path, dependencyConfig.path, libFile.path] : + [dependencyTs.path, libFile.path, dtsPath, dtsMapLocation], + otherWatchedFiles: () => [mainConfig.path], + expectsDts: !withRefs, // Dts script info present only if no project reference + expectsMap: !withRefs // Map script info present only if no project reference + }; + } + + function goToDefNoMapActionInfo(withRefs: boolean): ActionInfo { + return { + ...goToDefActionInfo(withRefs), + action: withRefs ? + goToDefFromMainTs : + goToDefFromMainTsWithNoMap, + closedInfos: () => withRefs ? + [dependencyTs.path, dependencyConfig.path, libFile.path] : + [libFile.path, dtsPath], // Because map is deleted, dts and dependency are released + otherWatchedFiles: () => withRefs ? + [mainConfig.path] : + [mainConfig.path, dtsMapPath], // Watches deleted file + expectsMap: false + }; + } + + function goToDefNoDtsActionInfo(withRefs: boolean): ActionInfo { + return { + ...goToDefActionInfo(withRefs), + action: withRefs ? + goToDefFromMainTs : + goToDefFromMainTsWithNoDts, + closedInfos: () => withRefs ? + [dependencyTs.path, dependencyConfig.path, libFile.path] : + [libFile.path], // No dts means no map, no dependency + expectsDts: false, + expectsMap: false + }; + } + + verifyScenario({ + mainScenario: "can go to definition correctly", + verifier: withRefs => [ + { + ...goToDefFromMainTsProjectInfoVerifier(withRefs), + main: () => goToDefActionInfo(withRefs), + noMap: () => goToDefNoMapActionInfo(withRefs), + mapFileCreated: "main", + mapFileDeleted: () => ({ + ...goToDefNoMapActionInfo(withRefs), + closedInfos: () => withRefs ? + [dependencyTs.path, dependencyConfig.path, libFile.path] : + // The script info for depedency is collected only after file open + [dependencyTs.path, libFile.path, dtsPath] + }), + noDts: () => goToDefNoDtsActionInfo(withRefs), + dtsFileCreated: "main", + dtsFileDeleted: () => ({ + ...goToDefNoDtsActionInfo(withRefs), + // The script info for map is collected only after file open + closedInfos: () => withRefs ? + [dependencyTs.path, dependencyConfig.path, libFile.path] : + [dependencyTs.path, libFile.path, dtsMapLocation], + expectsMap: !withRefs + }), + dependencyChange: () => ({ + ...goToDefActionInfo(withRefs), + action: goToDefFromMainTsWithDependencyChange, + expectsDts: false, + expectsMap: false + }), + noBuild: "main" + } + ] + }); + }); + + describe("from defining project", () => { + function renameActionInfo(): ActionInfo { + return { + action: renameFromDependencyTs, + closedInfos: () => [libFile.path, dtsLocation, dtsMapLocation], + otherWatchedFiles: () => [dependencyConfig.path], + expectsDts: true, + expectsMap: true + }; + } + + function renameNoMapActionInfo(): ActionInfo { + return { + ...renameActionInfo(), + closedInfos: () => [libFile.path, dtsLocation], // No map + otherWatchedFiles: () => [dependencyConfig.path, dtsMapLocation], // watch map + expectsMap: false + }; + } + + function renameNoDtsActionInfo(): ActionInfo { + return { + action: renameFromDependencyTs, + closedInfos: () => [libFile.path], // no dts or map since dts itself doesnt exist + otherWatchedFiles: () => [dependencyConfig.path, dtsPath], // watch deleted file + expectsDts: false, + expectsMap: false + }; + } + + verifyScenario({ + mainScenario: "rename locations from dependency", + verifier: () => [ + { + ...renameFromDependencyTsProjectInfoVerifier(), + main: renameActionInfo, + noMap: renameNoMapActionInfo, + mapFileCreated: "main", + mapFileDeleted: "noMap", + noDts: renameNoDtsActionInfo, + dtsFileCreated: "main", + dtsFileDeleted: () => ({ + ...renameNoDtsActionInfo(), + // Map is collected after file open + closedInfos: () => [libFile.path, dtsMapLocation], + expectsMap: true + }), + dependencyChange: () => ({ + ...renameActionInfo(), + action: renameFromDependencyTsWithDependencyChange + }), + noBuild: () => ({ + action: renameFromDependencyTs, + closedInfos: () => [libFile.path], // No dts or map since its not built/present + // Watching for creation of dts so that it can give correct results across projects + otherWatchedFiles: () => [dependencyConfig.path, dtsPath], + expectsDts: false, + expectsMap: false + }) + } + ] + }); + }); + + describe("when opening depedency and usage project", () => { + function closedInfos(withRefs: boolean) { + // DependencyTs is open, so omit it from closed infos + return () => withRefs ? + [dependencyConfig.path, libFile.path] : + [libFile.path, dtsPath, dtsMapLocation]; + } + + function otherWatchedFiles(withRefs: boolean) { + return () => withRefs ? + [mainConfig.path] : // Its in closed info + [mainConfig.path, dependencyConfig.path]; + } + + function goToDefActionInfo(withRefs: boolean): ActionInfo { + return { + action: goToDefFromMainTs, + closedInfos: closedInfos(withRefs), + otherWatchedFiles: otherWatchedFiles(withRefs), + expectsDts: !withRefs, // Dts script info present only if no project reference + expectsMap: !withRefs // Map script info present only if no project reference + }; + } + + function renameActionInfo(withRefs: boolean): ActionInfo { + return { + action: renameFromDependencyTsWithBothProjectsOpen, + closedInfos: closedInfos(withRefs), + otherWatchedFiles: otherWatchedFiles(withRefs), + expectsDts: !withRefs, // Dts script info present only if no project reference + expectsMap: !withRefs // Map script info present only if no project reference + }; + } + + function closedInfosNoMap(withRefs: boolean) { + return withRefs ? + closedInfos(withRefs) : + () => [libFile.path, dtsPath]; // No map + } + + function otherWatchedFilesNoMap(withRefs: boolean) { + return withRefs ? + otherWatchedFiles(withRefs) : + () => [mainConfig.path, dependencyConfig.path, dtsMapLocation]; // Watch map file + } + + function goToDefNoMapActionInfo(withRefs: boolean): ActionInfo { + return { + ...goToDefActionInfo(withRefs), + action: withRefs ? + goToDefFromMainTs : + goToDefFromMainTsWithNoMap, + closedInfos: closedInfosNoMap(withRefs), + otherWatchedFiles: otherWatchedFilesNoMap(withRefs), + expectsMap: false + }; + } + + function renameNoMapActionInfo(withRefs: boolean): ActionInfo { + return { + ...renameActionInfo(withRefs), + action: withRefs ? + renameFromDependencyTsWithBothProjectsOpen : + renameFromDependencyTs, + closedInfos: closedInfosNoMap(withRefs), + otherWatchedFiles: otherWatchedFilesNoMap(withRefs), + expectsMap: false + }; + } + + function closedInfosNoDts(withRefs: boolean) { + return withRefs ? + closedInfos(withRefs) : + () => [libFile.path]; // No dts or map + } + + function otherWatchedFilesNoDts(withRefs: boolean) { + return withRefs ? + otherWatchedFiles(withRefs) : + () => [mainConfig.path, dependencyConfig.path, dtsPath]; // Watch dts + } + + function goToDefNoDtsActionInfo(withRefs: boolean): ActionInfo { + return { + ...goToDefActionInfo(withRefs), + action: withRefs ? + goToDefFromMainTs : + goToDefFromMainTsWithNoDts, + closedInfos: closedInfosNoDts(withRefs), + expectsDts: false, + expectsMap: false + }; + } + + function renameNoDtsActionInfo(withRefs: boolean): ActionInfo { + return { + action: withRefs ? + renameFromDependencyTsWithBothProjectsOpen : + renameFromDependencyTs, + closedInfos: closedInfosNoDts(withRefs), + otherWatchedFiles: otherWatchedFilesNoDts(withRefs), + expectsDts: false, + expectsMap: false + }; + } + + function closedInfosDtsFileDeleted(withRefs: boolean) { + // Map collection after file open + return withRefs ? + closedInfos(withRefs) : + () => [libFile.path, dtsMapLocation]; + } + + verifyScenario({ + mainScenario: "goto Definition in usage and rename locations from defining project", + verifier: withRefs => [ + { + ...goToDefFromMainTsProjectInfoVerifier(withRefs), + main: () => goToDefActionInfo(withRefs), + noMap: () => goToDefNoMapActionInfo(withRefs), + mapFileCreated: "main", + mapFileDeleted: "noMap", + noDts: () => goToDefNoDtsActionInfo(withRefs), + dtsFileCreated: "main", + dtsFileDeleted: () => ({ + ...goToDefNoDtsActionInfo(withRefs), + // Map collection after file open + closedInfos: closedInfosDtsFileDeleted(withRefs), + expectsMap: !withRefs + }), + dependencyChange: () => ({ + ...goToDefActionInfo(withRefs), + action: goToDefFromMainTsWithDependencyChange, + expectsDts: false, + expectsMap: false + }), + noBuild: "main" + }, + { + ...renameFromDependencyTsProjectInfoVerifier(), + main: () => renameActionInfo(withRefs), + noMap: () => renameNoMapActionInfo(withRefs), + mapFileCreated: "main", + mapFileDeleted: "noMap", + noDts: () => renameNoDtsActionInfo(withRefs), + dtsFileCreated: "main", + dtsFileDeleted: () => ({ + ...renameNoDtsActionInfo(withRefs), + // Map collection after file open + closedInfos: closedInfosDtsFileDeleted(withRefs), + expectsMap: !withRefs + }), + dependencyChange: () => ({ + ...renameActionInfo(withRefs), + action: renameFromDependencyTsWithBothProjectsOpenWithDependencyChange + }), + noBuild: () => ({ + ...renameActionInfo(withRefs), + expectDts: false + }) + } + ] + }); + }); }); it("reusing d.ts files from composite and non composite projects", () => { From 15b68a93966530f184d471234e3a0566e8c37307 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Mon, 1 Jul 2019 14:43:11 -0700 Subject: [PATCH 016/140] Skip typechecking of source of project reference redirect --- src/compiler/builder.ts | 2 +- src/compiler/checker.ts | 4 +- src/compiler/program.ts | 2 +- src/compiler/utilities.ts | 9 +- src/server/scriptInfo.ts | 6 +- src/server/session.ts | 4 +- src/testRunner/tsconfig.json | 1 + .../tsserver/projectReferenceErrors.ts | 236 +++++++++++++ .../unittests/tsserver/projectReferences.ts | 322 +++++++++++------- 9 files changed, 460 insertions(+), 126 deletions(-) create mode 100644 src/testRunner/unittests/tsserver/projectReferenceErrors.ts diff --git a/src/compiler/builder.ts b/src/compiler/builder.ts index 704cdaf23f9..bd35bac6c5f 100644 --- a/src/compiler/builder.ts +++ b/src/compiler/builder.ts @@ -407,7 +407,7 @@ namespace ts { const options = program.getCompilerOptions(); forEach(program.getSourceFiles(), f => program.isSourceFileDefaultLibrary(f) && - !skipTypeChecking(f, options) && + !skipTypeChecking(f, options, program) && removeSemanticDiagnosticsOf(state, f.path) ); } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c2e6b0d518a..40040302123 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -338,7 +338,7 @@ namespace ts { return node && getTypeArgumentConstraint(node); }, getSuggestionDiagnostics: (file, ct) => { - if (skipTypeChecking(file, compilerOptions)) { + if (skipTypeChecking(file, compilerOptions, host)) { return emptyArray; } @@ -29657,7 +29657,7 @@ namespace ts { function checkSourceFileWorker(node: SourceFile) { const links = getNodeLinks(node); if (!(links.flags & NodeCheckFlags.TypeChecked)) { - if (skipTypeChecking(node, compilerOptions)) { + if (skipTypeChecking(node, compilerOptions, host)) { return; } diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 78e5f314879..2149e175ca2 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1701,7 +1701,7 @@ namespace ts { function getSemanticDiagnosticsForFileNoCache(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] | undefined { return runWithCancellationToken(() => { - if (skipTypeChecking(sourceFile, options)) { + if (skipTypeChecking(sourceFile, options, program)) { return emptyArray; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 562d066b64e..ab6c0bfd83d 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -8573,11 +8573,16 @@ namespace ts { return { pos: typeParameters.pos - 1, end: typeParameters.end + 1 }; } - export function skipTypeChecking(sourceFile: SourceFile, options: CompilerOptions) { + export interface HostWithIsSourceOfProjectReferenceRedirect { + isSourceOfProjectReferenceRedirect(fileName: string): boolean; + } + export function skipTypeChecking(sourceFile: SourceFile, options: CompilerOptions, host: HostWithIsSourceOfProjectReferenceRedirect) { // If skipLibCheck is enabled, skip reporting errors if file is a declaration file. // If skipDefaultLibCheck is enabled, skip reporting errors if file contains a // '/// ' directive. - return options.skipLibCheck && sourceFile.isDeclarationFile || options.skipDefaultLibCheck && sourceFile.hasNoDefaultLib; + return (options.skipLibCheck && sourceFile.isDeclarationFile || + options.skipDefaultLibCheck && sourceFile.hasNoDefaultLib) || + host.isSourceOfProjectReferenceRedirect(sourceFile.fileName); } export function isJsonEqual(a: unknown, b: unknown): boolean { diff --git a/src/server/scriptInfo.ts b/src/server/scriptInfo.ts index 68c448a7e76..a2e75e3dac9 100644 --- a/src/server/scriptInfo.ts +++ b/src/server/scriptInfo.ts @@ -495,15 +495,17 @@ namespace ts.server { // the default project; if no configured projects, the first external project should // be the default project; otherwise the first inferred project should be the default. let firstExternalProject; + let firstConfiguredProject; for (const project of this.containingProjects) { if (project.projectKind === ProjectKind.Configured) { - return project; + if (!project.isSourceOfProjectReferenceRedirect(this.fileName)) return project; + if (!firstConfiguredProject) firstConfiguredProject = project; } else if (project.projectKind === ProjectKind.External && !firstExternalProject) { firstExternalProject = project; } } - return firstExternalProject || this.containingProjects[0]; + return firstConfiguredProject || firstExternalProject || this.containingProjects[0]; } } diff --git a/src/server/session.ts b/src/server/session.ts index ff339b06a81..a5c13574805 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -1658,10 +1658,10 @@ namespace ts.server { } } - private createCheckList(fileNames: string[], defaultProject?: Project): PendingErrorCheck[] { + private createCheckList(fileNames: string[]): PendingErrorCheck[] { return mapDefined(fileNames, uncheckedFileName => { const fileName = toNormalizedPath(uncheckedFileName); - const project = defaultProject || this.projectService.tryGetDefaultProjectForFile(fileName); + const project = this.projectService.tryGetDefaultProjectForFile(fileName); return project && { fileName, project }; }); } diff --git a/src/testRunner/tsconfig.json b/src/testRunner/tsconfig.json index b2e7e3e78b9..9d67215ffd9 100644 --- a/src/testRunner/tsconfig.json +++ b/src/testRunner/tsconfig.json @@ -137,6 +137,7 @@ "unittests/tsserver/occurences.ts", "unittests/tsserver/openFile.ts", "unittests/tsserver/projectErrors.ts", + "unittests/tsserver/projectReferenceErrors.ts", "unittests/tsserver/projectReferences.ts", "unittests/tsserver/projects.ts", "unittests/tsserver/refactors.ts", diff --git a/src/testRunner/unittests/tsserver/projectReferenceErrors.ts b/src/testRunner/unittests/tsserver/projectReferenceErrors.ts new file mode 100644 index 00000000000..8006b916037 --- /dev/null +++ b/src/testRunner/unittests/tsserver/projectReferenceErrors.ts @@ -0,0 +1,236 @@ +namespace ts.projectSystem { + describe("unittests:: tsserver:: with project references and error reporting", () => { + const projectLocation = "/user/username/projects/myproject"; + const dependecyLocation = `${projectLocation}/dependency`; + const usageLocation = `${projectLocation}/usage`; + const dependencyTs: File = { + path: `${dependecyLocation}/fns.ts`, + content: `export function fn1() { } +export function fn2() { } +// Introduce error for fnErr import in main +// export function fnErr() { } +// Error in dependency ts file +export let x: string = 10;` + }; + const dependencyConfig: File = { + path: `${dependecyLocation}/tsconfig.json`, + content: JSON.stringify({ compilerOptions: { composite: true, declarationDir: "../decls" } }) + }; + const usageTs: File = { + path: `${usageLocation}/usage.ts`, + content: `import { + fn1, + fn2, + fnErr +} from '../decls/fns' +fn1(); +fn2(); +fnErr(); +` + }; + const usageConfig: File = { + path: `${usageLocation}/tsconfig.json`, + content: JSON.stringify({ + references: [{ path: "../dependency" }] + }) + }; + + interface CheckErrorsInFile { + session: TestSession; + host: TestServerHost; + expected: GetErrDiagnostics; + expectedSequenceId?: number; + } + function checkErrorsInFile({ session, host, expected: { file, syntax, semantic, suggestion }, expectedSequenceId }: CheckErrorsInFile) { + host.checkTimeoutQueueLengthAndRun(1); + checkErrorMessage(session, "syntaxDiag", { file: file.path, diagnostics: syntax }); + session.clearMessages(); + + host.runQueuedImmediateCallbacks(1); + checkErrorMessage(session, "semanticDiag", { file: file.path, diagnostics: semantic }); + session.clearMessages(); + + host.runQueuedImmediateCallbacks(1); + checkErrorMessage(session, "suggestionDiag", { file: file.path, diagnostics: suggestion }); + if (expectedSequenceId !== undefined) { + checkCompleteEvent(session, 2, expectedSequenceId); + } + session.clearMessages(); + } + + interface CheckAllErrors { + session: TestSession; + host: TestServerHost; + expected: ReadonlyArray; + expectedSequenceId: number; + } + function checkAllErrors({ session, host, expected, expectedSequenceId }: CheckAllErrors) { + for (let i = 0; i < expected.length; i++) { + checkErrorsInFile({ + session, + host, + expected: expected[i], + expectedSequenceId: i === expected.length - 1 ? expectedSequenceId : undefined + }); + } + } + + function verifyErrorsUsingGeterr({ openFiles, expectedGetErr }: VerifyScenario) { + it("verifies the errors in open file", () => { + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { canUseEvents: true, }); + openFilesForSession(openFiles(), session); + + session.clearMessages(); + const expectedSequenceId = session.getNextSeq(); + const expected = expectedGetErr(); + session.executeCommandSeq({ + command: protocol.CommandTypes.Geterr, + arguments: { + delay: 0, + files: expected.map(f => f.file.path) + } + }); + + checkAllErrors({ session, host, expected, expectedSequenceId }); + }); + } + + function verifyErrorsUsingGeterrForProject({ openFiles, expectedGetErrForProject }: VerifyScenario) { + it("verifies the errors in projects", () => { + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { canUseEvents: true, }); + openFilesForSession(openFiles(), session); + + session.clearMessages(); + for (const expected of expectedGetErrForProject()) { + const expectedSequenceId = session.getNextSeq(); + session.executeCommandSeq({ + command: protocol.CommandTypes.GeterrForProject, + arguments: { + delay: 0, + file: expected.project + } + }); + + checkAllErrors({ session, host, expected: expected.errors, expectedSequenceId }); + } + }); + } + + interface GetErrDiagnostics { + file: File; + syntax: protocol.Diagnostic[]; + semantic: protocol.Diagnostic[]; + suggestion: protocol.Diagnostic[]; + } + interface GetErrForProjectDiagnostics { + project: string; + errors: ReadonlyArray; + } + interface VerifyScenario { + openFiles: () => ReadonlyArray; + expectedGetErr: () => ReadonlyArray; + expectedGetErrForProject: () => ReadonlyArray; + } + function verifyScenario(scenario: VerifyScenario) { + verifyErrorsUsingGeterr(scenario); + verifyErrorsUsingGeterrForProject(scenario); + } + + function emptyDiagnostics(file: File): GetErrDiagnostics { + return { + file, + syntax: emptyArray, + semantic: emptyArray, + suggestion: emptyArray + }; + } + + function usageDiagnostics(): GetErrDiagnostics { + return { + file: usageTs, + syntax: emptyArray, + semantic: [ + createDiagnostic( + { line: 4, offset: 5 }, + { line: 4, offset: 10 }, + Diagnostics.Module_0_has_no_exported_member_1, + [`"../dependency/fns"`, "fnErr"], + "error", + ) + ], + suggestion: emptyArray + }; + } + + function dependencyDiagnostics(): GetErrDiagnostics { + return { + file: dependencyTs, + syntax: emptyArray, + semantic: [ + createDiagnostic( + { line: 6, offset: 12 }, + { line: 6, offset: 13 }, + Diagnostics.Type_0_is_not_assignable_to_type_1, + ["10", "string"], + "error", + ) + ], + suggestion: emptyArray + }; + } + + function usageProjectDiagnostics(): GetErrForProjectDiagnostics { + return { + project: usageTs.path, + errors: [ + usageDiagnostics(), + emptyDiagnostics(dependencyTs) + ] + }; + } + + function dependencyProjectDiagnostics(): GetErrForProjectDiagnostics { + return { + project: dependencyTs.path, + errors: [ + dependencyDiagnostics() + ] + }; + } + + describe("when dependency project is not open", () => { + verifyScenario({ + openFiles: () => [usageTs], + expectedGetErr: () => [ + usageDiagnostics() + ], + expectedGetErrForProject: () => [ + usageProjectDiagnostics(), + { + project: dependencyTs.path, + errors: [ + emptyDiagnostics(dependencyTs), + usageDiagnostics() + ] + } + ] + }); + }); + + describe("when the depedency file is open", () => { + verifyScenario({ + openFiles: () => [usageTs, dependencyTs], + expectedGetErr: () => [ + usageDiagnostics(), + dependencyDiagnostics(), + ], + expectedGetErrForProject: () => [ + usageProjectDiagnostics(), + dependencyProjectDiagnostics() + ] + }); + }); + }); +} diff --git a/src/testRunner/unittests/tsserver/projectReferences.ts b/src/testRunner/unittests/tsserver/projectReferences.ts index c5712df2e1a..f39ec72e03e 100644 --- a/src/testRunner/unittests/tsserver/projectReferences.ts +++ b/src/testRunner/unittests/tsserver/projectReferences.ts @@ -373,6 +373,9 @@ fn5(); otherWatchedFiles: () => readonly string[]; expectsDts: boolean; expectsMap: boolean; + freshMapInfo?: boolean; + freshDocumentMapper?: boolean; + skipDtsMapCheck?: boolean; } type ActionKey = keyof ActionInfoVerifier; type ActionInfoGetterFn = () => ActionInfo; @@ -385,6 +388,9 @@ fn5(); } interface ActionInfoVerifier { main: ActionInfoGetter; + change: ActionInfoGetter; + dtsChange: ActionInfoGetter; + mapChange: ActionInfoGetter; noMap: ActionInfoGetter; mapFileCreated: ActionInfoGetter; mapFileDeleted: ActionInfoGetter; @@ -461,14 +467,21 @@ fn5(); return info; } - function verifyDocumentPositionMapper(session: TestSession, dependencyMap: server.ScriptInfo | undefined, documentPositionMapper: server.ScriptInfo["documentPositionMapper"], equal: boolean) { - assert.strictEqual(session.getProjectService().filenameToScriptInfo.get(dtsMapPath), dependencyMap); + interface VerifyDocumentPositionMapper { + session: TestSession; + dependencyMap: server.ScriptInfo | undefined; + documentPositionMapper: server.ScriptInfo["documentPositionMapper"]; + equal: boolean; + debugInfo: string; + } + function verifyDocumentPositionMapper({ session, dependencyMap, documentPositionMapper, equal, debugInfo }: VerifyDocumentPositionMapper) { + assert.strictEqual(session.getProjectService().filenameToScriptInfo.get(dtsMapPath), dependencyMap, debugInfo); if (dependencyMap) { if (equal) { - assert.strictEqual(dependencyMap.documentPositionMapper, documentPositionMapper); + assert.strictEqual(dependencyMap.documentPositionMapper, documentPositionMapper, debugInfo); } else { - assert.notStrictEqual(dependencyMap.documentPositionMapper, documentPositionMapper); + assert.notStrictEqual(dependencyMap.documentPositionMapper, documentPositionMapper, debugInfo); } } } @@ -491,7 +504,6 @@ fn5(); sourceMapPath?: server.ScriptInfo["sourceMapFilePath"]; dependencyMap?: server.ScriptInfo | undefined; documentPositionMapper?: server.ScriptInfo["documentPositionMapper"]; - firstEquals?: boolean; } interface VerifyAllFnActionResult { actionInfos: readonly ActionInfo[]; @@ -506,44 +518,62 @@ fn5(); actionKey, dependencyMap, documentPositionMapper, - firstEquals }: VerifyAllFnAction): VerifyAllFnActionResult { const actionInfos = getActionInfo(verifiers, actionKey); let sourceMapPath: server.ScriptInfo["sourceMapFilePath"] | undefined; // action let first = true; - for (const { action, closedInfos, otherWatchedFiles, expectsDts, expectsMap } of actionInfos) { + for (const { + action, + closedInfos, + otherWatchedFiles, + expectsDts, + expectsMap, + freshMapInfo, + freshDocumentMapper, + skipDtsMapCheck + } of actionInfos) { for (let fn = 1; fn <= 5; fn++) { const fnAction = action(fn); verifyAction(session, fnAction); - const dtsInfo = verifyScriptInfoPresence(session, dtsPath, expectsDts, fnAction.reqName); - const dtsMapInfo = verifyScriptInfoPresence(session, dtsMapPath, expectsMap, fnAction.reqName); + const debugInfo = `${actionKey}:: ${fnAction.reqName}:: ${fn}`; + const dtsInfo = verifyScriptInfoPresence(session, dtsPath, expectsDts, debugInfo); + const dtsMapInfo = verifyScriptInfoPresence(session, dtsMapPath, expectsMap, debugInfo); verifyInfosWithRandom( session, host, openFiles(verifiers).map(f => f.path), closedInfos(), otherWatchedFiles(), - `${actionKey}:: ${fnAction.reqName}` + debugInfo ); if (dtsInfo) { - if (first) { - if (dtsMapInfo) { - assert.equal(dtsInfo.sourceMapFilePath, dtsMapPath, `${actionKey}:: ${fnAction.reqName}`); - } - else { - assert.isNotString(dtsInfo.sourceMapFilePath); - assert.isNotFalse(dtsInfo.sourceMapFilePath); - assert.isDefined(dtsInfo.sourceMapFilePath); + if (first || (fn === 1 && freshMapInfo)) { + if (!skipDtsMapCheck) { + if (dtsMapInfo) { + assert.equal(dtsInfo.sourceMapFilePath, dtsMapPath, debugInfo); + } + else { + assert.isNotString(dtsInfo.sourceMapFilePath, debugInfo); + assert.isNotFalse(dtsInfo.sourceMapFilePath, debugInfo); + assert.isDefined(dtsInfo.sourceMapFilePath, debugInfo); + } } } else { - assert.equal(dtsInfo.sourceMapFilePath, sourceMapPath, `${actionKey}:: ${fnAction.reqName}`); + assert.equal(dtsInfo.sourceMapFilePath, sourceMapPath, debugInfo); } } - if (!first || firstEquals !== undefined) { - verifyDocumentPositionMapper(session, dependencyMap, documentPositionMapper, !first || !!firstEquals); + + if (!first && (fn !== 1 || !freshMapInfo)) { + verifyDocumentPositionMapper({ + session, + dependencyMap, + documentPositionMapper, + equal: fn !== 1 || !freshDocumentMapper, + debugInfo + }); } sourceMapPath = dtsInfo && dtsInfo.sourceMapFilePath; dependencyMap = dtsMapInfo; @@ -566,15 +596,22 @@ fn5(); openFilesForSession([randomFile], session); const { closedInfos, otherWatchedFiles } = last(actionInfos); + const debugInfo = `${actionKey} Collection`; verifyInfosWithRandom( session, host, openFiles(verifiers).map(f => f.path), closedInfos(), otherWatchedFiles(), - `${actionKey} Collection` + debugInfo ); - verifyDocumentPositionMapper(session, dependencyMap, documentPositionMapper, /*equal*/ true); + verifyDocumentPositionMapper({ + session, + dependencyMap, + documentPositionMapper, + equal: true, + debugInfo + }); // Closing open file, removes dependencies too closeFilesForSession([...openFiles(verifiers), randomFile], session); @@ -601,7 +638,6 @@ fn5(); verifier, withRefs, change, - afterActionDocumentPositionMapperNotEquals, afterChangeActionKey }: VerifyScenarioWithChanges, timeoutBeforeAction: boolean, @@ -619,7 +655,13 @@ fn5(); if (timeoutBeforeAction) { host.runQueuedTimeoutCallbacks(); checkProject(session, verifiers); - verifyDocumentPositionMapper(session, dependencyMap, documentPositionMapper, /*equal*/ true); + verifyDocumentPositionMapper({ + session, + dependencyMap, + documentPositionMapper, + equal: true, + debugInfo: "After change timeout" + }); } // action @@ -629,8 +671,7 @@ fn5(); verifiers, actionKey: afterChangeActionKey, dependencyMap, - documentPositionMapper, - firstEquals: !afterActionDocumentPositionMapperNotEquals + documentPositionMapper }); }); } @@ -638,7 +679,6 @@ fn5(); interface VerifyScenarioWithChanges extends VerifierAndWithRefs { scenarioName: string; change: (host: TestServerHost, session: TestSession, verifiers: readonly DocumentPositionMapperVerifier[]) => void; - afterActionDocumentPositionMapperNotEquals?: true; afterChangeActionKey: ActionKey; } function verifyScenarioWithChanges(verify: VerifyScenarioWithChanges) { @@ -704,7 +744,7 @@ fn5(); // The dependency file is deleted when orphan files are collected host.deleteFile(fileLocation); // Verify with deleted action key - const result = verifyAllFnAction({ session, host, verifiers, actionKey: fileDeletedKey }); + verifyAllFnAction({ session, host, verifiers, actionKey: fileDeletedKey }); checkProject(session, verifiers, noDts); // Script info collection should behave as fileNotPresentKey @@ -714,7 +754,7 @@ fn5(); verifiers, { actionInfos: getActionInfo(verifiers, fileNotPresentKey), - actionKey: result.actionKey, + actionKey: fileNotPresentKey, dependencyMap: undefined, documentPositionMapper: undefined } @@ -748,7 +788,7 @@ fn5(); } }) ), - afterChangeActionKey: "main" + afterChangeActionKey: "change" }); // Edit dts to add new fn @@ -764,7 +804,7 @@ fn5(); //# sourceMappingURL=FnS.d.ts.map` ) ), - afterChangeActionKey: "main" + afterChangeActionKey: "dtsChange" }); // Edit map file to represent added new line @@ -776,8 +816,7 @@ fn5(); dtsMapLocation, `{"version":3,"file":"FnS.d.ts","sourceRoot":"","sources":["../dependency/FnS.ts"],"names":[],"mappings":"AAAA,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,eAAO,MAAM,CAAC,KAAK,CAAC"}` ), - afterChangeActionKey: "main", - afterActionDocumentPositionMapperNotEquals: true + afterChangeActionKey: "mapChange" }); verifyScenarioWhenFileNotPresent({ @@ -824,7 +863,7 @@ ${dependencyTs.content}`); afterChangeActionKey: "dependencyChange" }); - it("when d.ts file is not generated", () => { + it("when projects are not built", () => { const host = createServerHost(files); const session = createSession(host); const verifiers = verifier(withRefs); @@ -896,6 +935,12 @@ ${dependencyTs.content}`); { ...goToDefFromMainTsProjectInfoVerifier(withRefs), main: () => goToDefActionInfo(withRefs), + change: "main", + dtsChange: "main", + mapChange: () => ({ + ...goToDefActionInfo(withRefs), + freshDocumentMapper: true + }), noMap: () => goToDefNoMapActionInfo(withRefs), mapFileCreated: "main", mapFileDeleted: () => ({ @@ -938,15 +983,6 @@ ${dependencyTs.content}`); }; } - function renameNoMapActionInfo(): ActionInfo { - return { - ...renameActionInfo(), - closedInfos: () => [libFile.path, dtsLocation], // No map - otherWatchedFiles: () => [dependencyConfig.path, dtsMapLocation], // watch map - expectsMap: false - }; - } - function renameNoDtsActionInfo(): ActionInfo { return { action: renameFromDependencyTs, @@ -963,7 +999,18 @@ ${dependencyTs.content}`); { ...renameFromDependencyTsProjectInfoVerifier(), main: renameActionInfo, - noMap: renameNoMapActionInfo, + change: "main", + dtsChange: "main", + mapChange: () => ({ + ...renameActionInfo(), + freshDocumentMapper: true + }), + noMap: () => ({ + ...renameActionInfo(), + closedInfos: () => [libFile.path, dtsLocation], // No map + otherWatchedFiles: () => [dependencyConfig.path, dtsMapLocation], // watch map + expectsMap: false + }), mapFileCreated: "main", mapFileDeleted: "noMap", noDts: renameNoDtsActionInfo, @@ -992,24 +1039,16 @@ ${dependencyTs.content}`); }); describe("when opening depedency and usage project", () => { - function closedInfos(withRefs: boolean) { - // DependencyTs is open, so omit it from closed infos - return () => withRefs ? - [dependencyConfig.path, libFile.path] : - [libFile.path, dtsPath, dtsMapLocation]; - } - - function otherWatchedFiles(withRefs: boolean) { - return () => withRefs ? - [mainConfig.path] : // Its in closed info - [mainConfig.path, dependencyConfig.path]; - } - function goToDefActionInfo(withRefs: boolean): ActionInfo { return { action: goToDefFromMainTs, - closedInfos: closedInfos(withRefs), - otherWatchedFiles: otherWatchedFiles(withRefs), + // DependencyTs is open, so omit it from closed infos + closedInfos: () => withRefs ? + [dependencyConfig.path, libFile.path] : + [libFile.path, dtsPath, dtsMapLocation], + otherWatchedFiles: () => withRefs ? + [mainConfig.path] : // Its in closed info + [mainConfig.path, dependencyConfig.path], expectsDts: !withRefs, // Dts script info present only if no project reference expectsMap: !withRefs // Map script info present only if no project reference }; @@ -1018,33 +1057,30 @@ ${dependencyTs.content}`); function renameActionInfo(withRefs: boolean): ActionInfo { return { action: renameFromDependencyTsWithBothProjectsOpen, - closedInfos: closedInfos(withRefs), - otherWatchedFiles: otherWatchedFiles(withRefs), - expectsDts: !withRefs, // Dts script info present only if no project reference - expectsMap: !withRefs // Map script info present only if no project reference + // DependencyTs is open, so omit it from closed infos + closedInfos: () => withRefs ? + [dependencyConfig.path, libFile.path, dtsLocation, dtsMapLocation] : + [libFile.path, dtsPath, dtsMapLocation], + otherWatchedFiles: () => withRefs ? + [mainConfig.path] : // Its in closed info + [mainConfig.path, dependencyConfig.path], + expectsDts: true, + expectsMap: true }; } - function closedInfosNoMap(withRefs: boolean) { - return withRefs ? - closedInfos(withRefs) : - () => [libFile.path, dtsPath]; // No map - } - - function otherWatchedFilesNoMap(withRefs: boolean) { - return withRefs ? - otherWatchedFiles(withRefs) : - () => [mainConfig.path, dependencyConfig.path, dtsMapLocation]; // Watch map file - } - function goToDefNoMapActionInfo(withRefs: boolean): ActionInfo { return { - ...goToDefActionInfo(withRefs), action: withRefs ? goToDefFromMainTs : goToDefFromMainTsWithNoMap, - closedInfos: closedInfosNoMap(withRefs), - otherWatchedFiles: otherWatchedFilesNoMap(withRefs), + closedInfos: () => withRefs ? + [dependencyConfig.path, libFile.path] : + [libFile.path, dtsPath], // No map + otherWatchedFiles: () => withRefs ? + [mainConfig.path] : // Its in closed info + [mainConfig.path, dependencyConfig.path, dtsMapLocation], // Watch map file + expectsDts: !withRefs, // Dts script info present only if no project reference expectsMap: false }; } @@ -1055,31 +1091,25 @@ ${dependencyTs.content}`); action: withRefs ? renameFromDependencyTsWithBothProjectsOpen : renameFromDependencyTs, - closedInfos: closedInfosNoMap(withRefs), - otherWatchedFiles: otherWatchedFilesNoMap(withRefs), + closedInfos: () => withRefs ? + [dependencyConfig.path, libFile.path, dtsLocation] : + [libFile.path, dtsPath], // No map + otherWatchedFiles: () => withRefs ? + [mainConfig.path, dtsMapLocation] : // Its in closed info + [mainConfig.path, dependencyConfig.path, dtsMapLocation], // Watch map file expectsMap: false }; } - function closedInfosNoDts(withRefs: boolean) { - return withRefs ? - closedInfos(withRefs) : - () => [libFile.path]; // No dts or map - } - - function otherWatchedFilesNoDts(withRefs: boolean) { - return withRefs ? - otherWatchedFiles(withRefs) : - () => [mainConfig.path, dependencyConfig.path, dtsPath]; // Watch dts - } - function goToDefNoDtsActionInfo(withRefs: boolean): ActionInfo { return { ...goToDefActionInfo(withRefs), action: withRefs ? goToDefFromMainTs : goToDefFromMainTsWithNoDts, - closedInfos: closedInfosNoDts(withRefs), + closedInfos: () => withRefs ? + [dependencyConfig.path, libFile.path] : + [libFile.path], // No dts or map, expectsDts: false, expectsMap: false }; @@ -1090,49 +1120,100 @@ ${dependencyTs.content}`); action: withRefs ? renameFromDependencyTsWithBothProjectsOpen : renameFromDependencyTs, - closedInfos: closedInfosNoDts(withRefs), - otherWatchedFiles: otherWatchedFilesNoDts(withRefs), + closedInfos: () => withRefs ? + [dependencyConfig.path, libFile.path] : + [libFile.path], // No dts or map, + otherWatchedFiles: () => withRefs ? + [mainConfig.path, dtsLocation] : + [mainConfig.path, dependencyConfig.path, dtsPath], // Watch dts, expectsDts: false, expectsMap: false }; } - function closedInfosDtsFileDeleted(withRefs: boolean) { - // Map collection after file open - return withRefs ? - closedInfos(withRefs) : - () => [libFile.path, dtsMapLocation]; - } - verifyScenario({ mainScenario: "goto Definition in usage and rename locations from defining project", verifier: withRefs => [ { ...goToDefFromMainTsProjectInfoVerifier(withRefs), main: () => goToDefActionInfo(withRefs), + change: () => ({ + // Because before this rename is done the closed info remains same as rename's main operation + ...goToDefActionInfo(withRefs), + closedInfos: () => withRefs ? + [dependencyConfig.path, libFile.path, dtsLocation, dtsMapLocation] : + [libFile.path, dtsPath, dtsMapLocation], + expectsDts: true, + expectsMap: true + }), + dtsChange: "change", + mapChange: "change", noMap: () => goToDefNoMapActionInfo(withRefs), - mapFileCreated: "main", - mapFileDeleted: "noMap", + mapFileCreated: () => ({ + // Because before this rename is done the closed info remains same as rename's main + ...goToDefActionInfo(withRefs), + closedInfos: () => withRefs ? + [dependencyConfig.path, libFile.path, dtsLocation] : + [libFile.path, dtsPath, dtsMapLocation], + expectsDts: true, + // This operation doesnt need map so the map info path in dts is not refreshed + skipDtsMapCheck: withRefs + }), + mapFileDeleted: () => ({ + // Because before this rename is done the closed info remains same as rename's noMap operation + ...goToDefNoMapActionInfo(withRefs), + closedInfos: () => withRefs ? + [dependencyConfig.path, libFile.path, dtsLocation] : + [libFile.path, dtsPath], // No map, + expectsDts: true, + // This operation doesnt need map so the map info path in dts is not refreshed + skipDtsMapCheck: withRefs + }), noDts: () => goToDefNoDtsActionInfo(withRefs), - dtsFileCreated: "main", + dtsFileCreated: () => ({ + ...goToDefActionInfo(withRefs), + // Since the project for dependency is not updated, the watcher from rename for dts still there + otherWatchedFiles: () => withRefs ? + [mainConfig.path, dtsLocation] : + [mainConfig.path, dependencyConfig.path], + }), dtsFileDeleted: () => ({ ...goToDefNoDtsActionInfo(withRefs), // Map collection after file open - closedInfos: closedInfosDtsFileDeleted(withRefs), - expectsMap: !withRefs + closedInfos: () => withRefs ? + [dependencyConfig.path, libFile.path, dtsMapLocation] : + [libFile.path, dtsMapLocation], + expectsMap: true }), dependencyChange: () => ({ ...goToDefActionInfo(withRefs), action: goToDefFromMainTsWithDependencyChange, - expectsDts: false, - expectsMap: false + // From rename main action + closedInfos: () => withRefs ? + [dependencyConfig.path, libFile.path, dtsLocation, dtsMapLocation] : + [libFile.path, dtsPath, dtsMapLocation], + expectsDts: withRefs, + expectsMap: withRefs }), noBuild: "main" }, { ...renameFromDependencyTsProjectInfoVerifier(), - main: () => renameActionInfo(withRefs), - noMap: () => renameNoMapActionInfo(withRefs), + main: () => ({ + ...renameActionInfo(withRefs), + freshMapInfo: withRefs + }), + change: () => renameActionInfo(withRefs), + dtsChange: "change", + mapChange: () => ({ + ...renameActionInfo(withRefs), + freshDocumentMapper: withRefs + }), + noMap: () => ({ + ...renameNoMapActionInfo(withRefs), + freshMapInfo: withRefs, + freshDocumentMapper: withRefs + }), mapFileCreated: "main", mapFileDeleted: "noMap", noDts: () => renameNoDtsActionInfo(withRefs), @@ -1140,16 +1221,25 @@ ${dependencyTs.content}`); dtsFileDeleted: () => ({ ...renameNoDtsActionInfo(withRefs), // Map collection after file open - closedInfos: closedInfosDtsFileDeleted(withRefs), - expectsMap: !withRefs + closedInfos: () => withRefs ? + [dependencyConfig.path, libFile.path, dtsMapLocation] : + [libFile.path, dtsMapLocation], + expectsMap: true }), dependencyChange: () => ({ ...renameActionInfo(withRefs), action: renameFromDependencyTsWithBothProjectsOpenWithDependencyChange }), noBuild: () => ({ - ...renameActionInfo(withRefs), - expectDts: false + action: renameFromDependencyTsWithBothProjectsOpen, + closedInfos: () => withRefs ? + [dependencyConfig.path, libFile.path] : + [libFile.path], + otherWatchedFiles: () => withRefs ? + [mainConfig.path, dtsLocation] : // Its in closed info + [mainConfig.path, dependencyConfig.path], + expectsDts: false, + expectsMap: false }) } ] From 9be475bdaa9e40787e610ffe0a27ecfe9ae323a8 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Wed, 3 Jul 2019 15:47:32 -0700 Subject: [PATCH 017/140] Refactoring --- .../unittests/tsserver/projectReferences.ts | 532 ++++++++---------- 1 file changed, 222 insertions(+), 310 deletions(-) diff --git a/src/testRunner/unittests/tsserver/projectReferences.ts b/src/testRunner/unittests/tsserver/projectReferences.ts index f39ec72e03e..f9445dc6d19 100644 --- a/src/testRunner/unittests/tsserver/projectReferences.ts +++ b/src/testRunner/unittests/tsserver/projectReferences.ts @@ -105,6 +105,7 @@ export function fn4() { } export function fn5() { } ` }; + const dependencyTsPath = dependencyTs.path.toLowerCase(); const dependencyConfig: File = { path: `${dependecyLocation}/tsconfig.json`, content: JSON.stringify({ compilerOptions: { composite: true, declarationMap: true, declarationDir: "../decls" } }) @@ -362,6 +363,13 @@ fn5(); }; } + function removePath(array: readonly string[], ...delPaths: string[]) { + return array.filter(a => { + const aLower = a.toLowerCase(); + return delPaths.every(dPath => dPath !== aLower); + }); + } + interface Action { reqName: string; request: Partial; @@ -369,8 +377,8 @@ fn5(); } interface ActionInfo { action: (fn: number) => Action; - closedInfos: () => readonly string[]; - otherWatchedFiles: () => readonly string[]; + closedInfos: readonly string[]; + otherWatchedFiles: readonly string[]; expectsDts: boolean; expectsMap: boolean; freshMapInfo?: boolean; @@ -379,7 +387,11 @@ fn5(); } type ActionKey = keyof ActionInfoVerifier; type ActionInfoGetterFn = () => ActionInfo; - type ActionInfoGetter = ActionInfoGetterFn | ActionKey; + type ActionInfoSpreader = [ + ActionKey, // Key to get initial value and pass this value to spread function + (actionInfo: ActionInfo) => Partial> + ]; + type ActionInfoGetter = ActionInfoGetterFn | ActionKey | ActionInfoSpreader; interface ProjectInfoVerifier { openFile: File; openFileLastLine: number; @@ -486,14 +498,25 @@ fn5(); } } + function getActionInfoOfVerfier(verifier: DocumentPositionMapperVerifier, actionKey: ActionKey): ActionInfo { + const actionInfoGetter = verifier[actionKey]; + if (isString(actionInfoGetter)) { + return getActionInfoOfVerfier(verifier, actionInfoGetter); + } + + if (isArray(actionInfoGetter)) { + const initialValue = getActionInfoOfVerfier(verifier, actionInfoGetter[0]); + return { + ...initialValue, + ...actionInfoGetter[1](initialValue) + }; + } + + return actionInfoGetter(); + } + function getActionInfo(verifiers: readonly DocumentPositionMapperVerifier[], actionKey: ActionKey): ActionInfo[] { - return verifiers.map(v => { - let actionInfoGetter = v[actionKey]; - while (isString(actionInfoGetter)) { - actionInfoGetter = v[actionInfoGetter]; - } - return actionInfoGetter(); - }); + return verifiers.map(v => getActionInfoOfVerfier(v, actionKey)); } interface VerifyAllFnAction { @@ -543,8 +566,8 @@ fn5(); session, host, openFiles(verifiers).map(f => f.path), - closedInfos(), - otherWatchedFiles(), + closedInfos, + otherWatchedFiles, debugInfo ); @@ -601,8 +624,8 @@ fn5(); session, host, openFiles(verifiers).map(f => f.path), - closedInfos(), - otherWatchedFiles(), + closedInfos, + otherWatchedFiles, debugInfo ); verifyDocumentPositionMapper({ @@ -887,360 +910,249 @@ ${dependencyTs.content}`); } describe("from project that uses dependency", () => { - function goToDefActionInfo(withRefs: boolean): ActionInfo { - return { - action: goToDefFromMainTs, - closedInfos: () => withRefs ? - [dependencyTs.path, dependencyConfig.path, libFile.path] : - [dependencyTs.path, libFile.path, dtsPath, dtsMapLocation], - otherWatchedFiles: () => [mainConfig.path], - expectsDts: !withRefs, // Dts script info present only if no project reference - expectsMap: !withRefs // Map script info present only if no project reference - }; - } - - function goToDefNoMapActionInfo(withRefs: boolean): ActionInfo { - return { - ...goToDefActionInfo(withRefs), - action: withRefs ? - goToDefFromMainTs : - goToDefFromMainTsWithNoMap, - closedInfos: () => withRefs ? - [dependencyTs.path, dependencyConfig.path, libFile.path] : - [libFile.path, dtsPath], // Because map is deleted, dts and dependency are released - otherWatchedFiles: () => withRefs ? - [mainConfig.path] : - [mainConfig.path, dtsMapPath], // Watches deleted file - expectsMap: false - }; - } - - function goToDefNoDtsActionInfo(withRefs: boolean): ActionInfo { - return { - ...goToDefActionInfo(withRefs), - action: withRefs ? - goToDefFromMainTs : - goToDefFromMainTsWithNoDts, - closedInfos: () => withRefs ? - [dependencyTs.path, dependencyConfig.path, libFile.path] : - [libFile.path], // No dts means no map, no dependency - expectsDts: false, - expectsMap: false - }; - } - verifyScenario({ mainScenario: "can go to definition correctly", verifier: withRefs => [ { ...goToDefFromMainTsProjectInfoVerifier(withRefs), - main: () => goToDefActionInfo(withRefs), + main: () => ({ + action: goToDefFromMainTs, + closedInfos: withRefs ? + [dependencyTs.path, dependencyConfig.path, libFile.path] : + [dependencyTs.path, libFile.path, dtsPath, dtsMapLocation], + otherWatchedFiles: [mainConfig.path], + expectsDts: !withRefs, // Dts script info present only if no project reference + expectsMap: !withRefs // Map script info present only if no project reference + }), change: "main", dtsChange: "main", - mapChange: () => ({ - ...goToDefActionInfo(withRefs), + mapChange: ["main", () => ({ freshDocumentMapper: true - }), - noMap: () => goToDefNoMapActionInfo(withRefs), + })], + noMap: withRefs ? + "main" : + ["main", main => ({ + action: goToDefFromMainTsWithNoMap, + // Because map is deleted, dts and dependency are released + closedInfos: removePath(main.closedInfos, dtsMapPath, dependencyTsPath), + // Watches deleted file + otherWatchedFiles: main.otherWatchedFiles.concat(dtsMapLocation), + expectsMap: false + })], mapFileCreated: "main", - mapFileDeleted: () => ({ - ...goToDefNoMapActionInfo(withRefs), - closedInfos: () => withRefs ? - [dependencyTs.path, dependencyConfig.path, libFile.path] : + mapFileDeleted: withRefs ? + "main" : + ["noMap", noMap => ({ // The script info for depedency is collected only after file open - [dependencyTs.path, libFile.path, dtsPath] - }), - noDts: () => goToDefNoDtsActionInfo(withRefs), + closedInfos: noMap.closedInfos.concat(dependencyTs.path) + })], + noDts: withRefs ? + "main" : + ["main", main => ({ + action: goToDefFromMainTsWithNoDts, + // No dts, no map, no dependency + closedInfos: removePath(main.closedInfos, dtsPath, dtsMapPath, dependencyTsPath), + expectsDts: false, + expectsMap: false + })], dtsFileCreated: "main", - dtsFileDeleted: () => ({ - ...goToDefNoDtsActionInfo(withRefs), - // The script info for map is collected only after file open - closedInfos: () => withRefs ? - [dependencyTs.path, dependencyConfig.path, libFile.path] : - [dependencyTs.path, libFile.path, dtsMapLocation], - expectsMap: !withRefs - }), - dependencyChange: () => ({ - ...goToDefActionInfo(withRefs), + dtsFileDeleted: withRefs ? + "main" : + ["noDts", noDts => ({ + // The script info for map is collected only after file open + closedInfos: noDts.closedInfos.concat(dependencyTs.path, dtsMapLocation), + expectsMap: true + })], + dependencyChange: ["main", () => ({ action: goToDefFromMainTsWithDependencyChange, - expectsDts: false, - expectsMap: false - }), - noBuild: "main" + })], + noBuild: "noDts" } ] }); }); describe("from defining project", () => { - function renameActionInfo(): ActionInfo { - return { - action: renameFromDependencyTs, - closedInfos: () => [libFile.path, dtsLocation, dtsMapLocation], - otherWatchedFiles: () => [dependencyConfig.path], - expectsDts: true, - expectsMap: true - }; - } - - function renameNoDtsActionInfo(): ActionInfo { - return { - action: renameFromDependencyTs, - closedInfos: () => [libFile.path], // no dts or map since dts itself doesnt exist - otherWatchedFiles: () => [dependencyConfig.path, dtsPath], // watch deleted file - expectsDts: false, - expectsMap: false - }; - } - verifyScenario({ mainScenario: "rename locations from dependency", verifier: () => [ { ...renameFromDependencyTsProjectInfoVerifier(), - main: renameActionInfo, - change: "main", - dtsChange: "main", - mapChange: () => ({ - ...renameActionInfo(), - freshDocumentMapper: true - }), - noMap: () => ({ - ...renameActionInfo(), - closedInfos: () => [libFile.path, dtsLocation], // No map - otherWatchedFiles: () => [dependencyConfig.path, dtsMapLocation], // watch map - expectsMap: false - }), - mapFileCreated: "main", - mapFileDeleted: "noMap", - noDts: renameNoDtsActionInfo, - dtsFileCreated: "main", - dtsFileDeleted: () => ({ - ...renameNoDtsActionInfo(), - // Map is collected after file open - closedInfos: () => [libFile.path, dtsMapLocation], + main: () => ({ + action: renameFromDependencyTs, + closedInfos: [libFile.path, dtsLocation, dtsMapLocation], + otherWatchedFiles: [dependencyConfig.path], + expectsDts: true, expectsMap: true }), - dependencyChange: () => ({ - ...renameActionInfo(), - action: renameFromDependencyTsWithDependencyChange - }), - noBuild: () => ({ - action: renameFromDependencyTs, - closedInfos: () => [libFile.path], // No dts or map since its not built/present - // Watching for creation of dts so that it can give correct results across projects - otherWatchedFiles: () => [dependencyConfig.path, dtsPath], + change: "main", + dtsChange: "main", + mapChange: ["main", () => ({ + freshDocumentMapper: true + })], + noMap: ["main", main => ({ + // No map + closedInfos: removePath(main.closedInfos, dtsMapPath), + // watch map + otherWatchedFiles: [...main.otherWatchedFiles, dtsMapLocation], + expectsMap: false + })], + mapFileCreated: "main", + mapFileDeleted: "noMap", + noDts: ["main", main => ({ + // no dts or map since dts itself doesnt exist + closedInfos: removePath(main.closedInfos, dtsMapPath, dtsPath), + // watch deleted file + otherWatchedFiles: [...main.otherWatchedFiles, dtsLocation], expectsDts: false, expectsMap: false - }) + })], + dtsFileCreated: "main", + dtsFileDeleted: ["noDts", noDts => ({ + // Map is collected after file open + closedInfos: noDts.closedInfos.concat(dtsMapLocation), + expectsMap: true + })], + dependencyChange: ["main", () => ({ + action: renameFromDependencyTsWithDependencyChange + })], + noBuild: "noDts" } ] }); }); describe("when opening depedency and usage project", () => { - function goToDefActionInfo(withRefs: boolean): ActionInfo { - return { - action: goToDefFromMainTs, - // DependencyTs is open, so omit it from closed infos - closedInfos: () => withRefs ? - [dependencyConfig.path, libFile.path] : - [libFile.path, dtsPath, dtsMapLocation], - otherWatchedFiles: () => withRefs ? - [mainConfig.path] : // Its in closed info - [mainConfig.path, dependencyConfig.path], - expectsDts: !withRefs, // Dts script info present only if no project reference - expectsMap: !withRefs // Map script info present only if no project reference - }; - } - - function renameActionInfo(withRefs: boolean): ActionInfo { - return { - action: renameFromDependencyTsWithBothProjectsOpen, - // DependencyTs is open, so omit it from closed infos - closedInfos: () => withRefs ? - [dependencyConfig.path, libFile.path, dtsLocation, dtsMapLocation] : - [libFile.path, dtsPath, dtsMapLocation], - otherWatchedFiles: () => withRefs ? - [mainConfig.path] : // Its in closed info - [mainConfig.path, dependencyConfig.path], - expectsDts: true, - expectsMap: true - }; - } - - function goToDefNoMapActionInfo(withRefs: boolean): ActionInfo { - return { - action: withRefs ? - goToDefFromMainTs : - goToDefFromMainTsWithNoMap, - closedInfos: () => withRefs ? - [dependencyConfig.path, libFile.path] : - [libFile.path, dtsPath], // No map - otherWatchedFiles: () => withRefs ? - [mainConfig.path] : // Its in closed info - [mainConfig.path, dependencyConfig.path, dtsMapLocation], // Watch map file - expectsDts: !withRefs, // Dts script info present only if no project reference - expectsMap: false - }; - } - - function renameNoMapActionInfo(withRefs: boolean): ActionInfo { - return { - ...renameActionInfo(withRefs), - action: withRefs ? - renameFromDependencyTsWithBothProjectsOpen : - renameFromDependencyTs, - closedInfos: () => withRefs ? - [dependencyConfig.path, libFile.path, dtsLocation] : - [libFile.path, dtsPath], // No map - otherWatchedFiles: () => withRefs ? - [mainConfig.path, dtsMapLocation] : // Its in closed info - [mainConfig.path, dependencyConfig.path, dtsMapLocation], // Watch map file - expectsMap: false - }; - } - - function goToDefNoDtsActionInfo(withRefs: boolean): ActionInfo { - return { - ...goToDefActionInfo(withRefs), - action: withRefs ? - goToDefFromMainTs : - goToDefFromMainTsWithNoDts, - closedInfos: () => withRefs ? - [dependencyConfig.path, libFile.path] : - [libFile.path], // No dts or map, - expectsDts: false, - expectsMap: false - }; - } - - function renameNoDtsActionInfo(withRefs: boolean): ActionInfo { - return { - action: withRefs ? - renameFromDependencyTsWithBothProjectsOpen : - renameFromDependencyTs, - closedInfos: () => withRefs ? - [dependencyConfig.path, libFile.path] : - [libFile.path], // No dts or map, - otherWatchedFiles: () => withRefs ? - [mainConfig.path, dtsLocation] : - [mainConfig.path, dependencyConfig.path, dtsPath], // Watch dts, - expectsDts: false, - expectsMap: false - }; - } - verifyScenario({ mainScenario: "goto Definition in usage and rename locations from defining project", verifier: withRefs => [ { ...goToDefFromMainTsProjectInfoVerifier(withRefs), - main: () => goToDefActionInfo(withRefs), - change: () => ({ - // Because before this rename is done the closed info remains same as rename's main operation - ...goToDefActionInfo(withRefs), - closedInfos: () => withRefs ? - [dependencyConfig.path, libFile.path, dtsLocation, dtsMapLocation] : + main: () => ({ + action: goToDefFromMainTs, + // DependencyTs is open, so omit it from closed infos + closedInfos: withRefs ? + [dependencyConfig.path, libFile.path] : [libFile.path, dtsPath, dtsMapLocation], - expectsDts: true, - expectsMap: true + otherWatchedFiles: withRefs ? + [mainConfig.path] : // Its in closed info + [mainConfig.path, dependencyConfig.path], + expectsDts: !withRefs, // Dts script info present only if no project reference + expectsMap: !withRefs // Map script info present only if no project reference }), + change: withRefs ? + ["main", main => ({ + // Because before this rename is done the closed info remains same as rename's main operation + closedInfos: main.closedInfos.concat(dtsLocation, dtsMapLocation), + expectsDts: true, + expectsMap: true + })] : + "main", dtsChange: "change", mapChange: "change", - noMap: () => goToDefNoMapActionInfo(withRefs), - mapFileCreated: () => ({ - // Because before this rename is done the closed info remains same as rename's main - ...goToDefActionInfo(withRefs), - closedInfos: () => withRefs ? - [dependencyConfig.path, libFile.path, dtsLocation] : - [libFile.path, dtsPath, dtsMapLocation], - expectsDts: true, - // This operation doesnt need map so the map info path in dts is not refreshed - skipDtsMapCheck: withRefs - }), - mapFileDeleted: () => ({ - // Because before this rename is done the closed info remains same as rename's noMap operation - ...goToDefNoMapActionInfo(withRefs), - closedInfos: () => withRefs ? - [dependencyConfig.path, libFile.path, dtsLocation] : - [libFile.path, dtsPath], // No map, - expectsDts: true, - // This operation doesnt need map so the map info path in dts is not refreshed - skipDtsMapCheck: withRefs - }), - noDts: () => goToDefNoDtsActionInfo(withRefs), - dtsFileCreated: () => ({ - ...goToDefActionInfo(withRefs), - // Since the project for dependency is not updated, the watcher from rename for dts still there - otherWatchedFiles: () => withRefs ? - [mainConfig.path, dtsLocation] : - [mainConfig.path, dependencyConfig.path], - }), - dtsFileDeleted: () => ({ - ...goToDefNoDtsActionInfo(withRefs), + noMap: withRefs ? + "main" : + ["main", main => ({ + action: goToDefFromMainTsWithNoMap, + closedInfos: removePath(main.closedInfos, dtsMapPath), + otherWatchedFiles: main.otherWatchedFiles.concat(dtsMapLocation), + expectsMap: false + })], + mapFileCreated: withRefs ? + ["main", main => ({ + // Because before this rename is done the closed info remains same as rename's main + closedInfos: main.closedInfos.concat(dtsLocation), + expectsDts: true, + // This operation doesnt need map so the map info path in dts is not refreshed + skipDtsMapCheck: withRefs + })] : + "main", + mapFileDeleted: withRefs ? + ["noMap", noMap => ({ + // Because before this rename is done the closed info remains same as rename's noMap operation + closedInfos: noMap.closedInfos.concat(dtsLocation), + expectsDts: true, + // This operation doesnt need map so the map info path in dts is not refreshed + skipDtsMapCheck: true + })] : + "noMap", + noDts: withRefs ? + "main" : + ["main", main => ({ + action: goToDefFromMainTsWithNoDts, + closedInfos: removePath(main.closedInfos, dtsMapPath, dtsPath), + expectsDts: false, + expectsMap: false + })], + dtsFileCreated: withRefs ? + ["main", main => ({ + // Since the project for dependency is not updated, the watcher from rename for dts still there + otherWatchedFiles: main.otherWatchedFiles.concat(dtsLocation) + })] : + "main", + dtsFileDeleted: ["noDts", noDts => ({ // Map collection after file open - closedInfos: () => withRefs ? - [dependencyConfig.path, libFile.path, dtsMapLocation] : - [libFile.path, dtsMapLocation], + closedInfos: noDts.closedInfos.concat(dtsMapLocation), expectsMap: true - }), - dependencyChange: () => ({ - ...goToDefActionInfo(withRefs), + })], + dependencyChange: ["change", () => ({ action: goToDefFromMainTsWithDependencyChange, - // From rename main action - closedInfos: () => withRefs ? - [dependencyConfig.path, libFile.path, dtsLocation, dtsMapLocation] : - [libFile.path, dtsPath, dtsMapLocation], - expectsDts: withRefs, - expectsMap: withRefs - }), - noBuild: "main" + })], + noBuild: "noDts" }, { ...renameFromDependencyTsProjectInfoVerifier(), main: () => ({ - ...renameActionInfo(withRefs), + action: renameFromDependencyTsWithBothProjectsOpen, + // DependencyTs is open, so omit it from closed infos + closedInfos: withRefs ? + [dependencyConfig.path, libFile.path, dtsLocation, dtsMapLocation] : + [libFile.path, dtsPath, dtsMapLocation], + otherWatchedFiles: withRefs ? + [mainConfig.path] : // Its in closed info + [mainConfig.path, dependencyConfig.path], + expectsDts: true, + expectsMap: true, freshMapInfo: withRefs }), - change: () => renameActionInfo(withRefs), + change: ["main", () => ({ + freshMapInfo: false + })], dtsChange: "change", - mapChange: () => ({ - ...renameActionInfo(withRefs), + mapChange: ["main", () => ({ + freshMapInfo: false, freshDocumentMapper: withRefs - }), - noMap: () => ({ - ...renameNoMapActionInfo(withRefs), - freshMapInfo: withRefs, + })], + noMap: ["main", main => ({ + action: withRefs ? + renameFromDependencyTsWithBothProjectsOpen : + renameFromDependencyTs, + closedInfos: removePath(main.closedInfos, dtsMapPath), + otherWatchedFiles: main.otherWatchedFiles.concat(dtsMapLocation), + expectsMap: false, freshDocumentMapper: withRefs - }), + })], mapFileCreated: "main", mapFileDeleted: "noMap", - noDts: () => renameNoDtsActionInfo(withRefs), - dtsFileCreated: "main", - dtsFileDeleted: () => ({ - ...renameNoDtsActionInfo(withRefs), - // Map collection after file open - closedInfos: () => withRefs ? - [dependencyConfig.path, libFile.path, dtsMapLocation] : - [libFile.path, dtsMapLocation], - expectsMap: true - }), - dependencyChange: () => ({ - ...renameActionInfo(withRefs), - action: renameFromDependencyTsWithBothProjectsOpenWithDependencyChange - }), - noBuild: () => ({ - action: renameFromDependencyTsWithBothProjectsOpen, - closedInfos: () => withRefs ? - [dependencyConfig.path, libFile.path] : - [libFile.path], - otherWatchedFiles: () => withRefs ? - [mainConfig.path, dtsLocation] : // Its in closed info - [mainConfig.path, dependencyConfig.path], + noDts: ["change", change => ({ + action: withRefs ? + renameFromDependencyTsWithBothProjectsOpen : + renameFromDependencyTs, + closedInfos: removePath(change.closedInfos, dtsPath, dtsMapPath), + otherWatchedFiles: change.otherWatchedFiles.concat(dtsLocation), expectsDts: false, expectsMap: false - }) + })], + dtsFileCreated: "main", + dtsFileDeleted: ["noDts", noDts => ({ + // Map collection after file open + closedInfos: noDts.closedInfos.concat(dtsMapLocation) , + expectsMap: true + })], + dependencyChange: ["change", () => ({ + action: renameFromDependencyTsWithBothProjectsOpenWithDependencyChange + })], + noBuild: "noDts" } ] }); From b1fa2ebff5bfcd8bc69932cbec01d0c1479f091f Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 5 Jul 2019 12:17:01 -0700 Subject: [PATCH 018/140] Errors using DiagnosticsSync commands --- .../tsserver/projectReferenceErrors.ts | 88 ++++++++++++++++--- 1 file changed, 74 insertions(+), 14 deletions(-) diff --git a/src/testRunner/unittests/tsserver/projectReferenceErrors.ts b/src/testRunner/unittests/tsserver/projectReferenceErrors.ts index 8006b916037..303808cb4e4 100644 --- a/src/testRunner/unittests/tsserver/projectReferenceErrors.ts +++ b/src/testRunner/unittests/tsserver/projectReferenceErrors.ts @@ -61,7 +61,7 @@ fnErr(); interface CheckAllErrors { session: TestSession; host: TestServerHost; - expected: ReadonlyArray; + expected: readonly GetErrDiagnostics[]; expectedSequenceId: number; } function checkAllErrors({ session, host, expected, expectedSequenceId }: CheckAllErrors) { @@ -118,6 +118,40 @@ fnErr(); }); } + function verifyErrorsUsingSyncMethods({ openFiles, expectedSyncDiagnostics }: VerifyScenario) { + it("verifies the errors using sync commands", () => { + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host); + openFilesForSession(openFiles(), session); + for (const { file, project, syntax, semantic, suggestion } of expectedSyncDiagnostics()) { + const actualSyntax = session.executeCommandSeq({ + command: protocol.CommandTypes.SyntacticDiagnosticsSync, + arguments: { + file: file.path, + projectFileName: project + } + }).response as protocol.Diagnostic[]; + assert.deepEqual(actualSyntax, syntax, `Syntax diagnostics for file: ${file.path}, project: ${project}`); + const actualSemantic = session.executeCommandSeq({ + command: protocol.CommandTypes.SemanticDiagnosticsSync, + arguments: { + file: file.path, + projectFileName: project + } + }).response as protocol.Diagnostic[]; + assert.deepEqual(actualSemantic, semantic, `Semantic diagnostics for file: ${file.path}, project: ${project}`); + const actualSuggestion = session.executeCommandSeq({ + command: protocol.CommandTypes.SuggestionDiagnosticsSync, + arguments: { + file: file.path, + projectFileName: project + } + }).response as protocol.Diagnostic[]; + assert.deepEqual(actualSuggestion, suggestion, `Suggestion diagnostics for file: ${file.path}, project: ${project}`); + } + }); + } + interface GetErrDiagnostics { file: File; syntax: protocol.Diagnostic[]; @@ -126,16 +160,21 @@ fnErr(); } interface GetErrForProjectDiagnostics { project: string; - errors: ReadonlyArray; + errors: readonly GetErrDiagnostics[]; + } + interface SyncDiagnostics extends GetErrDiagnostics { + project?: string; } interface VerifyScenario { - openFiles: () => ReadonlyArray; - expectedGetErr: () => ReadonlyArray; - expectedGetErrForProject: () => ReadonlyArray; + openFiles: () => readonly File[]; + expectedGetErr: () => readonly GetErrDiagnostics[]; + expectedGetErrForProject: () => readonly GetErrForProjectDiagnostics[]; + expectedSyncDiagnostics: () => readonly SyncDiagnostics[]; } function verifyScenario(scenario: VerifyScenario) { verifyErrorsUsingGeterr(scenario); verifyErrorsUsingGeterrForProject(scenario); + verifyErrorsUsingSyncMethods(scenario); } function emptyDiagnostics(file: File): GetErrDiagnostics { @@ -169,13 +208,13 @@ fnErr(); file: dependencyTs, syntax: emptyArray, semantic: [ - createDiagnostic( - { line: 6, offset: 12 }, - { line: 6, offset: 13 }, - Diagnostics.Type_0_is_not_assignable_to_type_1, - ["10", "string"], - "error", - ) + createDiagnostic( + { line: 6, offset: 12 }, + { line: 6, offset: 13 }, + Diagnostics.Type_0_is_not_assignable_to_type_1, + ["10", "string"], + "error", + ) ], suggestion: emptyArray }; @@ -200,6 +239,10 @@ fnErr(); }; } + function syncDiagnostics(diagnostics: GetErrDiagnostics, project: string): SyncDiagnostics { + return { project, ...diagnostics }; + } + describe("when dependency project is not open", () => { verifyScenario({ openFiles: () => [usageTs], @@ -215,7 +258,15 @@ fnErr(); usageDiagnostics() ] } - ] + ], + expectedSyncDiagnostics: () => [ + // Without project + usageDiagnostics(), + emptyDiagnostics(dependencyTs), + // With project + syncDiagnostics(usageDiagnostics(), usageConfig.path), + syncDiagnostics(emptyDiagnostics(dependencyTs), usageConfig.path), + ], }); }); @@ -229,7 +280,16 @@ fnErr(); expectedGetErrForProject: () => [ usageProjectDiagnostics(), dependencyProjectDiagnostics() - ] + ], + expectedSyncDiagnostics: () => [ + // Without project + usageDiagnostics(), + dependencyDiagnostics(), + // With project + syncDiagnostics(usageDiagnostics(), usageConfig.path), + syncDiagnostics(emptyDiagnostics(dependencyTs), usageConfig.path), + syncDiagnostics(dependencyDiagnostics(), dependencyConfig.path), + ], }); }); }); From 824c22c460b9a57b9c67398890449cd6799fb4e0 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Mon, 8 Jul 2019 15:55:35 -0700 Subject: [PATCH 019/140] Source of project reference behave as if those files cannot be emitted. --- src/compiler/sys.ts | 47 +- src/harness/virtualFileSystemWithWatch.ts | 15 + src/server/project.ts | 9 +- src/server/session.ts | 4 +- src/testRunner/tsconfig.json | 1 + src/testRunner/unittests/tsbuildWatchMode.ts | 14 +- src/testRunner/unittests/tsserver/helpers.ts | 2 +- .../tsserver/projectReferenceCompileOnSave.ts | 410 ++++++++++++++++++ .../reference/api/tsserverlibrary.d.ts | 1 - 9 files changed, 468 insertions(+), 35 deletions(-) create mode 100644 src/testRunner/unittests/tsserver/projectReferenceCompileOnSave.ts diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index 5abc19cdbc4..b7eca0ee51c 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -472,6 +472,33 @@ namespace ts { } } + function recursiveCreateDirectory(directoryPath: string, sys: System) { + const basePath = getDirectoryPath(directoryPath); + const shouldCreateParent = basePath !== "" && directoryPath !== basePath && !sys.directoryExists(basePath); + if (shouldCreateParent) { + recursiveCreateDirectory(basePath, sys); + } + if (shouldCreateParent || !sys.directoryExists(directoryPath)) { + sys.createDirectory(directoryPath); + } + } + + /** + * patch writefile to create folder before writing the file + */ + /*@internal*/ + export function patchWriteFileEnsuringDirectory(sys: System) { + // patch writefile to create folder before writing the file + const originalWriteFile = sys.writeFile; + sys.writeFile = (path, data, writeBom) => { + const directoryPath = getDirectoryPath(normalizeSlashes(path)); + if (directoryPath && !sys.directoryExists(directoryPath)) { + recursiveCreateDirectory(directoryPath, sys); + } + originalWriteFile.call(sys, path, data, writeBom); + }; + } + /*@internal*/ interface NodeBuffer extends Uint8Array { write(str: string, offset?: number, length?: number, encoding?: string): number; @@ -1259,17 +1286,6 @@ namespace ts { }; } - function recursiveCreateDirectory(directoryPath: string, sys: System) { - const basePath = getDirectoryPath(directoryPath); - const shouldCreateParent = basePath !== "" && directoryPath !== basePath && !sys.directoryExists(basePath); - if (shouldCreateParent) { - recursiveCreateDirectory(basePath, sys); - } - if (shouldCreateParent || !sys.directoryExists(directoryPath)) { - sys.createDirectory(directoryPath); - } - } - let sys: System | undefined; if (typeof ChakraHost !== "undefined") { sys = getChakraSystem(); @@ -1281,14 +1297,7 @@ namespace ts { } if (sys) { // patch writefile to create folder before writing the file - const originalWriteFile = sys.writeFile; - sys.writeFile = (path, data, writeBom) => { - const directoryPath = getDirectoryPath(normalizeSlashes(path)); - if (directoryPath && !sys!.directoryExists(directoryPath)) { - recursiveCreateDirectory(directoryPath, sys!); - } - originalWriteFile.call(sys, path, data, writeBom); - }; + patchWriteFileEnsuringDirectory(sys); } return sys!; })(); diff --git a/src/harness/virtualFileSystemWithWatch.ts b/src/harness/virtualFileSystemWithWatch.ts index 9e615a02638..23127f49aad 100644 --- a/src/harness/virtualFileSystemWithWatch.ts +++ b/src/harness/virtualFileSystemWithWatch.ts @@ -66,6 +66,8 @@ interface Array {}` params.newLine, params.useWindowsStylePaths, params.environmentVariables); + // Just like sys, patch the host to use writeFile + patchWriteFileEnsuringDirectory(host); return host; } @@ -990,6 +992,19 @@ interface Array {}` } } + export type TestServerHostTrackingWrittenFiles = TestServerHost & { writtenFiles: Map; }; + + export function changeToHostTrackingWrittenFiles(inputHost: TestServerHost) { + const host = inputHost as TestServerHostTrackingWrittenFiles; + const originalWriteFile = host.writeFile; + host.writtenFiles = createMap(); + host.writeFile = (fileName, content) => { + originalWriteFile.call(host, fileName, content); + const path = host.toFullPath(fileName); + host.writtenFiles.set(path, true); + }; + return host; + } export const tsbuildProjectsLocation = "/user/username/projects"; export function getTsBuildProjectFilePath(project: string, file: string) { return `${tsbuildProjectsLocation}/${project}/${file}`; diff --git a/src/server/project.ts b/src/server/project.ts index cd5a3fec855..2811b04c413 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -537,8 +537,11 @@ namespace ts.server { return this.projectService.getSourceFileLike(fileName, this); } - private shouldEmitFile(scriptInfo: ScriptInfo) { - return scriptInfo && !scriptInfo.isDynamicOrHasMixedContent(); + /*@internal*/ + shouldEmitFile(scriptInfo: ScriptInfo | undefined) { + return scriptInfo && + !scriptInfo.isDynamicOrHasMixedContent() && + !this.program!.isSourceOfProjectReferenceRedirect(scriptInfo.path); } getCompileOnSaveAffectedFileList(scriptInfo: ScriptInfo): string[] { @@ -548,7 +551,7 @@ namespace ts.server { updateProjectIfDirty(this); this.builderState = BuilderState.create(this.program!, this.projectService.toCanonicalFileName, this.builderState); return mapDefined(BuilderState.getFilesAffectedBy(this.builderState, this.program!, scriptInfo.path, this.cancellationToken, data => this.projectService.host.createHash!(data)), // TODO: GH#18217 - sourceFile => this.shouldEmitFile(this.projectService.getScriptInfoForPath(sourceFile.path)!) ? sourceFile.fileName : undefined); + sourceFile => this.shouldEmitFile(this.projectService.getScriptInfoForPath(sourceFile.path)) ? sourceFile.fileName : undefined); } /** diff --git a/src/server/session.ts b/src/server/session.ts index a5c13574805..ff080998552 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -1030,7 +1030,9 @@ namespace ts.server { private getEmitOutput(args: protocol.FileRequestArgs): EmitOutput { const { file, project } = this.getFileAndProject(args); - return project.getLanguageService().getEmitOutput(file); + return project.shouldEmitFile(project.getScriptInfo(file)) ? + project.getLanguageService().getEmitOutput(file) : + { emitSkipped: true, outputFiles: [] }; } private mapDefinitionInfo(definitions: ReadonlyArray, project: Project): ReadonlyArray { diff --git a/src/testRunner/tsconfig.json b/src/testRunner/tsconfig.json index 9d67215ffd9..ee2aba6275f 100644 --- a/src/testRunner/tsconfig.json +++ b/src/testRunner/tsconfig.json @@ -137,6 +137,7 @@ "unittests/tsserver/occurences.ts", "unittests/tsserver/openFile.ts", "unittests/tsserver/projectErrors.ts", + "unittests/tsserver/projectReferenceCompileOnSave.ts", "unittests/tsserver/projectReferenceErrors.ts", "unittests/tsserver/projectReferences.ts", "unittests/tsserver/projects.ts", diff --git a/src/testRunner/unittests/tsbuildWatchMode.ts b/src/testRunner/unittests/tsbuildWatchMode.ts index 6a577888c7e..dcc2fdbb1ac 100644 --- a/src/testRunner/unittests/tsbuildWatchMode.ts +++ b/src/testRunner/unittests/tsbuildWatchMode.ts @@ -2,18 +2,12 @@ namespace ts.tscWatch { import projectsLocation = TestFSWithWatch.tsbuildProjectsLocation; import getFilePathInProject = TestFSWithWatch.getTsBuildProjectFilePath; import getFileFromProject = TestFSWithWatch.getTsBuildProjectFile; - type TsBuildWatchSystem = WatchedSystem & { writtenFiles: Map; }; + type TsBuildWatchSystem = TestFSWithWatch.TestServerHostTrackingWrittenFiles; function createTsBuildWatchSystem(fileOrFolderList: ReadonlyArray, params?: TestFSWithWatch.TestServerHostCreationParameters) { - const host = createWatchedSystem(fileOrFolderList, params) as TsBuildWatchSystem; - const originalWriteFile = host.writeFile; - host.writtenFiles = createMap(); - host.writeFile = (fileName, content) => { - originalWriteFile.call(host, fileName, content); - const path = host.toFullPath(fileName); - host.writtenFiles.set(path, true); - }; - return host; + return TestFSWithWatch.changeToHostTrackingWrittenFiles( + createWatchedSystem(fileOrFolderList, params) + ); } export function createSolutionBuilder(system: WatchedSystem, rootNames: ReadonlyArray, defaultOptions?: BuildOptions) { diff --git a/src/testRunner/unittests/tsserver/helpers.ts b/src/testRunner/unittests/tsserver/helpers.ts index 1c6bd4e9f59..12611f79266 100644 --- a/src/testRunner/unittests/tsserver/helpers.ts +++ b/src/testRunner/unittests/tsserver/helpers.ts @@ -498,7 +498,7 @@ namespace ts.projectSystem { return protocolToLocation(str)(start); } - function protocolToLocation(text: string): (pos: number) => protocol.Location { + export function protocolToLocation(text: string): (pos: number) => protocol.Location { const lineStarts = computeLineStarts(text); return pos => { const x = computeLineAndCharacterOfPosition(lineStarts, pos); diff --git a/src/testRunner/unittests/tsserver/projectReferenceCompileOnSave.ts b/src/testRunner/unittests/tsserver/projectReferenceCompileOnSave.ts new file mode 100644 index 00000000000..9602ef6360e --- /dev/null +++ b/src/testRunner/unittests/tsserver/projectReferenceCompileOnSave.ts @@ -0,0 +1,410 @@ +namespace ts.projectSystem { + describe("unittests:: tsserver:: with project references and compile on save", () => { + const projectLocation = "/user/username/projects/myproject"; + const dependecyLocation = `${projectLocation}/dependency`; + const usageLocation = `${projectLocation}/usage`; + const dependencyTs: File = { + path: `${dependecyLocation}/fns.ts`, + content: `export function fn1() { } +export function fn2() { } +` + }; + const dependencyConfig: File = { + path: `${dependecyLocation}/tsconfig.json`, + content: JSON.stringify({ + compilerOptions: { composite: true, declarationDir: "../decls" }, + compileOnSave: true + }) + }; + const usageTs: File = { + path: `${usageLocation}/usage.ts`, + content: `import { + fn1, + fn2, +} from '../decls/fns' +fn1(); +fn2(); +` + }; + const usageConfig: File = { + path: `${usageLocation}/tsconfig.json`, + content: JSON.stringify({ + compileOnSave: true, + references: [{ path: "../dependency" }] + }) + }; + + interface VerifySingleScenarioWorker extends VerifySingleScenario { + withProject: boolean; + } + function verifySingleScenarioWorker({ + withProject, scenario, openFiles, requestArgs, change, expectedResult + }: VerifySingleScenarioWorker) { + it(scenario, () => { + const host = TestFSWithWatch.changeToHostTrackingWrittenFiles( + createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]) + ); + const session = createSession(host); + openFilesForSession(openFiles(), session); + const reqArgs = requestArgs(); + const { + expectedAffected, + expectedEmit: { expectedEmitSuccess, expectedFiles }, + expectedEmitOutput + } = expectedResult(withProject); + + if (change) { + session.executeCommandSeq({ + command: protocol.CommandTypes.CompileOnSaveAffectedFileList, + arguments: { file: dependencyTs.path } + }); + const { file, insertString } = change(); + if (session.getProjectService().openFiles.has(file.path)) { + const toLocation = protocolToLocation(file.content); + const location = toLocation(file.content.length); + session.executeCommandSeq({ + command: protocol.CommandTypes.Change, + arguments: { + file: file.path, + ...location, + endLine: location.line, + endOffset: location.offset, + insertString + } + }); + } + else { + host.writeFile(file.path, `${file.content}${insertString}`); + } + host.writtenFiles.clear(); + } + + const args = withProject ? reqArgs : { file: reqArgs.file }; + // Verify CompileOnSaveAffectedFileList + const actualAffectedFiles = session.executeCommandSeq({ + command: protocol.CommandTypes.CompileOnSaveAffectedFileList, + arguments: args + }).response as protocol.CompileOnSaveAffectedFileListSingleProject[]; + assert.deepEqual(actualAffectedFiles, expectedAffected, "Affected files"); + + // Verify CompileOnSaveEmit + const actualEmit = session.executeCommandSeq({ + command: protocol.CommandTypes.CompileOnSaveEmitFile, + arguments: args + }).response; + assert.deepEqual(actualEmit, expectedEmitSuccess, "Emit files"); + assert.equal(host.writtenFiles.size, expectedFiles.length); + for (const file of expectedFiles) { + assert.equal(host.readFile(file.path), file.content, `Expected to write ${file.path}`); + assert.isTrue(host.writtenFiles.has(file.path), `${file.path} is newly written`); + } + + // Verify EmitOutput + const { exportedModulesFromDeclarationEmit: _1, ...actualEmitOutput } = session.executeCommandSeq({ + command: protocol.CommandTypes.EmitOutput, + arguments: args + }).response as EmitOutput; + assert.deepEqual(actualEmitOutput, expectedEmitOutput, "Emit output"); + }); + } + + interface VerifySingleScenario { + scenario: string; + openFiles: () => readonly File[]; + requestArgs: () => protocol.FileRequestArgs; + skipWithoutProject?: boolean; + change?: () => SingleScenarioChange; + expectedResult: GetSingleScenarioResult; + } + function verifySingleScenario(scenario: VerifySingleScenario) { + if (!scenario.skipWithoutProject) { + describe("without specifying project file", () => { + verifySingleScenarioWorker({ + withProject: false, + ...scenario + }); + }); + } + describe("with specifying project file", () => { + verifySingleScenarioWorker({ + withProject: true, + ...scenario + }); + }); + } + + interface SingleScenarioExpectedEmit { + expectedEmitSuccess: boolean; + expectedFiles: readonly File[]; + } + interface SingleScenarioResult { + expectedAffected: protocol.CompileOnSaveAffectedFileListSingleProject[]; + expectedEmit: SingleScenarioExpectedEmit; + expectedEmitOutput: EmitOutput; + } + type GetSingleScenarioResult = (withProject: boolean) => SingleScenarioResult; + interface SingleScenarioChange { + file: File; + insertString: string; + } + interface ScenarioDetails { + scenarioName: string; + requestArgs: () => protocol.FileRequestArgs; + skipWithoutProject?: boolean; + initial: GetSingleScenarioResult; + localChangeToDependency: GetSingleScenarioResult; + localChangeToUsage: GetSingleScenarioResult; + changeToDependency: GetSingleScenarioResult; + changeToUsage: GetSingleScenarioResult; + } + interface VerifyScenario { + openFiles: () => readonly File[]; + scenarios: readonly ScenarioDetails[]; + } + + const localChange = "function fn3() { }"; + const change = `export ${localChange}`; + const changeJs = `function fn3() { } +exports.fn3 = fn3;`; + const changeDts = "export declare function fn3(): void;"; + function verifyScenario({ openFiles, scenarios }: VerifyScenario) { + for (const { + scenarioName, requestArgs, skipWithoutProject, initial, + localChangeToDependency, localChangeToUsage, + changeToDependency, changeToUsage + } of scenarios) { + describe(scenarioName, () => { + verifySingleScenario({ + scenario: "with initial file open", + openFiles, + requestArgs, + skipWithoutProject, + expectedResult: initial + }); + + verifySingleScenario({ + scenario: "with local change to dependency", + openFiles, + requestArgs, + skipWithoutProject, + change: () => ({ file: dependencyTs, insertString: localChange }), + expectedResult: localChangeToDependency + }); + + verifySingleScenario({ + scenario: "with local change to usage", + openFiles, + requestArgs, + skipWithoutProject, + change: () => ({ file: usageTs, insertString: localChange }), + expectedResult: localChangeToUsage + }); + + verifySingleScenario({ + scenario: "with change to dependency", + openFiles, + requestArgs, + skipWithoutProject, + change: () => ({ file: dependencyTs, insertString: change }), + expectedResult: changeToDependency + }); + + verifySingleScenario({ + scenario: "with change to usage", + openFiles, + requestArgs, + skipWithoutProject, + change: () => ({ file: usageTs, insertString: change }), + expectedResult: changeToUsage + }); + }); + } + } + + function expectedAffectedFiles(config: File, fileNames: File[]): protocol.CompileOnSaveAffectedFileListSingleProject { + return { + projectFileName: config.path, + fileNames: fileNames.map(f => f.path), + projectUsesOutFile: false + }; + } + + function expectedUsageEmit(appendJsText?: string): SingleScenarioExpectedEmit { + const appendJs = appendJsText ? `${appendJsText} +` : ""; + return { + expectedEmitSuccess: true, + expectedFiles: [{ + path: `${usageLocation}/usage.js`, + content: `"use strict"; +exports.__esModule = true; +var fns_1 = require("../decls/fns"); +fns_1.fn1(); +fns_1.fn2(); +${appendJs}` + }] + }; + } + + function expectedEmitOutput({ expectedFiles }: SingleScenarioExpectedEmit): EmitOutput { + return { + outputFiles: expectedFiles.map(({ path, content }) => ({ + name: path, + text: content, + writeByteOrderMark: false + })), + emitSkipped: false + }; + } + + function expectedUsageEmitOutput(appendJsText?: string): EmitOutput { + return expectedEmitOutput(expectedUsageEmit(appendJsText)); + } + + function noEmit(): SingleScenarioExpectedEmit { + return { + expectedEmitSuccess: false, + expectedFiles: emptyArray + }; + } + + function noEmitOutput(): EmitOutput { + return { + emitSkipped: true, + outputFiles: [] + }; + } + + function expectedDependencyEmit(appendJsText?: string, appendDtsText?: string): SingleScenarioExpectedEmit { + const appendJs = appendJsText ? `${appendJsText} +` : ""; + const appendDts = appendDtsText ? `${appendDtsText} +` : ""; + return { + expectedEmitSuccess: true, + expectedFiles: [ + { + path: `${dependecyLocation}/fns.js`, + content: `"use strict"; +exports.__esModule = true; +function fn1() { } +exports.fn1 = fn1; +function fn2() { } +exports.fn2 = fn2; +${appendJs}` + }, + { + path: `${projectLocation}/decls/fns.d.ts`, + content: `export declare function fn1(): void; +export declare function fn2(): void; +${appendDts}` + } + ] + }; + } + + function expectedDependencyEmitOutput(appendJsText?: string, appendDtsText?: string): EmitOutput { + return expectedEmitOutput(expectedDependencyEmit(appendJsText, appendDtsText)); + } + + function scenarioDetailsOfUsage(isDependencyOpen?: boolean): ScenarioDetails[] { + return [ + { + scenarioName: "Of usageTs", + requestArgs: () => ({ file: usageTs.path, projectFileName: usageConfig.path }), + initial: () => initialUsageTs(), + // no change to usage so same as initial only usage file + localChangeToDependency: () => initialUsageTs(), + localChangeToUsage: () => initialUsageTs(localChange), + changeToDependency: () => initialUsageTs(), + changeToUsage: () => initialUsageTs(changeJs) + }, + { + scenarioName: "Of dependencyTs in usage project", + requestArgs: () => ({ file: dependencyTs.path, projectFileName: usageConfig.path }), + skipWithoutProject: !!isDependencyOpen, + initial: () => initialDependencyTs(), + localChangeToDependency: () => initialDependencyTs(/*noUsageFiles*/ true), + localChangeToUsage: () => initialDependencyTs(/*noUsageFiles*/ true), + changeToDependency: () => initialDependencyTs(), + changeToUsage: () => initialDependencyTs(/*noUsageFiles*/ true) + } + ]; + + function initialUsageTs(jsText?: string) { + return { + expectedAffected: [ + expectedAffectedFiles(usageConfig, [usageTs]) + ], + expectedEmit: expectedUsageEmit(jsText), + expectedEmitOutput: expectedUsageEmitOutput(jsText) + }; + } + + function initialDependencyTs(noUsageFiles?: true) { + return { + expectedAffected: [ + expectedAffectedFiles(usageConfig, noUsageFiles ? [] : [usageTs]) + ], + expectedEmit: noEmit(), + expectedEmitOutput: noEmitOutput() + }; + } + } + + function scenarioDetailsOfDependencyWhenOpen(): ScenarioDetails { + return { + scenarioName: "Of dependencyTs", + requestArgs: () => ({ file: dependencyTs.path, projectFileName: dependencyConfig.path }), + initial, + localChangeToDependency: withProject => ({ + expectedAffected: withProject ? + [ + expectedAffectedFiles(dependencyConfig, [dependencyTs]) + ] : + [ + expectedAffectedFiles(usageConfig, []), + expectedAffectedFiles(dependencyConfig, [dependencyTs]) + ], + expectedEmit: expectedDependencyEmit(localChange), + expectedEmitOutput: expectedDependencyEmitOutput(localChange) + }), + localChangeToUsage: withProject => initial(withProject, /*noUsageFiles*/ true), + changeToDependency: withProject => initial(withProject, /*noUsageFiles*/ undefined, changeJs, changeDts), + changeToUsage: withProject => initial(withProject, /*noUsageFiles*/ true) + }; + + function initial(withProject: boolean, noUsageFiles?: true, appendJs?: string, appendDts?: string): SingleScenarioResult { + return { + expectedAffected: withProject ? + [ + expectedAffectedFiles(dependencyConfig, [dependencyTs]) + ] : + [ + expectedAffectedFiles(usageConfig, noUsageFiles ? [] : [usageTs]), + expectedAffectedFiles(dependencyConfig, [dependencyTs]) + ], + expectedEmit: expectedDependencyEmit(appendJs, appendDts), + expectedEmitOutput: expectedDependencyEmitOutput(appendJs, appendDts) + }; + } + } + + describe("when dependency project is not open", () => { + verifyScenario({ + openFiles: () => [usageTs], + scenarios: scenarioDetailsOfUsage() + }); + }); + + describe("when the depedency file is open", () => { + verifyScenario({ + openFiles: () => [usageTs, dependencyTs], + scenarios: [ + ...scenarioDetailsOfUsage(/*isDependencyOpen*/ true), + scenarioDetailsOfDependencyWhenOpen(), + ] + }); + }); + }); +} diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index ea7003e471f..0b728ac95d8 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -8463,7 +8463,6 @@ declare namespace ts.server { getGlobalProjectErrors(): ReadonlyArray; getAllProjectErrors(): ReadonlyArray; getLanguageService(ensureSynchronized?: boolean): LanguageService; - private shouldEmitFile; getCompileOnSaveAffectedFileList(scriptInfo: ScriptInfo): string[]; /** * Returns true if emit was conducted From b63185097889376b4c02094b863af9cf752f34cc Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Wed, 10 Jul 2019 15:21:24 -0700 Subject: [PATCH 020/140] Add option disableSourceOfProjectReferenceRedirect to disable using sources of project reference redirect from editor --- src/compiler/commandLineParser.ts | 6 ++ src/compiler/diagnosticMessages.json | 4 + src/compiler/program.ts | 12 +-- src/compiler/types.ts | 3 +- src/server/editorServices.ts | 2 +- src/server/project.ts | 7 +- src/services/services.ts | 4 +- src/services/types.ts | 2 +- .../tsserver/events/projectLoading.ts | 84 ++++++++++++------- .../unittests/tsserver/projectReferences.ts | 30 +++++-- .../reference/api/tsserverlibrary.d.ts | 1 + tests/baselines/reference/api/typescript.d.ts | 1 + .../tsconfig.json | 5 ++ 13 files changed, 110 insertions(+), 51 deletions(-) create mode 100644 tests/baselines/reference/showConfig/Shows tsconfig for single option/disableSourceOfProjectReferenceRedirect/tsconfig.json diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 4747b89f08c..7f67b9c5097 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -751,6 +751,12 @@ namespace ts { category: Diagnostics.Advanced_Options, description: Diagnostics.Disable_size_limitations_on_JavaScript_projects }, + { + name: "disableSourceOfProjectReferenceRedirect", + type: "boolean", + category: Diagnostics.Advanced_Options, + description: Diagnostics.Disable_using_source_of_project_reference_redirect_files + }, { name: "noImplicitUseStrict", type: "boolean", diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 7d178f1d478..edc3903b38e 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3967,6 +3967,10 @@ "category": "Message", "code": 6220 }, + "Disable using source of project reference redirect files.": { + "category": "Message", + "code": 6221 + }, "Projects to reference": { "category": "Message", diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 2149e175ca2..63f58066174 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -814,7 +814,7 @@ namespace ts { let projectReferenceRedirects: Map | undefined; let mapFromFileToProjectReferenceRedirects: Map | undefined; let mapFromToProjectReferenceRedirectSource: Map | undefined; - const useSourceOfReference = !!host.useSourceInsteadOfReferenceRedirect && host.useSourceInsteadOfReferenceRedirect(); + const useSourceOfProjectReferenceRedirect = !!host.useSourceOfProjectReferenceRedirect && host.useSourceOfProjectReferenceRedirect(); const shouldCreateNewSourceFile = shouldProgramCreateNewSourceFiles(oldProgram, options); const structuralIsReused = tryReuseStructureFromOldProgram(); @@ -836,7 +836,7 @@ namespace ts { for (const parsedRef of resolvedProjectReferences) { if (!parsedRef) continue; const out = parsedRef.commandLine.options.outFile || parsedRef.commandLine.options.out; - if (useSourceOfReference) { + if (useSourceOfProjectReferenceRedirect) { if (out || getEmitModuleKind(parsedRef.commandLine.options) === ModuleKind.None) { for (const fileName of parsedRef.commandLine.fileNames) { processSourceFile(fileName, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined); @@ -1418,7 +1418,7 @@ namespace ts { for (const newSourceFile of newSourceFiles) { const filePath = newSourceFile.path; addFileToFilesByName(newSourceFile, filePath, newSourceFile.resolvedPath); - if (useSourceOfReference) { + if (useSourceOfProjectReferenceRedirect) { const redirectProject = getProjectReferenceRedirectProject(newSourceFile.fileName); if (redirectProject && !(redirectProject.commandLine.options.outFile || redirectProject.commandLine.options.out)) { const redirect = getProjectReferenceOutputName(redirectProject, newSourceFile.fileName); @@ -2252,7 +2252,7 @@ namespace ts { // Get source file from normalized fileName function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, refFile: SourceFile, refPos: number, refEnd: number, packageId: PackageId | undefined): SourceFile | undefined { - if (useSourceOfReference) { + if (useSourceOfProjectReferenceRedirect) { const source = getSourceOfProjectReferenceRedirect(fileName); if (source) { const file = isString(source) ? @@ -2309,7 +2309,7 @@ namespace ts { } let redirectedPath: Path | undefined; - if (refFile && !useSourceOfReference) { + if (refFile && !useSourceOfProjectReferenceRedirect) { const redirectProject = getProjectReferenceRedirectProject(fileName); if (redirectProject) { if (redirectProject.commandLine.options.outFile || redirectProject.commandLine.options.out) { @@ -2498,7 +2498,7 @@ namespace ts { } function isSourceOfProjectReferenceRedirect(fileName: string) { - return useSourceOfReference && !!getResolvedProjectReferenceToRedirect(fileName); + return useSourceOfProjectReferenceRedirect && !!getResolvedProjectReferenceToRedirect(fileName); } function forEachProjectReference( diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 16ea47beecc..69ac55e6e1b 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4645,6 +4645,7 @@ namespace ts { /* @internal */ diagnostics?: boolean; /* @internal */ extendedDiagnostics?: boolean; disableSizeLimit?: boolean; + disableSourceOfProjectReferenceRedirect?: boolean; downlevelIteration?: boolean; emitBOM?: boolean; emitDecoratorMetadata?: boolean; @@ -5169,7 +5170,7 @@ namespace ts { createHash?(data: string): string; getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined; /* @internal */ setResolvedProjectReferenceCallbacks?(callbacks: ResolvedProjectReferenceCallbacks): void; - /* @internal */ useSourceInsteadOfReferenceRedirect?(): boolean; + /* @internal */ useSourceOfProjectReferenceRedirect?(): boolean; // TODO: later handle this in better way in builder host instead once the api for tsbuild finalizes and doesn't use compilerHost as base /*@internal*/createDirectory?(directory: string): void; diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 6fea0bc4171..ab325d5ed33 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -2583,7 +2583,7 @@ namespace ts.server { if (!configFileName) return undefined; const configuredProject = this.findConfiguredProjectByProjectName(configFileName) || - this.createAndLoadConfiguredProject(configFileName, `Creating project for original file: ${originalFileInfo.fileName}${location !== originalLocation ? " for location " + location.fileName : ""}`); + this.createAndLoadConfiguredProject(configFileName, `Creating project for original file: ${originalFileInfo.fileName}${location !== originalLocation ? " for location: " + location.fileName : ""}`); if (configuredProject === project) return originalLocation; updateProjectIfDirty(configuredProject); // Keep this configured project as referenced from project diff --git a/src/server/project.ts b/src/server/project.ts index 2811b04c413..87ced54de8e 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -1540,11 +1540,12 @@ namespace ts.server { } /* @internal */ - useSourceInsteadOfReferenceRedirect = () => !!this.languageServiceEnabled; + useSourceOfProjectReferenceRedirect = () => !!this.languageServiceEnabled && + !this.getCompilerOptions().disableSourceOfProjectReferenceRedirect; fileExists(file: string): boolean { // Project references go to source file instead of .d.ts file - if (this.useSourceInsteadOfReferenceRedirect() && this.projectReferenceCallbacks) { + if (this.useSourceOfProjectReferenceRedirect() && this.projectReferenceCallbacks) { const source = this.projectReferenceCallbacks.getSourceOfProjectReferenceRedirect(file); if (source) return isString(source) ? super.fileExists(source) : true; } @@ -1553,7 +1554,7 @@ namespace ts.server { directoryExists(path: string): boolean { if (super.directoryExists(path)) return true; - if (!this.useSourceInsteadOfReferenceRedirect() || !this.projectReferenceCallbacks) return false; + if (!this.useSourceOfProjectReferenceRedirect() || !this.projectReferenceCallbacks) return false; if (!this.mapOfDeclarationDirectories) { this.mapOfDeclarationDirectories = createMap(); diff --git a/src/services/services.ts b/src/services/services.ts index 2f9ba6eec94..c4af3c94702 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1248,8 +1248,8 @@ namespace ts { if (host.setResolvedProjectReferenceCallbacks) { compilerHost.setResolvedProjectReferenceCallbacks = callbacks => host.setResolvedProjectReferenceCallbacks!(callbacks); } - if (host.useSourceInsteadOfReferenceRedirect) { - compilerHost.useSourceInsteadOfReferenceRedirect = () => host.useSourceInsteadOfReferenceRedirect!(); + if (host.useSourceOfProjectReferenceRedirect) { + compilerHost.useSourceOfProjectReferenceRedirect = () => host.useSourceOfProjectReferenceRedirect!(); } const documentRegistryBucketKey = documentRegistry.getKeyForCompilationSettings(newSettings); diff --git a/src/services/types.ts b/src/services/types.ts index b4fc25e587f..ec71813e1dc 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -239,7 +239,7 @@ namespace ts { /* @internal */ setResolvedProjectReferenceCallbacks?(callbacks: ResolvedProjectReferenceCallbacks): void; /* @internal */ - useSourceInsteadOfReferenceRedirect?(): boolean; + useSourceOfProjectReferenceRedirect?(): boolean; } /* @internal */ diff --git a/src/testRunner/unittests/tsserver/events/projectLoading.ts b/src/testRunner/unittests/tsserver/events/projectLoading.ts index 53fe28240f8..3cc25232bc2 100644 --- a/src/testRunner/unittests/tsserver/events/projectLoading.ts +++ b/src/testRunner/unittests/tsserver/events/projectLoading.ts @@ -73,44 +73,64 @@ namespace ts.projectSystem { verifyEvent(project, `Change in config file detected`); }); - it("when opening original location project", () => { - const aDTs: File = { - path: `${projectRoot}/a/a.d.ts`, - content: `export declare class A { + describe("when opening original location project", () => { + it("with project references", () => { + verify(); + }); + + it("when disableSourceOfProjectReferenceRedirect is true", () => { + verify(/*disableSourceOfProjectReferenceRedirect*/ true); + }); + + function verify(disableSourceOfProjectReferenceRedirect?: true) { + const aDTs: File = { + path: `${projectRoot}/a/a.d.ts`, + content: `export declare class A { } //# sourceMappingURL=a.d.ts.map ` - }; - const aDTsMap: File = { - path: `${projectRoot}/a/a.d.ts.map`, - content: `{"version":3,"file":"a.d.ts","sourceRoot":"","sources":["./a.ts"],"names":[],"mappings":"AAAA,qBAAa,CAAC;CAAI"}` - }; - const bTs: File = { - path: bTsPath, - content: `import {A} from "../a/a"; new A();` - }; - const configB: File = { - path: configBPath, - content: JSON.stringify({ - references: [{ path: "../a" }] - }) - }; + }; + const aDTsMap: File = { + path: `${projectRoot}/a/a.d.ts.map`, + content: `{"version":3,"file":"a.d.ts","sourceRoot":"","sources":["./a.ts"],"names":[],"mappings":"AAAA,qBAAa,CAAC;CAAI"}` + }; + const bTs: File = { + path: bTsPath, + content: `import {A} from "../a/a"; new A();` + }; + const configB: File = { + path: configBPath, + content: JSON.stringify({ + ...(disableSourceOfProjectReferenceRedirect && { + compilerOptions: { + disableSourceOfProjectReferenceRedirect + } + }), + references: [{ path: "../a" }] + }) + }; - const { service, session, verifyEventWithOpenTs, verifyEvent } = createSessionToVerifyEvent(files.concat(aDTs, aDTsMap, bTs, configB)); - verifyEventWithOpenTs(bTs, configB.path, 1); + const { service, session, verifyEventWithOpenTs, verifyEvent } = createSessionToVerifyEvent(files.concat(aDTs, aDTsMap, bTs, configB)); + verifyEventWithOpenTs(bTs, configB.path, 1); - session.executeCommandSeq({ - command: protocol.CommandTypes.References, - arguments: { - file: bTs.path, - ...protocolLocationFromSubstring(bTs.content, "A()") - } - }); + session.executeCommandSeq({ + command: protocol.CommandTypes.References, + arguments: { + file: bTs.path, + ...protocolLocationFromSubstring(bTs.content, "A()") + } + }); - checkNumberOfProjects(service, { configuredProjects: 2 }); - const project = service.configuredProjects.get(configA.path)!; - assert.isDefined(project); - verifyEvent(project, `Creating project for original file: ${aTs.path}`); + checkNumberOfProjects(service, { configuredProjects: 2 }); + const project = service.configuredProjects.get(configA.path)!; + assert.isDefined(project); + verifyEvent( + project, + disableSourceOfProjectReferenceRedirect ? + `Creating project for original file: ${aTs.path} for location: ${aDTs.path}` : + `Creating project for original file: ${aTs.path}` + ); + } }); describe("with external projects and config files ", () => { diff --git a/src/testRunner/unittests/tsserver/projectReferences.ts b/src/testRunner/unittests/tsserver/projectReferences.ts index f9445dc6d19..fe1ff10aac1 100644 --- a/src/testRunner/unittests/tsserver/projectReferences.ts +++ b/src/testRunner/unittests/tsserver/projectReferences.ts @@ -417,6 +417,7 @@ fn5(); interface VerifierAndWithRefs { withRefs: boolean; + disableSourceOfProjectReferenceRedirect?: true; verifier: (withRefs: boolean) => readonly DocumentPositionMapperVerifier[]; } @@ -426,7 +427,7 @@ fn5(); interface OpenTsFile extends VerifierAndWithRefs { onHostCreate?: (host: TestServerHost) => void; } - function openTsFile({ withRefs, verifier, onHostCreate }: OpenTsFile) { + function openTsFile({ withRefs, disableSourceOfProjectReferenceRedirect, verifier, onHostCreate }: OpenTsFile) { const host = createHost(files, [mainConfig.path]); if (!withRefs) { // Erase project reference @@ -434,11 +435,22 @@ fn5(); compilerOptions: { composite: true, declarationMap: true } })); } + else if (disableSourceOfProjectReferenceRedirect) { + // Erase project reference + host.writeFile(mainConfig.path, JSON.stringify({ + compilerOptions: { + composite: true, + declarationMap: true, + disableSourceOfProjectReferenceRedirect: !!disableSourceOfProjectReferenceRedirect + }, + references: [{ path: "../dependency" }] + })); + } if (onHostCreate) { onHostCreate(host); } const session = createSession(host); - const verifiers = verifier(withRefs); + const verifiers = verifier(withRefs && !disableSourceOfProjectReferenceRedirect); openFilesForSession([...openFiles(verifiers), randomFile], session); return { host, session, verifiers }; } @@ -786,9 +798,9 @@ fn5(); }); } - function verifyScenarioWorker({ mainScenario, verifier }: VerifyScenario, withRefs: boolean) { + function verifyScenarioWorker({ mainScenario, verifier }: VerifyScenario, withRefs: boolean, disableSourceOfProjectReferenceRedirect?: true) { it(mainScenario, () => { - const { host, session, verifiers } = openTsFile({ withRefs, verifier }); + const { host, session, verifiers } = openTsFile({ withRefs, disableSourceOfProjectReferenceRedirect, verifier }); checkProject(session, verifiers); verifyScenarioAndScriptInfoCollection(session, host, verifiers, "main"); }); @@ -798,6 +810,7 @@ fn5(); scenarioName: "when usage file changes, document position mapper doesnt change", verifier, withRefs, + disableSourceOfProjectReferenceRedirect, change: (_host, session, verifiers) => verifiers.forEach( verifier => session.executeCommandSeq({ command: protocol.CommandTypes.Change, @@ -819,6 +832,7 @@ fn5(); scenarioName: "when dependency .d.ts changes, document position mapper doesnt change", verifier, withRefs, + disableSourceOfProjectReferenceRedirect, change: host => host.writeFile( dtsLocation, host.readFile(dtsLocation)!.replace( @@ -835,6 +849,7 @@ fn5(); scenarioName: "when dependency file's map changes", verifier, withRefs, + disableSourceOfProjectReferenceRedirect, change: host => host.writeFile( dtsMapLocation, `{"version":3,"file":"FnS.d.ts","sourceRoot":"","sources":["../dependency/FnS.ts"],"names":[],"mappings":"AAAA,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,eAAO,MAAM,CAAC,KAAK,CAAC"}` @@ -846,6 +861,7 @@ fn5(); scenarioName: "with depedency files map file", verifier, withRefs, + disableSourceOfProjectReferenceRedirect, fileLocation: dtsMapLocation, fileNotPresentKey: "noMap", fileCreatedKey: "mapFileCreated", @@ -856,6 +872,7 @@ fn5(); scenarioName: "with depedency .d.ts file", verifier, withRefs, + disableSourceOfProjectReferenceRedirect, fileLocation: dtsLocation, fileNotPresentKey: "noDts", fileCreatedKey: "dtsFileCreated", @@ -863,7 +880,7 @@ fn5(); noDts: true }); - if (withRefs) { + if (withRefs && !disableSourceOfProjectReferenceRedirect) { verifyScenarioWithChanges({ scenarioName: "when defining project source changes", verifier, @@ -907,6 +924,9 @@ ${dependencyTs.content}`); describe("when main tsconfig has project reference", () => { verifyScenarioWorker(scenario, /*withRefs*/ true); }); + describe("when main tsconfig has but has disableSourceOfProjectReferenceRedirect", () => { + verifyScenarioWorker(scenario, /*withRefs*/ true); + }); } describe("from project that uses dependency", () => { diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 0b728ac95d8..09931908eda 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2513,6 +2513,7 @@ declare namespace ts { emitDeclarationOnly?: boolean; declarationDir?: string; disableSizeLimit?: boolean; + disableSourceOfProjectReferenceRedirect?: boolean; downlevelIteration?: boolean; emitBOM?: boolean; emitDecoratorMetadata?: boolean; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index be8eea8062b..34f6fd36dad 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2513,6 +2513,7 @@ declare namespace ts { emitDeclarationOnly?: boolean; declarationDir?: string; disableSizeLimit?: boolean; + disableSourceOfProjectReferenceRedirect?: boolean; downlevelIteration?: boolean; emitBOM?: boolean; emitDecoratorMetadata?: boolean; diff --git a/tests/baselines/reference/showConfig/Shows tsconfig for single option/disableSourceOfProjectReferenceRedirect/tsconfig.json b/tests/baselines/reference/showConfig/Shows tsconfig for single option/disableSourceOfProjectReferenceRedirect/tsconfig.json new file mode 100644 index 00000000000..c8b95e0909d --- /dev/null +++ b/tests/baselines/reference/showConfig/Shows tsconfig for single option/disableSourceOfProjectReferenceRedirect/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "disableSourceOfProjectReferenceRedirect": true + } +} From e89acb6358845b310753e132f5ae692c72d5bb6a Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 31 Jul 2019 16:30:54 -0700 Subject: [PATCH 021/140] Reflect effects of assertion calls in control flow analysis --- src/compiler/binder.ts | 22 +++++++++++++ src/compiler/checker.ts | 71 +++++++++++++++++++++++++++++++++++++++++ src/compiler/types.ts | 19 +++++++---- 3 files changed, 106 insertions(+), 6 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index d18ab45a347..16dffe46aad 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -706,6 +706,9 @@ namespace ts { case SyntaxKind.CaseClause: bindCaseClause(node); break; + case SyntaxKind.ExpressionStatement: + bindExpressionStatement(node); + break; case SyntaxKind.LabeledStatement: bindLabeledStatement(node); break; @@ -896,6 +899,11 @@ namespace ts { return flowNodeCreated({ flags: FlowFlags.Assignment, antecedent, node }); } + function createFlowCall(antecedent: FlowNode, node: CallExpression): FlowNode { + setFlowNodeReferenced(antecedent); + return flowNodeCreated({ flags: FlowFlags.Call, antecedent, node }); + } + function createFlowArrayMutation(antecedent: FlowNode, node: CallExpression | BinaryExpression): FlowNode { setFlowNodeReferenced(antecedent); const res: FlowArrayMutation = flowNodeCreated({ flags: FlowFlags.ArrayMutation, antecedent, node }); @@ -1276,6 +1284,20 @@ namespace ts { activeLabels!.pop(); } + function isDottedName(node: Expression) { + return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.PropertyAccessExpression && isQualifiedName((node).expression); + } + + function bindExpressionStatement(node: ExpressionStatement): void { + bind(node.expression); + if (node.expression.kind === SyntaxKind.CallExpression) { + const call = node.expression; + if (isDottedName(call.expression) && call.arguments.length >= 1) { + currentFlow = createFlowCall(currentFlow, call); + } + } + } + function bindLabeledStatement(node: LabeledStatement): void { const preStatementLabel = createLoopLabel(); const postStatementLabel = createBranchLabel(); diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3fa9c2da66e..2ed815e8978 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16864,6 +16864,44 @@ namespace ts { return false; } + function getTypeOfDottedName(node: Expression) { + if (node.kind === SyntaxKind.Identifier) { + const symbol = getResolvedSymbol(node); + const nonAliasSymbol = symbol.flags & SymbolFlags.Alias ? resolveAlias(symbol) : symbol; + return nonAliasSymbol.flags & (SymbolFlags.Function | SymbolFlags.Class | SymbolFlags.ValueModule) ? getTypeOfSymbol(nonAliasSymbol) : undefined; + } + if (node.kind === SyntaxKind.PropertyAccessExpression) { + const type = getTypeOfDottedName((node).expression); + if (type) { + const prop = getPropertyOfType(type, (node).name.escapedText); + return prop && prop.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.ValueModule) ? getTypeOfSymbol(prop) : undefined; + } + } + } + + function getIsAssertCall(node: CallExpression) { + const type = getTypeOfDottedName(node.expression); + if (type) { + const signature = getSingleCallSignature(type); + if (signature && signature.declaration) { + const typeNode = getEffectiveReturnTypeNode(signature.declaration); + if (typeNode && typeNode.kind === SyntaxKind.UnionType) { + const types = (typeNode).types; + return types.length === 2 && types[0].kind === SyntaxKind.VoidKeyword && types[1].kind === SyntaxKind.NeverKeyword; + } + } + } + return false; + } + + function isAssertCall(node: CallExpression) { + const links = getNodeLinks(node); + if (links.isAssertCall === undefined) { + links.isAssertCall = getIsAssertCall(node); + } + return links.isAssertCall; + } + function reportFlowControlError(node: Node) { const block = findAncestor(node, isFunctionOrModuleBlock); const sourceFile = getSourceFileOfNode(node); @@ -16962,6 +17000,13 @@ namespace ts { } } } + else if (flags & FlowFlags.Call) { + type = getTypeAtFlowCall(flow); + if (!type) { + flow = (flow).antecedent; + continue; + } + } else if (flags & FlowFlags.Condition) { type = getTypeAtFlowCondition(flow); } @@ -17057,6 +17102,32 @@ namespace ts { return undefined; } + function narrowTypeByAssertion(type: Type, expr: Expression): Type { + const node = skipParentheses(expr); + if (node.kind === SyntaxKind.BinaryExpression) { + if ((node).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) { + return narrowTypeByAssertion(narrowTypeByAssertion(type, (node).left), (node).right); + } + if ((node).operatorToken.kind === SyntaxKind.BarBarToken) { + return getUnionType([narrowTypeByAssertion(type, (node).left), narrowTypeByAssertion(type, (node).right)]); + } + } + return narrowType(type, node, /*assumeTrue*/ true); + } + + function getTypeAtFlowCall(flow: FlowCall): FlowType | undefined { + if (isAssertCall(flow.node)) { + const flowType = getTypeAtFlowNode(flow.antecedent); + const type = getTypeFromFlowType(flowType); + const narrowedType = narrowTypeByAssertion(type, flow.node.arguments[0]); + if (narrowedType === type) { + return flowType; + } + return createFlowType(narrowedType, isIncomplete(flowType)); + } + return undefined; + } + function getTypeAtFlowArrayMutation(flow: FlowArrayMutation): FlowType | undefined { if (declaredType === autoType || declaredType === autoArrayType) { const node = flow.node; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 099f7705f84..aec65b03367 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2550,12 +2550,13 @@ namespace ts { FalseCondition = 1 << 6, // Condition known to be false SwitchClause = 1 << 7, // Switch statement clause ArrayMutation = 1 << 8, // Potential array mutation - Referenced = 1 << 9, // Referenced as antecedent once - Shared = 1 << 10, // Referenced as antecedent more than once - PreFinally = 1 << 11, // Injected edge that links pre-finally label and pre-try flow - AfterFinally = 1 << 12, // Injected edge that links post-finally flow with the rest of the graph + Call = 1 << 9, // Potential assertion call + Referenced = 1 << 10, // Referenced as antecedent once + Shared = 1 << 11, // Referenced as antecedent more than once + PreFinally = 1 << 12, // Injected edge that links pre-finally label and pre-try flow + AfterFinally = 1 << 13, // Injected edge that links post-finally flow with the rest of the graph /** @internal */ - Cached = 1 << 13, // Indicates that at least one cross-call cache entry exists for this node, even if not a loop participant + Cached = 1 << 14, // Indicates that at least one cross-call cache entry exists for this node, even if not a loop participant Label = BranchLabel | LoopLabel, Condition = TrueCondition | FalseCondition } @@ -2574,7 +2575,7 @@ namespace ts { } export type FlowNode = - | AfterFinallyFlow | PreFinallyFlow | FlowStart | FlowLabel | FlowAssignment | FlowCondition | FlowSwitchClause | FlowArrayMutation; + | AfterFinallyFlow | PreFinallyFlow | FlowStart | FlowLabel | FlowAssignment | FlowCall | FlowCondition | FlowSwitchClause | FlowArrayMutation; export interface FlowNodeBase { flags: FlowFlags; id?: number; // Node id used by flow type cache in checker @@ -2599,6 +2600,11 @@ namespace ts { antecedent: FlowNode; } + export interface FlowCall extends FlowNodeBase { + node: CallExpression; + antecedent: FlowNode; + } + // FlowCondition represents a condition that is known to be true or false at the // node's location in the control flow. export interface FlowCondition extends FlowNodeBase { @@ -3902,6 +3908,7 @@ namespace ts { resolvedSymbol?: Symbol; // Cached name resolution result resolvedIndexInfo?: IndexInfo; // Cached indexing info resolution result maybeTypePredicate?: boolean; // Cached check whether call expression might reference a type predicate + isAssertCall?: boolean; enumMemberValue?: string | number; // Constant value of enum member isVisible?: boolean; // Is this node visible containsArgumentsReference?: boolean; // Whether a function-like declaration contains an 'arguments' reference From 77f2a412e15a3f3ac2a01d648a64e75670d47204 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 2 Aug 2019 17:57:26 -0700 Subject: [PATCH 022/140] Support 'asserts' type predicates in control flow analysis --- src/compiler/binder.ts | 6 +- src/compiler/checker.ts | 230 +++++++++++++++++++--------------------- src/compiler/emitter.ts | 14 ++- src/compiler/factory.ts | 7 +- src/compiler/parser.ts | 13 +++ src/compiler/scanner.ts | 1 + src/compiler/types.ts | 36 ++++--- src/compiler/visitor.ts | 1 + 8 files changed, 166 insertions(+), 142 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 16dffe46aad..2b917bc577c 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1284,12 +1284,14 @@ namespace ts { activeLabels!.pop(); } - function isDottedName(node: Expression) { - return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.PropertyAccessExpression && isQualifiedName((node).expression); + function isDottedName(node: Expression): boolean { + return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.PropertyAccessExpression && isDottedName((node).expression); } function bindExpressionStatement(node: ExpressionStatement): void { bind(node.expression); + // A top level call expression with a dotted function name and at least one argument + // is potentially an assertion and is therefore included in the control flow. if (node.expression.kind === SyntaxKind.CallExpression) { const call = node.expression; if (isDottedName(call.expression) && call.arguments.length >= 1) { diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2ed815e8978..c8ad1f66064 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -522,7 +522,7 @@ namespace ts { markerSubType.constraint = markerSuperType; const markerOtherType = createTypeParameter(); - const noTypePredicate = createIdentifierTypePredicate("<>", 0, anyType); + const noTypePredicate = createTypePredicate(TypePredicateKind.Identifier, "<>", 0, anyType); const anySignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*resolvedTypePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); const unknownSignature = createSignature(undefined, undefined, undefined, emptyArray, errorType, /*resolvedTypePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); @@ -4212,11 +4212,12 @@ namespace ts { let returnTypeNode: TypeNode | undefined; const typePredicate = getTypePredicateOfSignature(signature); if (typePredicate) { - const parameterName = typePredicate.kind === TypePredicateKind.Identifier ? + const assertsModifier = typePredicate.kind === TypePredicateKind.Assertion ? createToken(SyntaxKind.AssertsKeyword) : undefined; + const parameterName = typePredicate.kind !== TypePredicateKind.This ? setEmitFlags(createIdentifier(typePredicate.parameterName), EmitFlags.NoAsciiEscaping) : createThisTypeNode(); - const typeNode = typeToTypeNodeHelper(typePredicate.type, context); - returnTypeNode = createTypePredicateNode(parameterName, typeNode); + const typeNode = typePredicate.type && typeToTypeNodeHelper(typePredicate.type, context); + returnTypeNode = createTypePredicateNode(assertsModifier, parameterName, typeNode); } else { const returnType = getReturnTypeOfSignature(signature); @@ -4685,8 +4686,9 @@ namespace ts { function typePredicateToStringWorker(writer: EmitTextWriter) { const predicate = createTypePredicateNode( - typePredicate.kind === TypePredicateKind.Identifier ? createIdentifier(typePredicate.parameterName) : createThisTypeNode(), - nodeBuilder.typeToTypeNode(typePredicate.type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName)!, // TODO: GH#18217 + typePredicate.kind === TypePredicateKind.Assertion ? createToken(SyntaxKind.AssertsKeyword) : undefined, + typePredicate.kind !== TypePredicateKind.This ? createIdentifier(typePredicate.parameterName) : createThisTypeNode(), + typePredicate.type && nodeBuilder.typeToTypeNode(typePredicate.type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName)! // TODO: GH#18217 ); const printer = createPrinter({ removeComments: true }); const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); @@ -8432,12 +8434,8 @@ namespace ts { return isBracketed || !!typeExpression && typeExpression.type.kind === SyntaxKind.JSDocOptionalType; } - function createIdentifierTypePredicate(parameterName: string, parameterIndex: number, type: Type): IdentifierTypePredicate { - return { kind: TypePredicateKind.Identifier, parameterName, parameterIndex, type }; - } - - function createThisTypePredicate(type: Type): ThisTypePredicate { - return { kind: TypePredicateKind.This, type }; + function createTypePredicate(kind: TypePredicateKind, parameterName: string | undefined, parameterIndex: number | undefined, type: Type | undefined): TypePredicate { + return { kind, parameterName, parameterIndex, type } as TypePredicate; } /** @@ -8672,9 +8670,15 @@ namespace ts { } } - function signatureHasTypePredicate(signature: Signature): boolean { - return getTypePredicateOfSignature(signature) !== undefined; - } + // function hasAssertionTypePredicate(signature: Signature): boolean { + // const predicate = getTypePredicateOfSignature(signature); + // return !!predicate && predicate.kind === TypePredicateKind.Assertion; + // } + + // function hasBooleanTypePredicate(signature: Signature): boolean { + // const predicate = getTypePredicateOfSignature(signature); + // return !!predicate && (predicate.kind === TypePredicateKind.This || predicate.kind === TypePredicateKind.Identifier); + // } function getTypePredicateOfSignature(signature: Signature): TypePredicate | undefined { if (!signature.resolvedTypePredicate) { @@ -8703,18 +8707,13 @@ namespace ts { return signature.resolvedTypePredicate === noTypePredicate ? undefined : signature.resolvedTypePredicate; } - function createTypePredicateFromTypePredicateNode(node: TypePredicateNode, signature: Signature): IdentifierTypePredicate | ThisTypePredicate { - const { parameterName } = node; - const type = getTypeFromTypeNode(node.type); - if (parameterName.kind === SyntaxKind.Identifier) { - return createIdentifierTypePredicate( - parameterName.escapedText as string, - findIndex(signature.parameters, p => p.escapedName === parameterName.escapedText), - type); - } - else { - return createThisTypePredicate(type); - } + function createTypePredicateFromTypePredicateNode(node: TypePredicateNode, signature: Signature): TypePredicate { + const parameterName = node.parameterName; + const type = node.type && getTypeFromTypeNode(node.type); + return parameterName.kind === SyntaxKind.ThisType ? + createTypePredicate(TypePredicateKind.This, /*parameterName*/ undefined, /*parameterIndex*/ undefined, type) : + createTypePredicate(node.assertsModifier ? TypePredicateKind.Assertion : TypePredicateKind.Identifier, parameterName.escapedText as string, + findIndex(signature.parameters, p => p.escapedName === parameterName.escapedText), type); } function getReturnTypeOfSignature(signature: Signature): Type { @@ -9820,7 +9819,7 @@ namespace ts { const types: Type[] = []; for (const sig of signatures) { const pred = getTypePredicateOfSignature(sig); - if (!pred) { + if (!pred || pred.kind === TypePredicateKind.Assertion) { continue; } @@ -9840,15 +9839,11 @@ namespace ts { return undefined; } const unionType = getUnionType(types); - return isIdentifierTypePredicate(first) - ? createIdentifierTypePredicate(first.parameterName, first.parameterIndex, unionType) - : createThisTypePredicate(unionType); + return createTypePredicate(first.kind, first.parameterName, first.parameterIndex, unionType); } function typePredicateKindsMatch(a: TypePredicate, b: TypePredicate): boolean { - return isIdentifierTypePredicate(a) - ? isIdentifierTypePredicate(b) && a.parameterIndex === b.parameterIndex - : !isIdentifierTypePredicate(b); + return a.kind === b.kind && a.parameterIndex === b.parameterIndex; } // This function assumes the constituent type list is sorted and deduplicated. @@ -11114,7 +11109,7 @@ namespace ts { case SyntaxKind.TypeReference: return getTypeFromTypeReference(node); case SyntaxKind.TypePredicate: - return booleanType; + return (node).assertsModifier ? voidType : booleanType; case SyntaxKind.ExpressionWithTypeArguments: return getTypeFromTypeReference(node); case SyntaxKind.TypeQuery: @@ -11272,21 +11267,8 @@ namespace ts { return result; } - function instantiateTypePredicate(predicate: TypePredicate, mapper: TypeMapper): ThisTypePredicate | IdentifierTypePredicate { - if (isIdentifierTypePredicate(predicate)) { - return { - kind: TypePredicateKind.Identifier, - parameterName: predicate.parameterName, - parameterIndex: predicate.parameterIndex, - type: instantiateType(predicate.type, mapper) - }; - } - else { - return { - kind: TypePredicateKind.This, - type: instantiateType(predicate.type, mapper) - }; - } + function instantiateTypePredicate(predicate: TypePredicate, mapper: TypeMapper): TypePredicate { + return createTypePredicate(predicate.kind, predicate.parameterName, predicate.parameterIndex, instantiateType(predicate.type, mapper)); } function instantiateSignature(signature: Signature, mapper: TypeMapper, eraseTypeParameters?: boolean): Signature { @@ -12338,7 +12320,7 @@ namespace ts { // with respect to T. const sourceSig = callbackCheck ? undefined : getSingleCallSignature(getNonNullableType(sourceType)); const targetSig = callbackCheck ? undefined : getSingleCallSignature(getNonNullableType(targetType)); - const callbacks = sourceSig && targetSig && !signatureHasTypePredicate(sourceSig) && !signatureHasTypePredicate(targetSig) && + const callbacks = sourceSig && targetSig && !getTypePredicateOfSignature(sourceSig) && !getTypePredicateOfSignature(targetSig) && (getFalsyFlags(sourceType) & TypeFlags.Nullable) === (getFalsyFlags(targetType) & TypeFlags.Nullable); const related = callbacks ? // TODO: GH#18217 It will work if they're both `undefined`, but not if only one is @@ -12407,7 +12389,7 @@ namespace ts { return Ternary.False; } - if (source.kind === TypePredicateKind.Identifier) { + if (source.kind !== TypePredicateKind.This) { if (source.parameterIndex !== (target as IdentifierTypePredicate).parameterIndex) { if (reportErrors) { errorReporter!(Diagnostics.Parameter_0_is_not_in_the_same_position_as_parameter_1, source.parameterName, (target as IdentifierTypePredicate).parameterName); @@ -12417,7 +12399,9 @@ namespace ts { } } - const related = compareTypes(source.type, target.type, reportErrors); + const related = source.type === target.type ? Ternary.True : + source.type && target.type ? compareTypes(source.type, target.type, reportErrors) : + Ternary.False; if (related === Ternary.False && reportErrors) { errorReporter!(Diagnostics.Type_predicate_0_is_not_assignable_to_1, typePredicateToString(source), typePredicateToString(target)); } @@ -14602,16 +14586,18 @@ namespace ts { if (!ignoreReturnTypes) { const sourceTypePredicate = getTypePredicateOfSignature(source); const targetTypePredicate = getTypePredicateOfSignature(target); - result &= sourceTypePredicate !== undefined || targetTypePredicate !== undefined - ? compareTypePredicatesIdentical(sourceTypePredicate, targetTypePredicate, compareTypes) - // If they're both type predicates their return types will both be `boolean`, so no need to compare those. - : compareTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target)); + result &= sourceTypePredicate || targetTypePredicate ? + compareTypePredicatesIdentical(sourceTypePredicate, targetTypePredicate, compareTypes) : + compareTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target)); } return result; } function compareTypePredicatesIdentical(source: TypePredicate | undefined, target: TypePredicate | undefined, compareTypes: (s: Type, t: Type) => Ternary): Ternary { - return source === undefined || target === undefined || !typePredicateKindsMatch(source, target) ? Ternary.False : compareTypes(source.type, target.type); + return !(source && target && typePredicateKindsMatch(source, target)) ? Ternary.False : + source.type === target.type ? Ternary.True : + source.type && target.type ? compareTypes(source.type, target.type) : + Ternary.False; } function literalTypesWithSameBaseType(types: Type[]): boolean { @@ -15219,8 +15205,7 @@ namespace ts { function applyToReturnTypes(source: Signature, target: Signature, callback: (s: Type, t: Type) => void) { const sourceTypePredicate = getTypePredicateOfSignature(source); const targetTypePredicate = getTypePredicateOfSignature(target); - if (sourceTypePredicate && targetTypePredicate && sourceTypePredicate.kind === targetTypePredicate.kind && - (sourceTypePredicate.kind === TypePredicateKind.This || sourceTypePredicate.parameterIndex === (targetTypePredicate).parameterIndex)) { + if (sourceTypePredicate && targetTypePredicate && typePredicateKindsMatch(sourceTypePredicate, targetTypePredicate) && sourceTypePredicate.type && targetTypePredicate.type) { callback(sourceTypePredicate.type, targetTypePredicate.type); } else { @@ -16845,61 +16830,62 @@ namespace ts { return isLengthPushOrUnshift || isElementAssignment; } - function maybeTypePredicateCall(node: CallExpression) { - const links = getNodeLinks(node); - if (links.maybeTypePredicate === undefined) { - links.maybeTypePredicate = getMaybeTypePredicate(node); - } - return links.maybeTypePredicate; + function isDeclarationWithExplicitTypeAnnotation(declaration: Declaration | undefined) { + return !!(declaration && ( + declaration.kind === SyntaxKind.VariableDeclaration || declaration.kind === SyntaxKind.Parameter || + declaration.kind === SyntaxKind.PropertyDeclaration || declaration.kind === SyntaxKind.PropertySignature) && + (declaration as VariableDeclaration | ParameterDeclaration | PropertyDeclaration | PropertySignature).type); } - function getMaybeTypePredicate(node: CallExpression) { - if (node.expression.kind !== SyntaxKind.SuperKeyword) { - const funcType = checkNonNullExpression(node.expression); - if (funcType !== silentNeverType) { - const apparentType = getApparentType(funcType); - return apparentType !== errorType && some(getSignaturesOfType(apparentType, SignatureKind.Call), signatureHasTypePredicate); - } - } - return false; + function getExplicitTypeOfSymbol(symbol: Symbol) { + return symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.ValueModule) || + symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property) && isDeclarationWithExplicitTypeAnnotation(symbol.valueDeclaration) ? + getTypeOfSymbol(symbol) : undefined; } function getTypeOfDottedName(node: Expression) { + // We require the dotted function name in an assertion expression to be comprised of identifiers + // that reference function, method, class or value module symbols; or variable, property or + // parameter symbols with declarations that have explicit type annotations. Such references are + // resolvable with no possibility of triggering circularities in control flow analysis. if (node.kind === SyntaxKind.Identifier) { const symbol = getResolvedSymbol(node); - const nonAliasSymbol = symbol.flags & SymbolFlags.Alias ? resolveAlias(symbol) : symbol; - return nonAliasSymbol.flags & (SymbolFlags.Function | SymbolFlags.Class | SymbolFlags.ValueModule) ? getTypeOfSymbol(nonAliasSymbol) : undefined; + return getExplicitTypeOfSymbol(symbol.flags & SymbolFlags.Alias ? resolveAlias(symbol) : symbol); } if (node.kind === SyntaxKind.PropertyAccessExpression) { const type = getTypeOfDottedName((node).expression); if (type) { const prop = getPropertyOfType(type, (node).name.escapedText); - return prop && prop.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.ValueModule) ? getTypeOfSymbol(prop) : undefined; + return prop && getExplicitTypeOfSymbol(prop); } } } - function getIsAssertCall(node: CallExpression) { - const type = getTypeOfDottedName(node.expression); - if (type) { - const signature = getSingleCallSignature(type); - if (signature && signature.declaration) { - const typeNode = getEffectiveReturnTypeNode(signature.declaration); - if (typeNode && typeNode.kind === SyntaxKind.UnionType) { - const types = (typeNode).types; - return types.length === 2 && types[0].kind === SyntaxKind.VoidKeyword && types[1].kind === SyntaxKind.NeverKeyword; - } - } - } - return false; - } - - function isAssertCall(node: CallExpression) { + function getTypePredicateForCall(node: CallExpression) { const links = getNodeLinks(node); - if (links.isAssertCall === undefined) { - links.isAssertCall = getIsAssertCall(node); + if (links.resolvedTypePredicate === undefined) { + links.resolvedTypePredicate = computeTypePredicateForCall(node) || noTypePredicate; } - return links.isAssertCall; + return links.resolvedTypePredicate === noTypePredicate ? undefined : links.resolvedTypePredicate; + } + + function computeTypePredicateForCall(node: CallExpression) { + // A call expression parented by an expression statement is a potential assertion. Other call + // expressions are potential type predicate function calls. + const funcType = node.parent.kind === SyntaxKind.ExpressionStatement ? getTypeOfDottedName(node.expression) : + node.expression.kind !== SyntaxKind.SuperKeyword ? checkNonNullExpression(node.expression) : + undefined; + if (funcType && funcType !== silentNeverType) { + const apparentType = getApparentType(funcType); + if (some(getSignaturesOfType(apparentType, SignatureKind.Call), hasTypePredicate)) { + return getTypePredicateOfSignature(getResolvedSignature(node)); + } + } + return undefined; + } + + function hasTypePredicate(signature: Signature) { + return !!getTypePredicateOfSignature(signature); } function reportFlowControlError(node: Node) { @@ -17116,14 +17102,14 @@ namespace ts { } function getTypeAtFlowCall(flow: FlowCall): FlowType | undefined { - if (isAssertCall(flow.node)) { + const predicate = getTypePredicateForCall(flow.node); + if (predicate && predicate.kind === TypePredicateKind.Assertion) { const flowType = getTypeAtFlowNode(flow.antecedent); const type = getTypeFromFlowType(flowType); - const narrowedType = narrowTypeByAssertion(type, flow.node.arguments[0]); - if (narrowedType === type) { - return flowType; - } - return createFlowType(narrowedType, isIncomplete(flowType)); + const narrowedType = predicate.type ? + narrowTypeByTypePredicate(type, predicate, flow.node, /*assumeTrue*/ true) : + narrowTypeByAssertion(type, flow.node.arguments[predicate.parameterIndex]); + return narrowedType === type ? flowType : createFlowType(narrowedType, isIncomplete(flowType)); } return undefined; } @@ -17711,24 +17697,24 @@ namespace ts { getIntersectionType([type, candidate]); } - function narrowTypeByTypePredicate(type: Type, callExpression: CallExpression, assumeTrue: boolean): Type { - if (!hasMatchingArgument(callExpression, reference) || !maybeTypePredicateCall(callExpression)) { - return type; - } - const signature = getResolvedSignature(callExpression); - const predicate = getTypePredicateOfSignature(signature); - if (!predicate) { - return type; + function narrowTypeByCallExpression(type: Type, callExpression: CallExpression, assumeTrue: boolean): Type { + if (hasMatchingArgument(callExpression, reference)) { + const predicate = getTypePredicateForCall(callExpression); + if (predicate && predicate.kind !== TypePredicateKind.Assertion) { + return narrowTypeByTypePredicate(type, predicate, callExpression, assumeTrue); + } } + return type; + } + function narrowTypeByTypePredicate(type: Type, predicate: TypePredicate, callExpression: CallExpression, assumeTrue: boolean): Type { // Don't narrow from 'any' if the predicate type is exactly 'Object' or 'Function' if (isTypeAny(type) && (predicate.type === globalObjectType || predicate.type === globalFunctionType)) { return type; } - - if (isIdentifierTypePredicate(predicate)) { + if (predicate.kind !== TypePredicateKind.This) { const predicateArgument = callExpression.arguments[predicate.parameterIndex]; - if (predicateArgument) { + if (predicateArgument && predicate.type) { if (isMatchingReference(reference, predicateArgument)) { return getNarrowedType(type, predicate.type, assumeTrue, isTypeSubtypeOf); } @@ -17763,7 +17749,7 @@ namespace ts { case SyntaxKind.ElementAccessExpression: return narrowTypeByTruthiness(type, expr, assumeTrue); case SyntaxKind.CallExpression: - return narrowTypeByTypePredicate(type, expr, assumeTrue); + return narrowTypeByCallExpression(type, expr, assumeTrue); case SyntaxKind.ParenthesizedExpression: return narrowType(type, (expr).expression, assumeTrue); case SyntaxKind.BinaryExpression: @@ -25485,12 +25471,14 @@ namespace ts { error(parameterName, Diagnostics.A_type_predicate_cannot_reference_a_rest_parameter); } else { - const leadingError = () => chainDiagnosticMessages(/*details*/ undefined, Diagnostics.A_type_predicate_s_type_must_be_assignable_to_its_parameter_s_type); - checkTypeAssignableTo(typePredicate.type, - getTypeOfSymbol(signature.parameters[typePredicate.parameterIndex]), - node.type, - /*headMessage*/ undefined, - leadingError); + if (typePredicate.type) { + const leadingError = () => chainDiagnosticMessages(/*details*/ undefined, Diagnostics.A_type_predicate_s_type_must_be_assignable_to_its_parameter_s_type); + checkTypeAssignableTo(typePredicate.type, + getTypeOfSymbol(signature.parameters[typePredicate.parameterIndex]), + node.type, + /*headMessage*/ undefined, + leadingError); + } } } else if (parameterName) { diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 8681a452e2a..415f8f9680c 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1906,11 +1906,17 @@ namespace ts { // function emitTypePredicate(node: TypePredicateNode) { + if (node.assertsModifier) { + emit(node.assertsModifier); + writeSpace(); + } emit(node.parameterName); - writeSpace(); - writeKeyword("is"); - writeSpace(); - emit(node.type); + if (node.type) { + writeSpace(); + writeKeyword("is"); + writeSpace(); + emit(node.type); + } } function emitTypeReference(node: TypeReferenceNode) { diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 1f0294423a5..166999a7059 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -667,17 +667,18 @@ namespace ts { return createSynthesizedNode(kind); } - export function createTypePredicateNode(parameterName: Identifier | ThisTypeNode | string, type: TypeNode) { + export function createTypePredicateNode(assertsModifier: AssertsToken | undefined, parameterName: Identifier | ThisTypeNode | string, type: TypeNode | undefined) { const node = createSynthesizedNode(SyntaxKind.TypePredicate) as TypePredicateNode; + node.assertsModifier = assertsModifier; node.parameterName = asName(parameterName); node.type = type; return node; } - export function updateTypePredicateNode(node: TypePredicateNode, parameterName: Identifier | ThisTypeNode, type: TypeNode) { + export function updateTypePredicateNode(node: TypePredicateNode, assertsModifier: AssertsToken | undefined, parameterName: Identifier | ThisTypeNode, type: TypeNode | undefined) { return node.parameterName !== parameterName || node.type !== type - ? updateNode(createTypePredicateNode(parameterName, type), node) + ? updateNode(createTypePredicateNode(assertsModifier, parameterName, type), node) : node; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 254be93000b..3e0ea65476a 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2992,6 +2992,8 @@ namespace ts { return parseParenthesizedType(); case SyntaxKind.ImportKeyword: return parseImportType(); + case SyntaxKind.AssertsKeyword: + return lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine) ? parseAssertsTypePredicate() : parseTypeReference(); default: return parseTypeReference(); } @@ -3032,6 +3034,7 @@ namespace ts { case SyntaxKind.DotDotDotToken: case SyntaxKind.InferKeyword: case SyntaxKind.ImportKeyword: + case SyntaxKind.AssertsKeyword: return true; case SyntaxKind.FunctionKeyword: return !inStartOfParameter; @@ -3225,6 +3228,16 @@ namespace ts { } } + function parseAssertsTypePredicate(): TypeNode { + const node = createNode(SyntaxKind.TypePredicate); + node.assertsModifier = parseExpectedToken(SyntaxKind.AssertsKeyword); + node.parameterName = parseIdentifier(); + if (parseOptional(SyntaxKind.IsKeyword)) { + node.type = parseType(); + } + return finishNode(node); + } + function parseType(): TypeNode { // The rules about 'yield' only apply to actual code/expression contexts. They don't // apply to 'type' contexts. So we disable these parameters here before moving on. diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index f949893171a..31e54e283fe 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -65,6 +65,7 @@ namespace ts { abstract: SyntaxKind.AbstractKeyword, any: SyntaxKind.AnyKeyword, as: SyntaxKind.AsKeyword, + asserts: SyntaxKind.AssertsKeyword, bigint: SyntaxKind.BigIntKeyword, boolean: SyntaxKind.BooleanKeyword, break: SyntaxKind.BreakKeyword, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index aec65b03367..ba1ad79a8c2 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -32,6 +32,7 @@ namespace ts { | SyntaxKind.AbstractKeyword | SyntaxKind.AnyKeyword | SyntaxKind.AsKeyword + | SyntaxKind.AssertsKeyword | SyntaxKind.BigIntKeyword | SyntaxKind.BooleanKeyword | SyntaxKind.BreakKeyword @@ -250,6 +251,7 @@ namespace ts { // Contextual keywords AbstractKeyword, AsKeyword, + AssertsKeyword, AnyKeyword, AsyncKeyword, AwaitKeyword, @@ -734,6 +736,7 @@ namespace ts { export type AwaitKeywordToken = Token; export type PlusToken = Token; export type MinusToken = Token; + export type AssertsToken = Token; export type Modifier = Token @@ -1177,8 +1180,9 @@ namespace ts { export interface TypePredicateNode extends TypeNode { kind: SyntaxKind.TypePredicate; parent: SignatureDeclaration | JSDocTypeExpression; + assertsModifier?: AssertsToken; parameterName: Identifier | ThisTypeNode; - type: TypeNode; + type?: TypeNode; } export interface TypeQueryNode extends TypeNode { @@ -3493,25 +3497,32 @@ namespace ts { export const enum TypePredicateKind { This, - Identifier + Identifier, + Assertion } - export interface TypePredicateBase { - kind: TypePredicateKind; + export interface ThisTypePredicate { + kind: TypePredicateKind.This; + parameterName: undefined; + parameterIndex: undefined; type: Type; } - export interface ThisTypePredicate extends TypePredicateBase { - kind: TypePredicateKind.This; - } - - export interface IdentifierTypePredicate extends TypePredicateBase { + export interface IdentifierTypePredicate { kind: TypePredicateKind.Identifier; parameterName: string; parameterIndex: number; + type: Type; } - export type TypePredicate = IdentifierTypePredicate | ThisTypePredicate; + export interface AssertionTypePredicate { + kind: TypePredicateKind.Assertion; + parameterName: string; + parameterIndex: number; + type: Type | undefined; + } + + export type TypePredicate = ThisTypePredicate | IdentifierTypePredicate | AssertionTypePredicate; /* @internal */ export type AnyImportSyntax = ImportDeclaration | ImportEqualsDeclaration; @@ -3907,8 +3918,9 @@ namespace ts { resolvedSignature?: Signature; // Cached signature of signature node or call expression resolvedSymbol?: Symbol; // Cached name resolution result resolvedIndexInfo?: IndexInfo; // Cached indexing info resolution result - maybeTypePredicate?: boolean; // Cached check whether call expression might reference a type predicate - isAssertCall?: boolean; + //maybeTypePredicate?: boolean; // Cached check whether call expression might reference a type predicate + //isAssertCall?: boolean; + resolvedTypePredicate?: TypePredicate; // Cached type predicate for call expression enumMemberValue?: string | number; // Constant value of enum member isVisible?: boolean; // Is this node visible containsArgumentsReference?: boolean; // Whether a function-like declaration contains an 'arguments' reference diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index 53ccd81f7a6..aa497511f78 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -340,6 +340,7 @@ namespace ts { case SyntaxKind.TypePredicate: return updateTypePredicateNode(node, + visitNode((node).assertsModifier, visitor), visitNode((node).parameterName, visitor), visitNode((node).type, visitor, isTypeNode)); From 1f5bb970d987a7387a3531e1cea00f51b08fe20a Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 3 Aug 2019 08:28:53 -0700 Subject: [PATCH 023/140] Remove unused code --- src/compiler/checker.ts | 10 ---------- src/compiler/types.ts | 2 -- 2 files changed, 12 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c8ad1f66064..7dfb0cd2757 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8670,16 +8670,6 @@ namespace ts { } } - // function hasAssertionTypePredicate(signature: Signature): boolean { - // const predicate = getTypePredicateOfSignature(signature); - // return !!predicate && predicate.kind === TypePredicateKind.Assertion; - // } - - // function hasBooleanTypePredicate(signature: Signature): boolean { - // const predicate = getTypePredicateOfSignature(signature); - // return !!predicate && (predicate.kind === TypePredicateKind.This || predicate.kind === TypePredicateKind.Identifier); - // } - function getTypePredicateOfSignature(signature: Signature): TypePredicate | undefined { if (!signature.resolvedTypePredicate) { if (signature.target) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ba1ad79a8c2..3cdfba2aafb 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3918,8 +3918,6 @@ namespace ts { resolvedSignature?: Signature; // Cached signature of signature node or call expression resolvedSymbol?: Symbol; // Cached name resolution result resolvedIndexInfo?: IndexInfo; // Cached indexing info resolution result - //maybeTypePredicate?: boolean; // Cached check whether call expression might reference a type predicate - //isAssertCall?: boolean; resolvedTypePredicate?: TypePredicate; // Cached type predicate for call expression enumMemberValue?: string | number; // Constant value of enum member isVisible?: boolean; // Is this node visible From fe70a62ef1ef87d20a860c6bdea999cdfab76592 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 3 Aug 2019 08:55:55 -0700 Subject: [PATCH 024/140] Accept new API baselines --- .../reference/api/tsserverlibrary.d.ts | 465 +++++++++--------- tests/baselines/reference/api/typescript.d.ts | 465 +++++++++--------- 2 files changed, 480 insertions(+), 450 deletions(-) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index d73cbab6b5f..00c88fc4963 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -73,7 +73,7 @@ declare namespace ts { end: number; } export type JSDocSyntaxKind = SyntaxKind.EndOfFileToken | SyntaxKind.WhitespaceTrivia | SyntaxKind.AtToken | SyntaxKind.NewLineTrivia | SyntaxKind.AsteriskToken | SyntaxKind.OpenBraceToken | SyntaxKind.CloseBraceToken | SyntaxKind.LessThanToken | SyntaxKind.GreaterThanToken | SyntaxKind.OpenBracketToken | SyntaxKind.CloseBracketToken | SyntaxKind.EqualsToken | SyntaxKind.CommaToken | SyntaxKind.DotToken | SyntaxKind.Identifier | SyntaxKind.BacktickToken | SyntaxKind.Unknown | KeywordSyntaxKind; - export type KeywordSyntaxKind = SyntaxKind.AbstractKeyword | SyntaxKind.AnyKeyword | SyntaxKind.AsKeyword | SyntaxKind.BigIntKeyword | SyntaxKind.BooleanKeyword | SyntaxKind.BreakKeyword | SyntaxKind.CaseKeyword | SyntaxKind.CatchKeyword | SyntaxKind.ClassKeyword | SyntaxKind.ContinueKeyword | SyntaxKind.ConstKeyword | SyntaxKind.ConstructorKeyword | SyntaxKind.DebuggerKeyword | SyntaxKind.DeclareKeyword | SyntaxKind.DefaultKeyword | SyntaxKind.DeleteKeyword | SyntaxKind.DoKeyword | SyntaxKind.ElseKeyword | SyntaxKind.EnumKeyword | SyntaxKind.ExportKeyword | SyntaxKind.ExtendsKeyword | SyntaxKind.FalseKeyword | SyntaxKind.FinallyKeyword | SyntaxKind.ForKeyword | SyntaxKind.FromKeyword | SyntaxKind.FunctionKeyword | SyntaxKind.GetKeyword | SyntaxKind.IfKeyword | SyntaxKind.ImplementsKeyword | SyntaxKind.ImportKeyword | SyntaxKind.InKeyword | SyntaxKind.InferKeyword | SyntaxKind.InstanceOfKeyword | SyntaxKind.InterfaceKeyword | SyntaxKind.IsKeyword | SyntaxKind.KeyOfKeyword | SyntaxKind.LetKeyword | SyntaxKind.ModuleKeyword | SyntaxKind.NamespaceKeyword | SyntaxKind.NeverKeyword | SyntaxKind.NewKeyword | SyntaxKind.NullKeyword | SyntaxKind.NumberKeyword | SyntaxKind.ObjectKeyword | SyntaxKind.PackageKeyword | SyntaxKind.PrivateKeyword | SyntaxKind.ProtectedKeyword | SyntaxKind.PublicKeyword | SyntaxKind.ReadonlyKeyword | SyntaxKind.RequireKeyword | SyntaxKind.GlobalKeyword | SyntaxKind.ReturnKeyword | SyntaxKind.SetKeyword | SyntaxKind.StaticKeyword | SyntaxKind.StringKeyword | SyntaxKind.SuperKeyword | SyntaxKind.SwitchKeyword | SyntaxKind.SymbolKeyword | SyntaxKind.ThisKeyword | SyntaxKind.ThrowKeyword | SyntaxKind.TrueKeyword | SyntaxKind.TryKeyword | SyntaxKind.TypeKeyword | SyntaxKind.TypeOfKeyword | SyntaxKind.UndefinedKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.UnknownKeyword | SyntaxKind.VarKeyword | SyntaxKind.VoidKeyword | SyntaxKind.WhileKeyword | SyntaxKind.WithKeyword | SyntaxKind.YieldKeyword | SyntaxKind.AsyncKeyword | SyntaxKind.AwaitKeyword | SyntaxKind.OfKeyword; + export type KeywordSyntaxKind = SyntaxKind.AbstractKeyword | SyntaxKind.AnyKeyword | SyntaxKind.AsKeyword | SyntaxKind.AssertsKeyword | SyntaxKind.BigIntKeyword | SyntaxKind.BooleanKeyword | SyntaxKind.BreakKeyword | SyntaxKind.CaseKeyword | SyntaxKind.CatchKeyword | SyntaxKind.ClassKeyword | SyntaxKind.ContinueKeyword | SyntaxKind.ConstKeyword | SyntaxKind.ConstructorKeyword | SyntaxKind.DebuggerKeyword | SyntaxKind.DeclareKeyword | SyntaxKind.DefaultKeyword | SyntaxKind.DeleteKeyword | SyntaxKind.DoKeyword | SyntaxKind.ElseKeyword | SyntaxKind.EnumKeyword | SyntaxKind.ExportKeyword | SyntaxKind.ExtendsKeyword | SyntaxKind.FalseKeyword | SyntaxKind.FinallyKeyword | SyntaxKind.ForKeyword | SyntaxKind.FromKeyword | SyntaxKind.FunctionKeyword | SyntaxKind.GetKeyword | SyntaxKind.IfKeyword | SyntaxKind.ImplementsKeyword | SyntaxKind.ImportKeyword | SyntaxKind.InKeyword | SyntaxKind.InferKeyword | SyntaxKind.InstanceOfKeyword | SyntaxKind.InterfaceKeyword | SyntaxKind.IsKeyword | SyntaxKind.KeyOfKeyword | SyntaxKind.LetKeyword | SyntaxKind.ModuleKeyword | SyntaxKind.NamespaceKeyword | SyntaxKind.NeverKeyword | SyntaxKind.NewKeyword | SyntaxKind.NullKeyword | SyntaxKind.NumberKeyword | SyntaxKind.ObjectKeyword | SyntaxKind.PackageKeyword | SyntaxKind.PrivateKeyword | SyntaxKind.ProtectedKeyword | SyntaxKind.PublicKeyword | SyntaxKind.ReadonlyKeyword | SyntaxKind.RequireKeyword | SyntaxKind.GlobalKeyword | SyntaxKind.ReturnKeyword | SyntaxKind.SetKeyword | SyntaxKind.StaticKeyword | SyntaxKind.StringKeyword | SyntaxKind.SuperKeyword | SyntaxKind.SwitchKeyword | SyntaxKind.SymbolKeyword | SyntaxKind.ThisKeyword | SyntaxKind.ThrowKeyword | SyntaxKind.TrueKeyword | SyntaxKind.TryKeyword | SyntaxKind.TypeKeyword | SyntaxKind.TypeOfKeyword | SyntaxKind.UndefinedKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.UnknownKeyword | SyntaxKind.VarKeyword | SyntaxKind.VoidKeyword | SyntaxKind.WhileKeyword | SyntaxKind.WithKeyword | SyntaxKind.YieldKeyword | SyntaxKind.AsyncKeyword | SyntaxKind.AwaitKeyword | SyntaxKind.OfKeyword; export type JsxTokenSyntaxKind = SyntaxKind.LessThanSlashToken | SyntaxKind.EndOfFileToken | SyntaxKind.ConflictMarkerTrivia | SyntaxKind.JsxText | SyntaxKind.JsxTextAllWhiteSpaces | SyntaxKind.OpenBraceToken | SyntaxKind.LessThanToken; export enum SyntaxKind { Unknown = 0, @@ -198,205 +198,206 @@ declare namespace ts { YieldKeyword = 118, AbstractKeyword = 119, AsKeyword = 120, - AnyKeyword = 121, - AsyncKeyword = 122, - AwaitKeyword = 123, - BooleanKeyword = 124, - ConstructorKeyword = 125, - DeclareKeyword = 126, - GetKeyword = 127, - InferKeyword = 128, - IsKeyword = 129, - KeyOfKeyword = 130, - ModuleKeyword = 131, - NamespaceKeyword = 132, - NeverKeyword = 133, - ReadonlyKeyword = 134, - RequireKeyword = 135, - NumberKeyword = 136, - ObjectKeyword = 137, - SetKeyword = 138, - StringKeyword = 139, - SymbolKeyword = 140, - TypeKeyword = 141, - UndefinedKeyword = 142, - UniqueKeyword = 143, - UnknownKeyword = 144, - FromKeyword = 145, - GlobalKeyword = 146, - BigIntKeyword = 147, - OfKeyword = 148, - QualifiedName = 149, - ComputedPropertyName = 150, - TypeParameter = 151, - Parameter = 152, - Decorator = 153, - PropertySignature = 154, - PropertyDeclaration = 155, - MethodSignature = 156, - MethodDeclaration = 157, - Constructor = 158, - GetAccessor = 159, - SetAccessor = 160, - CallSignature = 161, - ConstructSignature = 162, - IndexSignature = 163, - TypePredicate = 164, - TypeReference = 165, - FunctionType = 166, - ConstructorType = 167, - TypeQuery = 168, - TypeLiteral = 169, - ArrayType = 170, - TupleType = 171, - OptionalType = 172, - RestType = 173, - UnionType = 174, - IntersectionType = 175, - ConditionalType = 176, - InferType = 177, - ParenthesizedType = 178, - ThisType = 179, - TypeOperator = 180, - IndexedAccessType = 181, - MappedType = 182, - LiteralType = 183, - ImportType = 184, - ObjectBindingPattern = 185, - ArrayBindingPattern = 186, - BindingElement = 187, - ArrayLiteralExpression = 188, - ObjectLiteralExpression = 189, - PropertyAccessExpression = 190, - ElementAccessExpression = 191, - CallExpression = 192, - NewExpression = 193, - TaggedTemplateExpression = 194, - TypeAssertionExpression = 195, - ParenthesizedExpression = 196, - FunctionExpression = 197, - ArrowFunction = 198, - DeleteExpression = 199, - TypeOfExpression = 200, - VoidExpression = 201, - AwaitExpression = 202, - PrefixUnaryExpression = 203, - PostfixUnaryExpression = 204, - BinaryExpression = 205, - ConditionalExpression = 206, - TemplateExpression = 207, - YieldExpression = 208, - SpreadElement = 209, - ClassExpression = 210, - OmittedExpression = 211, - ExpressionWithTypeArguments = 212, - AsExpression = 213, - NonNullExpression = 214, - MetaProperty = 215, - SyntheticExpression = 216, - TemplateSpan = 217, - SemicolonClassElement = 218, - Block = 219, - VariableStatement = 220, - EmptyStatement = 221, - ExpressionStatement = 222, - IfStatement = 223, - DoStatement = 224, - WhileStatement = 225, - ForStatement = 226, - ForInStatement = 227, - ForOfStatement = 228, - ContinueStatement = 229, - BreakStatement = 230, - ReturnStatement = 231, - WithStatement = 232, - SwitchStatement = 233, - LabeledStatement = 234, - ThrowStatement = 235, - TryStatement = 236, - DebuggerStatement = 237, - VariableDeclaration = 238, - VariableDeclarationList = 239, - FunctionDeclaration = 240, - ClassDeclaration = 241, - InterfaceDeclaration = 242, - TypeAliasDeclaration = 243, - EnumDeclaration = 244, - ModuleDeclaration = 245, - ModuleBlock = 246, - CaseBlock = 247, - NamespaceExportDeclaration = 248, - ImportEqualsDeclaration = 249, - ImportDeclaration = 250, - ImportClause = 251, - NamespaceImport = 252, - NamedImports = 253, - ImportSpecifier = 254, - ExportAssignment = 255, - ExportDeclaration = 256, - NamedExports = 257, - ExportSpecifier = 258, - MissingDeclaration = 259, - ExternalModuleReference = 260, - JsxElement = 261, - JsxSelfClosingElement = 262, - JsxOpeningElement = 263, - JsxClosingElement = 264, - JsxFragment = 265, - JsxOpeningFragment = 266, - JsxClosingFragment = 267, - JsxAttribute = 268, - JsxAttributes = 269, - JsxSpreadAttribute = 270, - JsxExpression = 271, - CaseClause = 272, - DefaultClause = 273, - HeritageClause = 274, - CatchClause = 275, - PropertyAssignment = 276, - ShorthandPropertyAssignment = 277, - SpreadAssignment = 278, - EnumMember = 279, - UnparsedPrologue = 280, - UnparsedPrepend = 281, - UnparsedText = 282, - UnparsedInternalText = 283, - UnparsedSyntheticReference = 284, - SourceFile = 285, - Bundle = 286, - UnparsedSource = 287, - InputFiles = 288, - JSDocTypeExpression = 289, - JSDocAllType = 290, - JSDocUnknownType = 291, - JSDocNullableType = 292, - JSDocNonNullableType = 293, - JSDocOptionalType = 294, - JSDocFunctionType = 295, - JSDocVariadicType = 296, - JSDocComment = 297, - JSDocTypeLiteral = 298, - JSDocSignature = 299, - JSDocTag = 300, - JSDocAugmentsTag = 301, - JSDocAuthorTag = 302, - JSDocClassTag = 303, - JSDocCallbackTag = 304, - JSDocEnumTag = 305, - JSDocParameterTag = 306, - JSDocReturnTag = 307, - JSDocThisTag = 308, - JSDocTypeTag = 309, - JSDocTemplateTag = 310, - JSDocTypedefTag = 311, - JSDocPropertyTag = 312, - SyntaxList = 313, - NotEmittedStatement = 314, - PartiallyEmittedExpression = 315, - CommaListExpression = 316, - MergeDeclarationMarker = 317, - EndOfDeclarationMarker = 318, - Count = 319, + AssertsKeyword = 121, + AnyKeyword = 122, + AsyncKeyword = 123, + AwaitKeyword = 124, + BooleanKeyword = 125, + ConstructorKeyword = 126, + DeclareKeyword = 127, + GetKeyword = 128, + InferKeyword = 129, + IsKeyword = 130, + KeyOfKeyword = 131, + ModuleKeyword = 132, + NamespaceKeyword = 133, + NeverKeyword = 134, + ReadonlyKeyword = 135, + RequireKeyword = 136, + NumberKeyword = 137, + ObjectKeyword = 138, + SetKeyword = 139, + StringKeyword = 140, + SymbolKeyword = 141, + TypeKeyword = 142, + UndefinedKeyword = 143, + UniqueKeyword = 144, + UnknownKeyword = 145, + FromKeyword = 146, + GlobalKeyword = 147, + BigIntKeyword = 148, + OfKeyword = 149, + QualifiedName = 150, + ComputedPropertyName = 151, + TypeParameter = 152, + Parameter = 153, + Decorator = 154, + PropertySignature = 155, + PropertyDeclaration = 156, + MethodSignature = 157, + MethodDeclaration = 158, + Constructor = 159, + GetAccessor = 160, + SetAccessor = 161, + CallSignature = 162, + ConstructSignature = 163, + IndexSignature = 164, + TypePredicate = 165, + TypeReference = 166, + FunctionType = 167, + ConstructorType = 168, + TypeQuery = 169, + TypeLiteral = 170, + ArrayType = 171, + TupleType = 172, + OptionalType = 173, + RestType = 174, + UnionType = 175, + IntersectionType = 176, + ConditionalType = 177, + InferType = 178, + ParenthesizedType = 179, + ThisType = 180, + TypeOperator = 181, + IndexedAccessType = 182, + MappedType = 183, + LiteralType = 184, + ImportType = 185, + ObjectBindingPattern = 186, + ArrayBindingPattern = 187, + BindingElement = 188, + ArrayLiteralExpression = 189, + ObjectLiteralExpression = 190, + PropertyAccessExpression = 191, + ElementAccessExpression = 192, + CallExpression = 193, + NewExpression = 194, + TaggedTemplateExpression = 195, + TypeAssertionExpression = 196, + ParenthesizedExpression = 197, + FunctionExpression = 198, + ArrowFunction = 199, + DeleteExpression = 200, + TypeOfExpression = 201, + VoidExpression = 202, + AwaitExpression = 203, + PrefixUnaryExpression = 204, + PostfixUnaryExpression = 205, + BinaryExpression = 206, + ConditionalExpression = 207, + TemplateExpression = 208, + YieldExpression = 209, + SpreadElement = 210, + ClassExpression = 211, + OmittedExpression = 212, + ExpressionWithTypeArguments = 213, + AsExpression = 214, + NonNullExpression = 215, + MetaProperty = 216, + SyntheticExpression = 217, + TemplateSpan = 218, + SemicolonClassElement = 219, + Block = 220, + VariableStatement = 221, + EmptyStatement = 222, + ExpressionStatement = 223, + IfStatement = 224, + DoStatement = 225, + WhileStatement = 226, + ForStatement = 227, + ForInStatement = 228, + ForOfStatement = 229, + ContinueStatement = 230, + BreakStatement = 231, + ReturnStatement = 232, + WithStatement = 233, + SwitchStatement = 234, + LabeledStatement = 235, + ThrowStatement = 236, + TryStatement = 237, + DebuggerStatement = 238, + VariableDeclaration = 239, + VariableDeclarationList = 240, + FunctionDeclaration = 241, + ClassDeclaration = 242, + InterfaceDeclaration = 243, + TypeAliasDeclaration = 244, + EnumDeclaration = 245, + ModuleDeclaration = 246, + ModuleBlock = 247, + CaseBlock = 248, + NamespaceExportDeclaration = 249, + ImportEqualsDeclaration = 250, + ImportDeclaration = 251, + ImportClause = 252, + NamespaceImport = 253, + NamedImports = 254, + ImportSpecifier = 255, + ExportAssignment = 256, + ExportDeclaration = 257, + NamedExports = 258, + ExportSpecifier = 259, + MissingDeclaration = 260, + ExternalModuleReference = 261, + JsxElement = 262, + JsxSelfClosingElement = 263, + JsxOpeningElement = 264, + JsxClosingElement = 265, + JsxFragment = 266, + JsxOpeningFragment = 267, + JsxClosingFragment = 268, + JsxAttribute = 269, + JsxAttributes = 270, + JsxSpreadAttribute = 271, + JsxExpression = 272, + CaseClause = 273, + DefaultClause = 274, + HeritageClause = 275, + CatchClause = 276, + PropertyAssignment = 277, + ShorthandPropertyAssignment = 278, + SpreadAssignment = 279, + EnumMember = 280, + UnparsedPrologue = 281, + UnparsedPrepend = 282, + UnparsedText = 283, + UnparsedInternalText = 284, + UnparsedSyntheticReference = 285, + SourceFile = 286, + Bundle = 287, + UnparsedSource = 288, + InputFiles = 289, + JSDocTypeExpression = 290, + JSDocAllType = 291, + JSDocUnknownType = 292, + JSDocNullableType = 293, + JSDocNonNullableType = 294, + JSDocOptionalType = 295, + JSDocFunctionType = 296, + JSDocVariadicType = 297, + JSDocComment = 298, + JSDocTypeLiteral = 299, + JSDocSignature = 300, + JSDocTag = 301, + JSDocAugmentsTag = 302, + JSDocAuthorTag = 303, + JSDocClassTag = 304, + JSDocCallbackTag = 305, + JSDocEnumTag = 306, + JSDocParameterTag = 307, + JSDocReturnTag = 308, + JSDocThisTag = 309, + JSDocTypeTag = 310, + JSDocTemplateTag = 311, + JSDocTypedefTag = 312, + JSDocPropertyTag = 313, + SyntaxList = 314, + NotEmittedStatement = 315, + PartiallyEmittedExpression = 316, + CommaListExpression = 317, + MergeDeclarationMarker = 318, + EndOfDeclarationMarker = 319, + Count = 320, FirstAssignment = 60, LastAssignment = 72, FirstCompoundAssignment = 61, @@ -404,15 +405,15 @@ declare namespace ts { FirstReservedWord = 74, LastReservedWord = 109, FirstKeyword = 74, - LastKeyword = 148, + LastKeyword = 149, FirstFutureReservedWord = 110, LastFutureReservedWord = 118, - FirstTypeNode = 164, - LastTypeNode = 184, + FirstTypeNode = 165, + LastTypeNode = 185, FirstPunctuation = 18, LastPunctuation = 72, FirstToken = 0, - LastToken = 148, + LastToken = 149, FirstTriviaToken = 2, LastTriviaToken = 7, FirstLiteralToken = 8, @@ -421,11 +422,11 @@ declare namespace ts { LastTemplateToken = 17, FirstBinaryOperator = 28, LastBinaryOperator = 72, - FirstNode = 149, - FirstJSDocNode = 289, - LastJSDocNode = 312, - FirstJSDocTagNode = 300, - LastJSDocTagNode = 312, + FirstNode = 150, + FirstJSDocNode = 290, + LastJSDocNode = 313, + FirstJSDocTagNode = 301, + LastJSDocTagNode = 313, } export enum NodeFlags { None = 0, @@ -516,6 +517,7 @@ declare namespace ts { export type AwaitKeywordToken = Token; export type PlusToken = Token; export type MinusToken = Token; + export type AssertsToken = Token; export type Modifier = Token | Token | Token | Token | Token | Token | Token | Token | Token | Token | Token; export type ModifiersArray = NodeArray; export interface Identifier extends PrimaryExpression, Declaration { @@ -769,8 +771,9 @@ declare namespace ts { export interface TypePredicateNode extends TypeNode { kind: SyntaxKind.TypePredicate; parent: SignatureDeclaration | JSDocTypeExpression; + assertsModifier?: AssertsToken; parameterName: Identifier | ThisTypeNode; - type: TypeNode; + type?: TypeNode; } export interface TypeQueryNode extends TypeNode { kind: SyntaxKind.TypeQuery; @@ -1661,10 +1664,11 @@ declare namespace ts { FalseCondition = 64, SwitchClause = 128, ArrayMutation = 256, - Referenced = 512, - Shared = 1024, - PreFinally = 2048, - AfterFinally = 4096, + Call = 512, + Referenced = 1024, + Shared = 2048, + PreFinally = 4096, + AfterFinally = 8192, Label = 12, Condition = 96 } @@ -1678,7 +1682,7 @@ declare namespace ts { antecedent: FlowNode; lock: FlowLock; } - export type FlowNode = AfterFinallyFlow | PreFinallyFlow | FlowStart | FlowLabel | FlowAssignment | FlowCondition | FlowSwitchClause | FlowArrayMutation; + export type FlowNode = AfterFinallyFlow | PreFinallyFlow | FlowStart | FlowLabel | FlowAssignment | FlowCall | FlowCondition | FlowSwitchClause | FlowArrayMutation; export interface FlowNodeBase { flags: FlowFlags; id?: number; @@ -1693,6 +1697,10 @@ declare namespace ts { node: Expression | VariableDeclaration | BindingElement; antecedent: FlowNode; } + export interface FlowCall extends FlowNodeBase { + node: CallExpression; + antecedent: FlowNode; + } export interface FlowCondition extends FlowNodeBase { expression: Expression; antecedent: FlowNode; @@ -2080,21 +2088,28 @@ declare namespace ts { } export enum TypePredicateKind { This = 0, - Identifier = 1 + Identifier = 1, + Assertion = 2 } - export interface TypePredicateBase { - kind: TypePredicateKind; + export interface ThisTypePredicate { + kind: TypePredicateKind.This; + parameterName: undefined; + parameterIndex: undefined; type: Type; } - export interface ThisTypePredicate extends TypePredicateBase { - kind: TypePredicateKind.This; - } - export interface IdentifierTypePredicate extends TypePredicateBase { + export interface IdentifierTypePredicate { kind: TypePredicateKind.Identifier; parameterName: string; parameterIndex: number; + type: Type; } - export type TypePredicate = IdentifierTypePredicate | ThisTypePredicate; + export interface AssertionTypePredicate { + kind: TypePredicateKind.Assertion; + parameterName: string; + parameterIndex: number; + type: Type | undefined; + } + export type TypePredicate = ThisTypePredicate | IdentifierTypePredicate | AssertionTypePredicate; export enum SymbolFlags { None = 0, FunctionScopedVariable = 1, @@ -3823,8 +3838,8 @@ declare namespace ts { function createIndexSignature(decorators: ReadonlyArray | undefined, modifiers: ReadonlyArray | undefined, parameters: ReadonlyArray, type: TypeNode): IndexSignatureDeclaration; function updateIndexSignature(node: IndexSignatureDeclaration, decorators: ReadonlyArray | undefined, modifiers: ReadonlyArray | undefined, parameters: ReadonlyArray, type: TypeNode): IndexSignatureDeclaration; function createKeywordTypeNode(kind: KeywordTypeNode["kind"]): KeywordTypeNode; - function createTypePredicateNode(parameterName: Identifier | ThisTypeNode | string, type: TypeNode): TypePredicateNode; - function updateTypePredicateNode(node: TypePredicateNode, parameterName: Identifier | ThisTypeNode, type: TypeNode): TypePredicateNode; + function createTypePredicateNode(assertsModifier: AssertsToken | undefined, parameterName: Identifier | ThisTypeNode | string, type: TypeNode | undefined): TypePredicateNode; + function updateTypePredicateNode(node: TypePredicateNode, assertsModifier: AssertsToken | undefined, parameterName: Identifier | ThisTypeNode, type: TypeNode | undefined): TypePredicateNode; function createTypeReferenceNode(typeName: string | EntityName, typeArguments: ReadonlyArray | undefined): TypeReferenceNode; function updateTypeReferenceNode(node: TypeReferenceNode, typeName: EntityName, typeArguments: NodeArray | undefined): TypeReferenceNode; function createFunctionTypeNode(typeParameters: ReadonlyArray | undefined, parameters: ReadonlyArray, type: TypeNode | undefined): FunctionTypeNode; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 1bb693c0845..df8d0e1ee79 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -73,7 +73,7 @@ declare namespace ts { end: number; } export type JSDocSyntaxKind = SyntaxKind.EndOfFileToken | SyntaxKind.WhitespaceTrivia | SyntaxKind.AtToken | SyntaxKind.NewLineTrivia | SyntaxKind.AsteriskToken | SyntaxKind.OpenBraceToken | SyntaxKind.CloseBraceToken | SyntaxKind.LessThanToken | SyntaxKind.GreaterThanToken | SyntaxKind.OpenBracketToken | SyntaxKind.CloseBracketToken | SyntaxKind.EqualsToken | SyntaxKind.CommaToken | SyntaxKind.DotToken | SyntaxKind.Identifier | SyntaxKind.BacktickToken | SyntaxKind.Unknown | KeywordSyntaxKind; - export type KeywordSyntaxKind = SyntaxKind.AbstractKeyword | SyntaxKind.AnyKeyword | SyntaxKind.AsKeyword | SyntaxKind.BigIntKeyword | SyntaxKind.BooleanKeyword | SyntaxKind.BreakKeyword | SyntaxKind.CaseKeyword | SyntaxKind.CatchKeyword | SyntaxKind.ClassKeyword | SyntaxKind.ContinueKeyword | SyntaxKind.ConstKeyword | SyntaxKind.ConstructorKeyword | SyntaxKind.DebuggerKeyword | SyntaxKind.DeclareKeyword | SyntaxKind.DefaultKeyword | SyntaxKind.DeleteKeyword | SyntaxKind.DoKeyword | SyntaxKind.ElseKeyword | SyntaxKind.EnumKeyword | SyntaxKind.ExportKeyword | SyntaxKind.ExtendsKeyword | SyntaxKind.FalseKeyword | SyntaxKind.FinallyKeyword | SyntaxKind.ForKeyword | SyntaxKind.FromKeyword | SyntaxKind.FunctionKeyword | SyntaxKind.GetKeyword | SyntaxKind.IfKeyword | SyntaxKind.ImplementsKeyword | SyntaxKind.ImportKeyword | SyntaxKind.InKeyword | SyntaxKind.InferKeyword | SyntaxKind.InstanceOfKeyword | SyntaxKind.InterfaceKeyword | SyntaxKind.IsKeyword | SyntaxKind.KeyOfKeyword | SyntaxKind.LetKeyword | SyntaxKind.ModuleKeyword | SyntaxKind.NamespaceKeyword | SyntaxKind.NeverKeyword | SyntaxKind.NewKeyword | SyntaxKind.NullKeyword | SyntaxKind.NumberKeyword | SyntaxKind.ObjectKeyword | SyntaxKind.PackageKeyword | SyntaxKind.PrivateKeyword | SyntaxKind.ProtectedKeyword | SyntaxKind.PublicKeyword | SyntaxKind.ReadonlyKeyword | SyntaxKind.RequireKeyword | SyntaxKind.GlobalKeyword | SyntaxKind.ReturnKeyword | SyntaxKind.SetKeyword | SyntaxKind.StaticKeyword | SyntaxKind.StringKeyword | SyntaxKind.SuperKeyword | SyntaxKind.SwitchKeyword | SyntaxKind.SymbolKeyword | SyntaxKind.ThisKeyword | SyntaxKind.ThrowKeyword | SyntaxKind.TrueKeyword | SyntaxKind.TryKeyword | SyntaxKind.TypeKeyword | SyntaxKind.TypeOfKeyword | SyntaxKind.UndefinedKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.UnknownKeyword | SyntaxKind.VarKeyword | SyntaxKind.VoidKeyword | SyntaxKind.WhileKeyword | SyntaxKind.WithKeyword | SyntaxKind.YieldKeyword | SyntaxKind.AsyncKeyword | SyntaxKind.AwaitKeyword | SyntaxKind.OfKeyword; + export type KeywordSyntaxKind = SyntaxKind.AbstractKeyword | SyntaxKind.AnyKeyword | SyntaxKind.AsKeyword | SyntaxKind.AssertsKeyword | SyntaxKind.BigIntKeyword | SyntaxKind.BooleanKeyword | SyntaxKind.BreakKeyword | SyntaxKind.CaseKeyword | SyntaxKind.CatchKeyword | SyntaxKind.ClassKeyword | SyntaxKind.ContinueKeyword | SyntaxKind.ConstKeyword | SyntaxKind.ConstructorKeyword | SyntaxKind.DebuggerKeyword | SyntaxKind.DeclareKeyword | SyntaxKind.DefaultKeyword | SyntaxKind.DeleteKeyword | SyntaxKind.DoKeyword | SyntaxKind.ElseKeyword | SyntaxKind.EnumKeyword | SyntaxKind.ExportKeyword | SyntaxKind.ExtendsKeyword | SyntaxKind.FalseKeyword | SyntaxKind.FinallyKeyword | SyntaxKind.ForKeyword | SyntaxKind.FromKeyword | SyntaxKind.FunctionKeyword | SyntaxKind.GetKeyword | SyntaxKind.IfKeyword | SyntaxKind.ImplementsKeyword | SyntaxKind.ImportKeyword | SyntaxKind.InKeyword | SyntaxKind.InferKeyword | SyntaxKind.InstanceOfKeyword | SyntaxKind.InterfaceKeyword | SyntaxKind.IsKeyword | SyntaxKind.KeyOfKeyword | SyntaxKind.LetKeyword | SyntaxKind.ModuleKeyword | SyntaxKind.NamespaceKeyword | SyntaxKind.NeverKeyword | SyntaxKind.NewKeyword | SyntaxKind.NullKeyword | SyntaxKind.NumberKeyword | SyntaxKind.ObjectKeyword | SyntaxKind.PackageKeyword | SyntaxKind.PrivateKeyword | SyntaxKind.ProtectedKeyword | SyntaxKind.PublicKeyword | SyntaxKind.ReadonlyKeyword | SyntaxKind.RequireKeyword | SyntaxKind.GlobalKeyword | SyntaxKind.ReturnKeyword | SyntaxKind.SetKeyword | SyntaxKind.StaticKeyword | SyntaxKind.StringKeyword | SyntaxKind.SuperKeyword | SyntaxKind.SwitchKeyword | SyntaxKind.SymbolKeyword | SyntaxKind.ThisKeyword | SyntaxKind.ThrowKeyword | SyntaxKind.TrueKeyword | SyntaxKind.TryKeyword | SyntaxKind.TypeKeyword | SyntaxKind.TypeOfKeyword | SyntaxKind.UndefinedKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.UnknownKeyword | SyntaxKind.VarKeyword | SyntaxKind.VoidKeyword | SyntaxKind.WhileKeyword | SyntaxKind.WithKeyword | SyntaxKind.YieldKeyword | SyntaxKind.AsyncKeyword | SyntaxKind.AwaitKeyword | SyntaxKind.OfKeyword; export type JsxTokenSyntaxKind = SyntaxKind.LessThanSlashToken | SyntaxKind.EndOfFileToken | SyntaxKind.ConflictMarkerTrivia | SyntaxKind.JsxText | SyntaxKind.JsxTextAllWhiteSpaces | SyntaxKind.OpenBraceToken | SyntaxKind.LessThanToken; export enum SyntaxKind { Unknown = 0, @@ -198,205 +198,206 @@ declare namespace ts { YieldKeyword = 118, AbstractKeyword = 119, AsKeyword = 120, - AnyKeyword = 121, - AsyncKeyword = 122, - AwaitKeyword = 123, - BooleanKeyword = 124, - ConstructorKeyword = 125, - DeclareKeyword = 126, - GetKeyword = 127, - InferKeyword = 128, - IsKeyword = 129, - KeyOfKeyword = 130, - ModuleKeyword = 131, - NamespaceKeyword = 132, - NeverKeyword = 133, - ReadonlyKeyword = 134, - RequireKeyword = 135, - NumberKeyword = 136, - ObjectKeyword = 137, - SetKeyword = 138, - StringKeyword = 139, - SymbolKeyword = 140, - TypeKeyword = 141, - UndefinedKeyword = 142, - UniqueKeyword = 143, - UnknownKeyword = 144, - FromKeyword = 145, - GlobalKeyword = 146, - BigIntKeyword = 147, - OfKeyword = 148, - QualifiedName = 149, - ComputedPropertyName = 150, - TypeParameter = 151, - Parameter = 152, - Decorator = 153, - PropertySignature = 154, - PropertyDeclaration = 155, - MethodSignature = 156, - MethodDeclaration = 157, - Constructor = 158, - GetAccessor = 159, - SetAccessor = 160, - CallSignature = 161, - ConstructSignature = 162, - IndexSignature = 163, - TypePredicate = 164, - TypeReference = 165, - FunctionType = 166, - ConstructorType = 167, - TypeQuery = 168, - TypeLiteral = 169, - ArrayType = 170, - TupleType = 171, - OptionalType = 172, - RestType = 173, - UnionType = 174, - IntersectionType = 175, - ConditionalType = 176, - InferType = 177, - ParenthesizedType = 178, - ThisType = 179, - TypeOperator = 180, - IndexedAccessType = 181, - MappedType = 182, - LiteralType = 183, - ImportType = 184, - ObjectBindingPattern = 185, - ArrayBindingPattern = 186, - BindingElement = 187, - ArrayLiteralExpression = 188, - ObjectLiteralExpression = 189, - PropertyAccessExpression = 190, - ElementAccessExpression = 191, - CallExpression = 192, - NewExpression = 193, - TaggedTemplateExpression = 194, - TypeAssertionExpression = 195, - ParenthesizedExpression = 196, - FunctionExpression = 197, - ArrowFunction = 198, - DeleteExpression = 199, - TypeOfExpression = 200, - VoidExpression = 201, - AwaitExpression = 202, - PrefixUnaryExpression = 203, - PostfixUnaryExpression = 204, - BinaryExpression = 205, - ConditionalExpression = 206, - TemplateExpression = 207, - YieldExpression = 208, - SpreadElement = 209, - ClassExpression = 210, - OmittedExpression = 211, - ExpressionWithTypeArguments = 212, - AsExpression = 213, - NonNullExpression = 214, - MetaProperty = 215, - SyntheticExpression = 216, - TemplateSpan = 217, - SemicolonClassElement = 218, - Block = 219, - VariableStatement = 220, - EmptyStatement = 221, - ExpressionStatement = 222, - IfStatement = 223, - DoStatement = 224, - WhileStatement = 225, - ForStatement = 226, - ForInStatement = 227, - ForOfStatement = 228, - ContinueStatement = 229, - BreakStatement = 230, - ReturnStatement = 231, - WithStatement = 232, - SwitchStatement = 233, - LabeledStatement = 234, - ThrowStatement = 235, - TryStatement = 236, - DebuggerStatement = 237, - VariableDeclaration = 238, - VariableDeclarationList = 239, - FunctionDeclaration = 240, - ClassDeclaration = 241, - InterfaceDeclaration = 242, - TypeAliasDeclaration = 243, - EnumDeclaration = 244, - ModuleDeclaration = 245, - ModuleBlock = 246, - CaseBlock = 247, - NamespaceExportDeclaration = 248, - ImportEqualsDeclaration = 249, - ImportDeclaration = 250, - ImportClause = 251, - NamespaceImport = 252, - NamedImports = 253, - ImportSpecifier = 254, - ExportAssignment = 255, - ExportDeclaration = 256, - NamedExports = 257, - ExportSpecifier = 258, - MissingDeclaration = 259, - ExternalModuleReference = 260, - JsxElement = 261, - JsxSelfClosingElement = 262, - JsxOpeningElement = 263, - JsxClosingElement = 264, - JsxFragment = 265, - JsxOpeningFragment = 266, - JsxClosingFragment = 267, - JsxAttribute = 268, - JsxAttributes = 269, - JsxSpreadAttribute = 270, - JsxExpression = 271, - CaseClause = 272, - DefaultClause = 273, - HeritageClause = 274, - CatchClause = 275, - PropertyAssignment = 276, - ShorthandPropertyAssignment = 277, - SpreadAssignment = 278, - EnumMember = 279, - UnparsedPrologue = 280, - UnparsedPrepend = 281, - UnparsedText = 282, - UnparsedInternalText = 283, - UnparsedSyntheticReference = 284, - SourceFile = 285, - Bundle = 286, - UnparsedSource = 287, - InputFiles = 288, - JSDocTypeExpression = 289, - JSDocAllType = 290, - JSDocUnknownType = 291, - JSDocNullableType = 292, - JSDocNonNullableType = 293, - JSDocOptionalType = 294, - JSDocFunctionType = 295, - JSDocVariadicType = 296, - JSDocComment = 297, - JSDocTypeLiteral = 298, - JSDocSignature = 299, - JSDocTag = 300, - JSDocAugmentsTag = 301, - JSDocAuthorTag = 302, - JSDocClassTag = 303, - JSDocCallbackTag = 304, - JSDocEnumTag = 305, - JSDocParameterTag = 306, - JSDocReturnTag = 307, - JSDocThisTag = 308, - JSDocTypeTag = 309, - JSDocTemplateTag = 310, - JSDocTypedefTag = 311, - JSDocPropertyTag = 312, - SyntaxList = 313, - NotEmittedStatement = 314, - PartiallyEmittedExpression = 315, - CommaListExpression = 316, - MergeDeclarationMarker = 317, - EndOfDeclarationMarker = 318, - Count = 319, + AssertsKeyword = 121, + AnyKeyword = 122, + AsyncKeyword = 123, + AwaitKeyword = 124, + BooleanKeyword = 125, + ConstructorKeyword = 126, + DeclareKeyword = 127, + GetKeyword = 128, + InferKeyword = 129, + IsKeyword = 130, + KeyOfKeyword = 131, + ModuleKeyword = 132, + NamespaceKeyword = 133, + NeverKeyword = 134, + ReadonlyKeyword = 135, + RequireKeyword = 136, + NumberKeyword = 137, + ObjectKeyword = 138, + SetKeyword = 139, + StringKeyword = 140, + SymbolKeyword = 141, + TypeKeyword = 142, + UndefinedKeyword = 143, + UniqueKeyword = 144, + UnknownKeyword = 145, + FromKeyword = 146, + GlobalKeyword = 147, + BigIntKeyword = 148, + OfKeyword = 149, + QualifiedName = 150, + ComputedPropertyName = 151, + TypeParameter = 152, + Parameter = 153, + Decorator = 154, + PropertySignature = 155, + PropertyDeclaration = 156, + MethodSignature = 157, + MethodDeclaration = 158, + Constructor = 159, + GetAccessor = 160, + SetAccessor = 161, + CallSignature = 162, + ConstructSignature = 163, + IndexSignature = 164, + TypePredicate = 165, + TypeReference = 166, + FunctionType = 167, + ConstructorType = 168, + TypeQuery = 169, + TypeLiteral = 170, + ArrayType = 171, + TupleType = 172, + OptionalType = 173, + RestType = 174, + UnionType = 175, + IntersectionType = 176, + ConditionalType = 177, + InferType = 178, + ParenthesizedType = 179, + ThisType = 180, + TypeOperator = 181, + IndexedAccessType = 182, + MappedType = 183, + LiteralType = 184, + ImportType = 185, + ObjectBindingPattern = 186, + ArrayBindingPattern = 187, + BindingElement = 188, + ArrayLiteralExpression = 189, + ObjectLiteralExpression = 190, + PropertyAccessExpression = 191, + ElementAccessExpression = 192, + CallExpression = 193, + NewExpression = 194, + TaggedTemplateExpression = 195, + TypeAssertionExpression = 196, + ParenthesizedExpression = 197, + FunctionExpression = 198, + ArrowFunction = 199, + DeleteExpression = 200, + TypeOfExpression = 201, + VoidExpression = 202, + AwaitExpression = 203, + PrefixUnaryExpression = 204, + PostfixUnaryExpression = 205, + BinaryExpression = 206, + ConditionalExpression = 207, + TemplateExpression = 208, + YieldExpression = 209, + SpreadElement = 210, + ClassExpression = 211, + OmittedExpression = 212, + ExpressionWithTypeArguments = 213, + AsExpression = 214, + NonNullExpression = 215, + MetaProperty = 216, + SyntheticExpression = 217, + TemplateSpan = 218, + SemicolonClassElement = 219, + Block = 220, + VariableStatement = 221, + EmptyStatement = 222, + ExpressionStatement = 223, + IfStatement = 224, + DoStatement = 225, + WhileStatement = 226, + ForStatement = 227, + ForInStatement = 228, + ForOfStatement = 229, + ContinueStatement = 230, + BreakStatement = 231, + ReturnStatement = 232, + WithStatement = 233, + SwitchStatement = 234, + LabeledStatement = 235, + ThrowStatement = 236, + TryStatement = 237, + DebuggerStatement = 238, + VariableDeclaration = 239, + VariableDeclarationList = 240, + FunctionDeclaration = 241, + ClassDeclaration = 242, + InterfaceDeclaration = 243, + TypeAliasDeclaration = 244, + EnumDeclaration = 245, + ModuleDeclaration = 246, + ModuleBlock = 247, + CaseBlock = 248, + NamespaceExportDeclaration = 249, + ImportEqualsDeclaration = 250, + ImportDeclaration = 251, + ImportClause = 252, + NamespaceImport = 253, + NamedImports = 254, + ImportSpecifier = 255, + ExportAssignment = 256, + ExportDeclaration = 257, + NamedExports = 258, + ExportSpecifier = 259, + MissingDeclaration = 260, + ExternalModuleReference = 261, + JsxElement = 262, + JsxSelfClosingElement = 263, + JsxOpeningElement = 264, + JsxClosingElement = 265, + JsxFragment = 266, + JsxOpeningFragment = 267, + JsxClosingFragment = 268, + JsxAttribute = 269, + JsxAttributes = 270, + JsxSpreadAttribute = 271, + JsxExpression = 272, + CaseClause = 273, + DefaultClause = 274, + HeritageClause = 275, + CatchClause = 276, + PropertyAssignment = 277, + ShorthandPropertyAssignment = 278, + SpreadAssignment = 279, + EnumMember = 280, + UnparsedPrologue = 281, + UnparsedPrepend = 282, + UnparsedText = 283, + UnparsedInternalText = 284, + UnparsedSyntheticReference = 285, + SourceFile = 286, + Bundle = 287, + UnparsedSource = 288, + InputFiles = 289, + JSDocTypeExpression = 290, + JSDocAllType = 291, + JSDocUnknownType = 292, + JSDocNullableType = 293, + JSDocNonNullableType = 294, + JSDocOptionalType = 295, + JSDocFunctionType = 296, + JSDocVariadicType = 297, + JSDocComment = 298, + JSDocTypeLiteral = 299, + JSDocSignature = 300, + JSDocTag = 301, + JSDocAugmentsTag = 302, + JSDocAuthorTag = 303, + JSDocClassTag = 304, + JSDocCallbackTag = 305, + JSDocEnumTag = 306, + JSDocParameterTag = 307, + JSDocReturnTag = 308, + JSDocThisTag = 309, + JSDocTypeTag = 310, + JSDocTemplateTag = 311, + JSDocTypedefTag = 312, + JSDocPropertyTag = 313, + SyntaxList = 314, + NotEmittedStatement = 315, + PartiallyEmittedExpression = 316, + CommaListExpression = 317, + MergeDeclarationMarker = 318, + EndOfDeclarationMarker = 319, + Count = 320, FirstAssignment = 60, LastAssignment = 72, FirstCompoundAssignment = 61, @@ -404,15 +405,15 @@ declare namespace ts { FirstReservedWord = 74, LastReservedWord = 109, FirstKeyword = 74, - LastKeyword = 148, + LastKeyword = 149, FirstFutureReservedWord = 110, LastFutureReservedWord = 118, - FirstTypeNode = 164, - LastTypeNode = 184, + FirstTypeNode = 165, + LastTypeNode = 185, FirstPunctuation = 18, LastPunctuation = 72, FirstToken = 0, - LastToken = 148, + LastToken = 149, FirstTriviaToken = 2, LastTriviaToken = 7, FirstLiteralToken = 8, @@ -421,11 +422,11 @@ declare namespace ts { LastTemplateToken = 17, FirstBinaryOperator = 28, LastBinaryOperator = 72, - FirstNode = 149, - FirstJSDocNode = 289, - LastJSDocNode = 312, - FirstJSDocTagNode = 300, - LastJSDocTagNode = 312, + FirstNode = 150, + FirstJSDocNode = 290, + LastJSDocNode = 313, + FirstJSDocTagNode = 301, + LastJSDocTagNode = 313, } export enum NodeFlags { None = 0, @@ -516,6 +517,7 @@ declare namespace ts { export type AwaitKeywordToken = Token; export type PlusToken = Token; export type MinusToken = Token; + export type AssertsToken = Token; export type Modifier = Token | Token | Token | Token | Token | Token | Token | Token | Token | Token | Token; export type ModifiersArray = NodeArray; export interface Identifier extends PrimaryExpression, Declaration { @@ -769,8 +771,9 @@ declare namespace ts { export interface TypePredicateNode extends TypeNode { kind: SyntaxKind.TypePredicate; parent: SignatureDeclaration | JSDocTypeExpression; + assertsModifier?: AssertsToken; parameterName: Identifier | ThisTypeNode; - type: TypeNode; + type?: TypeNode; } export interface TypeQueryNode extends TypeNode { kind: SyntaxKind.TypeQuery; @@ -1661,10 +1664,11 @@ declare namespace ts { FalseCondition = 64, SwitchClause = 128, ArrayMutation = 256, - Referenced = 512, - Shared = 1024, - PreFinally = 2048, - AfterFinally = 4096, + Call = 512, + Referenced = 1024, + Shared = 2048, + PreFinally = 4096, + AfterFinally = 8192, Label = 12, Condition = 96 } @@ -1678,7 +1682,7 @@ declare namespace ts { antecedent: FlowNode; lock: FlowLock; } - export type FlowNode = AfterFinallyFlow | PreFinallyFlow | FlowStart | FlowLabel | FlowAssignment | FlowCondition | FlowSwitchClause | FlowArrayMutation; + export type FlowNode = AfterFinallyFlow | PreFinallyFlow | FlowStart | FlowLabel | FlowAssignment | FlowCall | FlowCondition | FlowSwitchClause | FlowArrayMutation; export interface FlowNodeBase { flags: FlowFlags; id?: number; @@ -1693,6 +1697,10 @@ declare namespace ts { node: Expression | VariableDeclaration | BindingElement; antecedent: FlowNode; } + export interface FlowCall extends FlowNodeBase { + node: CallExpression; + antecedent: FlowNode; + } export interface FlowCondition extends FlowNodeBase { expression: Expression; antecedent: FlowNode; @@ -2080,21 +2088,28 @@ declare namespace ts { } export enum TypePredicateKind { This = 0, - Identifier = 1 + Identifier = 1, + Assertion = 2 } - export interface TypePredicateBase { - kind: TypePredicateKind; + export interface ThisTypePredicate { + kind: TypePredicateKind.This; + parameterName: undefined; + parameterIndex: undefined; type: Type; } - export interface ThisTypePredicate extends TypePredicateBase { - kind: TypePredicateKind.This; - } - export interface IdentifierTypePredicate extends TypePredicateBase { + export interface IdentifierTypePredicate { kind: TypePredicateKind.Identifier; parameterName: string; parameterIndex: number; + type: Type; } - export type TypePredicate = IdentifierTypePredicate | ThisTypePredicate; + export interface AssertionTypePredicate { + kind: TypePredicateKind.Assertion; + parameterName: string; + parameterIndex: number; + type: Type | undefined; + } + export type TypePredicate = ThisTypePredicate | IdentifierTypePredicate | AssertionTypePredicate; export enum SymbolFlags { None = 0, FunctionScopedVariable = 1, @@ -3823,8 +3838,8 @@ declare namespace ts { function createIndexSignature(decorators: ReadonlyArray | undefined, modifiers: ReadonlyArray | undefined, parameters: ReadonlyArray, type: TypeNode): IndexSignatureDeclaration; function updateIndexSignature(node: IndexSignatureDeclaration, decorators: ReadonlyArray | undefined, modifiers: ReadonlyArray | undefined, parameters: ReadonlyArray, type: TypeNode): IndexSignatureDeclaration; function createKeywordTypeNode(kind: KeywordTypeNode["kind"]): KeywordTypeNode; - function createTypePredicateNode(parameterName: Identifier | ThisTypeNode | string, type: TypeNode): TypePredicateNode; - function updateTypePredicateNode(node: TypePredicateNode, parameterName: Identifier | ThisTypeNode, type: TypeNode): TypePredicateNode; + function createTypePredicateNode(assertsModifier: AssertsToken | undefined, parameterName: Identifier | ThisTypeNode | string, type: TypeNode | undefined): TypePredicateNode; + function updateTypePredicateNode(node: TypePredicateNode, assertsModifier: AssertsToken | undefined, parameterName: Identifier | ThisTypeNode, type: TypeNode | undefined): TypePredicateNode; function createTypeReferenceNode(typeName: string | EntityName, typeArguments: ReadonlyArray | undefined): TypeReferenceNode; function updateTypeReferenceNode(node: TypeReferenceNode, typeName: EntityName, typeArguments: NodeArray | undefined): TypeReferenceNode; function createFunctionTypeNode(typeParameters: ReadonlyArray | undefined, parameters: ReadonlyArray, type: TypeNode | undefined): FunctionTypeNode; From 1c55e5de69c581da19184c1b9bfa08c800d1bb7c Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 5 Aug 2019 08:27:54 +0200 Subject: [PATCH 025/140] Address code review feedback --- src/compiler/binder.ts | 3 ++- src/compiler/checker.ts | 22 ++++++++++++---------- src/compiler/parser.ts | 5 ++--- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 2b917bc577c..e48943d3c83 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1285,7 +1285,8 @@ namespace ts { } function isDottedName(node: Expression): boolean { - return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.PropertyAccessExpression && isDottedName((node).expression); + return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.ThisKeyword || + node.kind === SyntaxKind.PropertyAccessExpression && isDottedName((node).expression); } function bindExpressionStatement(node: ExpressionStatement): void { diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7dfb0cd2757..66aa107c561 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16838,16 +16838,18 @@ namespace ts { // that reference function, method, class or value module symbols; or variable, property or // parameter symbols with declarations that have explicit type annotations. Such references are // resolvable with no possibility of triggering circularities in control flow analysis. - if (node.kind === SyntaxKind.Identifier) { - const symbol = getResolvedSymbol(node); - return getExplicitTypeOfSymbol(symbol.flags & SymbolFlags.Alias ? resolveAlias(symbol) : symbol); - } - if (node.kind === SyntaxKind.PropertyAccessExpression) { - const type = getTypeOfDottedName((node).expression); - if (type) { - const prop = getPropertyOfType(type, (node).name.escapedText); - return prop && getExplicitTypeOfSymbol(prop); - } + switch (node.kind) { + case SyntaxKind.Identifier: + const symbol = getResolvedSymbol(node); + return getExplicitTypeOfSymbol(symbol.flags & SymbolFlags.Alias ? resolveAlias(symbol) : symbol); + case SyntaxKind.ThisKeyword: + return checkThisExpression(node); + case SyntaxKind.PropertyAccessExpression: + const type = getTypeOfDottedName((node).expression); + if (type) { + const prop = getPropertyOfType(type, (node).name.escapedText); + return prop && getExplicitTypeOfSymbol(prop); + } } } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 3e0ea65476a..6dc0235a7d0 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3211,6 +3211,7 @@ namespace ts { const type = parseType(); if (typePredicateVariable) { const node = createNode(SyntaxKind.TypePredicate, typePredicateVariable.pos); + node.assertsModifier = undefined; node.parameterName = typePredicateVariable; node.type = type; return finishNode(node); @@ -3232,9 +3233,7 @@ namespace ts { const node = createNode(SyntaxKind.TypePredicate); node.assertsModifier = parseExpectedToken(SyntaxKind.AssertsKeyword); node.parameterName = parseIdentifier(); - if (parseOptional(SyntaxKind.IsKeyword)) { - node.type = parseType(); - } + node.type = parseOptional(SyntaxKind.IsKeyword) ? parseType() : undefined; return finishNode(node); } From df02ad6e59b0f3388f6644688303b4419f6e771a Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 8 Aug 2019 10:48:45 +0200 Subject: [PATCH 026/140] Reflect control flow effects of calls to never-returning functions --- src/compiler/binder.ts | 2 +- src/compiler/checker.ts | 76 ++++++++++++++++++++--------------------- src/compiler/types.ts | 2 +- 3 files changed, 39 insertions(+), 41 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index e48943d3c83..8e004b125ab 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1295,7 +1295,7 @@ namespace ts { // is potentially an assertion and is therefore included in the control flow. if (node.expression.kind === SyntaxKind.CallExpression) { const call = node.expression; - if (isDottedName(call.expression) && call.arguments.length >= 1) { + if (isDottedName(call.expression)) { currentFlow = createFlowCall(currentFlow, call); } } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 66aa107c561..01de800c7c8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16853,31 +16853,23 @@ namespace ts { } } - function getTypePredicateForCall(node: CallExpression) { + function isCallWithEffects(node: CallExpression) { const links = getNodeLinks(node); - if (links.resolvedTypePredicate === undefined) { - links.resolvedTypePredicate = computeTypePredicateForCall(node) || noTypePredicate; + if (links.isCallWithEffects === undefined) { + // A call expression parented by an expression statement is a potential assertion. Other call + // expressions are potential type predicate function calls. + const funcType = node.parent.kind === SyntaxKind.ExpressionStatement ? getTypeOfDottedName(node.expression) : + node.expression.kind !== SyntaxKind.SuperKeyword ? checkNonNullExpression(node.expression) : + undefined; + const apparentType = funcType && getApparentType(funcType) || unknownType; + links.isCallWithEffects = some(getSignaturesOfType(apparentType, SignatureKind.Call), hasTypePredicateOrNeverReturnType); } - return links.resolvedTypePredicate === noTypePredicate ? undefined : links.resolvedTypePredicate; + return links.isCallWithEffects; } - function computeTypePredicateForCall(node: CallExpression) { - // A call expression parented by an expression statement is a potential assertion. Other call - // expressions are potential type predicate function calls. - const funcType = node.parent.kind === SyntaxKind.ExpressionStatement ? getTypeOfDottedName(node.expression) : - node.expression.kind !== SyntaxKind.SuperKeyword ? checkNonNullExpression(node.expression) : - undefined; - if (funcType && funcType !== silentNeverType) { - const apparentType = getApparentType(funcType); - if (some(getSignaturesOfType(apparentType, SignatureKind.Call), hasTypePredicate)) { - return getTypePredicateOfSignature(getResolvedSignature(node)); - } - } - return undefined; - } - - function hasTypePredicate(signature: Signature) { - return !!getTypePredicateOfSignature(signature); + function hasTypePredicateOrNeverReturnType(signature: Signature) { + return !!(getTypePredicateOfSignature(signature) || + signature.declaration && (getReturnTypeFromAnnotation(signature.declaration) || unknownType).flags & TypeFlags.Never); } function reportFlowControlError(node: Node) { @@ -17094,14 +17086,20 @@ namespace ts { } function getTypeAtFlowCall(flow: FlowCall): FlowType | undefined { - const predicate = getTypePredicateForCall(flow.node); - if (predicate && predicate.kind === TypePredicateKind.Assertion) { - const flowType = getTypeAtFlowNode(flow.antecedent); - const type = getTypeFromFlowType(flowType); - const narrowedType = predicate.type ? - narrowTypeByTypePredicate(type, predicate, flow.node, /*assumeTrue*/ true) : - narrowTypeByAssertion(type, flow.node.arguments[predicate.parameterIndex]); - return narrowedType === type ? flowType : createFlowType(narrowedType, isIncomplete(flowType)); + if (isCallWithEffects(flow.node)) { + const signature = getResolvedSignature(flow.node); + const predicate = getTypePredicateOfSignature(signature); + if (predicate && predicate.kind === TypePredicateKind.Assertion) { + const flowType = getTypeAtFlowNode(flow.antecedent); + const type = getTypeFromFlowType(flowType); + const narrowedType = predicate.type ? + narrowTypeByTypePredicate(type, predicate, flow.node, /*assumeTrue*/ true) : + narrowTypeByAssertion(type, flow.node.arguments[predicate.parameterIndex]); + return narrowedType === type ? flowType : createFlowType(narrowedType, isIncomplete(flowType)); + } + if (getReturnTypeOfSignature(signature).flags & TypeFlags.Never) { + return neverType; + } } return undefined; } @@ -17690,8 +17688,9 @@ namespace ts { } function narrowTypeByCallExpression(type: Type, callExpression: CallExpression, assumeTrue: boolean): Type { - if (hasMatchingArgument(callExpression, reference)) { - const predicate = getTypePredicateForCall(callExpression); + if (hasMatchingArgument(callExpression, reference) && isCallWithEffects(callExpression)) { + const signature = getResolvedSignature(callExpression); + const predicate = getTypePredicateOfSignature(signature); if (predicate && predicate.kind !== TypePredicateKind.Assertion) { return narrowTypeByTypePredicate(type, predicate, callExpression, assumeTrue); } @@ -23652,15 +23651,14 @@ namespace ts { return eachTypeContainedIn(mapType(type, getRegularTypeOfLiteralType), switchTypes); } - function functionHasImplicitReturn(func: FunctionLikeDeclaration) { - if (!(func.flags & NodeFlags.HasImplicitReturn)) { - return false; - } + function isNeverFunctionCall(expr: Expression) { + return expr.kind === SyntaxKind.CallExpression && isCallWithEffects(expr) && !!(getTypeOfExpression(expr).flags & TypeFlags.Never); + } - if (some((func.body).statements, statement => statement.kind === SyntaxKind.SwitchStatement && isExhaustiveSwitchStatement(statement))) { - return false; - } - return true; + function functionHasImplicitReturn(func: FunctionLikeDeclaration) { + return !!(func.flags & NodeFlags.HasImplicitReturn) && !some((func.body).statements, statement => + statement.kind === SyntaxKind.SwitchStatement && isExhaustiveSwitchStatement(statement) || + statement.kind === SyntaxKind.ExpressionStatement && isNeverFunctionCall((statement).expression)); } /** NOTE: Return value of `[]` means a different thing than `undefined`. `[]` means func returns `void`, `undefined` means it returns `never`. */ diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 3cdfba2aafb..6b757736cc5 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3918,7 +3918,7 @@ namespace ts { resolvedSignature?: Signature; // Cached signature of signature node or call expression resolvedSymbol?: Symbol; // Cached name resolution result resolvedIndexInfo?: IndexInfo; // Cached indexing info resolution result - resolvedTypePredicate?: TypePredicate; // Cached type predicate for call expression + isCallWithEffects?: boolean; // Is call expression with possible control flow effects? enumMemberValue?: string | number; // Constant value of enum member isVisible?: boolean; // Is this node visible containsArgumentsReference?: boolean; // Whether a function-like declaration contains an 'arguments' reference From 99ab53edcd01fd217f575e805fd16ecf6c0ba7f9 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 9 Aug 2019 10:15:47 +0200 Subject: [PATCH 027/140] Make flow nodes more monomorphic --- src/compiler/binder.ts | 50 ++++++++++++++++++++++++----------------- src/compiler/checker.ts | 4 ++-- src/compiler/types.ts | 29 +++++++++++++++--------- 3 files changed, 50 insertions(+), 33 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 8e004b125ab..b4ccdf488b1 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -148,8 +148,8 @@ namespace ts { let Symbol: new (flags: SymbolFlags, name: __String) => Symbol; // tslint:disable-line variable-name let classifiableNames: UnderscoreEscapedMap; - const unreachableFlow: FlowNode = { flags: FlowFlags.Unreachable }; - const reportedUnreachableFlow: FlowNode = { flags: FlowFlags.Unreachable }; + const unreachableFlow = createFlowNode(FlowFlags.Unreachable, /*antecedent*/ undefined, /*node*/ undefined); + const reportedUnreachableFlow: FlowNode = createFlowNode(FlowFlags.Unreachable, /*antecedent*/ undefined, /*node*/ undefined); // state used to aggregate transform flags during bind. let subtreeTransformFlags: TransformFlags = TransformFlags.None; @@ -560,9 +560,9 @@ namespace ts { // A non-async, non-generator IIFE is considered part of the containing control flow. Return statements behave // similarly to break statements that exit to a label just past the statement body. if (!isIIFE) { - currentFlow = { flags: FlowFlags.Start }; + currentFlow = createFlowNode(FlowFlags.Start, /*antecedent*/ undefined, /*node*/ undefined) as FlowStart; if (containerFlags & (ContainerFlags.IsFunctionExpression | ContainerFlags.IsObjectLiteralOrClassExpressionMethod)) { - currentFlow.container = node; + currentFlow.node = node; } } // We create a return control flow graph for IIFEs and constructors. For constructors @@ -842,18 +842,22 @@ namespace ts { return isNarrowableReference(expr); } - function createBranchLabel(): FlowLabel { + function createFlowNode(flags: FlowFlags, antecedent: FlowNode | undefined, node: Node | undefined) { return { - flags: FlowFlags.BranchLabel, - antecedents: undefined - }; + flags, + antecedent, + node, + id: undefined, + antecedents: undefined, + } as FlowNode; + } + + function createBranchLabel(): FlowLabel { + return createFlowNode(FlowFlags.BranchLabel, /*antecedent*/ undefined, /*node*/ undefined) as FlowLabel; } function createLoopLabel(): FlowLabel { - return { - flags: FlowFlags.LoopLabel, - antecedents: undefined - }; + return createFlowNode(FlowFlags.LoopLabel, /*antecedent*/ undefined, /*node*/ undefined) as FlowLabel; } function setFlowNodeReferenced(flow: FlowNode) { @@ -883,7 +887,7 @@ namespace ts { return antecedent; } setFlowNodeReferenced(antecedent); - return flowNodeCreated({ flags, expression, antecedent }); + return flowNodeCreated(createFlowNode(flags, antecedent, expression)); } function createFlowSwitchClause(antecedent: FlowNode, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): FlowNode { @@ -891,23 +895,26 @@ namespace ts { return antecedent; } setFlowNodeReferenced(antecedent); - return flowNodeCreated({ flags: FlowFlags.SwitchClause, switchStatement, clauseStart, clauseEnd, antecedent }); + const result = createFlowNode(FlowFlags.SwitchClause, antecedent, /*node*/ undefined) as FlowSwitchClause; + result.switchStatement = switchStatement; + result.clauseStart = clauseStart; + result.clauseEnd = clauseEnd; + return flowNodeCreated(result); } function createFlowAssignment(antecedent: FlowNode, node: Expression | VariableDeclaration | BindingElement): FlowNode { setFlowNodeReferenced(antecedent); - return flowNodeCreated({ flags: FlowFlags.Assignment, antecedent, node }); + return flowNodeCreated(createFlowNode(FlowFlags.Assignment, antecedent, node)); } function createFlowCall(antecedent: FlowNode, node: CallExpression): FlowNode { setFlowNodeReferenced(antecedent); - return flowNodeCreated({ flags: FlowFlags.Call, antecedent, node }); + return flowNodeCreated(createFlowNode(FlowFlags.Call, antecedent, node)); } function createFlowArrayMutation(antecedent: FlowNode, node: CallExpression | BinaryExpression): FlowNode { setFlowNodeReferenced(antecedent); - const res: FlowArrayMutation = flowNodeCreated({ flags: FlowFlags.ArrayMutation, antecedent, node }); - return res; + return flowNodeCreated(createFlowNode(FlowFlags.ArrayMutation, antecedent, node)); } function finishFlowLabel(flow: FlowLabel): FlowNode { @@ -1185,7 +1192,8 @@ namespace ts { // // extra edges that we inject allows to control this behavior // if when walking the flow we step on post-finally edge - we can mark matching pre-finally edge as locked so it will be skipped. - const preFinallyFlow: PreFinallyFlow = { flags: FlowFlags.PreFinally, antecedent: preFinallyPrior, lock: {} }; + const preFinallyFlow = createFlowNode(FlowFlags.PreFinally, preFinallyPrior, /*node*/ undefined) as PreFinallyFlow; + preFinallyFlow.lock = {}; addAntecedent(preFinallyLabel, preFinallyFlow); currentFlow = finishFlowLabel(preFinallyLabel); @@ -1204,7 +1212,7 @@ namespace ts { } } if (!(currentFlow.flags & FlowFlags.Unreachable)) { - const afterFinallyFlow: AfterFinallyFlow = flowNodeCreated({ flags: FlowFlags.AfterFinally, antecedent: currentFlow }); + const afterFinallyFlow = flowNodeCreated(createFlowNode(FlowFlags.AfterFinally, currentFlow, /*node*/ undefined) as AfterFinallyFlow); preFinallyFlow.lock = afterFinallyFlow; currentFlow = afterFinallyFlow; } @@ -1828,7 +1836,7 @@ namespace ts { const host = getJSDocHost(typeAlias); container = findAncestor(host.parent, n => !!(getContainerFlags(n) & ContainerFlags.IsContainer)) || file; blockScopeContainer = getEnclosingBlockScopeContainer(host) || file; - currentFlow = { flags: FlowFlags.Start }; + currentFlow = createFlowNode(FlowFlags.Start, /*antecedent*/ undefined, /*node*/ undefined); parent = typeAlias; bind(typeAlias.typeExpression); if (isJSDocEnumTag(typeAlias) || !typeAlias.fullName || typeAlias.fullName.kind === SyntaxKind.Identifier) { diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 01de800c7c8..491dc35a2b2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17001,7 +17001,7 @@ namespace ts { } else if (flags & FlowFlags.Start) { // Check if we should continue with the control flow of the containing function. - const container = (flow).container; + const container = (flow).node; if (container && container !== flowContainer && reference.kind !== SyntaxKind.PropertyAccessExpression && reference.kind !== SyntaxKind.ElementAccessExpression && @@ -17150,7 +17150,7 @@ namespace ts { // *only* place a silent never type is ever generated. const assumeTrue = (flow.flags & FlowFlags.TrueCondition) !== 0; const nonEvolvingType = finalizeEvolvingArrayType(type); - const narrowedType = narrowType(nonEvolvingType, flow.expression, assumeTrue); + const narrowedType = narrowType(nonEvolvingType, flow.node, assumeTrue); if (narrowedType === nonEvolvingType) { return flowType; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 6b757736cc5..96a054e841b 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2565,6 +2565,22 @@ namespace ts { Condition = TrueCondition | FalseCondition } + export type FlowNode = + | AfterFinallyFlow + | PreFinallyFlow + | FlowStart + | FlowLabel + | FlowAssignment + | FlowCall + | FlowCondition + | FlowSwitchClause + | FlowArrayMutation; + + export interface FlowNodeBase { + flags: FlowFlags; + id: number | undefined; // Node id used by flow type cache in checker + } + export interface FlowLock { locked?: boolean; } @@ -2578,18 +2594,11 @@ namespace ts { lock: FlowLock; } - export type FlowNode = - | AfterFinallyFlow | PreFinallyFlow | FlowStart | FlowLabel | FlowAssignment | FlowCall | FlowCondition | FlowSwitchClause | FlowArrayMutation; - export interface FlowNodeBase { - flags: FlowFlags; - id?: number; // Node id used by flow type cache in checker - } - // FlowStart represents the start of a control flow. For a function expression or arrow - // function, the container property references the function (which in turn has a flowNode + // function, the node property references the function (which in turn has a flowNode // property for the containing control flow). export interface FlowStart extends FlowNodeBase { - container?: FunctionExpression | ArrowFunction | MethodDeclaration; + node?: FunctionExpression | ArrowFunction | MethodDeclaration; } // FlowLabel represents a junction with multiple possible preceding control flows. @@ -2612,7 +2621,7 @@ namespace ts { // FlowCondition represents a condition that is known to be true or false at the // node's location in the control flow. export interface FlowCondition extends FlowNodeBase { - expression: Expression; + node: Expression; antecedent: FlowNode; } From d5e08d485d783537c4bbdc5d72425763656cba5d Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 9 Aug 2019 10:16:16 +0200 Subject: [PATCH 028/140] Accept baseline API changes --- tests/baselines/reference/api/tsserverlibrary.d.ts | 14 +++++++------- tests/baselines/reference/api/typescript.d.ts | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 00c88fc4963..c1a271bb0af 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -1672,6 +1672,11 @@ declare namespace ts { Label = 12, Condition = 96 } + export type FlowNode = AfterFinallyFlow | PreFinallyFlow | FlowStart | FlowLabel | FlowAssignment | FlowCall | FlowCondition | FlowSwitchClause | FlowArrayMutation; + export interface FlowNodeBase { + flags: FlowFlags; + id: number | undefined; + } export interface FlowLock { locked?: boolean; } @@ -1682,13 +1687,8 @@ declare namespace ts { antecedent: FlowNode; lock: FlowLock; } - export type FlowNode = AfterFinallyFlow | PreFinallyFlow | FlowStart | FlowLabel | FlowAssignment | FlowCall | FlowCondition | FlowSwitchClause | FlowArrayMutation; - export interface FlowNodeBase { - flags: FlowFlags; - id?: number; - } export interface FlowStart extends FlowNodeBase { - container?: FunctionExpression | ArrowFunction | MethodDeclaration; + node?: FunctionExpression | ArrowFunction | MethodDeclaration; } export interface FlowLabel extends FlowNodeBase { antecedents: FlowNode[] | undefined; @@ -1702,7 +1702,7 @@ declare namespace ts { antecedent: FlowNode; } export interface FlowCondition extends FlowNodeBase { - expression: Expression; + node: Expression; antecedent: FlowNode; } export interface FlowSwitchClause extends FlowNodeBase { diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index df8d0e1ee79..0bb7d724ee0 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -1672,6 +1672,11 @@ declare namespace ts { Label = 12, Condition = 96 } + export type FlowNode = AfterFinallyFlow | PreFinallyFlow | FlowStart | FlowLabel | FlowAssignment | FlowCall | FlowCondition | FlowSwitchClause | FlowArrayMutation; + export interface FlowNodeBase { + flags: FlowFlags; + id: number | undefined; + } export interface FlowLock { locked?: boolean; } @@ -1682,13 +1687,8 @@ declare namespace ts { antecedent: FlowNode; lock: FlowLock; } - export type FlowNode = AfterFinallyFlow | PreFinallyFlow | FlowStart | FlowLabel | FlowAssignment | FlowCall | FlowCondition | FlowSwitchClause | FlowArrayMutation; - export interface FlowNodeBase { - flags: FlowFlags; - id?: number; - } export interface FlowStart extends FlowNodeBase { - container?: FunctionExpression | ArrowFunction | MethodDeclaration; + node?: FunctionExpression | ArrowFunction | MethodDeclaration; } export interface FlowLabel extends FlowNodeBase { antecedents: FlowNode[] | undefined; @@ -1702,7 +1702,7 @@ declare namespace ts { antecedent: FlowNode; } export interface FlowCondition extends FlowNodeBase { - expression: Expression; + node: Expression; antecedent: FlowNode; } export interface FlowSwitchClause extends FlowNodeBase { From 19f1d3ba0a8c0f85a99a770d3a344161b911d934 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 9 Aug 2019 12:35:28 +0200 Subject: [PATCH 029/140] Less aggressive monomorphism for flow nodes --- src/compiler/binder.ts | 41 +++++++++++++---------------------------- src/compiler/types.ts | 2 +- 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index b4ccdf488b1..19dd6bee232 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -148,8 +148,8 @@ namespace ts { let Symbol: new (flags: SymbolFlags, name: __String) => Symbol; // tslint:disable-line variable-name let classifiableNames: UnderscoreEscapedMap; - const unreachableFlow = createFlowNode(FlowFlags.Unreachable, /*antecedent*/ undefined, /*node*/ undefined); - const reportedUnreachableFlow: FlowNode = createFlowNode(FlowFlags.Unreachable, /*antecedent*/ undefined, /*node*/ undefined); + const unreachableFlow: FlowNode = { flags: FlowFlags.Unreachable }; + const reportedUnreachableFlow: FlowNode = { flags: FlowFlags.Unreachable }; // state used to aggregate transform flags during bind. let subtreeTransformFlags: TransformFlags = TransformFlags.None; @@ -560,7 +560,7 @@ namespace ts { // A non-async, non-generator IIFE is considered part of the containing control flow. Return statements behave // similarly to break statements that exit to a label just past the statement body. if (!isIIFE) { - currentFlow = createFlowNode(FlowFlags.Start, /*antecedent*/ undefined, /*node*/ undefined) as FlowStart; + currentFlow = { flags: FlowFlags.Start }; if (containerFlags & (ContainerFlags.IsFunctionExpression | ContainerFlags.IsObjectLiteralOrClassExpressionMethod)) { currentFlow.node = node; } @@ -842,22 +842,12 @@ namespace ts { return isNarrowableReference(expr); } - function createFlowNode(flags: FlowFlags, antecedent: FlowNode | undefined, node: Node | undefined) { - return { - flags, - antecedent, - node, - id: undefined, - antecedents: undefined, - } as FlowNode; - } - function createBranchLabel(): FlowLabel { - return createFlowNode(FlowFlags.BranchLabel, /*antecedent*/ undefined, /*node*/ undefined) as FlowLabel; + return { flags: FlowFlags.BranchLabel, antecedents: undefined }; } function createLoopLabel(): FlowLabel { - return createFlowNode(FlowFlags.LoopLabel, /*antecedent*/ undefined, /*node*/ undefined) as FlowLabel; + return { flags: FlowFlags.LoopLabel, antecedents: undefined }; } function setFlowNodeReferenced(flow: FlowNode) { @@ -887,7 +877,7 @@ namespace ts { return antecedent; } setFlowNodeReferenced(antecedent); - return flowNodeCreated(createFlowNode(flags, antecedent, expression)); + return flowNodeCreated({ flags, antecedent, node: expression }); } function createFlowSwitchClause(antecedent: FlowNode, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): FlowNode { @@ -895,26 +885,22 @@ namespace ts { return antecedent; } setFlowNodeReferenced(antecedent); - const result = createFlowNode(FlowFlags.SwitchClause, antecedent, /*node*/ undefined) as FlowSwitchClause; - result.switchStatement = switchStatement; - result.clauseStart = clauseStart; - result.clauseEnd = clauseEnd; - return flowNodeCreated(result); + return flowNodeCreated({ flags: FlowFlags.SwitchClause, antecedent, switchStatement, clauseStart, clauseEnd }); } function createFlowAssignment(antecedent: FlowNode, node: Expression | VariableDeclaration | BindingElement): FlowNode { setFlowNodeReferenced(antecedent); - return flowNodeCreated(createFlowNode(FlowFlags.Assignment, antecedent, node)); + return flowNodeCreated({ flags: FlowFlags.Assignment, antecedent, node }); } function createFlowCall(antecedent: FlowNode, node: CallExpression): FlowNode { setFlowNodeReferenced(antecedent); - return flowNodeCreated(createFlowNode(FlowFlags.Call, antecedent, node)); + return flowNodeCreated({ flags: FlowFlags.Call, antecedent, node }); } function createFlowArrayMutation(antecedent: FlowNode, node: CallExpression | BinaryExpression): FlowNode { setFlowNodeReferenced(antecedent); - return flowNodeCreated(createFlowNode(FlowFlags.ArrayMutation, antecedent, node)); + return flowNodeCreated({ flags: FlowFlags.ArrayMutation, antecedent, node }); } function finishFlowLabel(flow: FlowLabel): FlowNode { @@ -1192,8 +1178,7 @@ namespace ts { // // extra edges that we inject allows to control this behavior // if when walking the flow we step on post-finally edge - we can mark matching pre-finally edge as locked so it will be skipped. - const preFinallyFlow = createFlowNode(FlowFlags.PreFinally, preFinallyPrior, /*node*/ undefined) as PreFinallyFlow; - preFinallyFlow.lock = {}; + const preFinallyFlow: PreFinallyFlow = { flags: FlowFlags.PreFinally, antecedent: preFinallyPrior, lock: {} }; addAntecedent(preFinallyLabel, preFinallyFlow); currentFlow = finishFlowLabel(preFinallyLabel); @@ -1212,7 +1197,7 @@ namespace ts { } } if (!(currentFlow.flags & FlowFlags.Unreachable)) { - const afterFinallyFlow = flowNodeCreated(createFlowNode(FlowFlags.AfterFinally, currentFlow, /*node*/ undefined) as AfterFinallyFlow); + const afterFinallyFlow: AfterFinallyFlow = flowNodeCreated({ flags: FlowFlags.AfterFinally, antecedent: currentFlow }); preFinallyFlow.lock = afterFinallyFlow; currentFlow = afterFinallyFlow; } @@ -1836,7 +1821,7 @@ namespace ts { const host = getJSDocHost(typeAlias); container = findAncestor(host.parent, n => !!(getContainerFlags(n) & ContainerFlags.IsContainer)) || file; blockScopeContainer = getEnclosingBlockScopeContainer(host) || file; - currentFlow = createFlowNode(FlowFlags.Start, /*antecedent*/ undefined, /*node*/ undefined); + currentFlow = { flags: FlowFlags.Start }; parent = typeAlias; bind(typeAlias.typeExpression); if (isJSDocEnumTag(typeAlias) || !typeAlias.fullName || typeAlias.fullName.kind === SyntaxKind.Identifier) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 96a054e841b..2702f2c5249 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2578,7 +2578,7 @@ namespace ts { export interface FlowNodeBase { flags: FlowFlags; - id: number | undefined; // Node id used by flow type cache in checker + id?: number; // Node id used by flow type cache in checker } export interface FlowLock { From 83212e72407967c194762e2a2e097e2dc2076007 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 9 Aug 2019 12:35:48 +0200 Subject: [PATCH 030/140] Accept API baseline changes --- tests/baselines/reference/api/tsserverlibrary.d.ts | 2 +- tests/baselines/reference/api/typescript.d.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index c1a271bb0af..2579518fe17 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -1675,7 +1675,7 @@ declare namespace ts { export type FlowNode = AfterFinallyFlow | PreFinallyFlow | FlowStart | FlowLabel | FlowAssignment | FlowCall | FlowCondition | FlowSwitchClause | FlowArrayMutation; export interface FlowNodeBase { flags: FlowFlags; - id: number | undefined; + id?: number; } export interface FlowLock { locked?: boolean; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 0bb7d724ee0..4417b52af36 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -1675,7 +1675,7 @@ declare namespace ts { export type FlowNode = AfterFinallyFlow | PreFinallyFlow | FlowStart | FlowLabel | FlowAssignment | FlowCall | FlowCondition | FlowSwitchClause | FlowArrayMutation; export interface FlowNodeBase { flags: FlowFlags; - id: number | undefined; + id?: number; } export interface FlowLock { locked?: boolean; From cdeddf14e9a112e64403eecb09257ac51023467f Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 10 Aug 2019 08:38:18 +0200 Subject: [PATCH 031/140] Call getResolvedSignature only when needed for generics or overloads --- src/compiler/checker.ts | 27 ++++++++++++++++----------- src/compiler/types.ts | 2 +- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 71493cbe634..b2bc96fa9cd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16877,18 +16877,22 @@ namespace ts { } } - function isCallWithEffects(node: CallExpression) { + function getEffectsSignature(node: CallExpression) { const links = getNodeLinks(node); - if (links.isCallWithEffects === undefined) { + let signature = links.effectsSignature; + if (signature === undefined) { // A call expression parented by an expression statement is a potential assertion. Other call // expressions are potential type predicate function calls. const funcType = node.parent.kind === SyntaxKind.ExpressionStatement ? getTypeOfDottedName(node.expression) : node.expression.kind !== SyntaxKind.SuperKeyword ? checkNonNullExpression(node.expression) : undefined; - const apparentType = funcType && getApparentType(funcType) || unknownType; - links.isCallWithEffects = some(getSignaturesOfType(apparentType, SignatureKind.Call), hasTypePredicateOrNeverReturnType); + const signatures = getSignaturesOfType(funcType && getApparentType(funcType) || unknownType, SignatureKind.Call); + const candidate = signatures.length === 1 && !signatures[0].typeParameters ? signatures[0] : + some(signatures, hasTypePredicateOrNeverReturnType) ? getResolvedSignature(node) : + undefined; + signature = links.effectsSignature = candidate && hasTypePredicateOrNeverReturnType(candidate) ? candidate : unknownSignature; } - return links.isCallWithEffects; + return signature === unknownSignature ? undefined : signature; } function hasTypePredicateOrNeverReturnType(signature: Signature) { @@ -17110,8 +17114,8 @@ namespace ts { } function getTypeAtFlowCall(flow: FlowCall): FlowType | undefined { - if (isCallWithEffects(flow.node)) { - const signature = getResolvedSignature(flow.node); + const signature = getEffectsSignature(flow.node); + if (signature) { const predicate = getTypePredicateOfSignature(signature); if (predicate && predicate.kind === TypePredicateKind.Assertion) { const flowType = getTypeAtFlowNode(flow.antecedent); @@ -17712,9 +17716,9 @@ namespace ts { } function narrowTypeByCallExpression(type: Type, callExpression: CallExpression, assumeTrue: boolean): Type { - if (hasMatchingArgument(callExpression, reference) && isCallWithEffects(callExpression)) { - const signature = getResolvedSignature(callExpression); - const predicate = getTypePredicateOfSignature(signature); + if (hasMatchingArgument(callExpression, reference)) { + const signature = getEffectsSignature(callExpression); + const predicate = signature && getTypePredicateOfSignature(signature); if (predicate && predicate.kind !== TypePredicateKind.Assertion) { return narrowTypeByTypePredicate(type, predicate, callExpression, assumeTrue); } @@ -23695,7 +23699,8 @@ namespace ts { } function isNeverFunctionCall(expr: Expression) { - return expr.kind === SyntaxKind.CallExpression && isCallWithEffects(expr) && !!(getTypeOfExpression(expr).flags & TypeFlags.Never); + const signature = expr.kind === SyntaxKind.CallExpression && getEffectsSignature(expr); + return !!(signature && getReturnTypeOfSignature(signature).flags & TypeFlags.Never); } function functionHasImplicitReturn(func: FunctionLikeDeclaration) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 7038b45e24a..9be0bf42db9 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3927,7 +3927,7 @@ namespace ts { resolvedSignature?: Signature; // Cached signature of signature node or call expression resolvedSymbol?: Symbol; // Cached name resolution result resolvedIndexInfo?: IndexInfo; // Cached indexing info resolution result - isCallWithEffects?: boolean; // Is call expression with possible control flow effects? + effectsSignature?: Signature; // Signature with possible control flow effects enumMemberValue?: string | number; // Constant value of enum member isVisible?: boolean; // Is this node visible containsArgumentsReference?: boolean; // Whether a function-like declaration contains an 'arguments' reference From 0599f848575dcfbda5730c446003f4e59411446d Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 17 Aug 2019 06:23:07 -0700 Subject: [PATCH 032/140] Support 'asserts this' and 'asserts this is T' type predicates --- src/compiler/checker.ts | 34 ++++++++++++++++++---------------- src/compiler/parser.ts | 2 +- src/compiler/types.ts | 16 ++++++++++++---- 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 58af0a7134a..c919bb986e4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4228,8 +4228,10 @@ namespace ts { let returnTypeNode: TypeNode | undefined; const typePredicate = getTypePredicateOfSignature(signature); if (typePredicate) { - const assertsModifier = typePredicate.kind === TypePredicateKind.Assertion ? createToken(SyntaxKind.AssertsKeyword) : undefined; - const parameterName = typePredicate.kind !== TypePredicateKind.This ? + const assertsModifier = typePredicate.kind === TypePredicateKind.AssertsThis || typePredicate.kind === TypePredicateKind.AssertsIdentifier ? + createToken(SyntaxKind.AssertsKeyword) : + undefined; + const parameterName = typePredicate.kind === TypePredicateKind.Identifier || typePredicate.kind === TypePredicateKind.AssertsIdentifier ? setEmitFlags(createIdentifier(typePredicate.parameterName), EmitFlags.NoAsciiEscaping) : createThisTypeNode(); const typeNode = typePredicate.type && typeToTypeNodeHelper(typePredicate.type, context); @@ -4702,8 +4704,8 @@ namespace ts { function typePredicateToStringWorker(writer: EmitTextWriter) { const predicate = createTypePredicateNode( - typePredicate.kind === TypePredicateKind.Assertion ? createToken(SyntaxKind.AssertsKeyword) : undefined, - typePredicate.kind !== TypePredicateKind.This ? createIdentifier(typePredicate.parameterName) : createThisTypeNode(), + typePredicate.kind === TypePredicateKind.AssertsThis || typePredicate.kind === TypePredicateKind.AssertsIdentifier ? createToken(SyntaxKind.AssertsKeyword) : undefined, + typePredicate.kind === TypePredicateKind.Identifier || typePredicate.kind === TypePredicateKind.AssertsIdentifier ? createIdentifier(typePredicate.parameterName) : createThisTypeNode(), typePredicate.type && nodeBuilder.typeToTypeNode(typePredicate.type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName)! // TODO: GH#18217 ); const printer = createPrinter({ removeComments: true }); @@ -8721,8 +8723,8 @@ namespace ts { const parameterName = node.parameterName; const type = node.type && getTypeFromTypeNode(node.type); return parameterName.kind === SyntaxKind.ThisType ? - createTypePredicate(TypePredicateKind.This, /*parameterName*/ undefined, /*parameterIndex*/ undefined, type) : - createTypePredicate(node.assertsModifier ? TypePredicateKind.Assertion : TypePredicateKind.Identifier, parameterName.escapedText as string, + createTypePredicate(node.assertsModifier ? TypePredicateKind.AssertsThis : TypePredicateKind.This, /*parameterName*/ undefined, /*parameterIndex*/ undefined, type) : + createTypePredicate(node.assertsModifier ? TypePredicateKind.AssertsIdentifier : TypePredicateKind.Identifier, parameterName.escapedText as string, findIndex(signature.parameters, p => p.escapedName === parameterName.escapedText), type); } @@ -9829,7 +9831,7 @@ namespace ts { const types: Type[] = []; for (const sig of signatures) { const pred = getTypePredicateOfSignature(sig); - if (!pred || pred.kind === TypePredicateKind.Assertion) { + if (!pred || pred.kind === TypePredicateKind.AssertsThis || pred.kind === TypePredicateKind.AssertsIdentifier) { continue; } @@ -12400,7 +12402,7 @@ namespace ts { return Ternary.False; } - if (source.kind !== TypePredicateKind.This) { + if (source.kind === TypePredicateKind.Identifier || source.kind === TypePredicateKind.AssertsIdentifier) { if (source.parameterIndex !== (target as IdentifierTypePredicate).parameterIndex) { if (reportErrors) { errorReporter!(Diagnostics.Parameter_0_is_not_in_the_same_position_as_parameter_1, source.parameterName, (target as IdentifierTypePredicate).parameterName); @@ -17119,12 +17121,12 @@ namespace ts { const signature = getEffectsSignature(flow.node); if (signature) { const predicate = getTypePredicateOfSignature(signature); - if (predicate && predicate.kind === TypePredicateKind.Assertion) { + if (predicate && (predicate.kind === TypePredicateKind.AssertsThis || predicate.kind === TypePredicateKind.AssertsIdentifier)) { const flowType = getTypeAtFlowNode(flow.antecedent); const type = getTypeFromFlowType(flowType); - const narrowedType = predicate.type ? - narrowTypeByTypePredicate(type, predicate, flow.node, /*assumeTrue*/ true) : - narrowTypeByAssertion(type, flow.node.arguments[predicate.parameterIndex]); + const narrowedType = predicate.type ? narrowTypeByTypePredicate(type, predicate, flow.node, /*assumeTrue*/ true) : + predicate.kind === TypePredicateKind.AssertsIdentifier ? narrowTypeByAssertion(type, flow.node.arguments[predicate.parameterIndex]) : + type; return narrowedType === type ? flowType : createFlowType(narrowedType, isIncomplete(flowType)); } if (getReturnTypeOfSignature(signature).flags & TypeFlags.Never) { @@ -17721,7 +17723,7 @@ namespace ts { if (hasMatchingArgument(callExpression, reference)) { const signature = getEffectsSignature(callExpression); const predicate = signature && getTypePredicateOfSignature(signature); - if (predicate && predicate.kind !== TypePredicateKind.Assertion) { + if (predicate && (predicate.kind === TypePredicateKind.This || predicate.kind === TypePredicateKind.Identifier)) { return narrowTypeByTypePredicate(type, predicate, callExpression, assumeTrue); } } @@ -17733,7 +17735,7 @@ namespace ts { if (isTypeAny(type) && (predicate.type === globalObjectType || predicate.type === globalFunctionType)) { return type; } - if (predicate.kind !== TypePredicateKind.This) { + if (predicate.kind === TypePredicateKind.Identifier || predicate.kind === TypePredicateKind.AssertsIdentifier) { const predicateArgument = callExpression.arguments[predicate.parameterIndex]; if (predicateArgument && predicate.type) { if (isMatchingReference(reference, predicateArgument)) { @@ -17746,7 +17748,7 @@ namespace ts { } else { const invokedExpression = skipParentheses(callExpression.expression); - if (isAccessExpression(invokedExpression)) { + if (isAccessExpression(invokedExpression) && predicate.type) { const possibleReference = skipParentheses(invokedExpression.expression); if (isMatchingReference(reference, possibleReference)) { return getNarrowedType(type, predicate.type, assumeTrue, isTypeSubtypeOf); @@ -25501,7 +25503,7 @@ namespace ts { checkSourceElement(node.type); const { parameterName } = node; - if (isThisTypePredicate(typePredicate)) { + if (typePredicate.kind === TypePredicateKind.This || typePredicate.kind === TypePredicateKind.AssertsThis) { getTypeFromThisTypeNode(parameterName as ThisTypeNode); } else { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 3c2b7bd42cc..c1331165327 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3258,7 +3258,7 @@ namespace ts { function parseAssertsTypePredicate(): TypeNode { const node = createNode(SyntaxKind.TypePredicate); node.assertsModifier = parseExpectedToken(SyntaxKind.AssertsKeyword); - node.parameterName = parseIdentifier(); + node.parameterName = token() === SyntaxKind.ThisKeyword ? parseThisTypeNode() : parseIdentifier(); node.type = parseOptional(SyntaxKind.IsKeyword) ? parseType() : undefined; return finishNode(node); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 3b121c76e20..b27de58134a 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3514,7 +3514,8 @@ namespace ts { export const enum TypePredicateKind { This, Identifier, - Assertion + AssertsThis, + AssertsIdentifier } export interface ThisTypePredicate { @@ -3531,14 +3532,21 @@ namespace ts { type: Type; } - export interface AssertionTypePredicate { - kind: TypePredicateKind.Assertion; + export interface AssertsThisTypePredicate { + kind: TypePredicateKind.AssertsThis; + parameterName: undefined; + parameterIndex: undefined; + type: Type | undefined; + } + + export interface AssertsIdentifierTypePredicate { + kind: TypePredicateKind.AssertsIdentifier; parameterName: string; parameterIndex: number; type: Type | undefined; } - export type TypePredicate = ThisTypePredicate | IdentifierTypePredicate | AssertionTypePredicate; + export type TypePredicate = ThisTypePredicate | IdentifierTypePredicate | AssertsThisTypePredicate | AssertsIdentifierTypePredicate; /* @internal */ export type AnyImportSyntax = ImportDeclaration | ImportEqualsDeclaration; From e7cbfc41e5afbaa68bdc30e2865acd3a7b0b44e8 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 17 Aug 2019 07:05:49 -0700 Subject: [PATCH 033/140] Update API to be backwards compatible --- src/compiler/checker.ts | 4 ++-- src/compiler/factory.ts | 17 +++++++++++++---- src/compiler/visitor.ts | 2 +- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c919bb986e4..0af56d7f172 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4235,7 +4235,7 @@ namespace ts { setEmitFlags(createIdentifier(typePredicate.parameterName), EmitFlags.NoAsciiEscaping) : createThisTypeNode(); const typeNode = typePredicate.type && typeToTypeNodeHelper(typePredicate.type, context); - returnTypeNode = createTypePredicateNode(assertsModifier, parameterName, typeNode); + returnTypeNode = createTypePredicateNodeWithModifier(assertsModifier, parameterName, typeNode); } else { const returnType = getReturnTypeOfSignature(signature); @@ -4703,7 +4703,7 @@ namespace ts { return writer ? typePredicateToStringWorker(writer).getText() : usingSingleLineStringWriter(typePredicateToStringWorker); function typePredicateToStringWorker(writer: EmitTextWriter) { - const predicate = createTypePredicateNode( + const predicate = createTypePredicateNodeWithModifier( typePredicate.kind === TypePredicateKind.AssertsThis || typePredicate.kind === TypePredicateKind.AssertsIdentifier ? createToken(SyntaxKind.AssertsKeyword) : undefined, typePredicate.kind === TypePredicateKind.Identifier || typePredicate.kind === TypePredicateKind.AssertsIdentifier ? createIdentifier(typePredicate.parameterName) : createThisTypeNode(), typePredicate.type && nodeBuilder.typeToTypeNode(typePredicate.type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName)! // TODO: GH#18217 diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 9a484681acf..3118b9a2efe 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -667,7 +667,11 @@ namespace ts { return createSynthesizedNode(kind); } - export function createTypePredicateNode(assertsModifier: AssertsToken | undefined, parameterName: Identifier | ThisTypeNode | string, type: TypeNode | undefined) { + export function createTypePredicateNode(parameterName: Identifier | ThisTypeNode | string, type: TypeNode | undefined) { + return createTypePredicateNodeWithModifier(/*assertsModifier*/ undefined, parameterName, type); + } + + export function createTypePredicateNodeWithModifier(assertsModifier: AssertsToken | undefined, parameterName: Identifier | ThisTypeNode | string, type: TypeNode | undefined) { const node = createSynthesizedNode(SyntaxKind.TypePredicate) as TypePredicateNode; node.assertsModifier = assertsModifier; node.parameterName = asName(parameterName); @@ -675,10 +679,15 @@ namespace ts { return node; } - export function updateTypePredicateNode(node: TypePredicateNode, assertsModifier: AssertsToken | undefined, parameterName: Identifier | ThisTypeNode, type: TypeNode | undefined) { - return node.parameterName !== parameterName + export function updateTypePredicateNode(node: TypePredicateNode, parameterName: Identifier | ThisTypeNode, type: TypeNode | undefined) { + return updateTypePredicateNodeWithModifier(node, node.assertsModifier, parameterName, type); + } + + export function updateTypePredicateNodeWithModifier(node: TypePredicateNode, assertsModifier: AssertsToken | undefined, parameterName: Identifier | ThisTypeNode, type: TypeNode | undefined) { + return node.assertsModifier !== assertsModifier + || node.parameterName !== parameterName || node.type !== type - ? updateNode(createTypePredicateNode(assertsModifier, parameterName, type), node) + ? updateNode(createTypePredicateNodeWithModifier(assertsModifier, parameterName, type), node) : node; } diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index aa497511f78..266b794438b 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -339,7 +339,7 @@ namespace ts { // Types case SyntaxKind.TypePredicate: - return updateTypePredicateNode(node, + return updateTypePredicateNodeWithModifier(node, visitNode((node).assertsModifier, visitor), visitNode((node).parameterName, visitor), visitNode((node).type, visitor, isTypeNode)); From 2c36249ed6bd63f4fd66813985ae2dff681349a5 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 17 Aug 2019 07:07:27 -0700 Subject: [PATCH 034/140] Accept new API baselines --- .../reference/api/tsserverlibrary.d.ts | 21 +++++++++++++------ tests/baselines/reference/api/typescript.d.ts | 21 +++++++++++++------ 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 60222fc8bd3..c458e88300b 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2094,7 +2094,8 @@ declare namespace ts { export enum TypePredicateKind { This = 0, Identifier = 1, - Assertion = 2 + AssertsThis = 2, + AssertsIdentifier = 3 } export interface ThisTypePredicate { kind: TypePredicateKind.This; @@ -2108,13 +2109,19 @@ declare namespace ts { parameterIndex: number; type: Type; } - export interface AssertionTypePredicate { - kind: TypePredicateKind.Assertion; + export interface AssertsThisTypePredicate { + kind: TypePredicateKind.AssertsThis; + parameterName: undefined; + parameterIndex: undefined; + type: Type | undefined; + } + export interface AssertsIdentifierTypePredicate { + kind: TypePredicateKind.AssertsIdentifier; parameterName: string; parameterIndex: number; type: Type | undefined; } - export type TypePredicate = ThisTypePredicate | IdentifierTypePredicate | AssertionTypePredicate; + export type TypePredicate = ThisTypePredicate | IdentifierTypePredicate | AssertsThisTypePredicate | AssertsIdentifierTypePredicate; export enum SymbolFlags { None = 0, FunctionScopedVariable = 1, @@ -3843,8 +3850,10 @@ declare namespace ts { function createIndexSignature(decorators: ReadonlyArray | undefined, modifiers: ReadonlyArray | undefined, parameters: ReadonlyArray, type: TypeNode): IndexSignatureDeclaration; function updateIndexSignature(node: IndexSignatureDeclaration, decorators: ReadonlyArray | undefined, modifiers: ReadonlyArray | undefined, parameters: ReadonlyArray, type: TypeNode): IndexSignatureDeclaration; function createKeywordTypeNode(kind: KeywordTypeNode["kind"]): KeywordTypeNode; - function createTypePredicateNode(assertsModifier: AssertsToken | undefined, parameterName: Identifier | ThisTypeNode | string, type: TypeNode | undefined): TypePredicateNode; - function updateTypePredicateNode(node: TypePredicateNode, assertsModifier: AssertsToken | undefined, parameterName: Identifier | ThisTypeNode, type: TypeNode | undefined): TypePredicateNode; + function createTypePredicateNode(parameterName: Identifier | ThisTypeNode | string, type: TypeNode | undefined): TypePredicateNode; + function createTypePredicateNodeWithModifier(assertsModifier: AssertsToken | undefined, parameterName: Identifier | ThisTypeNode | string, type: TypeNode | undefined): TypePredicateNode; + function updateTypePredicateNode(node: TypePredicateNode, parameterName: Identifier | ThisTypeNode, type: TypeNode | undefined): TypePredicateNode; + function updateTypePredicateNodeWithModifier(node: TypePredicateNode, assertsModifier: AssertsToken | undefined, parameterName: Identifier | ThisTypeNode, type: TypeNode | undefined): TypePredicateNode; function createTypeReferenceNode(typeName: string | EntityName, typeArguments: ReadonlyArray | undefined): TypeReferenceNode; function updateTypeReferenceNode(node: TypeReferenceNode, typeName: EntityName, typeArguments: NodeArray | undefined): TypeReferenceNode; function createFunctionTypeNode(typeParameters: ReadonlyArray | undefined, parameters: ReadonlyArray, type: TypeNode | undefined): FunctionTypeNode; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index dbb9ac16f83..d8df06e936f 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2094,7 +2094,8 @@ declare namespace ts { export enum TypePredicateKind { This = 0, Identifier = 1, - Assertion = 2 + AssertsThis = 2, + AssertsIdentifier = 3 } export interface ThisTypePredicate { kind: TypePredicateKind.This; @@ -2108,13 +2109,19 @@ declare namespace ts { parameterIndex: number; type: Type; } - export interface AssertionTypePredicate { - kind: TypePredicateKind.Assertion; + export interface AssertsThisTypePredicate { + kind: TypePredicateKind.AssertsThis; + parameterName: undefined; + parameterIndex: undefined; + type: Type | undefined; + } + export interface AssertsIdentifierTypePredicate { + kind: TypePredicateKind.AssertsIdentifier; parameterName: string; parameterIndex: number; type: Type | undefined; } - export type TypePredicate = ThisTypePredicate | IdentifierTypePredicate | AssertionTypePredicate; + export type TypePredicate = ThisTypePredicate | IdentifierTypePredicate | AssertsThisTypePredicate | AssertsIdentifierTypePredicate; export enum SymbolFlags { None = 0, FunctionScopedVariable = 1, @@ -3843,8 +3850,10 @@ declare namespace ts { function createIndexSignature(decorators: ReadonlyArray | undefined, modifiers: ReadonlyArray | undefined, parameters: ReadonlyArray, type: TypeNode): IndexSignatureDeclaration; function updateIndexSignature(node: IndexSignatureDeclaration, decorators: ReadonlyArray | undefined, modifiers: ReadonlyArray | undefined, parameters: ReadonlyArray, type: TypeNode): IndexSignatureDeclaration; function createKeywordTypeNode(kind: KeywordTypeNode["kind"]): KeywordTypeNode; - function createTypePredicateNode(assertsModifier: AssertsToken | undefined, parameterName: Identifier | ThisTypeNode | string, type: TypeNode | undefined): TypePredicateNode; - function updateTypePredicateNode(node: TypePredicateNode, assertsModifier: AssertsToken | undefined, parameterName: Identifier | ThisTypeNode, type: TypeNode | undefined): TypePredicateNode; + function createTypePredicateNode(parameterName: Identifier | ThisTypeNode | string, type: TypeNode | undefined): TypePredicateNode; + function createTypePredicateNodeWithModifier(assertsModifier: AssertsToken | undefined, parameterName: Identifier | ThisTypeNode | string, type: TypeNode | undefined): TypePredicateNode; + function updateTypePredicateNode(node: TypePredicateNode, parameterName: Identifier | ThisTypeNode, type: TypeNode | undefined): TypePredicateNode; + function updateTypePredicateNodeWithModifier(node: TypePredicateNode, assertsModifier: AssertsToken | undefined, parameterName: Identifier | ThisTypeNode, type: TypeNode | undefined): TypePredicateNode; function createTypeReferenceNode(typeName: string | EntityName, typeArguments: ReadonlyArray | undefined): TypeReferenceNode; function updateTypeReferenceNode(node: TypeReferenceNode, typeName: EntityName, typeArguments: NodeArray | undefined): TypeReferenceNode; function createFunctionTypeNode(typeParameters: ReadonlyArray | undefined, parameters: ReadonlyArray, type: TypeNode | undefined): FunctionTypeNode; From c6e502be7d4682250b7ad8d88eb77f8187a719dc Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 22 Aug 2019 11:26:26 -0700 Subject: [PATCH 035/140] Verify config file errors --- .../tsserver/projectReferenceErrors.ts | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/testRunner/unittests/tsserver/projectReferenceErrors.ts b/src/testRunner/unittests/tsserver/projectReferenceErrors.ts index 303808cb4e4..62468fcc6f7 100644 --- a/src/testRunner/unittests/tsserver/projectReferenceErrors.ts +++ b/src/testRunner/unittests/tsserver/projectReferenceErrors.ts @@ -152,6 +152,25 @@ fnErr(); }); } + function verifyConfigFileErrors({ openFiles, expectedConfigFileDiagEvents }: VerifyScenario) { + it("verify config file errors", () => { + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const { session, events } = createSessionWithEventTracking(host, server.ConfigFileDiagEvent); + + for (const file of openFiles()) { + session.executeCommandSeq({ + command: protocol.CommandTypes.Open, + arguments: { file: file.path } + }); + } + + assert.deepEqual(events, expectedConfigFileDiagEvents().map(data => ({ + eventName: server.ConfigFileDiagEvent, + data + }))); + }); + } + interface GetErrDiagnostics { file: File; syntax: protocol.Diagnostic[]; @@ -170,11 +189,13 @@ fnErr(); expectedGetErr: () => readonly GetErrDiagnostics[]; expectedGetErrForProject: () => readonly GetErrForProjectDiagnostics[]; expectedSyncDiagnostics: () => readonly SyncDiagnostics[]; + expectedConfigFileDiagEvents: () => readonly server.ConfigFileDiagEvent["data"][]; } function verifyScenario(scenario: VerifyScenario) { verifyErrorsUsingGeterr(scenario); verifyErrorsUsingGeterrForProject(scenario); verifyErrorsUsingSyncMethods(scenario); + verifyConfigFileErrors(scenario); } function emptyDiagnostics(file: File): GetErrDiagnostics { @@ -243,6 +264,22 @@ fnErr(); return { project, ...diagnostics }; } + function usageConfigDiag(): server.ConfigFileDiagEvent["data"] { + return { + triggerFile: usageTs.path, + configFileName: usageConfig.path, + diagnostics: emptyArray + }; + } + + function dependencyConfigDiag(): server.ConfigFileDiagEvent["data"] { + return { + triggerFile: dependencyTs.path, + configFileName: dependencyConfig.path, + diagnostics: emptyArray + }; + } + describe("when dependency project is not open", () => { verifyScenario({ openFiles: () => [usageTs], @@ -267,6 +304,9 @@ fnErr(); syncDiagnostics(usageDiagnostics(), usageConfig.path), syncDiagnostics(emptyDiagnostics(dependencyTs), usageConfig.path), ], + expectedConfigFileDiagEvents: () => [ + usageConfigDiag() + ], }); }); @@ -290,6 +330,10 @@ fnErr(); syncDiagnostics(emptyDiagnostics(dependencyTs), usageConfig.path), syncDiagnostics(dependencyDiagnostics(), dependencyConfig.path), ], + expectedConfigFileDiagEvents: () => [ + usageConfigDiag(), + dependencyConfigDiag() + ], }); }); }); From 076dde482045de6ff7189d75459a5aab756b4336 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 22 Aug 2019 12:59:08 -0700 Subject: [PATCH 036/140] Test with --out as well --- .../tsserver/projectReferenceErrors.ts | 399 +++++++++++------- 1 file changed, 244 insertions(+), 155 deletions(-) diff --git a/src/testRunner/unittests/tsserver/projectReferenceErrors.ts b/src/testRunner/unittests/tsserver/projectReferenceErrors.ts index 62468fcc6f7..ac023743da3 100644 --- a/src/testRunner/unittests/tsserver/projectReferenceErrors.ts +++ b/src/testRunner/unittests/tsserver/projectReferenceErrors.ts @@ -3,37 +3,6 @@ namespace ts.projectSystem { const projectLocation = "/user/username/projects/myproject"; const dependecyLocation = `${projectLocation}/dependency`; const usageLocation = `${projectLocation}/usage`; - const dependencyTs: File = { - path: `${dependecyLocation}/fns.ts`, - content: `export function fn1() { } -export function fn2() { } -// Introduce error for fnErr import in main -// export function fnErr() { } -// Error in dependency ts file -export let x: string = 10;` - }; - const dependencyConfig: File = { - path: `${dependecyLocation}/tsconfig.json`, - content: JSON.stringify({ compilerOptions: { composite: true, declarationDir: "../decls" } }) - }; - const usageTs: File = { - path: `${usageLocation}/usage.ts`, - content: `import { - fn1, - fn2, - fnErr -} from '../decls/fns' -fn1(); -fn2(); -fnErr(); -` - }; - const usageConfig: File = { - path: `${usageLocation}/tsconfig.json`, - content: JSON.stringify({ - references: [{ path: "../dependency" }] - }) - }; interface CheckErrorsInFile { session: TestSession; @@ -75,9 +44,9 @@ fnErr(); } } - function verifyErrorsUsingGeterr({ openFiles, expectedGetErr }: VerifyScenario) { + function verifyErrorsUsingGeterr({ allFiles, openFiles, expectedGetErr }: VerifyScenario) { it("verifies the errors in open file", () => { - const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const host = createServerHost([...allFiles(), libFile]); const session = createSession(host, { canUseEvents: true, }); openFilesForSession(openFiles(), session); @@ -96,9 +65,9 @@ fnErr(); }); } - function verifyErrorsUsingGeterrForProject({ openFiles, expectedGetErrForProject }: VerifyScenario) { + function verifyErrorsUsingGeterrForProject({ allFiles, openFiles, expectedGetErrForProject }: VerifyScenario) { it("verifies the errors in projects", () => { - const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const host = createServerHost([...allFiles(), libFile]); const session = createSession(host, { canUseEvents: true, }); openFilesForSession(openFiles(), session); @@ -118,9 +87,9 @@ fnErr(); }); } - function verifyErrorsUsingSyncMethods({ openFiles, expectedSyncDiagnostics }: VerifyScenario) { + function verifyErrorsUsingSyncMethods({ allFiles, openFiles, expectedSyncDiagnostics }: VerifyScenario) { it("verifies the errors using sync commands", () => { - const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const host = createServerHost([...allFiles(), libFile]); const session = createSession(host); openFilesForSession(openFiles(), session); for (const { file, project, syntax, semantic, suggestion } of expectedSyncDiagnostics()) { @@ -152,9 +121,9 @@ fnErr(); }); } - function verifyConfigFileErrors({ openFiles, expectedConfigFileDiagEvents }: VerifyScenario) { + function verifyConfigFileErrors({ allFiles, openFiles, expectedConfigFileDiagEvents }: VerifyScenario) { it("verify config file errors", () => { - const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const host = createServerHost([...allFiles(), libFile]); const { session, events } = createSessionWithEventTracking(host, server.ConfigFileDiagEvent); for (const file of openFiles()) { @@ -185,6 +154,7 @@ fnErr(); project?: string; } interface VerifyScenario { + allFiles: () => readonly File[]; openFiles: () => readonly File[]; expectedGetErr: () => readonly GetErrDiagnostics[]; expectedGetErrForProject: () => readonly GetErrForProjectDiagnostics[]; @@ -207,133 +177,252 @@ fnErr(); }; } - function usageDiagnostics(): GetErrDiagnostics { - return { - file: usageTs, - syntax: emptyArray, - semantic: [ - createDiagnostic( - { line: 4, offset: 5 }, - { line: 4, offset: 10 }, - Diagnostics.Module_0_has_no_exported_member_1, - [`"../dependency/fns"`, "fnErr"], - "error", - ) - ], - suggestion: emptyArray - }; - } - - function dependencyDiagnostics(): GetErrDiagnostics { - return { - file: dependencyTs, - syntax: emptyArray, - semantic: [ - createDiagnostic( - { line: 6, offset: 12 }, - { line: 6, offset: 13 }, - Diagnostics.Type_0_is_not_assignable_to_type_1, - ["10", "string"], - "error", - ) - ], - suggestion: emptyArray - }; - } - - function usageProjectDiagnostics(): GetErrForProjectDiagnostics { - return { - project: usageTs.path, - errors: [ - usageDiagnostics(), - emptyDiagnostics(dependencyTs) - ] - }; - } - - function dependencyProjectDiagnostics(): GetErrForProjectDiagnostics { - return { - project: dependencyTs.path, - errors: [ - dependencyDiagnostics() - ] - }; - } - function syncDiagnostics(diagnostics: GetErrDiagnostics, project: string): SyncDiagnostics { return { project, ...diagnostics }; } - function usageConfigDiag(): server.ConfigFileDiagEvent["data"] { - return { - triggerFile: usageTs.path, - configFileName: usageConfig.path, - diagnostics: emptyArray - }; + interface VerifyUsageAndDependency { + allFiles: readonly [File, File, File, File]; // dependencyTs, dependencyConfig, usageTs, usageConfig + usageDiagnostics(): GetErrDiagnostics; + dependencyDiagnostics(): GetErrDiagnostics; + + } + function verifyUsageAndDependency({ allFiles, usageDiagnostics, dependencyDiagnostics }: VerifyUsageAndDependency) { + const [dependencyTs, dependencyConfig, usageTs, usageConfig] = allFiles; + function usageProjectDiagnostics(): GetErrForProjectDiagnostics { + return { + project: usageTs.path, + errors: [ + usageDiagnostics(), + emptyDiagnostics(dependencyTs) + ] + }; + } + + function dependencyProjectDiagnostics(): GetErrForProjectDiagnostics { + return { + project: dependencyTs.path, + errors: [ + dependencyDiagnostics() + ] + }; + } + + function usageConfigDiag(): server.ConfigFileDiagEvent["data"] { + return { + triggerFile: usageTs.path, + configFileName: usageConfig.path, + diagnostics: emptyArray + }; + } + + function dependencyConfigDiag(): server.ConfigFileDiagEvent["data"] { + return { + triggerFile: dependencyTs.path, + configFileName: dependencyConfig.path, + diagnostics: emptyArray + }; + } + + describe("when dependency project is not open", () => { + verifyScenario({ + allFiles: () => allFiles, + openFiles: () => [usageTs], + expectedGetErr: () => [ + usageDiagnostics() + ], + expectedGetErrForProject: () => [ + usageProjectDiagnostics(), + { + project: dependencyTs.path, + errors: [ + emptyDiagnostics(dependencyTs), + usageDiagnostics() + ] + } + ], + expectedSyncDiagnostics: () => [ + // Without project + usageDiagnostics(), + emptyDiagnostics(dependencyTs), + // With project + syncDiagnostics(usageDiagnostics(), usageConfig.path), + syncDiagnostics(emptyDiagnostics(dependencyTs), usageConfig.path), + ], + expectedConfigFileDiagEvents: () => [ + usageConfigDiag() + ], + }); + }); + + describe("when the depedency file is open", () => { + verifyScenario({ + allFiles: () => allFiles, + openFiles: () => [usageTs, dependencyTs], + expectedGetErr: () => [ + usageDiagnostics(), + dependencyDiagnostics(), + ], + expectedGetErrForProject: () => [ + usageProjectDiagnostics(), + dependencyProjectDiagnostics() + ], + expectedSyncDiagnostics: () => [ + // Without project + usageDiagnostics(), + dependencyDiagnostics(), + // With project + syncDiagnostics(usageDiagnostics(), usageConfig.path), + syncDiagnostics(emptyDiagnostics(dependencyTs), usageConfig.path), + syncDiagnostics(dependencyDiagnostics(), dependencyConfig.path), + ], + expectedConfigFileDiagEvents: () => [ + usageConfigDiag(), + dependencyConfigDiag() + ], + }); + }); } - function dependencyConfigDiag(): server.ConfigFileDiagEvent["data"] { - return { - triggerFile: dependencyTs.path, - configFileName: dependencyConfig.path, - diagnostics: emptyArray + describe("with module scenario", () => { + const dependencyTs: File = { + path: `${dependecyLocation}/fns.ts`, + content: `export function fn1() { } +export function fn2() { } +// Introduce error for fnErr import in main +// export function fnErr() { } +// Error in dependency ts file +export let x: string = 10;` }; - } + const dependencyConfig: File = { + path: `${dependecyLocation}/tsconfig.json`, + content: JSON.stringify({ compilerOptions: { composite: true, declarationDir: "../decls" } }) + }; + const usageTs: File = { + path: `${usageLocation}/usage.ts`, + content: `import { + fn1, + fn2, + fnErr +} from '../decls/fns' +fn1(); +fn2(); +fnErr(); +` + }; + const usageConfig: File = { + path: `${usageLocation}/tsconfig.json`, + content: JSON.stringify({ + references: [{ path: "../dependency" }] + }) + }; + function usageDiagnostics(): GetErrDiagnostics { + return { + file: usageTs, + syntax: emptyArray, + semantic: [ + createDiagnostic( + { line: 4, offset: 5 }, + { line: 4, offset: 10 }, + Diagnostics.Module_0_has_no_exported_member_1, + [`"../dependency/fns"`, "fnErr"], + "error", + ) + ], + suggestion: emptyArray + }; + } - describe("when dependency project is not open", () => { - verifyScenario({ - openFiles: () => [usageTs], - expectedGetErr: () => [ - usageDiagnostics() - ], - expectedGetErrForProject: () => [ - usageProjectDiagnostics(), - { - project: dependencyTs.path, - errors: [ - emptyDiagnostics(dependencyTs), - usageDiagnostics() - ] - } - ], - expectedSyncDiagnostics: () => [ - // Without project - usageDiagnostics(), - emptyDiagnostics(dependencyTs), - // With project - syncDiagnostics(usageDiagnostics(), usageConfig.path), - syncDiagnostics(emptyDiagnostics(dependencyTs), usageConfig.path), - ], - expectedConfigFileDiagEvents: () => [ - usageConfigDiag() - ], + function dependencyDiagnostics(): GetErrDiagnostics { + return { + file: dependencyTs, + syntax: emptyArray, + semantic: [ + createDiagnostic( + { line: 6, offset: 12 }, + { line: 6, offset: 13 }, + Diagnostics.Type_0_is_not_assignable_to_type_1, + ["10", "string"], + "error", + ) + ], + suggestion: emptyArray + }; + } + + verifyUsageAndDependency({ + allFiles: [dependencyTs, dependencyConfig, usageTs, usageConfig], + usageDiagnostics, + dependencyDiagnostics }); }); - describe("when the depedency file is open", () => { - verifyScenario({ - openFiles: () => [usageTs, dependencyTs], - expectedGetErr: () => [ - usageDiagnostics(), - dependencyDiagnostics(), - ], - expectedGetErrForProject: () => [ - usageProjectDiagnostics(), - dependencyProjectDiagnostics() - ], - expectedSyncDiagnostics: () => [ - // Without project - usageDiagnostics(), - dependencyDiagnostics(), - // With project - syncDiagnostics(usageDiagnostics(), usageConfig.path), - syncDiagnostics(emptyDiagnostics(dependencyTs), usageConfig.path), - syncDiagnostics(dependencyDiagnostics(), dependencyConfig.path), - ], - expectedConfigFileDiagEvents: () => [ - usageConfigDiag(), - dependencyConfigDiag() - ], + describe("with non module --out", () => { + const dependencyTs: File = { + path: `${dependecyLocation}/fns.ts`, + content: `function fn1() { } +function fn2() { } +// Introduce error for fnErr import in main +// function fnErr() { } +// Error in dependency ts file +let x: string = 10;` + }; + const dependencyConfig: File = { + path: `${dependecyLocation}/tsconfig.json`, + content: JSON.stringify({ compilerOptions: { composite: true, outFile: "../dependency.js" } }) + }; + const usageTs: File = { + path: `${usageLocation}/usage.ts`, + content: `fn1(); +fn2(); +fnErr(); +` + }; + const usageConfig: File = { + path: `${usageLocation}/tsconfig.json`, + content: JSON.stringify({ + compilerOptions: { outFile: "../usage.js" }, + references: [{ path: "../dependency" }] + }) + }; + function usageDiagnostics(): GetErrDiagnostics { + return { + file: usageTs, + syntax: emptyArray, + semantic: [ + createDiagnostic( + { line: 3, offset: 1 }, + { line: 3, offset: 6 }, + Diagnostics.Cannot_find_name_0, + ["fnErr"], + "error", + ) + ], + suggestion: emptyArray + }; + } + + function dependencyDiagnostics(): GetErrDiagnostics { + return { + file: dependencyTs, + syntax: emptyArray, + semantic: [ + createDiagnostic( + { line: 6, offset: 5 }, + { line: 6, offset: 6 }, + Diagnostics.Type_0_is_not_assignable_to_type_1, + ["10", "string"], + "error", + ) + ], + suggestion: emptyArray + }; + } + + verifyUsageAndDependency({ + allFiles: [dependencyTs, dependencyConfig, usageTs, usageConfig], + usageDiagnostics, + dependencyDiagnostics }); }); }); From a469fd82b9f33071841da9c2a38237915c105c11 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 22 Aug 2019 13:14:50 -0700 Subject: [PATCH 037/140] Should not report that files are not part of config for files that are not going to be emitted --- src/compiler/program.ts | 11 ++++++++--- .../unittests/tsserver/projectReferenceErrors.ts | 3 ++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 62f003910ad..45918e26e36 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1008,9 +1008,15 @@ namespace ts { return ts.toPath(fileName, currentDirectory, getCanonicalFileName); } + function isValidSourceFileForEmit(file: SourceFile) { + // source file is allowed to be emitted and its not source of project reference redirect + return sourceFileMayBeEmitted(file, options, isSourceFileFromExternalLibrary, getResolvedProjectReferenceToRedirect) && + !isSourceOfProjectReferenceRedirect(file.fileName); + } + function getCommonSourceDirectory() { if (commonSourceDirectory === undefined) { - const emittedFiles = filter(files, file => sourceFileMayBeEmitted(file, options, isSourceFileFromExternalLibrary, getResolvedProjectReferenceToRedirect)); + const emittedFiles = filter(files, file => isValidSourceFileForEmit(file)); if (options.rootDir && checkSourceFilesBelongToPath(emittedFiles, options.rootDir)) { // If a rootDir is specified use it as the commonSourceDirectory commonSourceDirectory = getNormalizedAbsolutePath(options.rootDir, currentDirectory); @@ -2933,8 +2939,7 @@ namespace ts { const rootPaths = arrayToSet(rootNames, toPath); for (const file of files) { // Ignore file that is not emitted - if (!sourceFileMayBeEmitted(file, options, isSourceFileFromExternalLibrary, getResolvedProjectReferenceToRedirect)) continue; - if (!rootPaths.has(file.path)) { + if (isValidSourceFileForEmit(file) && !rootPaths.has(file.path)) { addProgramDiagnosticAtRefPath( file, rootPaths, diff --git a/src/testRunner/unittests/tsserver/projectReferenceErrors.ts b/src/testRunner/unittests/tsserver/projectReferenceErrors.ts index ac023743da3..a3ec4848615 100644 --- a/src/testRunner/unittests/tsserver/projectReferenceErrors.ts +++ b/src/testRunner/unittests/tsserver/projectReferenceErrors.ts @@ -313,6 +313,7 @@ fnErr(); const usageConfig: File = { path: `${usageLocation}/tsconfig.json`, content: JSON.stringify({ + compilerOptions: { composite: true }, references: [{ path: "../dependency" }] }) }; @@ -381,7 +382,7 @@ fnErr(); const usageConfig: File = { path: `${usageLocation}/tsconfig.json`, content: JSON.stringify({ - compilerOptions: { outFile: "../usage.js" }, + compilerOptions: { composite: true, outFile: "../usage.js" }, references: [{ path: "../dependency" }] }) }; From 643351ca2d3618e9ce02a6b91901552ba12f5468 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 23 Aug 2019 09:54:55 -0400 Subject: [PATCH 038/140] Support deferred resolution of type arguments in type references --- src/compiler/checker.ts | 149 ++++++++++++++++++++++------------- src/compiler/symbolWalker.ts | 5 +- src/compiler/types.ts | 4 +- 3 files changed, 100 insertions(+), 58 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 53f96d507b8..b7e645e99d8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -508,6 +508,7 @@ namespace ts { getIndexTypeOfStructuredType, getConstraintOfTypeParameter, getFirstIdentifier, + getTypeArguments, ), getAmbientModules, getJsxIntrinsicTagNamesAt, @@ -3539,6 +3540,7 @@ namespace ts { } function createNodeBuilder() { + let depth = 0; return { typeToTypeNode: (type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => withContext(enclosingDeclaration, flags, tracker, context => typeToTypeNodeHelper(type, context)), @@ -3700,6 +3702,12 @@ namespace ts { return createThis(); } + if (!inTypeAlias && type.aliasSymbol && (context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope || isTypeSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration))) { + const typeArgumentNodes = mapToTypeNodes(type.aliasTypeArguments, context); + if (isReservedMemberName(type.aliasSymbol.escapedName) && !(type.aliasSymbol.flags & SymbolFlags.Class)) return createTypeReferenceNode(createIdentifier(""), typeArgumentNodes); + return symbolToTypeNode(type.aliasSymbol, context, SymbolFlags.Type, typeArgumentNodes); + } + const objectFlags = getObjectFlags(type); if (objectFlags & ObjectFlags.Reference) { @@ -3722,11 +3730,6 @@ namespace ts { ? symbolToTypeNode(type.symbol, context, SymbolFlags.Type) : createTypeReferenceNode(createIdentifier("?"), /*typeArguments*/ undefined); } - if (!inTypeAlias && type.aliasSymbol && (context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope || isTypeSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration))) { - const typeArgumentNodes = mapToTypeNodes(type.aliasTypeArguments, context); - if (isReservedMemberName(type.aliasSymbol.escapedName) && !(type.aliasSymbol.flags & SymbolFlags.Class)) return createTypeReferenceNode(createIdentifier(""), typeArgumentNodes); - return symbolToTypeNode(type.aliasSymbol, context, SymbolFlags.Type, typeArgumentNodes); - } if (type.flags & (TypeFlags.Union | TypeFlags.Intersection)) { const types = type.flags & TypeFlags.Union ? formatUnionTypes((type).types) : (type).types; if (length(types) === 1) { @@ -3904,14 +3907,18 @@ namespace ts { } function typeReferenceToTypeNode(type: TypeReference) { - const typeArguments: ReadonlyArray = type.typeArguments || emptyArray; + const typeArguments: ReadonlyArray = getTypeArguments(type); if (type.target === globalArrayType || type.target === globalReadonlyArrayType) { if (context.flags & NodeBuilderFlags.WriteArrayAsGenericType) { - const typeArgumentNode = typeToTypeNodeHelper(typeArguments[0], context); - return createTypeReferenceNode(type.target === globalArrayType ? "Array" : "ReadonlyArray", [typeArgumentNode]); + depth++; + const typeArgumentNode = typeToTypeNodeHelper(depth >= 5 ? anyType : typeArguments[0], context); + depth--; + createTypeReferenceNode(type.target === globalArrayType ? "Array" : "ReadonlyArray", [typeArgumentNode]); } - const elementType = typeToTypeNodeHelper(typeArguments[0], context); + depth++; + const elementType = typeToTypeNodeHelper(depth >= 5 ? anyType : typeArguments[0], context); + depth--; const arrayType = createArrayTypeNode(elementType); return type.target === globalArrayType ? arrayType : createTypeOperatorNode(SyntaxKind.ReadonlyKeyword, arrayType); } @@ -6231,7 +6238,7 @@ namespace ts { const signatures = getSignaturesOfType(type, SignatureKind.Construct); if (signatures.length === 1) { const s = signatures[0]; - return !s.typeParameters && s.parameters.length === 1 && s.hasRestParameter && getTypeOfParameter(s.parameters[0]) === anyArrayType; + return !s.typeParameters && s.parameters.length === 1 && s.hasRestParameter && getElementTypeOfArrayType(getTypeOfParameter(s.parameters[0])) === anyType; } return false; } @@ -6402,7 +6409,7 @@ namespace ts { const outerTypeParameters = (type).outerTypeParameters; if (outerTypeParameters) { const last = outerTypeParameters.length - 1; - const typeArguments = (type).typeArguments!; + const typeArguments = getTypeArguments(type); return outerTypeParameters[last].symbol !== typeArguments[last].symbol; } return true; @@ -6493,7 +6500,7 @@ namespace ts { (type).instantiations = createMap(); (type).instantiations.set(getTypeListId(type.typeParameters), type); (type).target = type; - (type).typeArguments = type.typeParameters; + (type).resolvedTypeArguments = type.typeParameters; type.thisType = createTypeParameter(symbol); type.thisType.isThisType = true; type.thisType.constraint = type; @@ -7017,7 +7024,7 @@ namespace ts { function getTypeWithThisArgument(type: Type, thisArgument?: Type, needApparentType?: boolean): Type { if (getObjectFlags(type) & ObjectFlags.Reference) { const target = (type).target; - const typeArguments = (type).typeArguments; + const typeArguments = getTypeArguments(type); if (length(target.typeParameters) === length(typeArguments)) { const ref = createTypeReference(target, concatenate(typeArguments, [thisArgument || target.thisType!])); return needApparentType ? getApparentType(ref) : ref; @@ -7082,9 +7089,9 @@ namespace ts { function resolveTypeReferenceMembers(type: TypeReference): void { const source = resolveDeclaredMembers(type.target); const typeParameters = concatenate(source.typeParameters!, [source.thisType!]); - const typeArguments = type.typeArguments && type.typeArguments.length === typeParameters.length ? - type.typeArguments : concatenate(type.typeArguments, [type]); - resolveObjectTypeMembers(type, source, typeParameters, typeArguments); + const typeArguments = getTypeArguments(type); + const paddedTypeArguments = typeArguments.length === typeParameters.length ? typeArguments : concatenate(typeArguments, [type]); + resolveObjectTypeMembers(type, source, typeParameters, paddedTypeArguments); } function createSignature( @@ -7135,7 +7142,7 @@ namespace ts { const restParameter = sig.parameters[restIndex]; const restType = getTypeOfSymbol(restParameter); if (isTupleType(restType)) { - const elementTypes = restType.typeArguments || emptyArray; + const elementTypes = getTypeArguments(restType); const minLength = restType.target.minLength; const tupleRestIndex = restType.target.hasRestElement ? elementTypes.length - 1 : -1; const restParams = map(elementTypes, (t, i) => { @@ -9056,7 +9063,7 @@ namespace ts { target.instantiations.set(id, type); type.objectFlags |= typeArguments ? getPropagatingFlagsOfTypes(typeArguments, /*excludeKinds*/ 0) : 0; type.target = target; - type.typeArguments = typeArguments; + type.resolvedTypeArguments = typeArguments; } return type; } @@ -9066,10 +9073,28 @@ namespace ts { type.symbol = source.symbol; type.objectFlags = source.objectFlags; type.target = source.target; - type.typeArguments = source.typeArguments; + type.resolvedTypeArguments = source.resolvedTypeArguments; return type; } + function createDeferredTypeReference(target: GenericType, typeArgumentNodes: ReadonlyArray, mapper?: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: ReadonlyArray): TypeReference { + const type = createObjectType(ObjectFlags.Reference, target.symbol); + type.target = target; + type.typeArgumentNodes = typeArgumentNodes; + type.mapper = mapper; + type.aliasSymbol = aliasSymbol; + type.aliasTypeArguments = aliasTypeArguments; + return type; + } + + function getTypeArguments(type: TypeReference): ReadonlyArray { + if (!type.resolvedTypeArguments) { + const typeArguments = type.typeArgumentNodes ? map(type.typeArgumentNodes, getTypeFromTypeNode) : emptyArray; + type.resolvedTypeArguments = type.mapper ? instantiateTypes(typeArguments, type.mapper) : typeArguments; + } + return type.resolvedTypeArguments; + } + function getTypeReferenceArity(type: TypeReference): number { return length(type.target.typeParameters); } @@ -9559,7 +9584,10 @@ namespace ts { function getTypeFromArrayTypeNode(node: ArrayTypeNode): Type { const links = getNodeLinks(node); if (!links.resolvedType) { - links.resolvedType = createArrayType(getTypeFromTypeNode(node.elementType), isReadonlyTypeOperator(node.parent)); + const target = isReadonlyTypeOperator(node.parent) ? globalReadonlyArrayType : globalArrayType; + const aliasSymbol = getAliasSymbolForTypeNode(node); + const aliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol); + links.resolvedType = createDeferredTypeReference(target, [node.elementType], /*mapper*/ undefined, aliasSymbol, aliasTypeArguments); } return links.resolvedType; } @@ -9603,7 +9631,7 @@ namespace ts { type.instantiations = createMap(); type.instantiations.set(getTypeListId(type.typeParameters), type); type.target = type; - type.typeArguments = type.typeParameters; + type.resolvedTypeArguments = type.typeParameters; type.thisType = createTypeParameter(); type.thisType.isThisType = true; type.thisType.constraint = type; @@ -9659,7 +9687,7 @@ namespace ts { index = Math.min(index, getTypeReferenceArity(type) - 1); } return createTupleType( - (type.typeArguments || emptyArray).slice(index), + getTypeArguments(type).slice(index), Math.max(0, tuple.minLength - index), tuple.hasRestElement, tuple.readonly, @@ -11507,7 +11535,7 @@ namespace ts { function instantiateMappedTupleType(tupleType: TupleTypeReference, mappedType: MappedType, mapper: TypeMapper) { const minLength = tupleType.target.minLength; - const elementTypes = map(tupleType.typeArguments || emptyArray, (_, i) => + const elementTypes = map(getTypeArguments(tupleType), (_, i) => instantiateMappedTypeTemplate(mappedType, getLiteralType("" + i), i >= minLength, mapper)); const modifiers = getMappedTypeModifiers(mappedType); const newMinLength = modifiers & MappedTypeModifiers.IncludeOptional ? 0 : @@ -11616,9 +11644,19 @@ namespace ts { return getAnonymousTypeInstantiation(type, mapper); } if (objectFlags & ObjectFlags.Reference) { - const typeArguments = (type).typeArguments; - const newTypeArguments = instantiateTypes(typeArguments, mapper); - return newTypeArguments !== typeArguments ? createTypeReference((type).target, newTypeArguments) : type; + const resolvedTypeArguments = (type).resolvedTypeArguments; + if (resolvedTypeArguments) { + const newTypeArguments = instantiateTypes(resolvedTypeArguments, mapper); + return newTypeArguments !== resolvedTypeArguments ? createTypeReference((type).target, newTypeArguments) : type; + } + else { + const typeArgumentNodes = (type).typeArgumentNodes; + if (typeArgumentNodes) { + const combinedMapper = combineTypeMappers((type).mapper, mapper); + return createDeferredTypeReference((type).target, typeArgumentNodes, combinedMapper, + (type).aliasSymbol, instantiateTypes((type).aliasTypeArguments, combinedMapper)); + } + } } return type; } @@ -13284,8 +13322,8 @@ namespace ts { source.aliasTypeArguments && source.aliasSymbol === target.aliasSymbol) { propagateSidebandVarianceFlags(source.aliasTypeArguments, getAliasVariances(source.aliasSymbol)); } - if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source).target === (target).target && length((source).typeArguments)) { - propagateSidebandVarianceFlags((source).typeArguments!, getVariances((source).target)); + if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source).target === (target).target && length(getTypeArguments(source))) { + propagateSidebandVarianceFlags(getTypeArguments(source), getVariances((source).target)); } } return related === RelationComparisonResult.Succeeded ? Ternary.True : Ternary.False; @@ -13569,7 +13607,7 @@ namespace ts { // type references (which are intended by be compared structurally). Obtain the variance // information for the type parameters and relate the type arguments accordingly. const variances = getVariances((source).target); - const varianceResult = relateVariances((source).typeArguments, (target).typeArguments, variances, isIntersectionConstituent); + const varianceResult = relateVariances(getTypeArguments(source), getTypeArguments(target), variances, isIntersectionConstituent); if (varianceResult !== undefined) { return varianceResult; } @@ -13995,8 +14033,9 @@ namespace ts { } const targetCount = getTypeReferenceArity(target) - 1; const sourceCount = getTypeReferenceArity(source) - (sourceRestType ? 1 : 0); + const sourceTypeArguments = getTypeArguments(source); for (let i = targetCount; i < sourceCount; i++) { - const related = isRelatedTo((source).typeArguments![i], targetRestType, reportErrors); + const related = isRelatedTo(sourceTypeArguments[i], targetRestType, reportErrors); if (!related) { if (reportErrors) { reportError(Diagnostics.Property_0_is_incompatible_with_rest_element_type, "" + i); @@ -14408,7 +14447,7 @@ namespace ts { } function isTypeReferenceWithGenericArguments(type: Type): boolean { - return !!(getObjectFlags(type) & ObjectFlags.Reference) && some((type).typeArguments, t => isUnconstrainedTypeParameter(t) || isTypeReferenceWithGenericArguments(t)); + return !!(getObjectFlags(type) & ObjectFlags.Reference) && some(getTypeArguments(type), t => isUnconstrainedTypeParameter(t) || isTypeReferenceWithGenericArguments(t)); } /** @@ -14417,7 +14456,7 @@ namespace ts { */ function getTypeReferenceId(type: TypeReference, typeParameters: Type[], depth = 0) { let result = "" + type.target.id; - for (const t of type.typeArguments!) { + for (const t of getTypeArguments(type)) { if (isUnconstrainedTypeParameter(t)) { let index = typeParameters.indexOf(t); if (index < 0) { @@ -14688,7 +14727,7 @@ namespace ts { } function getElementTypeOfArrayType(type: Type): Type | undefined { - return isArrayType(type) && (type as TypeReference).typeArguments ? (type as TypeReference).typeArguments![0] : undefined; + return isArrayType(type) ? getTypeArguments(type as TypeReference)[0] : undefined; } function isArrayLikeType(type: Type): boolean { @@ -14698,7 +14737,7 @@ namespace ts { } function isEmptyArrayLiteralType(type: Type): boolean { - const elementType = isArrayType(type) ? (type).typeArguments![0] : undefined; + const elementType = isArrayType(type) ? getTypeArguments(type)[0] : undefined; return elementType === undefinedWideningType || elementType === implicitNeverType; } @@ -14796,7 +14835,7 @@ namespace ts { } function getRestTypeOfTupleType(type: TupleTypeReference) { - return type.target.hasRestElement ? type.typeArguments![type.target.typeParameters!.length - 1] : undefined; + return type.target.hasRestElement ? getTypeArguments(type)[type.target.typeParameters!.length - 1] : undefined; } function getRestArrayTypeOfTupleType(type: TupleTypeReference) { @@ -15085,7 +15124,7 @@ namespace ts { result = getIntersectionType(sameMap((type).types, getWidenedType)); } else if (isArrayType(type) || isTupleType(type)) { - result = createTypeReference((type).target, sameMap((type).typeArguments, getWidenedType)); + result = createTypeReference((type).target, sameMap(getTypeArguments(type), getWidenedType)); } if (result && context === undefined) { type.widened = result; @@ -15122,7 +15161,7 @@ namespace ts { } } if (isArrayType(type) || isTupleType(type)) { - for (const t of (type).typeArguments!) { + for (const t of getTypeArguments(type)) { if (reportWideningErrorsInType(t)) { errorReported = true; } @@ -15332,7 +15371,7 @@ namespace ts { function couldContainTypeVariables(type: Type): boolean { const objectFlags = getObjectFlags(type); return !!(type.flags & TypeFlags.Instantiable || - objectFlags & ObjectFlags.Reference && forEach((type).typeArguments, couldContainTypeVariables) || + objectFlags & ObjectFlags.Reference && forEach(getTypeArguments(type), couldContainTypeVariables) || objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && type.symbol.declarations || objectFlags & ObjectFlags.Mapped || type.flags & TypeFlags.UnionOrIntersection && !(type.flags & TypeFlags.EnumLiteral) && couldUnionOrIntersectionContainTypeVariables(type)); @@ -15408,10 +15447,10 @@ namespace ts { // For arrays and tuples we infer new arrays and tuples where the reverse mapping has been // applied to the element type(s). if (isArrayType(source)) { - return createArrayType(inferReverseMappedType((source).typeArguments![0], target, constraint), isReadonlyArrayType(source)); + return createArrayType(inferReverseMappedType(getTypeArguments(source)[0], target, constraint), isReadonlyArrayType(source)); } if (isTupleType(source)) { - const elementTypes = map(source.typeArguments || emptyArray, t => inferReverseMappedType(t, target, constraint)); + const elementTypes = map(getTypeArguments(source), t => inferReverseMappedType(t, target, constraint)); const minLength = getMappedTypeModifiers(target) & MappedTypeModifiers.IncludeOptional ? getTypeReferenceArity(source) - (source.target.hasRestElement ? 1 : 0) : source.target.minLength; return createTupleType(elementTypes, minLength, source.target.hasRestElement, source.target.readonly, source.target.associatedNames); @@ -15625,7 +15664,7 @@ namespace ts { if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && ( (source).target === (target).target || isArrayType(source) && isArrayType(target))) { // If source and target are references to the same generic type, infer from type arguments - inferFromTypeArguments((source).typeArguments || emptyArray, (target).typeArguments || emptyArray, getVariances((source).target)); + inferFromTypeArguments(getTypeArguments(source), getTypeArguments(target), getVariances((source).target)); } else if (source.flags & TypeFlags.Index && target.flags & TypeFlags.Index) { contravariant = !contravariant; @@ -15945,10 +15984,10 @@ namespace ts { const targetRestType = getRestTypeOfTupleType(target); const fixedLength = targetLength < sourceLength || sourceRestType ? targetLength : sourceLength; for (let i = 0; i < fixedLength; i++) { - inferFromTypes(i < sourceLength ? (source).typeArguments![i] : sourceRestType!, target.typeArguments![i]); + inferFromTypes(i < sourceLength ? getTypeArguments(source)[i] : sourceRestType!, getTypeArguments(target)[i]); } if (targetRestType) { - const types = fixedLength < sourceLength ? (source).typeArguments!.slice(fixedLength, sourceLength) : []; + const types = fixedLength < sourceLength ? getTypeArguments(source).slice(fixedLength, sourceLength) : []; if (sourceRestType) { types.push(sourceRestType); } @@ -18598,7 +18637,7 @@ namespace ts { } function getThisTypeArgument(type: Type): Type | undefined { - return getObjectFlags(type) & ObjectFlags.Reference && (type).target === globalThisType ? (type).typeArguments![0] : undefined; + return getObjectFlags(type) & ObjectFlags.Reference && (type).target === globalThisType ? getTypeArguments(type)[0] : undefined; } function getThisTypeFromContextualType(type: Type): Type | undefined { @@ -21651,7 +21690,7 @@ namespace ts { const spreadArgument = args[length - 1]; const type = flowLoopCount ? checkExpression(spreadArgument.expression) : checkExpressionCached(spreadArgument.expression); if (isTupleType(type)) { - const typeArguments = (type).typeArguments || emptyArray; + const typeArguments = getTypeArguments(type); const restIndex = type.target.hasRestElement ? typeArguments.length - 1 : -1; const syntheticArgs = map(typeArguments, (t, i) => createSyntheticExpression(spreadArgument, t, /*isSpread*/ i === restIndex)); return concatenate(args.slice(0, length - 1), syntheticArgs); @@ -23199,7 +23238,7 @@ namespace ts { // otherwise would return the type 'undefined'). const restType = getTypeOfSymbol(signature.parameters[paramCount]); const index = pos - paramCount; - if (!isTupleType(restType) || restType.target.hasRestElement || index < (restType.typeArguments || emptyArray).length) { + if (!isTupleType(restType) || restType.target.hasRestElement || index < getTypeArguments(restType).length) { return getIndexedAccessType(restType, getLiteralType(index)); } } @@ -23233,7 +23272,7 @@ namespace ts { if (signature.hasRestParameter) { const restType = getTypeOfSymbol(signature.parameters[length - 1]); if (isTupleType(restType)) { - return length + (restType.typeArguments || emptyArray).length - 1; + return length + getTypeArguments(restType).length - 1; } } return length; @@ -24975,7 +25014,7 @@ namespace ts { function padTupleType(type: TupleTypeReference, pattern: ArrayBindingPattern) { const patternElements = pattern.elements; const arity = getTypeReferenceArity(type); - const elementTypes = arity ? type.typeArguments!.slice() : []; + const elementTypes = arity ? getTypeArguments(type).slice() : []; for (let i = arity; i < patternElements.length; i++) { const e = patternElements[i]; if (i < patternElements.length - 1 || !(e.kind === SyntaxKind.BindingElement && e.dotDotDotToken)) { @@ -26542,7 +26581,7 @@ namespace ts { } if (isReferenceToType(promise, getGlobalPromiseType(/*reportErrors*/ false))) { - return typeAsPromise.promisedTypeOfPromise = (promise).typeArguments![0]; + return typeAsPromise.promisedTypeOfPromise = getTypeArguments(promise)[0]; } const thenFunction = getTypeOfPropertyOfType(promise, "then" as __String)!; // TODO: GH#18217 @@ -28435,7 +28474,7 @@ namespace ts { let globalType: Type; if (isReferenceToType(type, globalType = resolver.getGlobalIterableType(/*reportErrors*/ false)) || isReferenceToType(type, globalType = resolver.getGlobalIterableIteratorType(/*reportErrors*/ false))) { - const [yieldType] = (type as GenericType).typeArguments!; + const [yieldType] = getTypeArguments(type as GenericType); // The "return" and "next" types of `Iterable` and `IterableIterator` are defined by the // iteration types of their `[Symbol.iterator]()` method. The same is true for their async cousins. // While we define these as `any` and `undefined` in our libs by default, a custom lib *could* use @@ -28448,7 +28487,7 @@ namespace ts { // just grab its related type arguments: // - `Generator` or `AsyncGenerator` if (isReferenceToType(type, resolver.getGlobalGeneratorType(/*reportErrors*/ false))) { - const [yieldType, returnType, nextType] = (type as GenericType).typeArguments!; + const [yieldType, returnType, nextType] = getTypeArguments(type as GenericType); return (type as IterableOrIteratorType)[resolver.iterableCacheKey] = createIterationTypes(yieldType, returnType, nextType); } } @@ -28536,7 +28575,7 @@ namespace ts { // - `Generator` or `AsyncGenerator` const globalType = resolver.getGlobalIterableIteratorType(/*reportErrors*/ false); if (isReferenceToType(type, globalType)) { - const [yieldType] = (type as GenericType).typeArguments!; + const [yieldType] = getTypeArguments(type as GenericType); // The "return" and "next" types of `IterableIterator` and `AsyncIterableIterator` are defined by the // iteration types of their `next`, `return`, and `throw` methods. While we define these as `any` // and `undefined` in our libs by default, a custom lib *could* use different definitions. @@ -28548,7 +28587,7 @@ namespace ts { } if (isReferenceToType(type, resolver.getGlobalIteratorType(/*reportErrors*/ false)) || isReferenceToType(type, resolver.getGlobalGeneratorType(/*reportErrors*/ false))) { - const [yieldType, returnType, nextType] = (type as GenericType).typeArguments!; + const [yieldType, returnType, nextType] = getTypeArguments(type as GenericType); return (type as IterableOrIteratorType)[resolver.iteratorCacheKey] = createIterationTypes(yieldType, returnType, nextType); } } @@ -28590,11 +28629,11 @@ namespace ts { // As an optimization, if the type is an instantiation of one of the global `IteratorYieldResult` // or `IteratorReturnResult` types, then just grab its type argument. if (isReferenceToType(type, getGlobalIteratorYieldResultType(/*reportErrors*/ false))) { - const yieldType = (type as GenericType).typeArguments![0]; + const yieldType = getTypeArguments(type as GenericType)[0]; return (type as IterableOrIteratorType).iterationTypesOfIteratorResult = createIterationTypes(yieldType, /*returnType*/ undefined, /*nextType*/ undefined); } if (isReferenceToType(type, getGlobalIteratorReturnResultType(/*reportErrors*/ false))) { - const returnType = (type as GenericType).typeArguments![0]; + const returnType = getTypeArguments(type as GenericType)[0]; return (type as IterableOrIteratorType).iterationTypesOfIteratorResult = createIterationTypes(/*yieldType*/ undefined, returnType, /*nextType*/ undefined); } diff --git a/src/compiler/symbolWalker.ts b/src/compiler/symbolWalker.ts index 1f6930076be..76bffca9740 100644 --- a/src/compiler/symbolWalker.ts +++ b/src/compiler/symbolWalker.ts @@ -10,7 +10,8 @@ namespace ts { getResolvedSymbol: (node: Node) => Symbol, getIndexTypeOfStructuredType: (type: Type, kind: IndexKind) => Type | undefined, getConstraintOfTypeParameter: (typeParameter: TypeParameter) => Type | undefined, - getFirstIdentifier: (node: EntityNameOrEntityNameExpression) => Identifier) { + getFirstIdentifier: (node: EntityNameOrEntityNameExpression) => Identifier, + getTypeArguments: (type: TypeReference) => ReadonlyArray) { return getSymbolWalker; @@ -89,7 +90,7 @@ namespace ts { function visitTypeReference(type: TypeReference): void { visitType(type.target); - forEach(type.typeArguments, visitType); + forEach(getTypeArguments(type), visitType); } function visitTypeParameter(type: TypeParameter): void { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index b3565e7797d..f61aecbc9c3 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4200,7 +4200,9 @@ namespace ts { */ export interface TypeReference extends ObjectType { target: GenericType; // Type reference target - typeArguments?: ReadonlyArray; // Type reference type arguments (undefined if none) + resolvedTypeArguments?: ReadonlyArray; // Type reference type arguments (undefined if none) + typeArgumentNodes?: ReadonlyArray; + mapper?: TypeMapper; /* @internal */ literalType?: TypeReference; // Clone of type with ObjectFlags.ArrayLiteral set } From b24fcd0bc5cd76ca9fe82deac21495030689ba4d Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 24 Aug 2019 08:54:59 -0400 Subject: [PATCH 039/140] Recursive tuple types + fix instantiation of recursive type references --- src/compiler/checker.ts | 69 ++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b7e645e99d8..10761123a6b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9581,13 +9581,25 @@ namespace ts { return createTypeFromGenericGlobalType(readonly ? globalReadonlyArrayType : globalArrayType, [elementType]); } - function getTypeFromArrayTypeNode(node: ArrayTypeNode): Type { + function getArrayOrTupleTargetType(node: ArrayTypeNode | TupleTypeNode): GenericType { + const readonly = isReadonlyTypeOperator(node.parent); + if (node.kind === SyntaxKind.ArrayType || node.elementTypes.length === 1 && node.elementTypes[0].kind === SyntaxKind.RestType) { + return readonly ? globalReadonlyArrayType : globalArrayType; + } + const lastElement = lastOrUndefined(node.elementTypes); + const restElement = lastElement && lastElement.kind === SyntaxKind.RestType ? lastElement : undefined; + const minLength = findLastIndex(node.elementTypes, n => n.kind !== SyntaxKind.OptionalType && n !== restElement) + 1; + return getTupleTypeOfArity(node.elementTypes.length, minLength, !!restElement, readonly, /*associatedNames*/ undefined); + } + + function getTypeFromArrayOrTupleTypeNode(node: ArrayTypeNode | TupleTypeNode): Type { const links = getNodeLinks(node); if (!links.resolvedType) { - const target = isReadonlyTypeOperator(node.parent) ? globalReadonlyArrayType : globalArrayType; + const target = getArrayOrTupleTargetType(node); const aliasSymbol = getAliasSymbolForTypeNode(node); const aliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol); - links.resolvedType = createDeferredTypeReference(target, [node.elementType], /*mapper*/ undefined, aliasSymbol, aliasTypeArguments); + const elementTypes = node.kind === SyntaxKind.ArrayType ? [node.elementType] : node.elementTypes; + links.resolvedType = elementTypes.length ? createDeferredTypeReference(target, elementTypes, /*mapper*/ undefined, aliasSymbol, aliasTypeArguments) : target; } return links.resolvedType; } @@ -9665,21 +9677,6 @@ namespace ts { return elementTypes.length ? createTypeReference(tupleType, elementTypes) : tupleType; } - function getTypeFromTupleTypeNode(node: TupleTypeNode): Type { - const links = getNodeLinks(node); - if (!links.resolvedType) { - const lastElement = lastOrUndefined(node.elementTypes); - const restElement = lastElement && lastElement.kind === SyntaxKind.RestType ? lastElement : undefined; - const minLength = findLastIndex(node.elementTypes, n => n.kind !== SyntaxKind.OptionalType && n !== restElement) + 1; - const elementTypes = map(node.elementTypes, n => { - const type = getTypeFromTypeNode(n); - return n === restElement && getIndexTypeOfType(type, IndexKind.Number) || type; - }); - links.resolvedType = createTupleType(elementTypes, minLength, !!restElement, isReadonlyTypeOperator(node.parent)); - } - return links.resolvedType; - } - function sliceTupleType(type: TupleTypeReference, index: number) { const tuple = type.target; if (tuple.hasRestElement) { @@ -11169,9 +11166,8 @@ namespace ts { case SyntaxKind.TypeQuery: return getTypeFromTypeQueryNode(node); case SyntaxKind.ArrayType: - return getTypeFromArrayTypeNode(node); case SyntaxKind.TupleType: - return getTypeFromTupleTypeNode(node); + return getTypeFromArrayOrTupleTypeNode(node); case SyntaxKind.OptionalType: return getTypeFromOptionalTypeNode(node); case SyntaxKind.UnionType: @@ -11183,10 +11179,11 @@ namespace ts { case SyntaxKind.JSDocOptionalType: return addOptionality(getTypeFromTypeNode((node as JSDocOptionalType).type)); case SyntaxKind.ParenthesizedType: - case SyntaxKind.RestType: case SyntaxKind.JSDocNonNullableType: case SyntaxKind.JSDocTypeExpression: - return getTypeFromTypeNode((node).type); + return getTypeFromTypeNode((node).type); + case SyntaxKind.RestType: + return getElementTypeOfArrayType(getTypeFromTypeNode((node).type)) || errorType; case SyntaxKind.JSDocVariadicType: return getTypeFromJSDocVariadicType(node as JSDocVariadicType); case SyntaxKind.FunctionType: @@ -11644,19 +11641,15 @@ namespace ts { return getAnonymousTypeInstantiation(type, mapper); } if (objectFlags & ObjectFlags.Reference) { + const typeArgumentNodes = (type).typeArgumentNodes; + if (typeArgumentNodes) { + const combinedMapper = combineTypeMappers((type).mapper, mapper); + return createDeferredTypeReference((type).target, typeArgumentNodes, combinedMapper, + (type).aliasSymbol, instantiateTypes((type).aliasTypeArguments, combinedMapper)); + } const resolvedTypeArguments = (type).resolvedTypeArguments; - if (resolvedTypeArguments) { - const newTypeArguments = instantiateTypes(resolvedTypeArguments, mapper); - return newTypeArguments !== resolvedTypeArguments ? createTypeReference((type).target, newTypeArguments) : type; - } - else { - const typeArgumentNodes = (type).typeArgumentNodes; - if (typeArgumentNodes) { - const combinedMapper = combineTypeMappers((type).mapper, mapper); - return createDeferredTypeReference((type).target, typeArgumentNodes, combinedMapper, - (type).aliasSymbol, instantiateTypes((type).aliasTypeArguments, combinedMapper)); - } - } + const newTypeArguments = instantiateTypes(resolvedTypeArguments, mapper); + return newTypeArguments !== resolvedTypeArguments ? createTypeReference((type).target, newTypeArguments) : type; } return type; } @@ -14446,8 +14439,12 @@ namespace ts { return type.flags & TypeFlags.TypeParameter && !getConstraintOfTypeParameter(type); } + function isNonDeferredTypeReference(type: Type): type is TypeReference { + return !!(getObjectFlags(type) & ObjectFlags.Reference) && !(type).typeArgumentNodes; + } + function isTypeReferenceWithGenericArguments(type: Type): boolean { - return !!(getObjectFlags(type) & ObjectFlags.Reference) && some(getTypeArguments(type), t => isUnconstrainedTypeParameter(t) || isTypeReferenceWithGenericArguments(t)); + return isNonDeferredTypeReference(type) && some(getTypeArguments(type), t => isUnconstrainedTypeParameter(t) || isTypeReferenceWithGenericArguments(t)); } /** @@ -26090,7 +26087,7 @@ namespace ts { grammarErrorOnNode(e, Diagnostics.A_rest_element_must_be_last_in_a_tuple_type); break; } - if (!isArrayType(getTypeFromTypeNode(e))) { + if (!isArrayType(getTypeFromTypeNode((e).type))) { error(e, Diagnostics.A_rest_element_type_must_be_an_array_type); } } From 52a1a14331e6938226ca61c9ccb3ea7e115c2956 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 26 Aug 2019 07:08:37 -0400 Subject: [PATCH 040/140] Instantiate deferred type references like anonymous types --- src/compiler/checker.ts | 48 +++++++++++++++++++++-------------------- src/compiler/types.ts | 11 ++++++++-- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 10761123a6b..b752f8fa5ff 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9077,10 +9077,10 @@ namespace ts { return type; } - function createDeferredTypeReference(target: GenericType, typeArgumentNodes: ReadonlyArray, mapper?: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: ReadonlyArray): TypeReference { - const type = createObjectType(ObjectFlags.Reference, target.symbol); + function createDeferredTypeReference(target: GenericType, node: ArrayTypeNode | TupleTypeNode, mapper?: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: ReadonlyArray): DeferredTypeReference { + const type = createObjectType(ObjectFlags.Reference, target.symbol); type.target = target; - type.typeArgumentNodes = typeArgumentNodes; + type.node = node; type.mapper = mapper; type.aliasSymbol = aliasSymbol; type.aliasTypeArguments = aliasTypeArguments; @@ -9089,7 +9089,7 @@ namespace ts { function getTypeArguments(type: TypeReference): ReadonlyArray { if (!type.resolvedTypeArguments) { - const typeArguments = type.typeArgumentNodes ? map(type.typeArgumentNodes, getTypeFromTypeNode) : emptyArray; + const typeArguments = type.node ? map(type.node.kind === SyntaxKind.ArrayType ? [type.node.elementType] : type.node.elementTypes, getTypeFromTypeNode) : emptyArray; type.resolvedTypeArguments = type.mapper ? instantiateTypes(typeArguments, type.mapper) : typeArguments; } return type.resolvedTypeArguments; @@ -9598,8 +9598,8 @@ namespace ts { const target = getArrayOrTupleTargetType(node); const aliasSymbol = getAliasSymbolForTypeNode(node); const aliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol); - const elementTypes = node.kind === SyntaxKind.ArrayType ? [node.elementType] : node.elementTypes; - links.resolvedType = elementTypes.length ? createDeferredTypeReference(target, elementTypes, /*mapper*/ undefined, aliasSymbol, aliasTypeArguments) : target; + links.resolvedType = node.kind === SyntaxKind.TupleType && node.elementTypes.length === 0 ? target : + createDeferredTypeReference(target, node, /*mapper*/ undefined, aliasSymbol, aliasTypeArguments); } return links.resolvedType; } @@ -11393,17 +11393,17 @@ namespace ts { return result; } - function getAnonymousTypeInstantiation(type: AnonymousType, mapper: TypeMapper) { + function getObjectTypeInstantiation(type: AnonymousType | DeferredTypeReference, mapper: TypeMapper) { const target = type.objectFlags & ObjectFlags.Instantiated ? type.target! : type; - const { symbol } = target; - const links = getSymbolLinks(symbol); + const node = type.objectFlags & ObjectFlags.Reference ? (type).node! : type.symbol.declarations[0]; + const links = getNodeLinks(node); let typeParameters = links.outerTypeParameters; if (!typeParameters) { // The first time an anonymous type is instantiated we compute and store a list of the type // parameters that are in scope (and therefore potentially referenced). For type literals that // aren't the right hand side of a generic type alias declaration we optimize by reducing the // set of type parameters to those that are possibly referenced in the literal. - let declaration = symbol.declarations[0]; + let declaration = node; if (isInJSFile(declaration)) { const paramTag = findAncestor(declaration, isJSDocParameterTag); if (paramTag) { @@ -11419,7 +11419,7 @@ namespace ts { outerTypeParameters = addRange(outerTypeParameters, templateTagParameters); } typeParameters = outerTypeParameters || emptyArray; - typeParameters = symbol.flags & SymbolFlags.TypeLiteral && !target.aliasTypeArguments ? + typeParameters = (target.objectFlags & ObjectFlags.Reference || target.symbol.flags & SymbolFlags.TypeLiteral) && !target.aliasTypeArguments ? filter(typeParameters, tp => isTypeParameterPossiblyReferenced(tp, declaration)) : typeParameters; links.outerTypeParameters = typeParameters; @@ -11432,13 +11432,14 @@ namespace ts { // We are instantiating an anonymous type that has one or more type parameters in scope. Apply the // mapper to the type parameters to produce the effective list of type arguments, and compute the // instantiation cache key from the type IDs of the type arguments. - const combinedMapper = type.objectFlags & ObjectFlags.Instantiated ? combineTypeMappers(type.mapper!, mapper) : mapper; - const typeArguments: Type[] = map(typeParameters, combinedMapper); + const typeArguments: Type[] = map(typeParameters, combineTypeMappers(type.mapper, mapper)); const id = getTypeListId(typeArguments); let result = links.instantiations!.get(id); if (!result) { const newMapper = createTypeMapper(typeParameters, typeArguments); - result = target.objectFlags & ObjectFlags.Mapped ? instantiateMappedType(target, newMapper) : instantiateAnonymousType(target, newMapper); + result = target.objectFlags & ObjectFlags.Reference ? instantiateDeferredTypeReference(type, newMapper) : + target.objectFlags & ObjectFlags.Mapped ? instantiateMappedType(target, newMapper) : + instantiateAnonymousType(target, newMapper); links.instantiations!.set(id, result); } return result; @@ -11570,6 +11571,10 @@ namespace ts { return result; } + function instantiateDeferredTypeReference(type: DeferredTypeReference, mapper: TypeMapper): TypeReference { + return createDeferredTypeReference(type.target, type.node, mapper, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper)); + } + function getConditionalTypeInstantiation(type: ConditionalType, mapper: TypeMapper): Type { const root = type.root; if (root.outerTypeParameters) { @@ -11635,17 +11640,14 @@ namespace ts { // interface, in an object type literal, or in an object literal expression, we may need // to instantiate the type because it might reference a type parameter. return couldContainTypeVariables(type) ? - getAnonymousTypeInstantiation(type, mapper) : type; + getObjectTypeInstantiation(type, mapper) : type; } if (objectFlags & ObjectFlags.Mapped) { - return getAnonymousTypeInstantiation(type, mapper); + return getObjectTypeInstantiation(type, mapper); } if (objectFlags & ObjectFlags.Reference) { - const typeArgumentNodes = (type).typeArgumentNodes; - if (typeArgumentNodes) { - const combinedMapper = combineTypeMappers((type).mapper, mapper); - return createDeferredTypeReference((type).target, typeArgumentNodes, combinedMapper, - (type).aliasSymbol, instantiateTypes((type).aliasTypeArguments, combinedMapper)); + if ((type).node) { + return getObjectTypeInstantiation(type, mapper); } const resolvedTypeArguments = (type).resolvedTypeArguments; const newTypeArguments = instantiateTypes(resolvedTypeArguments, mapper); @@ -14440,7 +14442,7 @@ namespace ts { } function isNonDeferredTypeReference(type: Type): type is TypeReference { - return !!(getObjectFlags(type) & ObjectFlags.Reference) && !(type).typeArgumentNodes; + return !!(getObjectFlags(type) & ObjectFlags.Reference) && !(type).node; } function isTypeReferenceWithGenericArguments(type: Type): boolean { @@ -22849,7 +22851,7 @@ namespace ts { * Indicates whether a declaration can be treated as a constructor in a JavaScript * file. */ - function isJSConstructor(node: Declaration | undefined): boolean { + function isJSConstructor(node: Node | undefined): boolean { if (!node || !isInJSFile(node)) { return false; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index f61aecbc9c3..1b8c8df94e2 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3954,6 +3954,8 @@ namespace ts { contextFreeType?: Type; // Cached context-free type used by the first pass of inference; used when a function's return is partially contextually sensitive deferredNodes?: Map; // Set of nodes whose checking has been deferred capturedBlockScopeBindings?: Symbol[]; // Block-scoped bindings captured beneath this part of an IterationStatement + outerTypeParameters?: TypeParameter[]; // Outer type parameters of anonymous object type + instantiations?: Map; // Instantiations of generic type alias (undefined if non-generic) } export const enum TypeFlags { @@ -4200,13 +4202,18 @@ namespace ts { */ export interface TypeReference extends ObjectType { target: GenericType; // Type reference target - resolvedTypeArguments?: ReadonlyArray; // Type reference type arguments (undefined if none) - typeArgumentNodes?: ReadonlyArray; + node?: ArrayTypeNode | TupleTypeNode; mapper?: TypeMapper; + resolvedTypeArguments?: ReadonlyArray; // Resolved ype reference type arguments /* @internal */ literalType?: TypeReference; // Clone of type with ObjectFlags.ArrayLiteral set } + export interface DeferredTypeReference extends TypeReference { + node: ArrayTypeNode | TupleTypeNode; + mapper?: TypeMapper; + } + /* @internal */ export const enum VarianceFlags { Invariant = 0, // Neither covariant nor contravariant From dd47fffe8fefed52d9d1d62fb4ba32c7f7bd651c Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 26 Aug 2019 11:00:20 -0400 Subject: [PATCH 041/140] Properly handle recursive array and tuple types in printback --- src/compiler/checker.ts | 68 ++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b752f8fa5ff..81eda207fc3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3540,7 +3540,6 @@ namespace ts { } function createNodeBuilder() { - let depth = 0; return { typeToTypeNode: (type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => withContext(enclosingDeclaration, flags, tracker, context => typeToTypeNodeHelper(type, context)), @@ -3712,7 +3711,7 @@ namespace ts { if (objectFlags & ObjectFlags.Reference) { Debug.assert(!!(type.flags & TypeFlags.Object)); - return typeReferenceToTypeNode(type); + return (type).node ? visitAndTransformType(type, typeReferenceToTypeNode) : typeReferenceToTypeNode(type); } if (type.flags & TypeFlags.TypeParameter || objectFlags & ObjectFlags.ClassOrInterface) { if (type.flags & TypeFlags.TypeParameter && contains(context.inferTypeParameters, type)) { @@ -3804,10 +3803,7 @@ namespace ts { function createAnonymousTypeNode(type: ObjectType): TypeNode { const typeId = "" + type.id; const symbol = type.symbol; - let id: string; if (symbol) { - const isConstructorObject = getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & SymbolFlags.Class; - id = (isConstructorObject ? "+" : "") + getSymbolId(symbol); if (isJSConstructor(symbol.valueDeclaration)) { // Instance and static types share the same symbol; only add 'typeof' for the static side. const isInstanceType = type === getInferredClassType(symbol) ? SymbolFlags.Type : SymbolFlags.Value; @@ -3831,25 +3827,7 @@ namespace ts { } } else { - // Since instantiations of the same anonymous type have the same symbol, tracking symbols instead - // of types allows us to catch circular references to instantiations of the same anonymous type - if (!context.visitedTypes) { - context.visitedTypes = createMap(); - } - if (!context.symbolDepth) { - context.symbolDepth = createMap(); - } - - const depth = context.symbolDepth.get(id) || 0; - if (depth > 10) { - return createElidedInformationPlaceholder(context); - } - context.symbolDepth.set(id, depth + 1); - context.visitedTypes.set(typeId, true); - const result = createTypeNodeFromObjectType(type); - context.visitedTypes.delete(typeId); - context.symbolDepth.set(id, depth); - return result; + return visitAndTransformType(type, createTypeNodeFromObjectType); } } else { @@ -3871,6 +3849,37 @@ namespace ts { } } + function visitAndTransformType(type: Type, transform: (type: Type) => T) { + const typeId = "" + type.id; + const isConstructorObject = getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & SymbolFlags.Class; + const id = getObjectFlags(type) & ObjectFlags.Reference ? "N" + getNodeId((type).node) : + (isConstructorObject ? "+" : "") + getSymbolId(type.symbol); + // Since instantiations of the same anonymous type have the same symbol, tracking symbols instead + // of types allows us to catch circular references to instantiations of the same anonymous type + if (!context.visitedTypes) { + context.visitedTypes = createMap(); + } + if (id && !context.symbolDepth) { + context.symbolDepth = createMap(); + } + + let depth: number | undefined; + if (id) { + depth = context.symbolDepth!.get(id) || 0; + if (depth > 10) { + return createElidedInformationPlaceholder(context); + } + context.symbolDepth!.set(id, depth + 1); + } + context.visitedTypes.set(typeId, true); + const result = transform(type); + context.visitedTypes.delete(typeId); + if (id) { + context.symbolDepth!.set(id, depth!); + } + return result; + } + function createTypeNodeFromObjectType(type: ObjectType): TypeNode { if (isGenericMappedType(type)) { return createMappedTypeNodeFromType(type); @@ -3910,15 +3919,10 @@ namespace ts { const typeArguments: ReadonlyArray = getTypeArguments(type); if (type.target === globalArrayType || type.target === globalReadonlyArrayType) { if (context.flags & NodeBuilderFlags.WriteArrayAsGenericType) { - depth++; - const typeArgumentNode = typeToTypeNodeHelper(depth >= 5 ? anyType : typeArguments[0], context); - depth--; - createTypeReferenceNode(type.target === globalArrayType ? "Array" : "ReadonlyArray", [typeArgumentNode]); + const typeArgumentNode = typeToTypeNodeHelper(typeArguments[0], context); + return createTypeReferenceNode(type.target === globalArrayType ? "Array" : "ReadonlyArray", [typeArgumentNode]); } - - depth++; - const elementType = typeToTypeNodeHelper(depth >= 5 ? anyType : typeArguments[0], context); - depth--; + const elementType = typeToTypeNodeHelper(typeArguments[0], context); const arrayType = createArrayTypeNode(elementType); return type.target === globalArrayType ? arrayType : createTypeOperatorNode(SyntaxKind.ReadonlyKeyword, arrayType); } From 3be6e75d6aee0c2a0a3be1b42ab84aa8c5c2e8ac Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Mon, 26 Aug 2019 11:13:17 -0700 Subject: [PATCH 042/140] Improve names in infer-from-usage Basically, drop "Context" from all names, because it just indicates that it's an implementation of the State monad. --- src/services/codefixes/inferFromUsage.ts | 238 +++++++++++------------ 1 file changed, 119 insertions(+), 119 deletions(-) diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index 396d7f44fa8..417ed5c625c 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -359,7 +359,7 @@ namespace ts.codefix { const references = getReferences(token, program, cancellationToken); const checker = program.getTypeChecker(); const types = InferFromReference.inferTypesFromReferences(references, checker, cancellationToken); - return InferFromReference.unifyFromContext(types, checker); + return InferFromReference.unifyFromUsage(types, checker); } function inferFunctionReferencesFromUsage(containingFunction: FunctionLike, sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): ReadonlyArray | undefined { @@ -395,33 +395,33 @@ namespace ts.codefix { } namespace InferFromReference { - interface CallContext { + interface CallUsage { argumentTypes: Type[]; - returnType: UsageContext; + returnType: Usage; } - interface UsageContext { + interface Usage { isNumber?: boolean; isString?: boolean; /** Used ambiguously, eg x + ___ or object[___]; results in string | number if no other evidence exists */ isNumberOrString?: boolean; candidateTypes?: Type[]; - properties?: UnderscoreEscapedMap; - callContexts?: CallContext[]; - constructContexts?: CallContext[]; - numberIndexContext?: UsageContext; - stringIndexContext?: UsageContext; + properties?: UnderscoreEscapedMap; + calls?: CallUsage[]; + constructs?: CallUsage[]; + numberIndex?: Usage; + stringIndex?: Usage; candidateThisTypes?: Type[]; } export function inferTypesFromReferences(references: ReadonlyArray, checker: TypeChecker, cancellationToken: CancellationToken): Type[] { - const usageContext: UsageContext = {}; + const usage: Usage = {}; for (const reference of references) { cancellationToken.throwIfCancellationRequested(); - inferTypeFromContext(reference, checker, usageContext); + calculateUsageOfNode(reference, checker, usage); } - return inferFromContext(usageContext, checker); + return inferFromUsage(usage, checker); } export function inferTypeForParametersFromReferences(references: ReadonlyArray | undefined, declaration: FunctionLike, program: Program, cancellationToken: CancellationToken): ParameterInference[] | undefined { @@ -430,35 +430,35 @@ namespace ts.codefix { } const checker = program.getTypeChecker(); - const usageContext: UsageContext = {}; + const usage: Usage = {}; for (const reference of references) { cancellationToken.throwIfCancellationRequested(); - inferTypeFromContext(reference, checker, usageContext); + calculateUsageOfNode(reference, checker, usage); } - const callContexts = [...usageContext.constructContexts || [], ...usageContext.callContexts || []]; + const calls = [...usage.constructs || [], ...usage.calls || []]; return declaration.parameters.map((parameter, parameterIndex): ParameterInference => { const types = []; const isRest = isRestParameter(parameter); let isOptional = false; - for (const callContext of callContexts) { - if (callContext.argumentTypes.length <= parameterIndex) { + for (const call of calls) { + if (call.argumentTypes.length <= parameterIndex) { isOptional = isInJSFile(declaration); types.push(checker.getUndefinedType()); } else if (isRest) { - for (let i = parameterIndex; i < callContext.argumentTypes.length; i++) { - types.push(checker.getBaseTypeOfLiteralType(callContext.argumentTypes[i])); + for (let i = parameterIndex; i < call.argumentTypes.length; i++) { + types.push(checker.getBaseTypeOfLiteralType(call.argumentTypes[i])); } } else { - types.push(checker.getBaseTypeOfLiteralType(callContext.argumentTypes[parameterIndex])); + types.push(checker.getBaseTypeOfLiteralType(call.argumentTypes[parameterIndex])); } } if (isIdentifier(parameter.name)) { const inferred = inferTypesFromReferences(getReferences(parameter.name, program, cancellationToken), checker, cancellationToken); types.push(...(isRest ? mapDefined(inferred, checker.getElementTypeOfArrayType) : inferred)); } - const type = unifyFromContext(types, checker); + const type = unifyFromUsage(types, checker); return { type: isRest ? checker.createArrayType(type) : type, isOptional: isOptional && !isRest, @@ -473,89 +473,89 @@ namespace ts.codefix { } const checker = program.getTypeChecker(); - const usageContext: UsageContext = {}; + const usage: Usage = {}; for (const reference of references) { cancellationToken.throwIfCancellationRequested(); - inferTypeFromContext(reference, checker, usageContext); + calculateUsageOfNode(reference, checker, usage); } - return unifyFromContext(usageContext.candidateThisTypes || emptyArray, checker); + return unifyFromUsage(usage.candidateThisTypes || emptyArray, checker); } - function inferTypeFromContext(node: Expression, checker: TypeChecker, usageContext: UsageContext): void { + function calculateUsageOfNode(node: Expression, checker: TypeChecker, usage: Usage): void { while (isRightSideOfQualifiedNameOrPropertyAccess(node)) { node = node.parent; } switch (node.parent.kind) { case SyntaxKind.PostfixUnaryExpression: - usageContext.isNumber = true; + usage.isNumber = true; break; case SyntaxKind.PrefixUnaryExpression: - inferTypeFromPrefixUnaryExpressionContext(node.parent, usageContext); + inferTypeFromPrefixUnaryExpression(node.parent, usage); break; case SyntaxKind.BinaryExpression: - inferTypeFromBinaryExpressionContext(node, node.parent, checker, usageContext); + inferTypeFromBinaryExpression(node, node.parent, checker, usage); break; case SyntaxKind.CaseClause: case SyntaxKind.DefaultClause: - inferTypeFromSwitchStatementLabelContext(node.parent, checker, usageContext); + inferTypeFromSwitchStatementLabel(node.parent, checker, usage); break; case SyntaxKind.CallExpression: case SyntaxKind.NewExpression: if ((node.parent).expression === node) { - inferTypeFromCallExpressionContext(node.parent, checker, usageContext); + inferTypeFromCallExpression(node.parent, checker, usage); } else { - inferTypeFromContextualType(node, checker, usageContext); + inferTypeFromContextualType(node, checker, usage); } break; case SyntaxKind.PropertyAccessExpression: - inferTypeFromPropertyAccessExpressionContext(node.parent, checker, usageContext); + inferTypeFromPropertyAccessExpression(node.parent, checker, usage); break; case SyntaxKind.ElementAccessExpression: - inferTypeFromPropertyElementExpressionContext(node.parent, node, checker, usageContext); + inferTypeFromPropertyElementExpression(node.parent, node, checker, usage); break; case SyntaxKind.PropertyAssignment: case SyntaxKind.ShorthandPropertyAssignment: - inferTypeFromPropertyAssignment(node.parent, checker, usageContext); + inferTypeFromPropertyAssignment(node.parent, checker, usage); break; case SyntaxKind.PropertyDeclaration: - inferTypeFromPropertyDeclaration(node.parent, checker, usageContext); + inferTypeFromPropertyDeclaration(node.parent, checker, usage); break; case SyntaxKind.VariableDeclaration: { const { name, initializer } = node.parent as VariableDeclaration; if (node === name) { if (initializer) { // This can happen for `let x = null;` which still has an implicit-any error. - addCandidateType(usageContext, checker.getTypeAtLocation(initializer)); + addCandidateType(usage, checker.getTypeAtLocation(initializer)); } break; } } // falls through default: - return inferTypeFromContextualType(node, checker, usageContext); + return inferTypeFromContextualType(node, checker, usage); } } - function inferTypeFromContextualType(node: Expression, checker: TypeChecker, usageContext: UsageContext): void { + function inferTypeFromContextualType(node: Expression, checker: TypeChecker, usage: Usage): void { if (isExpressionNode(node)) { - addCandidateType(usageContext, checker.getContextualType(node)); + addCandidateType(usage, checker.getContextualType(node)); } } - function inferTypeFromPrefixUnaryExpressionContext(node: PrefixUnaryExpression, usageContext: UsageContext): void { + function inferTypeFromPrefixUnaryExpression(node: PrefixUnaryExpression, usage: Usage): void { switch (node.operator) { case SyntaxKind.PlusPlusToken: case SyntaxKind.MinusMinusToken: case SyntaxKind.MinusToken: case SyntaxKind.TildeToken: - usageContext.isNumber = true; + usage.isNumber = true; break; case SyntaxKind.PlusToken: - usageContext.isNumberOrString = true; + usage.isNumberOrString = true; break; // case SyntaxKind.ExclamationToken: @@ -563,7 +563,7 @@ namespace ts.codefix { } } - function inferTypeFromBinaryExpressionContext(node: Expression, parent: BinaryExpression, checker: TypeChecker, usageContext: UsageContext): void { + function inferTypeFromBinaryExpression(node: Expression, parent: BinaryExpression, checker: TypeChecker, usage: Usage): void { switch (parent.operatorToken.kind) { // ExponentiationOperator case SyntaxKind.AsteriskAsteriskToken: @@ -606,10 +606,10 @@ namespace ts.codefix { case SyntaxKind.GreaterThanEqualsToken: const operandType = checker.getTypeAtLocation(parent.left === node ? parent.right : parent.left); if (operandType.flags & TypeFlags.EnumLike) { - addCandidateType(usageContext, operandType); + addCandidateType(usage, operandType); } else { - usageContext.isNumber = true; + usage.isNumber = true; } break; @@ -617,16 +617,16 @@ namespace ts.codefix { case SyntaxKind.PlusToken: const otherOperandType = checker.getTypeAtLocation(parent.left === node ? parent.right : parent.left); if (otherOperandType.flags & TypeFlags.EnumLike) { - addCandidateType(usageContext, otherOperandType); + addCandidateType(usage, otherOperandType); } else if (otherOperandType.flags & TypeFlags.NumberLike) { - usageContext.isNumber = true; + usage.isNumber = true; } else if (otherOperandType.flags & TypeFlags.StringLike) { - usageContext.isString = true; + usage.isString = true; } else { - usageContext.isNumberOrString = true; + usage.isNumberOrString = true; } break; @@ -636,12 +636,12 @@ namespace ts.codefix { case SyntaxKind.EqualsEqualsEqualsToken: case SyntaxKind.ExclamationEqualsEqualsToken: case SyntaxKind.ExclamationEqualsToken: - addCandidateType(usageContext, checker.getTypeAtLocation(parent.left === node ? parent.right : parent.left)); + addCandidateType(usage, checker.getTypeAtLocation(parent.left === node ? parent.right : parent.left)); break; case SyntaxKind.InKeyword: if (node === parent.left) { - usageContext.isString = true; + usage.isString = true; } break; @@ -651,7 +651,7 @@ namespace ts.codefix { (node.parent.parent.kind === SyntaxKind.VariableDeclaration || isAssignmentExpression(node.parent.parent, /*excludeCompoundAssignment*/ true))) { // var x = x || {}; // TODO: use getFalsyflagsOfType - addCandidateType(usageContext, checker.getTypeAtLocation(parent.right)); + addCandidateType(usage, checker.getTypeAtLocation(parent.right)); } break; @@ -663,68 +663,68 @@ namespace ts.codefix { } } - function inferTypeFromSwitchStatementLabelContext(parent: CaseOrDefaultClause, checker: TypeChecker, usageContext: UsageContext): void { - addCandidateType(usageContext, checker.getTypeAtLocation(parent.parent.parent.expression)); + function inferTypeFromSwitchStatementLabel(parent: CaseOrDefaultClause, checker: TypeChecker, usage: Usage): void { + addCandidateType(usage, checker.getTypeAtLocation(parent.parent.parent.expression)); } - function inferTypeFromCallExpressionContext(parent: CallExpression | NewExpression, checker: TypeChecker, usageContext: UsageContext): void { - const callContext: CallContext = { + function inferTypeFromCallExpression(parent: CallExpression | NewExpression, checker: TypeChecker, usage: Usage): void { + const call: CallUsage = { argumentTypes: [], returnType: {} }; if (parent.arguments) { for (const argument of parent.arguments) { - callContext.argumentTypes.push(checker.getTypeAtLocation(argument)); + call.argumentTypes.push(checker.getTypeAtLocation(argument)); } } - inferTypeFromContext(parent, checker, callContext.returnType); + calculateUsageOfNode(parent, checker, call.returnType); if (parent.kind === SyntaxKind.CallExpression) { - (usageContext.callContexts || (usageContext.callContexts = [])).push(callContext); + (usage.calls || (usage.calls = [])).push(call); } else { - (usageContext.constructContexts || (usageContext.constructContexts = [])).push(callContext); + (usage.constructs || (usage.constructs = [])).push(call); } } - function inferTypeFromPropertyAccessExpressionContext(parent: PropertyAccessExpression, checker: TypeChecker, usageContext: UsageContext): void { + function inferTypeFromPropertyAccessExpression(parent: PropertyAccessExpression, checker: TypeChecker, usage: Usage): void { const name = escapeLeadingUnderscores(parent.name.text); - if (!usageContext.properties) { - usageContext.properties = createUnderscoreEscapedMap(); + if (!usage.properties) { + usage.properties = createUnderscoreEscapedMap(); } - const propertyUsageContext = usageContext.properties.get(name) || { }; - inferTypeFromContext(parent, checker, propertyUsageContext); - usageContext.properties.set(name, propertyUsageContext); + const propertyUsage = usage.properties.get(name) || { }; + calculateUsageOfNode(parent, checker, propertyUsage); + usage.properties.set(name, propertyUsage); } - function inferTypeFromPropertyElementExpressionContext(parent: ElementAccessExpression, node: Expression, checker: TypeChecker, usageContext: UsageContext): void { + function inferTypeFromPropertyElementExpression(parent: ElementAccessExpression, node: Expression, checker: TypeChecker, usage: Usage): void { if (node === parent.argumentExpression) { - usageContext.isNumberOrString = true; + usage.isNumberOrString = true; return; } else { const indexType = checker.getTypeAtLocation(parent.argumentExpression); - const indexUsageContext = {}; - inferTypeFromContext(parent, checker, indexUsageContext); + const indexUsage = {}; + calculateUsageOfNode(parent, checker, indexUsage); if (indexType.flags & TypeFlags.NumberLike) { - usageContext.numberIndexContext = indexUsageContext; + usage.numberIndex = indexUsage; } else { - usageContext.stringIndexContext = indexUsageContext; + usage.stringIndex = indexUsage; } } } - function inferTypeFromPropertyAssignment(assignment: PropertyAssignment | ShorthandPropertyAssignment, checker: TypeChecker, usageContext: UsageContext) { + function inferTypeFromPropertyAssignment(assignment: PropertyAssignment | ShorthandPropertyAssignment, checker: TypeChecker, usage: Usage) { const nodeWithRealType = isVariableDeclaration(assignment.parent.parent) ? assignment.parent.parent : assignment.parent; - addCandidateThisType(usageContext, checker.getTypeAtLocation(nodeWithRealType)); + addCandidateThisType(usage, checker.getTypeAtLocation(nodeWithRealType)); } - function inferTypeFromPropertyDeclaration(declaration: PropertyDeclaration, checker: TypeChecker, usageContext: UsageContext) { - addCandidateThisType(usageContext, checker.getTypeAtLocation(declaration.parent)); + function inferTypeFromPropertyDeclaration(declaration: PropertyDeclaration, checker: TypeChecker, usage: Usage) { + addCandidateThisType(usage, checker.getTypeAtLocation(declaration.parent)); } interface Priority { @@ -745,7 +745,7 @@ namespace ts.codefix { return inferences.filter(i => toRemove.every(f => !f(i))); } - export function unifyFromContext(inferences: ReadonlyArray, checker: TypeChecker, fallback = checker.getAnyType()): Type { + export function unifyFromUsage(inferences: ReadonlyArray, checker: TypeChecker, fallback = checker.getAnyType()): Type { if (!inferences.length) return fallback; // 1. string or number individually override string | number @@ -815,82 +815,82 @@ namespace ts.codefix { numberIndices.length ? checker.createIndexInfo(checker.getUnionType(numberIndices), numberIndexReadonly) : undefined); } - function inferFromContext(usageContext: UsageContext, checker: TypeChecker) { + function inferFromUsage(usage: Usage, checker: TypeChecker) { const types = []; - if (usageContext.isNumber) { + if (usage.isNumber) { types.push(checker.getNumberType()); } - if (usageContext.isString) { + if (usage.isString) { types.push(checker.getStringType()); } - if (usageContext.isNumberOrString) { + if (usage.isNumberOrString) { types.push(checker.getUnionType([checker.getStringType(), checker.getNumberType()])); } - types.push(...(usageContext.candidateTypes || []).map(t => checker.getBaseTypeOfLiteralType(t))); + types.push(...(usage.candidateTypes || []).map(t => checker.getBaseTypeOfLiteralType(t))); - if (usageContext.properties && hasCallContext(usageContext.properties.get("then" as __String))) { - const paramType = getParameterTypeFromCallContexts(0, usageContext.properties.get("then" as __String)!.callContexts!, /*isRestParameter*/ false, checker)!; // TODO: GH#18217 + if (usage.properties && hasCalls(usage.properties.get("then" as __String))) { + const paramType = getParameterTypeFromCalls(0, usage.properties.get("then" as __String)!.calls!, /*isRestParameter*/ false, checker)!; // TODO: GH#18217 const types = paramType.getCallSignatures().map(c => c.getReturnType()); types.push(checker.createPromiseType(types.length ? checker.getUnionType(types, UnionReduction.Subtype) : checker.getAnyType())); } - else if (usageContext.properties && hasCallContext(usageContext.properties.get("push" as __String))) { - types.push(checker.createArrayType(getParameterTypeFromCallContexts(0, usageContext.properties.get("push" as __String)!.callContexts!, /*isRestParameter*/ false, checker)!)); + else if (usage.properties && hasCalls(usage.properties.get("push" as __String))) { + types.push(checker.createArrayType(getParameterTypeFromCalls(0, usage.properties.get("push" as __String)!.calls!, /*isRestParameter*/ false, checker)!)); } - if (usageContext.numberIndexContext) { - types.push(checker.createArrayType(recur(usageContext.numberIndexContext))); + if (usage.numberIndex) { + types.push(checker.createArrayType(recur(usage.numberIndex))); } - else if (usageContext.properties || usageContext.callContexts || usageContext.constructContexts || usageContext.stringIndexContext) { + else if (usage.properties || usage.calls || usage.constructs || usage.stringIndex) { const members = createUnderscoreEscapedMap(); const callSignatures: Signature[] = []; const constructSignatures: Signature[] = []; let stringIndexInfo: IndexInfo | undefined; - if (usageContext.properties) { - usageContext.properties.forEach((context, name) => { + if (usage.properties) { + usage.properties.forEach((u, name) => { const symbol = checker.createSymbol(SymbolFlags.Property, name); - symbol.type = recur(context); + symbol.type = recur(u); members.set(name, symbol); }); } - if (usageContext.callContexts) { - for (const callContext of usageContext.callContexts) { - callSignatures.push(getSignatureFromCallContext(callContext, checker)); + if (usage.calls) { + for (const call of usage.calls) { + callSignatures.push(getSignatureFromCall(call, checker)); } } - if (usageContext.constructContexts) { - for (const constructContext of usageContext.constructContexts) { - constructSignatures.push(getSignatureFromCallContext(constructContext, checker)); + if (usage.constructs) { + for (const construct of usage.constructs) { + constructSignatures.push(getSignatureFromCall(construct, checker)); } } - if (usageContext.stringIndexContext) { - stringIndexInfo = checker.createIndexInfo(recur(usageContext.stringIndexContext), /*isReadonly*/ false); + if (usage.stringIndex) { + stringIndexInfo = checker.createIndexInfo(recur(usage.stringIndex), /*isReadonly*/ false); } types.push(checker.createAnonymousType(/*symbol*/ undefined!, members, callSignatures, constructSignatures, stringIndexInfo, /*numberIndexInfo*/ undefined)); // TODO: GH#18217 } return types; - function recur(innerContext: UsageContext): Type { - return unifyFromContext(inferFromContext(innerContext, checker), checker); + function recur(innerUsage: Usage): Type { + return unifyFromUsage(inferFromUsage(innerUsage, checker), checker); } } - function getParameterTypeFromCallContexts(parameterIndex: number, callContexts: CallContext[], isRestParameter: boolean, checker: TypeChecker) { + function getParameterTypeFromCalls(parameterIndex: number, calls: CallUsage[], isRestParameter: boolean, checker: TypeChecker) { let types: Type[] = []; - if (callContexts) { - for (const callContext of callContexts) { - if (callContext.argumentTypes.length > parameterIndex) { + if (calls) { + for (const call of calls) { + if (call.argumentTypes.length > parameterIndex) { if (isRestParameter) { - types = concatenate(types, map(callContext.argumentTypes.slice(parameterIndex), a => checker.getBaseTypeOfLiteralType(a))); + types = concatenate(types, map(call.argumentTypes.slice(parameterIndex), a => checker.getBaseTypeOfLiteralType(a))); } else { - types.push(checker.getBaseTypeOfLiteralType(callContext.argumentTypes[parameterIndex])); + types.push(checker.getBaseTypeOfLiteralType(call.argumentTypes[parameterIndex])); } } } @@ -903,32 +903,32 @@ namespace ts.codefix { return undefined; } - function getSignatureFromCallContext(callContext: CallContext, checker: TypeChecker): Signature { + function getSignatureFromCall(call: CallUsage, checker: TypeChecker): Signature { const parameters: Symbol[] = []; - for (let i = 0; i < callContext.argumentTypes.length; i++) { + for (let i = 0; i < call.argumentTypes.length; i++) { const symbol = checker.createSymbol(SymbolFlags.FunctionScopedVariable, escapeLeadingUnderscores(`arg${i}`)); - symbol.type = checker.getWidenedType(checker.getBaseTypeOfLiteralType(callContext.argumentTypes[i])); + symbol.type = checker.getWidenedType(checker.getBaseTypeOfLiteralType(call.argumentTypes[i])); parameters.push(symbol); } - const returnType = unifyFromContext(inferFromContext(callContext.returnType, checker), checker, checker.getVoidType()); + const returnType = unifyFromUsage(inferFromUsage(call.returnType, checker), checker, checker.getVoidType()); // TODO: GH#18217 - return checker.createSignature(/*declaration*/ undefined!, /*typeParameters*/ undefined, /*thisParameter*/ undefined, parameters, returnType, /*typePredicate*/ undefined, callContext.argumentTypes.length, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); + return checker.createSignature(/*declaration*/ undefined!, /*typeParameters*/ undefined, /*thisParameter*/ undefined, parameters, returnType, /*typePredicate*/ undefined, call.argumentTypes.length, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); } - function addCandidateType(context: UsageContext, type: Type | undefined) { + function addCandidateType(usage: Usage, type: Type | undefined) { if (type && !(type.flags & TypeFlags.Any) && !(type.flags & TypeFlags.Never)) { - (context.candidateTypes || (context.candidateTypes = [])).push(type); + (usage.candidateTypes || (usage.candidateTypes = [])).push(type); } } - function addCandidateThisType(context: UsageContext, type: Type | undefined) { + function addCandidateThisType(usage: Usage, type: Type | undefined) { if (type && !(type.flags & TypeFlags.Any) && !(type.flags & TypeFlags.Never)) { - (context.candidateThisTypes || (context.candidateThisTypes = [])).push(type); + (usage.candidateThisTypes || (usage.candidateThisTypes = [])).push(type); } } - function hasCallContext(usageContext: UsageContext | undefined): boolean { - return !!usageContext && !!usageContext.callContexts; + function hasCalls(usage: Usage | undefined): boolean { + return !!usage && !!usage.calls; } } } From 5310fd0156f6714506c1b6b7892d21177e30a898 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 27 Aug 2019 06:51:21 -0400 Subject: [PATCH 043/140] Minor fixes --- src/compiler/checker.ts | 12 +++++------- src/compiler/types.ts | 4 ++++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 13dbc1c7886..e49e4492265 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3876,8 +3876,9 @@ namespace ts { function visitAndTransformType(type: Type, transform: (type: Type) => T) { const typeId = "" + type.id; const isConstructorObject = getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & SymbolFlags.Class; - const id = getObjectFlags(type) & ObjectFlags.Reference ? "N" + getNodeId((type).node) : - (isConstructorObject ? "+" : "") + getSymbolId(type.symbol); + const id = getObjectFlags(type) & ObjectFlags.Reference && (type).node ? "N" + getNodeId((type).node!) : + type.symbol ? (isConstructorObject ? "+" : "") + getSymbolId(type.symbol) : + undefined; // Since instantiations of the same anonymous type have the same symbol, tracking symbols instead // of types allows us to catch circular references to instantiations of the same anonymous type if (!context.visitedTypes) { @@ -29347,12 +29348,9 @@ namespace ts { if (!(staticBaseType.symbol && staticBaseType.symbol.flags & SymbolFlags.Class) && !(baseConstructorType.flags & TypeFlags.TypeVariable)) { // When the static base type is a "class-like" constructor function (but not actually a class), we verify - // that all instantiated base constructor signatures return the same type. We can simply compare the type - // references (as opposed to checking the structure of the types) because elsewhere we have already checked - // that the base type is a class or interface type (and not, for example, an anonymous object type). - // (Javascript constructor functions have this property trivially true since their return type is ignored.) + // that all instantiated base constructor signatures return the same type. const constructors = getInstantiatedConstructorsForTypeArguments(staticBaseType, baseTypeNode.typeArguments, baseTypeNode); - if (forEach(constructors, sig => !isJSConstructor(sig.declaration) && getReturnTypeOfSignature(sig) !== baseType)) { + if (forEach(constructors, sig => !isJSConstructor(sig.declaration) && !isTypeIdenticalTo(getReturnTypeOfSignature(sig), baseType))) { error(baseTypeNode.expression, Diagnostics.Base_constructors_must_all_have_the_same_return_type); } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ce4c6a90819..21f09ffcd5c 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4203,14 +4203,18 @@ namespace ts { export interface TypeReference extends ObjectType { target: GenericType; // Type reference target node?: ArrayTypeNode | TupleTypeNode; + /* @internal */ mapper?: TypeMapper; + /* @internal */ resolvedTypeArguments?: ReadonlyArray; // Resolved ype reference type arguments /* @internal */ literalType?: TypeReference; // Clone of type with ObjectFlags.ArrayLiteral set } export interface DeferredTypeReference extends TypeReference { + /* @internal */ node: ArrayTypeNode | TupleTypeNode; + /* @internal */ mapper?: TypeMapper; } From 5c21f4312154a5fa9a09c98ec621ce01fbafba08 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 27 Aug 2019 06:51:47 -0400 Subject: [PATCH 044/140] Accept new baselines --- .../reference/api/tsserverlibrary.d.ts | 4 +- tests/baselines/reference/api/typescript.d.ts | 4 +- .../baselines/reference/arrayFrom.errors.txt | 2 + .../reference/castingTuple.errors.txt | 2 + .../reference/checkJsxChildrenProperty3.types | 4 +- .../checkJsxChildrenProperty4.errors.txt | 16 +- .../reference/checkJsxChildrenProperty4.types | 4 +- .../complexRecursiveCollections.types | 16 +- .../reference/conditionalTypes1.types | 2 +- .../contextualSignatureInstantiation.types | 2 +- .../contextualTypingOfOptionalMembers.types | 14 +- ...EmitDestructuringParameterProperties.types | 2 +- .../reference/destructuringControlFlow.types | 2 +- .../destructuringInFunctionType.types | 6 +- .../destructuringParameterProperties1.types | 2 +- .../destructuringParameterProperties5.types | 2 +- ...ectDependenceBetweenTypeAliases.errors.txt | 29 +--- .../directDependenceBetweenTypeAliases.types | 34 ++--- ...cessPrivateMemberOfGenericConstraint.types | 2 +- tests/baselines/reference/inferTypes1.types | 12 +- .../interfaceExtendsObjectIntersection.types | 4 +- ...rfaceExtendsObjectIntersectionErrors.types | 4 +- .../intersectionTypeWithLeadingOperator.types | 2 +- ...onfusableWithMultipleChildrenNoError.types | 4 +- .../reference/mapOnTupleTypes02.types | 8 +- .../optionalTupleElements1.errors.txt | 24 +-- .../reference/optionalTupleElements1.types | 140 +++++++++--------- .../reference/readonlyArraysAndTuples.types | 4 +- .../reference/readonlyArraysAndTuples2.types | 4 +- .../reference/recursiveMappedTypes.types | 8 +- .../recursiveResolveTypeMembers.errors.txt | 4 +- .../recursiveTypesWithTypeof.errors.txt | 7 +- .../reference/recursiveTypesWithTypeof.types | 6 +- .../reference/restTupleElements1.types | 40 ++--- ...nDestructuringForArrayBindingPattern.types | 66 ++++----- ...DestructuringForArrayBindingPattern2.types | 106 ++++++------- ...gForArrayBindingPatternDefaultValues.types | 60 ++++---- ...ForArrayBindingPatternDefaultValues2.types | 90 +++++------ ...estructuringForOfArrayBindingPattern.types | 132 ++++++++--------- ...structuringForOfArrayBindingPattern2.types | 132 ++++++++--------- ...orOfArrayBindingPatternDefaultValues.types | 120 +++++++-------- ...rOfArrayBindingPatternDefaultValues2.types | 120 +++++++-------- ...cturingParametertArrayBindingPattern.types | 36 ++--- ...turingParametertArrayBindingPattern2.types | 36 ++--- ...tertArrayBindingPatternDefaultValues.types | 36 ++--- ...ertArrayBindingPatternDefaultValues2.types | 28 ++-- ...VariableStatementArrayBindingPattern.types | 14 +- ...ariableStatementArrayBindingPattern2.types | 14 +- ...ariableStatementArrayBindingPattern3.types | 104 ++++++------- ...mentArrayBindingPatternDefaultValues.types | 14 +- ...entArrayBindingPatternDefaultValues2.types | 12 +- ...entArrayBindingPatternDefaultValues3.types | 94 ++++++------ .../reference/specedNoStackBlown.types | 4 +- .../spreadBooleanRespectsFreshness.types | 6 +- .../reference/spreadTypeVariable.types | 2 +- .../baselines/reference/tupleTypes.errors.txt | 4 +- tests/baselines/reference/typeAliases.types | 12 +- ...dNarrowsIndexedAccessOfKnownProperty.types | 8 +- .../reference/typeInferenceLiteralUnion.types | 4 +- .../typePredicateStructuralMatch.types | 54 +++---- .../unionTypeWithLeadingOperator.types | 2 +- .../reference/unionsOfTupleTypes1.errors.txt | 16 +- .../reference/unionsOfTupleTypes1.types | 42 +++--- 63 files changed, 885 insertions(+), 903 deletions(-) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index bffe2114d19..c70f389e210 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2351,7 +2351,9 @@ declare namespace ts { */ export interface TypeReference extends ObjectType { target: GenericType; - typeArguments?: ReadonlyArray; + node?: ArrayTypeNode | TupleTypeNode; + } + export interface DeferredTypeReference extends TypeReference { } export interface GenericType extends InterfaceType, TypeReference { } diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 457a1acb227..c7b96ded9b2 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2351,7 +2351,9 @@ declare namespace ts { */ export interface TypeReference extends ObjectType { target: GenericType; - typeArguments?: ReadonlyArray; + node?: ArrayTypeNode | TupleTypeNode; + } + export interface DeferredTypeReference extends TypeReference { } export interface GenericType extends InterfaceType, TypeReference { } diff --git a/tests/baselines/reference/arrayFrom.errors.txt b/tests/baselines/reference/arrayFrom.errors.txt index 615bd1bf769..7d9645f9420 100644 --- a/tests/baselines/reference/arrayFrom.errors.txt +++ b/tests/baselines/reference/arrayFrom.errors.txt @@ -1,6 +1,7 @@ tests/cases/compiler/arrayFrom.ts(20,7): error TS2322: Type 'A[]' is not assignable to type 'B[]'. Property 'b' is missing in type 'A' but required in type 'B'. tests/cases/compiler/arrayFrom.ts(23,7): error TS2322: Type 'A[]' is not assignable to type 'B[]'. + Type 'A' is not assignable to type 'B'. ==== tests/cases/compiler/arrayFrom.ts (2 errors) ==== @@ -33,6 +34,7 @@ tests/cases/compiler/arrayFrom.ts(23,7): error TS2322: Type 'A[]' is not assigna const result6: B[] = Array.from(inputALike); // expect error ~~~~~~~ !!! error TS2322: Type 'A[]' is not assignable to type 'B[]'. +!!! error TS2322: Type 'A' is not assignable to type 'B'. const result7: B[] = Array.from(inputALike, ({ a }): B => ({ b: a })); const result8: A[] = Array.from(inputARand); const result9: B[] = Array.from(inputARand, ({ a }): B => ({ b: a })); diff --git a/tests/baselines/reference/castingTuple.errors.txt b/tests/baselines/reference/castingTuple.errors.txt index 0a1d592e8b1..56941dfddd0 100644 --- a/tests/baselines/reference/castingTuple.errors.txt +++ b/tests/baselines/reference/castingTuple.errors.txt @@ -4,6 +4,7 @@ tests/cases/conformance/types/tuple/castingTuple.ts(14,15): error TS2352: Conver Types of property 'length' are incompatible. Type '3' is not comparable to type '2'. tests/cases/conformance/types/tuple/castingTuple.ts(15,14): error TS2352: Conversion of type '[number, string]' to type '[number, string, boolean]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. + Property '2' is missing in type '[number, string]' but required in type '[number, string, boolean]'. tests/cases/conformance/types/tuple/castingTuple.ts(18,21): error TS2352: Conversion of type '[C, D]' to type '[C, D, A]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. Property '2' is missing in type '[C, D]' but required in type '[C, D, A]'. tests/cases/conformance/types/tuple/castingTuple.ts(20,33): error TS2493: Tuple type '[C, D, A]' of length '3' has no element at index '5'. @@ -40,6 +41,7 @@ tests/cases/conformance/types/tuple/castingTuple.ts(33,1): error TS2304: Cannot var longer = numStrTuple as [number, string, boolean] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS2352: Conversion of type '[number, string]' to type '[number, string, boolean]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. +!!! error TS2352: Property '2' is missing in type '[number, string]' but required in type '[number, string, boolean]'. var classCDTuple: [C, D] = [new C(), new D()]; var interfaceIITuple = <[I, I]>classCDTuple; var classCDATuple = <[C, D, A]>classCDTuple; diff --git a/tests/baselines/reference/checkJsxChildrenProperty3.types b/tests/baselines/reference/checkJsxChildrenProperty3.types index f2ed3dc8fd0..2d4380a1975 100644 --- a/tests/baselines/reference/checkJsxChildrenProperty3.types +++ b/tests/baselines/reference/checkJsxChildrenProperty3.types @@ -31,11 +31,11 @@ class FetchUser extends React.Component { ? this.props.children(this.state.result) >this.props.children(this.state.result) : JSX.Element ->this.props.children : ((user: IUser) => JSX.Element) | (((user: IUser) => JSX.Element) & string) | (((user: IUser) => JSX.Element) & number) | (((user: IUser) => JSX.Element) & false) | (((user: IUser) => JSX.Element) & true) | (((user: IUser) => JSX.Element) & React.ReactElement) | (((user: IUser) => JSX.Element) & (string | number | boolean | any[] | React.ReactElement)[]) +>this.props.children : ((user: IUser) => JSX.Element) | (((user: IUser) => JSX.Element) & string) | (((user: IUser) => JSX.Element) & number) | (((user: IUser) => JSX.Element) & false) | (((user: IUser) => JSX.Element) & true) | (((user: IUser) => JSX.Element) & React.ReactElement) | (((user: IUser) => JSX.Element) & (string | number | boolean | React.ReactElement | any[])[]) >this.props : IFetchUserProps & { children?: React.ReactNode; } >this : this >props : IFetchUserProps & { children?: React.ReactNode; } ->children : ((user: IUser) => JSX.Element) | (((user: IUser) => JSX.Element) & string) | (((user: IUser) => JSX.Element) & number) | (((user: IUser) => JSX.Element) & false) | (((user: IUser) => JSX.Element) & true) | (((user: IUser) => JSX.Element) & React.ReactElement) | (((user: IUser) => JSX.Element) & (string | number | boolean | any[] | React.ReactElement)[]) +>children : ((user: IUser) => JSX.Element) | (((user: IUser) => JSX.Element) & string) | (((user: IUser) => JSX.Element) & number) | (((user: IUser) => JSX.Element) & false) | (((user: IUser) => JSX.Element) & true) | (((user: IUser) => JSX.Element) & React.ReactElement) | (((user: IUser) => JSX.Element) & (string | number | boolean | React.ReactElement | any[])[]) >this.state.result : any >this.state : any >this : this diff --git a/tests/baselines/reference/checkJsxChildrenProperty4.errors.txt b/tests/baselines/reference/checkJsxChildrenProperty4.errors.txt index 34bd2189964..40eb1d77677 100644 --- a/tests/baselines/reference/checkJsxChildrenProperty4.errors.txt +++ b/tests/baselines/reference/checkJsxChildrenProperty4.errors.txt @@ -1,8 +1,8 @@ tests/cases/conformance/jsx/file.tsx(24,28): error TS2551: Property 'NAme' does not exist on type 'IUser'. Did you mean 'Name'? -tests/cases/conformance/jsx/file.tsx(36,15): error TS2322: Type '(user: IUser) => Element' is not assignable to type 'string | number | boolean | any[] | ReactElement'. - Type '(user: IUser) => Element' is missing the following properties from type 'ReactElement': type, props -tests/cases/conformance/jsx/file.tsx(39,15): error TS2322: Type '(user: IUser) => Element' is not assignable to type 'string | number | boolean | any[] | ReactElement'. - Type '(user: IUser) => Element' is missing the following properties from type 'ReactElement': type, props +tests/cases/conformance/jsx/file.tsx(36,15): error TS2322: Type '(user: IUser) => Element' is not assignable to type 'string | number | boolean | ReactElement | any[]'. + Type '(user: IUser) => Element' is missing the following properties from type 'any[]': push, pop, concat, join, and 15 more. +tests/cases/conformance/jsx/file.tsx(39,15): error TS2322: Type '(user: IUser) => Element' is not assignable to type 'string | number | boolean | ReactElement | any[]'. + Type '(user: IUser) => Element' is missing the following properties from type 'any[]': push, pop, concat, join, and 15 more. ==== tests/cases/conformance/jsx/file.tsx (3 errors) ==== @@ -50,8 +50,8 @@ tests/cases/conformance/jsx/file.tsx(39,15): error TS2322: Type '(user: IUser) = ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) } ~~~~~~~~~~~~~ -!!! error TS2322: Type '(user: IUser) => Element' is not assignable to type 'string | number | boolean | any[] | ReactElement'. -!!! error TS2322: Type '(user: IUser) => Element' is missing the following properties from type 'ReactElement': type, props +!!! error TS2322: Type '(user: IUser) => Element' is not assignable to type 'string | number | boolean | ReactElement | any[]'. +!!! error TS2322: Type '(user: IUser) => Element' is missing the following properties from type 'any[]': push, pop, concat, join, and 15 more. !!! related TS6212 tests/cases/conformance/jsx/file.tsx:36:15: Did you mean to call this expression? { user => ( ~~~~~~~~~ @@ -59,8 +59,8 @@ tests/cases/conformance/jsx/file.tsx(39,15): error TS2322: Type '(user: IUser) = ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) } ~~~~~~~~~~~~~ -!!! error TS2322: Type '(user: IUser) => Element' is not assignable to type 'string | number | boolean | any[] | ReactElement'. -!!! error TS2322: Type '(user: IUser) => Element' is missing the following properties from type 'ReactElement': type, props +!!! error TS2322: Type '(user: IUser) => Element' is not assignable to type 'string | number | boolean | ReactElement | any[]'. +!!! error TS2322: Type '(user: IUser) => Element' is missing the following properties from type 'any[]': push, pop, concat, join, and 15 more. !!! related TS6212 tests/cases/conformance/jsx/file.tsx:39:15: Did you mean to call this expression? ); diff --git a/tests/baselines/reference/checkJsxChildrenProperty4.types b/tests/baselines/reference/checkJsxChildrenProperty4.types index 067e8f2611a..4f753cf9f3b 100644 --- a/tests/baselines/reference/checkJsxChildrenProperty4.types +++ b/tests/baselines/reference/checkJsxChildrenProperty4.types @@ -31,11 +31,11 @@ class FetchUser extends React.Component { ? this.props.children(this.state.result) >this.props.children(this.state.result) : JSX.Element ->this.props.children : ((user: IUser) => JSX.Element) | (((user: IUser) => JSX.Element) & string) | (((user: IUser) => JSX.Element) & number) | (((user: IUser) => JSX.Element) & false) | (((user: IUser) => JSX.Element) & true) | (((user: IUser) => JSX.Element) & React.ReactElement) | (((user: IUser) => JSX.Element) & (string | number | boolean | any[] | React.ReactElement)[]) +>this.props.children : ((user: IUser) => JSX.Element) | (((user: IUser) => JSX.Element) & string) | (((user: IUser) => JSX.Element) & number) | (((user: IUser) => JSX.Element) & false) | (((user: IUser) => JSX.Element) & true) | (((user: IUser) => JSX.Element) & React.ReactElement) | (((user: IUser) => JSX.Element) & (string | number | boolean | React.ReactElement | any[])[]) >this.props : IFetchUserProps & { children?: React.ReactNode; } >this : this >props : IFetchUserProps & { children?: React.ReactNode; } ->children : ((user: IUser) => JSX.Element) | (((user: IUser) => JSX.Element) & string) | (((user: IUser) => JSX.Element) & number) | (((user: IUser) => JSX.Element) & false) | (((user: IUser) => JSX.Element) & true) | (((user: IUser) => JSX.Element) & React.ReactElement) | (((user: IUser) => JSX.Element) & (string | number | boolean | any[] | React.ReactElement)[]) +>children : ((user: IUser) => JSX.Element) | (((user: IUser) => JSX.Element) & string) | (((user: IUser) => JSX.Element) & number) | (((user: IUser) => JSX.Element) & false) | (((user: IUser) => JSX.Element) & true) | (((user: IUser) => JSX.Element) & React.ReactElement) | (((user: IUser) => JSX.Element) & (string | number | boolean | React.ReactElement | any[])[]) >this.state.result : any >this.state : any >this : this diff --git a/tests/baselines/reference/complexRecursiveCollections.types b/tests/baselines/reference/complexRecursiveCollections.types index feaff620486..2450407e90d 100644 --- a/tests/baselines/reference/complexRecursiveCollections.types +++ b/tests/baselines/reference/complexRecursiveCollections.types @@ -1029,28 +1029,28 @@ declare module Immutable { >value : T[K] merge(...collections: Array | Iterable<[string, any]>>): this; ->merge : (...collections: (Iterable<[string, any]> | Partial)[]) => this ->collections : (Iterable<[string, any]> | Partial)[] +>merge : (...collections: (Partial | Iterable<[string, any]>)[]) => this +>collections : (Partial | Iterable<[string, any]>)[] mergeDeep(...collections: Array | Iterable<[string, any]>>): this; ->mergeDeep : (...collections: (Iterable<[string, any]> | Partial)[]) => this ->collections : (Iterable<[string, any]> | Partial)[] +>mergeDeep : (...collections: (Partial | Iterable<[string, any]>)[]) => this +>collections : (Partial | Iterable<[string, any]>)[] mergeWith(merger: (oldVal: any, newVal: any, key: keyof T) => any, ...collections: Array | Iterable<[string, any]>>): this; ->mergeWith : (merger: (oldVal: any, newVal: any, key: keyof T) => any, ...collections: (Iterable<[string, any]> | Partial)[]) => this +>mergeWith : (merger: (oldVal: any, newVal: any, key: keyof T) => any, ...collections: (Partial | Iterable<[string, any]>)[]) => this >merger : (oldVal: any, newVal: any, key: keyof T) => any >oldVal : any >newVal : any >key : keyof T ->collections : (Iterable<[string, any]> | Partial)[] +>collections : (Partial | Iterable<[string, any]>)[] mergeDeepWith(merger: (oldVal: any, newVal: any, key: any) => any, ...collections: Array | Iterable<[string, any]>>): this; ->mergeDeepWith : (merger: (oldVal: any, newVal: any, key: any) => any, ...collections: (Iterable<[string, any]> | Partial)[]) => this +>mergeDeepWith : (merger: (oldVal: any, newVal: any, key: any) => any, ...collections: (Partial | Iterable<[string, any]>)[]) => this >merger : (oldVal: any, newVal: any, key: any) => any >oldVal : any >newVal : any >key : any ->collections : (Iterable<[string, any]> | Partial)[] +>collections : (Partial | Iterable<[string, any]>)[] delete(key: K): this; >delete : (key: K) => this diff --git a/tests/baselines/reference/conditionalTypes1.types b/tests/baselines/reference/conditionalTypes1.types index 234fc071d74..2d5af28ca5e 100644 --- a/tests/baselines/reference/conditionalTypes1.types +++ b/tests/baselines/reference/conditionalTypes1.types @@ -494,7 +494,7 @@ function f21(x: T, y: ZeroOf) { } type T35 = T[]; ->T35 : T[] +>T35 : T35 >a : string >b : number diff --git a/tests/baselines/reference/contextualSignatureInstantiation.types b/tests/baselines/reference/contextualSignatureInstantiation.types index ae5a4000537..57e8f79a28f 100644 --- a/tests/baselines/reference/contextualSignatureInstantiation.types +++ b/tests/baselines/reference/contextualSignatureInstantiation.types @@ -108,7 +108,7 @@ var d = bar(1, "one", h); // Should be number[] | string[] var d = bar("one", 1, h); // Should be number[] | string[] >d : number[] | string[] ->bar("one", 1, h) : number[] | string[] +>bar("one", 1, h) : string[] | number[] >bar : (x: T, y: U, cb: (x: T, y: U) => V) => V >"one" : "one" >1 : 1 diff --git a/tests/baselines/reference/contextualTypingOfOptionalMembers.types b/tests/baselines/reference/contextualTypingOfOptionalMembers.types index f4a9e23190d..9df692608c2 100644 --- a/tests/baselines/reference/contextualTypingOfOptionalMembers.types +++ b/tests/baselines/reference/contextualTypingOfOptionalMembers.types @@ -124,17 +124,17 @@ app2({ type ActionsArray = ((state: State) => State)[]; ->ActionsArray : ((state: State) => State)[] +>ActionsArray : ActionsArray >state : State declare function app3>(obj: Options): void; ->app3 : State)[]>(obj: Options) => void +>app3 : >(obj: Options) => void >obj : Options app3({ >app3({ state: 100, actions: [ s => s // Should be typed number => number ], view: (s, a) => undefined as any,}) : void ->app3 : State)[]>(obj: Options) => void ->{ state: 100, actions: [ s => s // Should be typed number => number ], view: (s, a) => undefined as any,} : { state: number; actions: ((s: number) => number)[]; view: (s: number, a: ((state: number) => number)[]) => any; } +>app3 : >(obj: Options) => void +>{ state: 100, actions: [ s => s // Should be typed number => number ], view: (s, a) => undefined as any,} : { state: number; actions: ((s: number) => number)[]; view: (s: number, a: ActionsArray) => any; } state: 100, >state : number @@ -151,10 +151,10 @@ app3({ ], view: (s, a) => undefined as any, ->view : (s: number, a: ((state: number) => number)[]) => any ->(s, a) => undefined as any : (s: number, a: ((state: number) => number)[]) => any +>view : (s: number, a: ActionsArray) => any +>(s, a) => undefined as any : (s: number, a: ActionsArray) => any >s : number ->a : ((state: number) => number)[] +>a : ActionsArray >undefined as any : any >undefined : undefined diff --git a/tests/baselines/reference/declarationEmitDestructuringParameterProperties.types b/tests/baselines/reference/declarationEmitDestructuringParameterProperties.types index b7407b0232f..d76fd67f9d6 100644 --- a/tests/baselines/reference/declarationEmitDestructuringParameterProperties.types +++ b/tests/baselines/reference/declarationEmitDestructuringParameterProperties.types @@ -10,7 +10,7 @@ class C1 { } type TupleType1 =[string, number, boolean]; ->TupleType1 : [string, number, boolean] +>TupleType1 : TupleType1 class C2 { >C2 : C2 diff --git a/tests/baselines/reference/destructuringControlFlow.types b/tests/baselines/reference/destructuringControlFlow.types index 347aae32c10..b6b9967ba43 100644 --- a/tests/baselines/reference/destructuringControlFlow.types +++ b/tests/baselines/reference/destructuringControlFlow.types @@ -161,7 +161,7 @@ function f4() { // Repro from #31770 type KeyValue = [string, string?]; ->KeyValue : [string, (string | undefined)?] +>KeyValue : KeyValue let [key, value]: KeyValue = ["foo"]; >key : string diff --git a/tests/baselines/reference/destructuringInFunctionType.types b/tests/baselines/reference/destructuringInFunctionType.types index c6c0f439ac5..b5b0ff041c6 100644 --- a/tests/baselines/reference/destructuringInFunctionType.types +++ b/tests/baselines/reference/destructuringInFunctionType.types @@ -9,7 +9,7 @@ interface c { c } >c : any type T1 = ([a, b, c]); ->T1 : [a, b, c] +>T1 : T1 type F1 = ([a, b, c]) => void; >F1 : F1 @@ -26,7 +26,7 @@ type F2 = ({ a }) => void; >a : any type T3 = ([{ a: b }, { b: a }]); ->T3 : [{ a: b; }, { b: a; }] +>T3 : T3 >a : b >b : a @@ -38,7 +38,7 @@ type F3 = ([{ a: b }, { b: a }]) => void; >a : any type T4 = ([{ a: [b, c] }]); ->T4 : [{ a: [b, c]; }] +>T4 : T4 >a : [b, c] type F4 = ([{ a: [b, c] }]) => void; diff --git a/tests/baselines/reference/destructuringParameterProperties1.types b/tests/baselines/reference/destructuringParameterProperties1.types index ff12edbac2e..13bacf49b13 100644 --- a/tests/baselines/reference/destructuringParameterProperties1.types +++ b/tests/baselines/reference/destructuringParameterProperties1.types @@ -10,7 +10,7 @@ class C1 { } type TupleType1 = [string, number, boolean]; ->TupleType1 : [string, number, boolean] +>TupleType1 : TupleType1 class C2 { >C2 : C2 diff --git a/tests/baselines/reference/destructuringParameterProperties5.types b/tests/baselines/reference/destructuringParameterProperties5.types index 60c3d074c6e..976b79e9495 100644 --- a/tests/baselines/reference/destructuringParameterProperties5.types +++ b/tests/baselines/reference/destructuringParameterProperties5.types @@ -6,7 +6,7 @@ type ObjType1 = { x: number; y: string; z: boolean } >z : boolean type TupleType1 = [ObjType1, number, string] ->TupleType1 : [ObjType1, number, string] +>TupleType1 : TupleType1 class C1 { >C1 : C1 diff --git a/tests/baselines/reference/directDependenceBetweenTypeAliases.errors.txt b/tests/baselines/reference/directDependenceBetweenTypeAliases.errors.txt index 68ea92f8fb5..d3960267177 100644 --- a/tests/baselines/reference/directDependenceBetweenTypeAliases.errors.txt +++ b/tests/baselines/reference/directDependenceBetweenTypeAliases.errors.txt @@ -4,18 +4,9 @@ tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts( tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(7,6): error TS2456: Type alias 'T0_3' circularly references itself. tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(11,6): error TS2456: Type alias 'T1' circularly references itself. tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(14,6): error TS2456: Type alias 'T2' circularly references itself. -tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(16,6): error TS2456: Type alias 'T2_1' circularly references itself. -tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(19,6): error TS2456: Type alias 'T3' circularly references itself. -tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(22,6): error TS2456: Type alias 'T4' circularly references itself. -tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(25,5): error TS2502: 'x' is referenced directly or indirectly in its own type annotation. -tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(26,6): error TS2456: Type alias 'T5' circularly references itself. -tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(29,6): error TS2456: Type alias 'T6' circularly references itself. -tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(30,6): error TS2456: Type alias 'T7' circularly references itself. -tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(31,5): error TS2502: 'yy' is referenced directly or indirectly in its own type annotation. -tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(32,6): error TS2456: Type alias 'T8' circularly references itself. -==== tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts (15 errors) ==== +==== tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts (6 errors) ==== // It is an error for the type specified in a type alias to depend on that type alias // A type alias directly depends on the type it aliases. @@ -44,40 +35,22 @@ tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts( !!! error TS2456: Type alias 'T2' circularly references itself. class C {} type T2_1 = T2_1[] | number - ~~~~ -!!! error TS2456: Type alias 'T2_1' circularly references itself. // An array type directly depends on its element type. type T3 = T3[] - ~~ -!!! error TS2456: Type alias 'T3' circularly references itself. // A tuple type directly depends on each of its element types. type T4 = [number, T4] - ~~ -!!! error TS2456: Type alias 'T4' circularly references itself. // A type query directly depends on the type of the referenced entity. var x: T5[] = [] - ~ -!!! error TS2502: 'x' is referenced directly or indirectly in its own type annotation. type T5 = typeof x - ~~ -!!! error TS2456: Type alias 'T5' circularly references itself. class C1 {} type T6 = T7 | number - ~~ -!!! error TS2456: Type alias 'T6' circularly references itself. type T7 = typeof yy - ~~ -!!! error TS2456: Type alias 'T7' circularly references itself. var yy: [string, T8[]]; - ~~ -!!! error TS2502: 'yy' is referenced directly or indirectly in its own type annotation. type T8 = C - ~~ -!!! error TS2456: Type alias 'T8' circularly references itself. // legal cases type T9 = () => T9 diff --git a/tests/baselines/reference/directDependenceBetweenTypeAliases.types b/tests/baselines/reference/directDependenceBetweenTypeAliases.types index 3363b20b851..431b65eea8c 100644 --- a/tests/baselines/reference/directDependenceBetweenTypeAliases.types +++ b/tests/baselines/reference/directDependenceBetweenTypeAliases.types @@ -27,40 +27,40 @@ class C {} >C : C type T2_1 = T2_1[] | number ->T2_1 : any +>T2_1 : T2_1 // An array type directly depends on its element type. type T3 = T3[] ->T3 : any +>T3 : T3 // A tuple type directly depends on each of its element types. type T4 = [number, T4] ->T4 : any +>T4 : T4 // A type query directly depends on the type of the referenced entity. var x: T5[] = [] ->x : any +>x : any[][][][][][][][][][][] >[] : undefined[] type T5 = typeof x ->T5 : any ->x : any +>T5 : any[][][][][][][][][][][] +>x : any[][][][][][][][][][][] class C1 {} >C1 : C1 type T6 = T7 | number ->T6 : any +>T6 : T6 type T7 = typeof yy ->T7 : any ->yy : any +>T7 : [string, C[]] +>yy : [string, C[]] var yy: [string, T8[]]; ->yy : any +>yy : [string, C[]] type T8 = C ->T8 : any +>T8 : C // legal cases type T9 = () => T9 @@ -72,17 +72,17 @@ type T10 = { x: T10 } | { new(v: T10): string } >v : T10 type T11 = T12[] ->T11 : [{ x: [any, string][]; }, string][] +>T11 : T11 type T12 = [T13, string] ->T12 : [{ x: [any, string][]; }, string] +>T12 : T12 type T13 = typeof zz ->T13 : { x: [any, string][]; } ->zz : { x: [any, string][]; } +>T13 : { x: T11; } +>zz : { x: T11; } var zz: { x: T11 } ->zz : { x: [any, string][]; } ->x : [{ x: [any, string][]; }, string][] +>zz : { x: T11; } +>x : T11 diff --git a/tests/baselines/reference/indexedAccessPrivateMemberOfGenericConstraint.types b/tests/baselines/reference/indexedAccessPrivateMemberOfGenericConstraint.types index abdbaa84862..f3a96fba6a8 100644 --- a/tests/baselines/reference/indexedAccessPrivateMemberOfGenericConstraint.types +++ b/tests/baselines/reference/indexedAccessPrivateMemberOfGenericConstraint.types @@ -14,7 +14,7 @@ class B { } type X = [T["a"], (T | B)["a"]]; ->X : [T["a"], (B | T)["a"]] +>X : X type Y = T["a"]; >Y : T["a"] diff --git a/tests/baselines/reference/inferTypes1.types b/tests/baselines/reference/inferTypes1.types index 2696b520ae8..02fa41fe4c8 100644 --- a/tests/baselines/reference/inferTypes1.types +++ b/tests/baselines/reference/inferTypes1.types @@ -269,19 +269,19 @@ type T78 = T extends T76 ? T76 : never; >T78 : T78 type Foo = [T, U]; ->Foo : [T, U] +>Foo : Foo type Bar = T extends Foo ? Foo : never; >Bar : Bar type T90 = Bar<[string, string]>; // [string, string] ->T90 : [string, string] +>T90 : Foo type T91 = Bar<[string, "a"]>; // [string, "a"] ->T91 : [string, "a"] +>T91 : Foo type T92 = Bar<[string, "a"] & { x: string }>; // [string, "a"] ->T92 : [string, "a"] +>T92 : Foo >x : string type T93 = Bar<["a", string]>; // never @@ -371,13 +371,13 @@ const z2: string = ex.obj.nested.attr; // Repros from #21631 type A1> = [T, U]; ->A1 : [T, U] +>A1 : A1 type B1 = S extends A1 ? [T, U] : never; >B1 : B1 type A2 = [T, U]; ->A2 : [T, U] +>A2 : A2 type B2 = S extends A2 ? [T, U] : never; >B2 : B2 diff --git a/tests/baselines/reference/interfaceExtendsObjectIntersection.types b/tests/baselines/reference/interfaceExtendsObjectIntersection.types index cc166a6e57c..af638969078 100644 --- a/tests/baselines/reference/interfaceExtendsObjectIntersection.types +++ b/tests/baselines/reference/interfaceExtendsObjectIntersection.types @@ -15,10 +15,10 @@ type T4 = new () => { a: number }; >a : number type T5 = number[]; ->T5 : number[] +>T5 : T5 type T6 = [string, number]; ->T6 : [string, number] +>T6 : T6 type T7 = { [P in 'a' | 'b' | 'c']: string }; >T7 : T7 diff --git a/tests/baselines/reference/interfaceExtendsObjectIntersectionErrors.types b/tests/baselines/reference/interfaceExtendsObjectIntersectionErrors.types index 6b81e8d2f54..2fc15b53994 100644 --- a/tests/baselines/reference/interfaceExtendsObjectIntersectionErrors.types +++ b/tests/baselines/reference/interfaceExtendsObjectIntersectionErrors.types @@ -8,10 +8,10 @@ type T2 = T1 & { b: number }; >b : number type T3 = number[]; ->T3 : number[] +>T3 : T3 type T4 = [string, number]; ->T4 : [string, number] +>T4 : T4 type T5 = { [P in 'a' | 'b' | 'c']: string }; >T5 : T5 diff --git a/tests/baselines/reference/intersectionTypeWithLeadingOperator.types b/tests/baselines/reference/intersectionTypeWithLeadingOperator.types index 9961f051f7f..826da4d8c51 100644 --- a/tests/baselines/reference/intersectionTypeWithLeadingOperator.types +++ b/tests/baselines/reference/intersectionTypeWithLeadingOperator.types @@ -12,7 +12,7 @@ type B = >bar : number type C = [& { foo: 1 } & { bar: 2 }, & { foo: 3 } & { bar: 4 }]; ->C : [{ foo: 1; } & { bar: 2; }, { foo: 3; } & { bar: 4; }] +>C : C >foo : 1 >bar : 2 >foo : 3 diff --git a/tests/baselines/reference/jsxChildrenSingleChildConfusableWithMultipleChildrenNoError.types b/tests/baselines/reference/jsxChildrenSingleChildConfusableWithMultipleChildrenNoError.types index dd302f40679..59292bac60f 100644 --- a/tests/baselines/reference/jsxChildrenSingleChildConfusableWithMultipleChildrenNoError.types +++ b/tests/baselines/reference/jsxChildrenSingleChildConfusableWithMultipleChildrenNoError.types @@ -5,12 +5,12 @@ import * as React from 'react' >React : typeof React type Tab = [string, React.ReactNode] // [tabName, tabContent] ->Tab : [string, React.ReactNode] +>Tab : Tab >React : any interface Props { children: Tab[] ->children : [string, React.ReactNode][] +>children : Tab[] } function TabLayout(props: Props) { diff --git a/tests/baselines/reference/mapOnTupleTypes02.types b/tests/baselines/reference/mapOnTupleTypes02.types index 2bb394ec120..3f443a735cb 100644 --- a/tests/baselines/reference/mapOnTupleTypes02.types +++ b/tests/baselines/reference/mapOnTupleTypes02.types @@ -1,15 +1,15 @@ === tests/cases/compiler/mapOnTupleTypes02.ts === export type Point = [number, number]; ->Point : [number, number] +>Point : Point export function increment(point: Point) { ->increment : (point: [number, number]) => number[] ->point : [number, number] +>increment : (point: Point) => number[] +>point : Point return point.map(d => d + 1); >point.map(d => d + 1) : number[] >point.map : (callbackfn: (value: number, index: number, array: number[]) => U, thisArg?: any) => U[] ->point : [number, number] +>point : Point >map : (callbackfn: (value: number, index: number, array: number[]) => U, thisArg?: any) => U[] >d => d + 1 : (d: number) => number >d : number diff --git a/tests/baselines/reference/optionalTupleElements1.errors.txt b/tests/baselines/reference/optionalTupleElements1.errors.txt index ac9f5f244da..bb5fd2c01d8 100644 --- a/tests/baselines/reference/optionalTupleElements1.errors.txt +++ b/tests/baselines/reference/optionalTupleElements1.errors.txt @@ -1,25 +1,25 @@ tests/cases/conformance/types/tuple/optionalTupleElements1.ts(11,29): error TS1257: A required element cannot follow an optional element. -tests/cases/conformance/types/tuple/optionalTupleElements1.ts(15,5): error TS2322: Type '[number, string, (boolean | undefined)?]' is not assignable to type '[number, string, boolean]'. +tests/cases/conformance/types/tuple/optionalTupleElements1.ts(15,5): error TS2322: Type 'T2' is not assignable to type 'T1'. Types of property '2' are incompatible. Type 'boolean | undefined' is not assignable to type 'boolean'. Type 'undefined' is not assignable to type 'boolean'. -tests/cases/conformance/types/tuple/optionalTupleElements1.ts(16,5): error TS2322: Type '[number, (string | undefined)?, (boolean | undefined)?]' is not assignable to type '[number, string, boolean]'. +tests/cases/conformance/types/tuple/optionalTupleElements1.ts(16,5): error TS2322: Type 'T3' is not assignable to type 'T1'. Types of property '1' are incompatible. Type 'string | undefined' is not assignable to type 'string'. Type 'undefined' is not assignable to type 'string'. -tests/cases/conformance/types/tuple/optionalTupleElements1.ts(17,5): error TS2322: Type '[(number | undefined)?, (string | undefined)?, (boolean | undefined)?]' is not assignable to type '[number, string, boolean]'. +tests/cases/conformance/types/tuple/optionalTupleElements1.ts(17,5): error TS2322: Type 'T4' is not assignable to type 'T1'. Types of property '0' are incompatible. Type 'number | undefined' is not assignable to type 'number'. Type 'undefined' is not assignable to type 'number'. -tests/cases/conformance/types/tuple/optionalTupleElements1.ts(20,5): error TS2322: Type '[number, (string | undefined)?, (boolean | undefined)?]' is not assignable to type '[number, string, (boolean | undefined)?]'. +tests/cases/conformance/types/tuple/optionalTupleElements1.ts(20,5): error TS2322: Type 'T3' is not assignable to type 'T2'. Types of property '1' are incompatible. Type 'string | undefined' is not assignable to type 'string'. Type 'undefined' is not assignable to type 'string'. -tests/cases/conformance/types/tuple/optionalTupleElements1.ts(21,5): error TS2322: Type '[(number | undefined)?, (string | undefined)?, (boolean | undefined)?]' is not assignable to type '[number, string, (boolean | undefined)?]'. +tests/cases/conformance/types/tuple/optionalTupleElements1.ts(21,5): error TS2322: Type 'T4' is not assignable to type 'T2'. Types of property '0' are incompatible. Type 'number | undefined' is not assignable to type 'number'. Type 'undefined' is not assignable to type 'number'. -tests/cases/conformance/types/tuple/optionalTupleElements1.ts(25,5): error TS2322: Type '[(number | undefined)?, (string | undefined)?, (boolean | undefined)?]' is not assignable to type '[number, (string | undefined)?, (boolean | undefined)?]'. +tests/cases/conformance/types/tuple/optionalTupleElements1.ts(25,5): error TS2322: Type 'T4' is not assignable to type 'T3'. Types of property '0' are incompatible. Type 'number | undefined' is not assignable to type 'number'. Type 'undefined' is not assignable to type 'number'. @@ -44,19 +44,19 @@ tests/cases/conformance/types/tuple/optionalTupleElements1.ts(25,5): error TS232 t1 = t1; t1 = t2; // Error ~~ -!!! error TS2322: Type '[number, string, (boolean | undefined)?]' is not assignable to type '[number, string, boolean]'. +!!! error TS2322: Type 'T2' is not assignable to type 'T1'. !!! error TS2322: Types of property '2' are incompatible. !!! error TS2322: Type 'boolean | undefined' is not assignable to type 'boolean'. !!! error TS2322: Type 'undefined' is not assignable to type 'boolean'. t1 = t3; // Error ~~ -!!! error TS2322: Type '[number, (string | undefined)?, (boolean | undefined)?]' is not assignable to type '[number, string, boolean]'. +!!! error TS2322: Type 'T3' is not assignable to type 'T1'. !!! error TS2322: Types of property '1' are incompatible. !!! error TS2322: Type 'string | undefined' is not assignable to type 'string'. !!! error TS2322: Type 'undefined' is not assignable to type 'string'. t1 = t4; // Error ~~ -!!! error TS2322: Type '[(number | undefined)?, (string | undefined)?, (boolean | undefined)?]' is not assignable to type '[number, string, boolean]'. +!!! error TS2322: Type 'T4' is not assignable to type 'T1'. !!! error TS2322: Types of property '0' are incompatible. !!! error TS2322: Type 'number | undefined' is not assignable to type 'number'. !!! error TS2322: Type 'undefined' is not assignable to type 'number'. @@ -64,13 +64,13 @@ tests/cases/conformance/types/tuple/optionalTupleElements1.ts(25,5): error TS232 t2 = t2; t2 = t3; // Error ~~ -!!! error TS2322: Type '[number, (string | undefined)?, (boolean | undefined)?]' is not assignable to type '[number, string, (boolean | undefined)?]'. +!!! error TS2322: Type 'T3' is not assignable to type 'T2'. !!! error TS2322: Types of property '1' are incompatible. !!! error TS2322: Type 'string | undefined' is not assignable to type 'string'. !!! error TS2322: Type 'undefined' is not assignable to type 'string'. t2 = t4; // Error ~~ -!!! error TS2322: Type '[(number | undefined)?, (string | undefined)?, (boolean | undefined)?]' is not assignable to type '[number, string, (boolean | undefined)?]'. +!!! error TS2322: Type 'T4' is not assignable to type 'T2'. !!! error TS2322: Types of property '0' are incompatible. !!! error TS2322: Type 'number | undefined' is not assignable to type 'number'. !!! error TS2322: Type 'undefined' is not assignable to type 'number'. @@ -79,7 +79,7 @@ tests/cases/conformance/types/tuple/optionalTupleElements1.ts(25,5): error TS232 t3 = t3; t3 = t4; // Error ~~ -!!! error TS2322: Type '[(number | undefined)?, (string | undefined)?, (boolean | undefined)?]' is not assignable to type '[number, (string | undefined)?, (boolean | undefined)?]'. +!!! error TS2322: Type 'T4' is not assignable to type 'T3'. !!! error TS2322: Types of property '0' are incompatible. !!! error TS2322: Type 'number | undefined' is not assignable to type 'number'. !!! error TS2322: Type 'undefined' is not assignable to type 'number'. diff --git a/tests/baselines/reference/optionalTupleElements1.types b/tests/baselines/reference/optionalTupleElements1.types index 630a54df517..b784bf72e58 100644 --- a/tests/baselines/reference/optionalTupleElements1.types +++ b/tests/baselines/reference/optionalTupleElements1.types @@ -1,15 +1,15 @@ === tests/cases/conformance/types/tuple/optionalTupleElements1.ts === type T1 = [number, string, boolean]; ->T1 : [number, string, boolean] +>T1 : T1 type T2 = [number, string, boolean?]; ->T2 : [number, string, (boolean | undefined)?] +>T2 : T2 type T3 = [number, string?, boolean?]; ->T3 : [number, (string | undefined)?, (boolean | undefined)?] +>T3 : T3 type T4 = [number?, string?, boolean?]; ->T4 : [(number | undefined)?, (string | undefined)?, (boolean | undefined)?] +>T4 : T4 type L1 = T1["length"]; >L1 : 3 @@ -24,122 +24,122 @@ type L4 = T4["length"]; >L4 : 0 | 3 | 2 | 1 type T5 = [number, string?, boolean]; // Error ->T5 : [number, string | undefined, boolean] +>T5 : T5 function f1(t1: T1, t2: T2, t3: T3, t4: T4) { ->f1 : (t1: [number, string, boolean], t2: [number, string, (boolean | undefined)?], t3: [number, (string | undefined)?, (boolean | undefined)?], t4: [(number | undefined)?, (string | undefined)?, (boolean | undefined)?]) => void ->t1 : [number, string, boolean] ->t2 : [number, string, (boolean | undefined)?] ->t3 : [number, (string | undefined)?, (boolean | undefined)?] ->t4 : [(number | undefined)?, (string | undefined)?, (boolean | undefined)?] +>f1 : (t1: T1, t2: T2, t3: T3, t4: T4) => void +>t1 : T1 +>t2 : T2 +>t3 : T3 +>t4 : T4 t1 = t1; ->t1 = t1 : [number, string, boolean] ->t1 : [number, string, boolean] ->t1 : [number, string, boolean] +>t1 = t1 : T1 +>t1 : T1 +>t1 : T1 t1 = t2; // Error ->t1 = t2 : [number, string, (boolean | undefined)?] ->t1 : [number, string, boolean] ->t2 : [number, string, (boolean | undefined)?] +>t1 = t2 : T2 +>t1 : T1 +>t2 : T2 t1 = t3; // Error ->t1 = t3 : [number, (string | undefined)?, (boolean | undefined)?] ->t1 : [number, string, boolean] ->t3 : [number, (string | undefined)?, (boolean | undefined)?] +>t1 = t3 : T3 +>t1 : T1 +>t3 : T3 t1 = t4; // Error ->t1 = t4 : [(number | undefined)?, (string | undefined)?, (boolean | undefined)?] ->t1 : [number, string, boolean] ->t4 : [(number | undefined)?, (string | undefined)?, (boolean | undefined)?] +>t1 = t4 : T4 +>t1 : T1 +>t4 : T4 t2 = t1; ->t2 = t1 : [number, string, boolean] ->t2 : [number, string, (boolean | undefined)?] ->t1 : [number, string, boolean] +>t2 = t1 : T1 +>t2 : T2 +>t1 : T1 t2 = t2; ->t2 = t2 : [number, string, (boolean | undefined)?] ->t2 : [number, string, (boolean | undefined)?] ->t2 : [number, string, (boolean | undefined)?] +>t2 = t2 : T2 +>t2 : T2 +>t2 : T2 t2 = t3; // Error ->t2 = t3 : [number, (string | undefined)?, (boolean | undefined)?] ->t2 : [number, string, (boolean | undefined)?] ->t3 : [number, (string | undefined)?, (boolean | undefined)?] +>t2 = t3 : T3 +>t2 : T2 +>t3 : T3 t2 = t4; // Error ->t2 = t4 : [(number | undefined)?, (string | undefined)?, (boolean | undefined)?] ->t2 : [number, string, (boolean | undefined)?] ->t4 : [(number | undefined)?, (string | undefined)?, (boolean | undefined)?] +>t2 = t4 : T4 +>t2 : T2 +>t4 : T4 t3 = t1; ->t3 = t1 : [number, string, boolean] ->t3 : [number, (string | undefined)?, (boolean | undefined)?] ->t1 : [number, string, boolean] +>t3 = t1 : T1 +>t3 : T3 +>t1 : T1 t3 = t2; ->t3 = t2 : [number, string, (boolean | undefined)?] ->t3 : [number, (string | undefined)?, (boolean | undefined)?] ->t2 : [number, string, (boolean | undefined)?] +>t3 = t2 : T2 +>t3 : T3 +>t2 : T2 t3 = t3; ->t3 = t3 : [number, (string | undefined)?, (boolean | undefined)?] ->t3 : [number, (string | undefined)?, (boolean | undefined)?] ->t3 : [number, (string | undefined)?, (boolean | undefined)?] +>t3 = t3 : T3 +>t3 : T3 +>t3 : T3 t3 = t4; // Error ->t3 = t4 : [(number | undefined)?, (string | undefined)?, (boolean | undefined)?] ->t3 : [number, (string | undefined)?, (boolean | undefined)?] ->t4 : [(number | undefined)?, (string | undefined)?, (boolean | undefined)?] +>t3 = t4 : T4 +>t3 : T3 +>t4 : T4 t4 = t1; ->t4 = t1 : [number, string, boolean] ->t4 : [(number | undefined)?, (string | undefined)?, (boolean | undefined)?] ->t1 : [number, string, boolean] +>t4 = t1 : T1 +>t4 : T4 +>t1 : T1 t4 = t2; ->t4 = t2 : [number, string, (boolean | undefined)?] ->t4 : [(number | undefined)?, (string | undefined)?, (boolean | undefined)?] ->t2 : [number, string, (boolean | undefined)?] +>t4 = t2 : T2 +>t4 : T4 +>t2 : T2 t4 = t3; ->t4 = t3 : [number, (string | undefined)?, (boolean | undefined)?] ->t4 : [(number | undefined)?, (string | undefined)?, (boolean | undefined)?] ->t3 : [number, (string | undefined)?, (boolean | undefined)?] +>t4 = t3 : T3 +>t4 : T4 +>t3 : T3 t4 = t4; ->t4 = t4 : [(number | undefined)?, (string | undefined)?, (boolean | undefined)?] ->t4 : [(number | undefined)?, (string | undefined)?, (boolean | undefined)?] ->t4 : [(number | undefined)?, (string | undefined)?, (boolean | undefined)?] +>t4 = t4 : T4 +>t4 : T4 +>t4 : T4 } let t2: T2; ->t2 : [number, string, (boolean | undefined)?] +>t2 : T2 let t3: T3; ->t3 : [number, (string | undefined)?, (boolean | undefined)?] +>t3 : T3 let t4: T4; ->t4 : [(number | undefined)?, (string | undefined)?, (boolean | undefined)?] +>t4 : T4 t2 = [42, "hello"]; >t2 = [42, "hello"] : [number, string] ->t2 : [number, string, (boolean | undefined)?] +>t2 : T2 >[42, "hello"] : [number, string] >42 : 42 >"hello" : "hello" t3 = [42, "hello"]; >t3 = [42, "hello"] : [number, string] ->t3 : [number, (string | undefined)?, (boolean | undefined)?] +>t3 : T3 >[42, "hello"] : [number, string] >42 : 42 >"hello" : "hello" t3 = [42,,true] >t3 = [42,,true] : [number, undefined, true] ->t3 : [number, (string | undefined)?, (boolean | undefined)?] +>t3 : T3 >[42,,true] : [number, undefined, true] >42 : 42 > : undefined @@ -147,20 +147,20 @@ t3 = [42,,true] t3 = [42]; >t3 = [42] : [number] ->t3 : [number, (string | undefined)?, (boolean | undefined)?] +>t3 : T3 >[42] : [number] >42 : 42 t4 = [42, "hello"]; >t4 = [42, "hello"] : [number, string] ->t4 : [(number | undefined)?, (string | undefined)?, (boolean | undefined)?] +>t4 : T4 >[42, "hello"] : [number, string] >42 : 42 >"hello" : "hello" t4 = [42,,true]; >t4 = [42,,true] : [number, undefined, true] ->t4 : [(number | undefined)?, (string | undefined)?, (boolean | undefined)?] +>t4 : T4 >[42,,true] : [number, undefined, true] >42 : 42 > : undefined @@ -168,7 +168,7 @@ t4 = [42,,true]; t4 = [,"hello", true]; >t4 = [,"hello", true] : [undefined, string, true] ->t4 : [(number | undefined)?, (string | undefined)?, (boolean | undefined)?] +>t4 : T4 >[,"hello", true] : [undefined, string, true] > : undefined >"hello" : "hello" @@ -176,7 +176,7 @@ t4 = [,"hello", true]; t4 = [,,true]; >t4 = [,,true] : [undefined, undefined, true] ->t4 : [(number | undefined)?, (string | undefined)?, (boolean | undefined)?] +>t4 : T4 >[,,true] : [undefined, undefined, true] > : undefined > : undefined @@ -184,6 +184,6 @@ t4 = [,,true]; t4 = []; >t4 = [] : [] ->t4 : [(number | undefined)?, (string | undefined)?, (boolean | undefined)?] +>t4 : T4 >[] : [] diff --git a/tests/baselines/reference/readonlyArraysAndTuples.types b/tests/baselines/reference/readonlyArraysAndTuples.types index 5075319ef95..2d4086a0193 100644 --- a/tests/baselines/reference/readonlyArraysAndTuples.types +++ b/tests/baselines/reference/readonlyArraysAndTuples.types @@ -1,6 +1,6 @@ === tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts === type T10 = string[]; ->T10 : string[] +>T10 : T10 type T11 = Array; >T11 : string[] @@ -12,7 +12,7 @@ type T13 = ReadonlyArray; >T13 : readonly string[] type T20 = [number, number]; ->T20 : [number, number] +>T20 : T20 type T21 = readonly [number, number]; >T21 : readonly [number, number] diff --git a/tests/baselines/reference/readonlyArraysAndTuples2.types b/tests/baselines/reference/readonlyArraysAndTuples2.types index 9e49820fdbe..7b8c7124806 100644 --- a/tests/baselines/reference/readonlyArraysAndTuples2.types +++ b/tests/baselines/reference/readonlyArraysAndTuples2.types @@ -1,6 +1,6 @@ === tests/cases/conformance/types/tuple/readonlyArraysAndTuples2.ts === type T10 = string[]; ->T10 : string[] +>T10 : T10 type T11 = Array; >T11 : string[] @@ -12,7 +12,7 @@ type T13 = ReadonlyArray; >T13 : readonly string[] type T20 = [number, number]; ->T20 : [number, number] +>T20 : T20 type T21 = readonly [number, number]; >T21 : readonly [number, number] diff --git a/tests/baselines/reference/recursiveMappedTypes.types b/tests/baselines/reference/recursiveMappedTypes.types index 34cfd2d6100..02a555cdcb1 100644 --- a/tests/baselines/reference/recursiveMappedTypes.types +++ b/tests/baselines/reference/recursiveMappedTypes.types @@ -25,10 +25,10 @@ export type Circular = {[P in keyof T]: Circular}; >Circular : Circular type tup = [number, number, number, number]; ->tup : [number, number, number, number] +>tup : tup function foo(arg: Circular): tup { ->foo : (arg: any) => [number, number, number, number] +>foo : (arg: any) => tup >arg : any return arg; @@ -44,10 +44,10 @@ type DeepMap = { }; type tpl = [string, [string, [string]]]; ->tpl : [string, [string, [string]]] +>tpl : tpl type arr = string[][]; ->arr : string[][] +>arr : arr type t1 = DeepMap; // [number, [number, [number]]] >t1 : [number, [number, [number]]] diff --git a/tests/baselines/reference/recursiveResolveTypeMembers.errors.txt b/tests/baselines/reference/recursiveResolveTypeMembers.errors.txt index ad5fe6dc1ae..7bb5c554984 100644 --- a/tests/baselines/reference/recursiveResolveTypeMembers.errors.txt +++ b/tests/baselines/reference/recursiveResolveTypeMembers.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/recursiveResolveTypeMembers.ts(4,49): error TS2577: Return type annotation circularly references itself. +tests/cases/compiler/recursiveResolveTypeMembers.ts(4,49): error TS2589: Type instantiation is excessively deep and possibly infinite. tests/cases/compiler/recursiveResolveTypeMembers.ts(4,58): error TS2304: Cannot find name 'H'. tests/cases/compiler/recursiveResolveTypeMembers.ts(4,62): error TS2574: A rest element type must be an array type. tests/cases/compiler/recursiveResolveTypeMembers.ts(4,79): error TS2304: Cannot find name 'R'. @@ -10,7 +10,7 @@ tests/cases/compiler/recursiveResolveTypeMembers.ts(4,79): error TS2304: Cannot type PromisedTuple void> = U extends (h: infer H, ...args: infer R) => [Promise, ...PromisedTuple] ? [] : [] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2577: Return type annotation circularly references itself. +!!! error TS2589: Type instantiation is excessively deep and possibly infinite. ~ !!! error TS2304: Cannot find name 'H'. ~~~~~~~~~~~~~~~~~~~ diff --git a/tests/baselines/reference/recursiveTypesWithTypeof.errors.txt b/tests/baselines/reference/recursiveTypesWithTypeof.errors.txt index 0604e38bd94..2807613c3d9 100644 --- a/tests/baselines/reference/recursiveTypesWithTypeof.errors.txt +++ b/tests/baselines/reference/recursiveTypesWithTypeof.errors.txt @@ -3,7 +3,7 @@ tests/cases/conformance/types/specifyingTypes/typeQueries/recursiveTypesWithType tests/cases/conformance/types/specifyingTypes/typeQueries/recursiveTypesWithTypeof.ts(6,5): error TS2502: 'e' is referenced directly or indirectly in its own type annotation. tests/cases/conformance/types/specifyingTypes/typeQueries/recursiveTypesWithTypeof.ts(10,5): error TS2502: 'f' is referenced directly or indirectly in its own type annotation. tests/cases/conformance/types/specifyingTypes/typeQueries/recursiveTypesWithTypeof.ts(12,5): error TS2502: 'f2' is referenced directly or indirectly in its own type annotation. -tests/cases/conformance/types/specifyingTypes/typeQueries/recursiveTypesWithTypeof.ts(14,5): error TS2502: 'f3' is referenced directly or indirectly in its own type annotation. +tests/cases/conformance/types/specifyingTypes/typeQueries/recursiveTypesWithTypeof.ts(15,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'f3' must be of type 'Foo[]>[]>[]>[]>[]>[]>[]>[]>[]>[]>[]', but here has type 'any'. tests/cases/conformance/types/specifyingTypes/typeQueries/recursiveTypesWithTypeof.ts(51,5): error TS2502: 'hy3' is referenced directly or indirectly in its own type annotation. @@ -32,9 +32,10 @@ tests/cases/conformance/types/specifyingTypes/typeQueries/recursiveTypesWithType !!! error TS2502: 'f2' is referenced directly or indirectly in its own type annotation. var f2: any; var f3: Foo[]; - ~~ -!!! error TS2502: 'f3' is referenced directly or indirectly in its own type annotation. var f3: any; + ~~ +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'f3' must be of type 'Foo[]>[]>[]>[]>[]>[]>[]>[]>[]>[]>[]', but here has type 'any'. +!!! related TS6203 tests/cases/conformance/types/specifyingTypes/typeQueries/recursiveTypesWithTypeof.ts:14:5: 'f3' was also declared here. // None of these declarations should have any errors! // Truly recursive types diff --git a/tests/baselines/reference/recursiveTypesWithTypeof.types b/tests/baselines/reference/recursiveTypesWithTypeof.types index 5625e7919cd..1a527bfa470 100644 --- a/tests/baselines/reference/recursiveTypesWithTypeof.types +++ b/tests/baselines/reference/recursiveTypesWithTypeof.types @@ -37,11 +37,11 @@ var f2: any; >f2 : any var f3: Foo[]; ->f3 : any ->f3 : any +>f3 : Foo[]>[]>[]>[]>[]>[]>[]>[]>[]>[]>[] +>f3 : Foo[]>[]>[]>[]>[]>[]>[]>[]>[]>[]>[] var f3: any; ->f3 : any +>f3 : Foo[]>[]>[]>[]>[]>[]>[]>[]>[]>[]>[] // None of these declarations should have any errors! // Truly recursive types diff --git a/tests/baselines/reference/restTupleElements1.types b/tests/baselines/reference/restTupleElements1.types index ffa20bf503e..88c98395f21 100644 --- a/tests/baselines/reference/restTupleElements1.types +++ b/tests/baselines/reference/restTupleElements1.types @@ -1,42 +1,42 @@ === tests/cases/conformance/types/tuple/restTupleElements1.ts === type T00 = [string?]; ->T00 : [(string | undefined)?] +>T00 : T00 type T01 = [string, string?]; ->T01 : [string, (string | undefined)?] +>T01 : T01 type T02 = [string?, string]; // Error ->T02 : [string | undefined, string] +>T02 : T02 type T03 = [...string[]]; ->T03 : string[] +>T03 : T03 type T04 = [...[...string[]]]; ->T04 : string[] +>T04 : T04 type T05 = [...[...[...string[]]]]; ->T05 : string[] +>T05 : T05 type T06 = [string, ...string[]]; ->T06 : [string, ...string[]] +>T06 : T06 type T07 = [...string[], string]; // Error ->T07 : [string[], string] +>T07 : T07 type T08 = [...string]; // Error ->T08 : string[] +>T08 : T08 type T09 = [...string?]; // Error ->T09 : (string | null)[] +>T09 : T09 type T10 = [string, ...[...string[]]]; ->T10 : [string, ...string[]] +>T10 : T10 type T11 = [string, ...[...[...string[]]]]; ->T11 : [string, ...string[]] +>T11 : T11 type T15 = [boolean, number, ...string[]]; ->T15 : [boolean, number, ...string[]] +>T15 : T15 type L15 = T15["length"]; // number >L15 : number @@ -101,7 +101,7 @@ assign<[number, ...number[]], [number, number, number, string]>(); // Error >assign : () => void type T20 = [number, string, ...boolean[]]; ->T20 : [number, string, ...boolean[]] +>T20 : T20 type T21 = T20[0]; >T21 : number @@ -128,7 +128,7 @@ type T28 = T20[number]; >T28 : string | number | boolean declare const t: T20; ->t : [number, string, ...boolean[]] +>t : T20 declare const x: number; >x : number @@ -136,31 +136,31 @@ declare const x: number; let e0 = t[0]; // number >e0 : number >t[0] : number ->t : [number, string, ...boolean[]] +>t : T20 >0 : 0 let e1 = t[1]; // string >e1 : string >t[1] : string ->t : [number, string, ...boolean[]] +>t : T20 >1 : 1 let e2 = t[2]; // boolean >e2 : boolean >t[2] : boolean ->t : [number, string, ...boolean[]] +>t : T20 >2 : 2 let e3 = t[3]; // boolean >e3 : boolean >t[3] : boolean ->t : [number, string, ...boolean[]] +>t : T20 >3 : 3 let ex = t[x]; // number | string | boolean >ex : string | number | boolean >t[x] : string | number | boolean ->t : [number, string, ...boolean[]] +>t : T20 >x : number declare function f0(x: [T, ...U[]]): [T, U]; diff --git a/tests/baselines/reference/sourceMapValidationDestructuringForArrayBindingPattern.types b/tests/baselines/reference/sourceMapValidationDestructuringForArrayBindingPattern.types index 8ea11e087f8..eff8a930963 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringForArrayBindingPattern.types +++ b/tests/baselines/reference/sourceMapValidationDestructuringForArrayBindingPattern.types @@ -7,27 +7,27 @@ declare var console: { >msg : any } type Robot = [number, string, string]; ->Robot : [number, string, string] +>Robot : Robot type MultiSkilledRobot = [string, [string, string]]; ->MultiSkilledRobot : [string, [string, string]] +>MultiSkilledRobot : MultiSkilledRobot let robotA: Robot = [1, "mower", "mowing"]; ->robotA : [number, string, string] +>robotA : Robot >[1, "mower", "mowing"] : [number, string, string] >1 : 1 >"mower" : "mower" >"mowing" : "mowing" function getRobot() { ->getRobot : () => [number, string, string] +>getRobot : () => Robot return robotA; ->robotA : [number, string, string] +>robotA : Robot } let multiRobotA: MultiSkilledRobot = ["mower", ["mowing", ""]]; ->multiRobotA : [string, [string, string]] +>multiRobotA : MultiSkilledRobot >["mower", ["mowing", ""]] : [string, [string, string]] >"mower" : "mower" >["mowing", ""] : [string, string] @@ -35,7 +35,7 @@ let multiRobotA: MultiSkilledRobot = ["mower", ["mowing", ""]]; >"" : "" let multiRobotB: MultiSkilledRobot = ["trimmer", ["trimming", "edging"]]; ->multiRobotB : [string, [string, string]] +>multiRobotB : MultiSkilledRobot >["trimmer", ["trimming", "edging"]] : [string, [string, string]] >"trimmer" : "trimmer" >["trimming", "edging"] : [string, string] @@ -43,16 +43,16 @@ let multiRobotB: MultiSkilledRobot = ["trimmer", ["trimming", "edging"]]; >"edging" : "edging" function getMultiRobot() { ->getMultiRobot : () => [string, [string, string]] +>getMultiRobot : () => MultiSkilledRobot return multiRobotA; ->multiRobotA : [string, [string, string]] +>multiRobotA : MultiSkilledRobot } for (let [, nameA] = robotA, i = 0; i < 1; i++) { > : undefined >nameA : string ->robotA : [number, string, string] +>robotA : Robot >i : number >0 : 0 >i < 1 : boolean @@ -71,8 +71,8 @@ for (let [, nameA] = robotA, i = 0; i < 1; i++) { for (let [, nameA] = getRobot(), i = 0; i < 1; i++) { > : undefined >nameA : string ->getRobot() : [number, string, string] ->getRobot : () => [number, string, string] +>getRobot() : Robot +>getRobot : () => Robot >i : number >0 : 0 >i < 1 : boolean @@ -114,7 +114,7 @@ for (let [, [primarySkillA, secondarySkillA]] = multiRobotA, i = 0; i < 1; i++) > : undefined >primarySkillA : string >secondarySkillA : string ->multiRobotA : [string, [string, string]] +>multiRobotA : MultiSkilledRobot >i : number >0 : 0 >i < 1 : boolean @@ -134,8 +134,8 @@ for (let [, [primarySkillA, secondarySkillA]] = getMultiRobot(), i = 0; i < 1; i > : undefined >primarySkillA : string >secondarySkillA : string ->getMultiRobot() : [string, [string, string]] ->getMultiRobot : () => [string, [string, string]] +>getMultiRobot() : MultiSkilledRobot +>getMultiRobot : () => MultiSkilledRobot >i : number >0 : 0 >i < 1 : boolean @@ -178,7 +178,7 @@ for (let [, [primarySkillA, secondarySkillA]] = ["trimmer", ["trimming", "edging for (let [numberB] = robotA, i = 0; i < 1; i++) { >numberB : number ->robotA : [number, string, string] +>robotA : Robot >i : number >0 : 0 >i < 1 : boolean @@ -196,8 +196,8 @@ for (let [numberB] = robotA, i = 0; i < 1; i++) { } for (let [numberB] = getRobot(), i = 0; i < 1; i++) { >numberB : number ->getRobot() : [number, string, string] ->getRobot : () => [number, string, string] +>getRobot() : Robot +>getRobot : () => Robot >i : number >0 : 0 >i < 1 : boolean @@ -236,7 +236,7 @@ for (let [numberB] = [2, "trimmer", "trimming"], i = 0; i < 1; i++) { } for (let [nameB] = multiRobotA, i = 0; i < 1; i++) { >nameB : string ->multiRobotA : [string, [string, string]] +>multiRobotA : MultiSkilledRobot >i : number >0 : 0 >i < 1 : boolean @@ -254,8 +254,8 @@ for (let [nameB] = multiRobotA, i = 0; i < 1; i++) { } for (let [nameB] = getMultiRobot(), i = 0; i < 1; i++) { >nameB : string ->getMultiRobot() : [string, [string, string]] ->getMultiRobot : () => [string, [string, string]] +>getMultiRobot() : MultiSkilledRobot +>getMultiRobot : () => MultiSkilledRobot >i : number >0 : 0 >i < 1 : boolean @@ -298,7 +298,7 @@ for (let [numberA2, nameA2, skillA2] = robotA, i = 0; i < 1; i++) { >numberA2 : number >nameA2 : string >skillA2 : string ->robotA : [number, string, string] +>robotA : Robot >i : number >0 : 0 >i < 1 : boolean @@ -318,8 +318,8 @@ for (let [numberA2, nameA2, skillA2] = getRobot(), i = 0; i < 1; i++) { >numberA2 : number >nameA2 : string >skillA2 : string ->getRobot() : [number, string, string] ->getRobot : () => [number, string, string] +>getRobot() : Robot +>getRobot : () => Robot >i : number >0 : 0 >i < 1 : boolean @@ -362,7 +362,7 @@ for (let [nameMA, [primarySkillA, secondarySkillA]] = multiRobotA, i = 0; i < 1; >nameMA : string >primarySkillA : string >secondarySkillA : string ->multiRobotA : [string, [string, string]] +>multiRobotA : MultiSkilledRobot >i : number >0 : 0 >i < 1 : boolean @@ -382,8 +382,8 @@ for (let [nameMA, [primarySkillA, secondarySkillA]] = getMultiRobot(), i = 0; i >nameMA : string >primarySkillA : string >secondarySkillA : string ->getMultiRobot() : [string, [string, string]] ->getMultiRobot : () => [string, [string, string]] +>getMultiRobot() : MultiSkilledRobot +>getMultiRobot : () => MultiSkilledRobot >i : number >0 : 0 >i < 1 : boolean @@ -427,7 +427,7 @@ for (let [nameMA, [primarySkillA, secondarySkillA]] = ["trimmer", ["trimming", " for (let [numberA3, ...robotAInfo] = robotA, i = 0; i < 1; i++) { >numberA3 : number >robotAInfo : [string, string] ->robotA : [number, string, string] +>robotA : Robot >i : number >0 : 0 >i < 1 : boolean @@ -446,8 +446,8 @@ for (let [numberA3, ...robotAInfo] = robotA, i = 0; i < 1; i++) { for (let [numberA3, ...robotAInfo] = getRobot(), i = 0; i < 1; i++) { >numberA3 : number >robotAInfo : [string, string] ->getRobot() : [number, string, string] ->getRobot : () => [number, string, string] +>getRobot() : Robot +>getRobot : () => Robot >i : number >0 : 0 >i < 1 : boolean @@ -487,7 +487,7 @@ for (let [numberA3, ...robotAInfo] = [2, "trimmer", "trimming"], i = 0; i < 1; i } for (let [...multiRobotAInfo] = multiRobotA, i = 0; i < 1; i++) { >multiRobotAInfo : [string, [string, string]] ->multiRobotA : [string, [string, string]] +>multiRobotA : MultiSkilledRobot >i : number >0 : 0 >i < 1 : boolean @@ -505,8 +505,8 @@ for (let [...multiRobotAInfo] = multiRobotA, i = 0; i < 1; i++) { } for (let [...multiRobotAInfo] = getMultiRobot(), i = 0; i < 1; i++) { >multiRobotAInfo : [string, [string, string]] ->getMultiRobot() : [string, [string, string]] ->getMultiRobot : () => [string, [string, string]] +>getMultiRobot() : MultiSkilledRobot +>getMultiRobot : () => MultiSkilledRobot >i : number >0 : 0 >i < 1 : boolean diff --git a/tests/baselines/reference/sourceMapValidationDestructuringForArrayBindingPattern2.types b/tests/baselines/reference/sourceMapValidationDestructuringForArrayBindingPattern2.types index 3f198ebc80f..bfa1757d616 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringForArrayBindingPattern2.types +++ b/tests/baselines/reference/sourceMapValidationDestructuringForArrayBindingPattern2.types @@ -7,27 +7,27 @@ declare var console: { >msg : any } type Robot = [number, string, string]; ->Robot : [number, string, string] +>Robot : Robot type MultiSkilledRobot = [string, [string, string]]; ->MultiSkilledRobot : [string, [string, string]] +>MultiSkilledRobot : MultiSkilledRobot let robotA: Robot = [1, "mower", "mowing"]; ->robotA : [number, string, string] +>robotA : Robot >[1, "mower", "mowing"] : [number, string, string] >1 : 1 >"mower" : "mower" >"mowing" : "mowing" function getRobot() { ->getRobot : () => [number, string, string] +>getRobot : () => Robot return robotA; ->robotA : [number, string, string] +>robotA : Robot } let multiRobotA: MultiSkilledRobot = ["mower", ["mowing", ""]]; ->multiRobotA : [string, [string, string]] +>multiRobotA : MultiSkilledRobot >["mower", ["mowing", ""]] : [string, [string, string]] >"mower" : "mower" >["mowing", ""] : [string, string] @@ -35,7 +35,7 @@ let multiRobotA: MultiSkilledRobot = ["mower", ["mowing", ""]]; >"" : "" let multiRobotB: MultiSkilledRobot = ["trimmer", ["trimming", "edging"]]; ->multiRobotB : [string, [string, string]] +>multiRobotB : MultiSkilledRobot >["trimmer", ["trimming", "edging"]] : [string, [string, string]] >"trimmer" : "trimmer" >["trimming", "edging"] : [string, string] @@ -43,10 +43,10 @@ let multiRobotB: MultiSkilledRobot = ["trimmer", ["trimming", "edging"]]; >"edging" : "edging" function getMultiRobot() { ->getMultiRobot : () => [string, [string, string]] +>getMultiRobot : () => MultiSkilledRobot return multiRobotA; ->multiRobotA : [string, [string, string]] +>multiRobotA : MultiSkilledRobot } let nameA: string, primarySkillA: string, secondarySkillA: string; @@ -74,11 +74,11 @@ let i: number; for ([, nameA] = robotA, i = 0; i < 1; i++) { >[, nameA] = robotA, i = 0 : 0 ->[, nameA] = robotA : [number, string, string] +>[, nameA] = robotA : Robot >[, nameA] : [undefined, string] > : undefined >nameA : string ->robotA : [number, string, string] +>robotA : Robot >i = 0 : 0 >i : number >0 : 0 @@ -97,12 +97,12 @@ for ([, nameA] = robotA, i = 0; i < 1; i++) { } for ([, nameA] = getRobot(), i = 0; i < 1; i++) { >[, nameA] = getRobot(), i = 0 : 0 ->[, nameA] = getRobot() : [number, string, string] +>[, nameA] = getRobot() : Robot >[, nameA] : [undefined, string] > : undefined >nameA : string ->getRobot() : [number, string, string] ->getRobot : () => [number, string, string] +>getRobot() : Robot +>getRobot : () => Robot >i = 0 : 0 >i : number >0 : 0 @@ -147,13 +147,13 @@ for ([, nameA] = [2, "trimmer", "trimming"], i = 0; i < 1; i++) { } for ([, [primarySkillA, secondarySkillA]] = multiRobotA, i = 0; i < 1; i++) { >[, [primarySkillA, secondarySkillA]] = multiRobotA, i = 0 : 0 ->[, [primarySkillA, secondarySkillA]] = multiRobotA : [string, [string, string]] +>[, [primarySkillA, secondarySkillA]] = multiRobotA : MultiSkilledRobot >[, [primarySkillA, secondarySkillA]] : [undefined, [string, string]] > : undefined >[primarySkillA, secondarySkillA] : [string, string] >primarySkillA : string >secondarySkillA : string ->multiRobotA : [string, [string, string]] +>multiRobotA : MultiSkilledRobot >i = 0 : 0 >i : number >0 : 0 @@ -172,14 +172,14 @@ for ([, [primarySkillA, secondarySkillA]] = multiRobotA, i = 0; i < 1; i++) { } for ([, [primarySkillA, secondarySkillA]] = getMultiRobot(), i = 0; i < 1; i++) { >[, [primarySkillA, secondarySkillA]] = getMultiRobot(), i = 0 : 0 ->[, [primarySkillA, secondarySkillA]] = getMultiRobot() : [string, [string, string]] +>[, [primarySkillA, secondarySkillA]] = getMultiRobot() : MultiSkilledRobot >[, [primarySkillA, secondarySkillA]] : [undefined, [string, string]] > : undefined >[primarySkillA, secondarySkillA] : [string, string] >primarySkillA : string >secondarySkillA : string ->getMultiRobot() : [string, [string, string]] ->getMultiRobot : () => [string, [string, string]] +>getMultiRobot() : MultiSkilledRobot +>getMultiRobot : () => MultiSkilledRobot >i = 0 : 0 >i : number >0 : 0 @@ -228,10 +228,10 @@ for ([, [primarySkillA, secondarySkillA]] = ["trimmer", ["trimming", "edging"]], for ([numberB] = robotA, i = 0; i < 1; i++) { >[numberB] = robotA, i = 0 : 0 ->[numberB] = robotA : [number, string, string] +>[numberB] = robotA : Robot >[numberB] : [number] >numberB : number ->robotA : [number, string, string] +>robotA : Robot >i = 0 : 0 >i : number >0 : 0 @@ -250,11 +250,11 @@ for ([numberB] = robotA, i = 0; i < 1; i++) { } for ([numberB] = getRobot(), i = 0; i < 1; i++) { >[numberB] = getRobot(), i = 0 : 0 ->[numberB] = getRobot() : [number, string, string] +>[numberB] = getRobot() : Robot >[numberB] : [number] >numberB : number ->getRobot() : [number, string, string] ->getRobot : () => [number, string, string] +>getRobot() : Robot +>getRobot : () => Robot >i = 0 : 0 >i : number >0 : 0 @@ -298,10 +298,10 @@ for ([numberB] = [2, "trimmer", "trimming"], i = 0; i < 1; i++) { } for ([nameB] = multiRobotA, i = 0; i < 1; i++) { >[nameB] = multiRobotA, i = 0 : 0 ->[nameB] = multiRobotA : [string, [string, string]] +>[nameB] = multiRobotA : MultiSkilledRobot >[nameB] : [string] >nameB : string ->multiRobotA : [string, [string, string]] +>multiRobotA : MultiSkilledRobot >i = 0 : 0 >i : number >0 : 0 @@ -320,11 +320,11 @@ for ([nameB] = multiRobotA, i = 0; i < 1; i++) { } for ([nameB] = getMultiRobot(), i = 0; i < 1; i++) { >[nameB] = getMultiRobot(), i = 0 : 0 ->[nameB] = getMultiRobot() : [string, [string, string]] +>[nameB] = getMultiRobot() : MultiSkilledRobot >[nameB] : [string] >nameB : string ->getMultiRobot() : [string, [string, string]] ->getMultiRobot : () => [string, [string, string]] +>getMultiRobot() : MultiSkilledRobot +>getMultiRobot : () => MultiSkilledRobot >i = 0 : 0 >i : number >0 : 0 @@ -370,12 +370,12 @@ for ([nameB] = ["trimmer", ["trimming", "edging"]], i = 0; i < 1; i++) { for ([numberA2, nameA2, skillA2] = robotA, i = 0; i < 1; i++) { >[numberA2, nameA2, skillA2] = robotA, i = 0 : 0 ->[numberA2, nameA2, skillA2] = robotA : [number, string, string] +>[numberA2, nameA2, skillA2] = robotA : Robot >[numberA2, nameA2, skillA2] : [number, string, string] >numberA2 : number >nameA2 : string >skillA2 : string ->robotA : [number, string, string] +>robotA : Robot >i = 0 : 0 >i : number >0 : 0 @@ -394,13 +394,13 @@ for ([numberA2, nameA2, skillA2] = robotA, i = 0; i < 1; i++) { } for ([numberA2, nameA2, skillA2] = getRobot(), i = 0; i < 1; i++) { >[numberA2, nameA2, skillA2] = getRobot(), i = 0 : 0 ->[numberA2, nameA2, skillA2] = getRobot() : [number, string, string] +>[numberA2, nameA2, skillA2] = getRobot() : Robot >[numberA2, nameA2, skillA2] : [number, string, string] >numberA2 : number >nameA2 : string >skillA2 : string ->getRobot() : [number, string, string] ->getRobot : () => [number, string, string] +>getRobot() : Robot +>getRobot : () => Robot >i = 0 : 0 >i : number >0 : 0 @@ -446,13 +446,13 @@ for ([numberA2, nameA2, skillA2] = [2, "trimmer", "trimming"], i = 0; i < 1; i++ } for ([nameMA, [primarySkillA, secondarySkillA]] = multiRobotA, i = 0; i < 1; i++) { >[nameMA, [primarySkillA, secondarySkillA]] = multiRobotA, i = 0 : 0 ->[nameMA, [primarySkillA, secondarySkillA]] = multiRobotA : [string, [string, string]] +>[nameMA, [primarySkillA, secondarySkillA]] = multiRobotA : MultiSkilledRobot >[nameMA, [primarySkillA, secondarySkillA]] : [string, [string, string]] >nameMA : string >[primarySkillA, secondarySkillA] : [string, string] >primarySkillA : string >secondarySkillA : string ->multiRobotA : [string, [string, string]] +>multiRobotA : MultiSkilledRobot >i = 0 : 0 >i : number >0 : 0 @@ -471,14 +471,14 @@ for ([nameMA, [primarySkillA, secondarySkillA]] = multiRobotA, i = 0; i < 1; i++ } for ([nameMA, [primarySkillA, secondarySkillA]] = getMultiRobot(), i = 0; i < 1; i++) { >[nameMA, [primarySkillA, secondarySkillA]] = getMultiRobot(), i = 0 : 0 ->[nameMA, [primarySkillA, secondarySkillA]] = getMultiRobot() : [string, [string, string]] +>[nameMA, [primarySkillA, secondarySkillA]] = getMultiRobot() : MultiSkilledRobot >[nameMA, [primarySkillA, secondarySkillA]] : [string, [string, string]] >nameMA : string >[primarySkillA, secondarySkillA] : [string, string] >primarySkillA : string >secondarySkillA : string ->getMultiRobot() : [string, [string, string]] ->getMultiRobot : () => [string, [string, string]] +>getMultiRobot() : MultiSkilledRobot +>getMultiRobot : () => MultiSkilledRobot >i = 0 : 0 >i : number >0 : 0 @@ -527,12 +527,12 @@ for ([nameMA, [primarySkillA, secondarySkillA]] = ["trimmer", ["trimming", "edgi for ([numberA3, ...robotAInfo] = robotA, i = 0; i < 1; i++) { >[numberA3, ...robotAInfo] = robotA, i = 0 : 0 ->[numberA3, ...robotAInfo] = robotA : [number, string, string] +>[numberA3, ...robotAInfo] = robotA : Robot >[numberA3, ...robotAInfo] : [number, ...(string | number)[]] >numberA3 : number >...robotAInfo : string | number >robotAInfo : (string | number)[] ->robotA : [number, string, string] +>robotA : Robot >i = 0 : 0 >i : number >0 : 0 @@ -551,13 +551,13 @@ for ([numberA3, ...robotAInfo] = robotA, i = 0; i < 1; i++) { } for ([numberA3, ...robotAInfo] = getRobot(), i = 0; i < 1; i++) { >[numberA3, ...robotAInfo] = getRobot(), i = 0 : 0 ->[numberA3, ...robotAInfo] = getRobot() : [number, string, string] +>[numberA3, ...robotAInfo] = getRobot() : Robot >[numberA3, ...robotAInfo] : [number, ...(string | number)[]] >numberA3 : number >...robotAInfo : string | number >robotAInfo : (string | number)[] ->getRobot() : [number, string, string] ->getRobot : () => [number, string, string] +>getRobot() : Robot +>getRobot : () => Robot >i = 0 : 0 >i : number >0 : 0 @@ -576,12 +576,12 @@ for ([numberA3, ...robotAInfo] = getRobot(), i = 0; i < 1; i++) { } for ([numberA3, ...robotAInfo] = [2, "trimmer", "trimming"], i = 0; i < 1; i++) { >[numberA3, ...robotAInfo] = [2, "trimmer", "trimming"], i = 0 : 0 ->[numberA3, ...robotAInfo] = [2, "trimmer", "trimming"] : [number, string, string] +>[numberA3, ...robotAInfo] = [2, "trimmer", "trimming"] : Robot >[numberA3, ...robotAInfo] : [number, ...(string | number)[]] >numberA3 : number >...robotAInfo : string | number >robotAInfo : (string | number)[] ->[2, "trimmer", "trimming"] : [number, string, string] +>[2, "trimmer", "trimming"] : Robot >[2, "trimmer", "trimming"] : [number, string, string] >2 : 2 >"trimmer" : "trimmer" @@ -604,11 +604,11 @@ for ([numberA3, ...robotAInfo] = [2, "trimmer", "trimming"], i = 0; i < 1 } for ([...multiRobotAInfo] = multiRobotA, i = 0; i < 1; i++) { >[...multiRobotAInfo] = multiRobotA, i = 0 : 0 ->[...multiRobotAInfo] = multiRobotA : [string, [string, string]] +>[...multiRobotAInfo] = multiRobotA : MultiSkilledRobot >[...multiRobotAInfo] : (string | [string, string])[] >...multiRobotAInfo : string | [string, string] >multiRobotAInfo : (string | [string, string])[] ->multiRobotA : [string, [string, string]] +>multiRobotA : MultiSkilledRobot >i = 0 : 0 >i : number >0 : 0 @@ -627,12 +627,12 @@ for ([...multiRobotAInfo] = multiRobotA, i = 0; i < 1; i++) { } for ([...multiRobotAInfo] = getMultiRobot(), i = 0; i < 1; i++) { >[...multiRobotAInfo] = getMultiRobot(), i = 0 : 0 ->[...multiRobotAInfo] = getMultiRobot() : [string, [string, string]] +>[...multiRobotAInfo] = getMultiRobot() : MultiSkilledRobot >[...multiRobotAInfo] : (string | [string, string])[] >...multiRobotAInfo : string | [string, string] >multiRobotAInfo : (string | [string, string])[] ->getMultiRobot() : [string, [string, string]] ->getMultiRobot : () => [string, [string, string]] +>getMultiRobot() : MultiSkilledRobot +>getMultiRobot : () => MultiSkilledRobot >i = 0 : 0 >i : number >0 : 0 @@ -651,11 +651,11 @@ for ([...multiRobotAInfo] = getMultiRobot(), i = 0; i < 1; i++) { } for ([...multiRobotAInfo] = ["trimmer", ["trimming", "edging"]], i = 0; i < 1; i++) { >[...multiRobotAInfo] = ["trimmer", ["trimming", "edging"]], i = 0 : 0 ->[...multiRobotAInfo] = ["trimmer", ["trimming", "edging"]] : [string, [string, string]] +>[...multiRobotAInfo] = ["trimmer", ["trimming", "edging"]] : MultiSkilledRobot >[...multiRobotAInfo] : (string | [string, string])[] >...multiRobotAInfo : string | [string, string] >multiRobotAInfo : (string | [string, string])[] ->["trimmer", ["trimming", "edging"]] : [string, [string, string]] +>["trimmer", ["trimming", "edging"]] : MultiSkilledRobot >["trimmer", ["trimming", "edging"]] : [string, [string, string]] >"trimmer" : "trimmer" >["trimming", "edging"] : [string, string] diff --git a/tests/baselines/reference/sourceMapValidationDestructuringForArrayBindingPatternDefaultValues.types b/tests/baselines/reference/sourceMapValidationDestructuringForArrayBindingPatternDefaultValues.types index ee16f28a9d5..2dab0c1cd6b 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringForArrayBindingPatternDefaultValues.types +++ b/tests/baselines/reference/sourceMapValidationDestructuringForArrayBindingPatternDefaultValues.types @@ -7,27 +7,27 @@ declare var console: { >msg : any } type Robot = [number, string, string]; ->Robot : [number, string, string] +>Robot : Robot type MultiSkilledRobot = [string, string[]]; ->MultiSkilledRobot : [string, string[]] +>MultiSkilledRobot : MultiSkilledRobot let robotA: Robot = [1, "mower", "mowing"]; ->robotA : [number, string, string] +>robotA : Robot >[1, "mower", "mowing"] : [number, string, string] >1 : 1 >"mower" : "mower" >"mowing" : "mowing" function getRobot() { ->getRobot : () => [number, string, string] +>getRobot : () => Robot return robotA; ->robotA : [number, string, string] +>robotA : Robot } let multiRobotA: MultiSkilledRobot = ["mower", ["mowing", ""]]; ->multiRobotA : [string, string[]] +>multiRobotA : MultiSkilledRobot >["mower", ["mowing", ""]] : [string, string[]] >"mower" : "mower" >["mowing", ""] : string[] @@ -35,7 +35,7 @@ let multiRobotA: MultiSkilledRobot = ["mower", ["mowing", ""]]; >"" : "" let multiRobotB: MultiSkilledRobot = ["trimmer", ["trimming", "edging"]]; ->multiRobotB : [string, string[]] +>multiRobotB : MultiSkilledRobot >["trimmer", ["trimming", "edging"]] : [string, string[]] >"trimmer" : "trimmer" >["trimming", "edging"] : string[] @@ -43,17 +43,17 @@ let multiRobotB: MultiSkilledRobot = ["trimmer", ["trimming", "edging"]]; >"edging" : "edging" function getMultiRobot() { ->getMultiRobot : () => [string, string[]] +>getMultiRobot : () => MultiSkilledRobot return multiRobotA; ->multiRobotA : [string, string[]] +>multiRobotA : MultiSkilledRobot } for (let [, nameA ="name"] = robotA, i = 0; i < 1; i++) { > : undefined >nameA : string >"name" : "name" ->robotA : [number, string, string] +>robotA : Robot >i : number >0 : 0 >i < 1 : boolean @@ -73,8 +73,8 @@ for (let [, nameA = "name"] = getRobot(), i = 0; i < 1; i++) { > : undefined >nameA : string >"name" : "name" ->getRobot() : [number, string, string] ->getRobot : () => [number, string, string] +>getRobot() : Robot +>getRobot : () => Robot >i : number >0 : 0 >i < 1 : boolean @@ -128,7 +128,7 @@ for (let [, [ >["none", "none"] : [string, string] >"none" : "none" >"none" : "none" ->multiRobotA : [string, string[]] +>multiRobotA : MultiSkilledRobot >i : number >0 : 0 >i < 1 : boolean @@ -159,8 +159,8 @@ for (let [, [ >["none", "none"] : [string, string] >"none" : "none" >"none" : "none" ->getMultiRobot() : [string, string[]] ->getMultiRobot : () => [string, string[]] +>getMultiRobot() : MultiSkilledRobot +>getMultiRobot : () => MultiSkilledRobot >i : number >0 : 0 >i < 1 : boolean @@ -216,7 +216,7 @@ for (let [numberB = -1] = robotA, i = 0; i < 1; i++) { >numberB : number >-1 : -1 >1 : 1 ->robotA : [number, string, string] +>robotA : Robot >i : number >0 : 0 >i < 1 : boolean @@ -236,8 +236,8 @@ for (let [numberB = -1] = getRobot(), i = 0; i < 1; i++) { >numberB : number >-1 : -1 >1 : 1 ->getRobot() : [number, string, string] ->getRobot : () => [number, string, string] +>getRobot() : Robot +>getRobot : () => Robot >i : number >0 : 0 >i < 1 : boolean @@ -279,7 +279,7 @@ for (let [numberB = -1] = [2, "trimmer", "trimming"], i = 0; i < 1; i++) { for (let [nameB = "name"] = multiRobotA, i = 0; i < 1; i++) { >nameB : string >"name" : "name" ->multiRobotA : [string, string[]] +>multiRobotA : MultiSkilledRobot >i : number >0 : 0 >i < 1 : boolean @@ -298,8 +298,8 @@ for (let [nameB = "name"] = multiRobotA, i = 0; i < 1; i++) { for (let [nameB = "name"] = getMultiRobot(), i = 0; i < 1; i++) { >nameB : string >"name" : "name" ->getMultiRobot() : [string, string[]] ->getMultiRobot : () => [string, string[]] +>getMultiRobot() : MultiSkilledRobot +>getMultiRobot : () => MultiSkilledRobot >i : number >0 : 0 >i < 1 : boolean @@ -347,7 +347,7 @@ for (let [numberA2 = -1, nameA2 = "name", skillA2 = "skill"] = robotA, i = 0; i >"name" : "name" >skillA2 : string >"skill" : "skill" ->robotA : [number, string, string] +>robotA : Robot >i : number >0 : 0 >i < 1 : boolean @@ -371,8 +371,8 @@ for (let [numberA2 = -1, nameA2 = "name", skillA2 = "skill"] = getRobot(), i = 0 >"name" : "name" >skillA2 : string >"skill" : "skill" ->getRobot() : [number, string, string] ->getRobot : () => [number, string, string] +>getRobot() : Robot +>getRobot : () => Robot >i : number >0 : 0 >i < 1 : boolean @@ -435,7 +435,7 @@ for (let >"none" : "none" ] = multiRobotA, i = 0; i < 1; i++) { ->multiRobotA : [string, string[]] +>multiRobotA : MultiSkilledRobot >i : number >0 : 0 >i < 1 : boolean @@ -470,8 +470,8 @@ for (let [nameMA = "noName", >"none" : "none" ] = getMultiRobot(), i = 0; i < 1; i++) { ->getMultiRobot() : [string, string[]] ->getMultiRobot : () => [string, string[]] +>getMultiRobot() : MultiSkilledRobot +>getMultiRobot : () => MultiSkilledRobot >i : number >0 : 0 >i < 1 : boolean @@ -532,7 +532,7 @@ for (let [numberA3 = -1, ...robotAInfo] = robotA, i = 0; i < 1; i++) { >-1 : -1 >1 : 1 >robotAInfo : [string, string] ->robotA : [number, string, string] +>robotA : Robot >i : number >0 : 0 >i < 1 : boolean @@ -553,8 +553,8 @@ for (let [numberA3 = -1, ...robotAInfo] = getRobot(), i = 0; i < 1; i++) { >-1 : -1 >1 : 1 >robotAInfo : [string, string] ->getRobot() : [number, string, string] ->getRobot : () => [number, string, string] +>getRobot() : Robot +>getRobot : () => Robot >i : number >0 : 0 >i < 1 : boolean diff --git a/tests/baselines/reference/sourceMapValidationDestructuringForArrayBindingPatternDefaultValues2.types b/tests/baselines/reference/sourceMapValidationDestructuringForArrayBindingPatternDefaultValues2.types index 9175ee68dca..aa06efe3965 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringForArrayBindingPatternDefaultValues2.types +++ b/tests/baselines/reference/sourceMapValidationDestructuringForArrayBindingPatternDefaultValues2.types @@ -7,27 +7,27 @@ declare var console: { >msg : any } type Robot = [number, string, string]; ->Robot : [number, string, string] +>Robot : Robot type MultiSkilledRobot = [string, [string, string]]; ->MultiSkilledRobot : [string, [string, string]] +>MultiSkilledRobot : MultiSkilledRobot let robotA: Robot = [1, "mower", "mowing"]; ->robotA : [number, string, string] +>robotA : Robot >[1, "mower", "mowing"] : [number, string, string] >1 : 1 >"mower" : "mower" >"mowing" : "mowing" function getRobot() { ->getRobot : () => [number, string, string] +>getRobot : () => Robot return robotA; ->robotA : [number, string, string] +>robotA : Robot } let multiRobotA: MultiSkilledRobot = ["mower", ["mowing", ""]]; ->multiRobotA : [string, [string, string]] +>multiRobotA : MultiSkilledRobot >["mower", ["mowing", ""]] : [string, [string, string]] >"mower" : "mower" >["mowing", ""] : [string, string] @@ -35,7 +35,7 @@ let multiRobotA: MultiSkilledRobot = ["mower", ["mowing", ""]]; >"" : "" let multiRobotB: MultiSkilledRobot = ["trimmer", ["trimming", "edging"]]; ->multiRobotB : [string, [string, string]] +>multiRobotB : MultiSkilledRobot >["trimmer", ["trimming", "edging"]] : [string, [string, string]] >"trimmer" : "trimmer" >["trimming", "edging"] : [string, string] @@ -43,10 +43,10 @@ let multiRobotB: MultiSkilledRobot = ["trimmer", ["trimming", "edging"]]; >"edging" : "edging" function getMultiRobot() { ->getMultiRobot : () => [string, [string, string]] +>getMultiRobot : () => MultiSkilledRobot return multiRobotA; ->multiRobotA : [string, [string, string]] +>multiRobotA : MultiSkilledRobot } let nameA: string, primarySkillA: string, secondarySkillA: string; @@ -74,13 +74,13 @@ let i: number; for ([, nameA = "name"] = robotA, i = 0; i < 1; i++) { >[, nameA = "name"] = robotA, i = 0 : 0 ->[, nameA = "name"] = robotA : [number, string, string] +>[, nameA = "name"] = robotA : Robot >[, nameA = "name"] : [undefined, string] > : undefined >nameA = "name" : "name" >nameA : string >"name" : "name" ->robotA : [number, string, string] +>robotA : Robot >i = 0 : 0 >i : number >0 : 0 @@ -99,14 +99,14 @@ for ([, nameA = "name"] = robotA, i = 0; i < 1; i++) { } for ([, nameA = "name"] = getRobot(), i = 0; i < 1; i++) { >[, nameA = "name"] = getRobot(), i = 0 : 0 ->[, nameA = "name"] = getRobot() : [number, string, string] +>[, nameA = "name"] = getRobot() : Robot >[, nameA = "name"] : [undefined, string] > : undefined >nameA = "name" : "name" >nameA : string >"name" : "name" ->getRobot() : [number, string, string] ->getRobot : () => [number, string, string] +>getRobot() : Robot +>getRobot : () => Robot >i = 0 : 0 >i : number >0 : 0 @@ -153,7 +153,7 @@ for ([, nameA = "name"] = [2, "trimmer", "trimming"], i = 0; i < 1; i++) { } for ([, [ >[, [ primarySkillA = "primary", secondarySkillA = "secondary"] = ["none", "none"]] = multiRobotA, i = 0 : 0 ->[, [ primarySkillA = "primary", secondarySkillA = "secondary"] = ["none", "none"]] = multiRobotA : [string, [string, string]] +>[, [ primarySkillA = "primary", secondarySkillA = "secondary"] = ["none", "none"]] = multiRobotA : MultiSkilledRobot >[, [ primarySkillA = "primary", secondarySkillA = "secondary"] = ["none", "none"]] : [undefined, [string, string]] > : undefined >[ primarySkillA = "primary", secondarySkillA = "secondary"] = ["none", "none"] : [string, string] @@ -173,7 +173,7 @@ for ([, [ >["none", "none"] : [string, string] >"none" : "none" >"none" : "none" ->multiRobotA : [string, [string, string]] +>multiRobotA : MultiSkilledRobot >i = 0 : 0 >i : number >0 : 0 @@ -192,7 +192,7 @@ for ([, [ } for ([, [ >[, [ primarySkillA = "primary", secondarySkillA = "secondary"] = ["none", "none"]] = getMultiRobot(), i = 0 : 0 ->[, [ primarySkillA = "primary", secondarySkillA = "secondary"] = ["none", "none"]] = getMultiRobot() : [string, [string, string]] +>[, [ primarySkillA = "primary", secondarySkillA = "secondary"] = ["none", "none"]] = getMultiRobot() : MultiSkilledRobot >[, [ primarySkillA = "primary", secondarySkillA = "secondary"] = ["none", "none"]] : [undefined, [string, string]] > : undefined >[ primarySkillA = "primary", secondarySkillA = "secondary"] = ["none", "none"] : [string, string] @@ -212,8 +212,8 @@ for ([, [ >["none", "none"] : [string, string] >"none" : "none" >"none" : "none" ->getMultiRobot() : [string, [string, string]] ->getMultiRobot : () => [string, [string, string]] +>getMultiRobot() : MultiSkilledRobot +>getMultiRobot : () => MultiSkilledRobot >i = 0 : 0 >i : number >0 : 0 @@ -276,13 +276,13 @@ for ([, [ for ([numberB = -1] = robotA, i = 0; i < 1; i++) { >[numberB = -1] = robotA, i = 0 : 0 ->[numberB = -1] = robotA : [number, string, string] +>[numberB = -1] = robotA : Robot >[numberB = -1] : [number] >numberB = -1 : -1 >numberB : number >-1 : -1 >1 : 1 ->robotA : [number, string, string] +>robotA : Robot >i = 0 : 0 >i : number >0 : 0 @@ -301,14 +301,14 @@ for ([numberB = -1] = robotA, i = 0; i < 1; i++) { } for ([numberB = -1] = getRobot(), i = 0; i < 1; i++) { >[numberB = -1] = getRobot(), i = 0 : 0 ->[numberB = -1] = getRobot() : [number, string, string] +>[numberB = -1] = getRobot() : Robot >[numberB = -1] : [number] >numberB = -1 : -1 >numberB : number >-1 : -1 >1 : 1 ->getRobot() : [number, string, string] ->getRobot : () => [number, string, string] +>getRobot() : Robot +>getRobot : () => Robot >i = 0 : 0 >i : number >0 : 0 @@ -355,12 +355,12 @@ for ([numberB = -1] = [2, "trimmer", "trimming"], i = 0; i < 1; i++) { } for ([nameB = "name"] = multiRobotA, i = 0; i < 1; i++) { >[nameB = "name"] = multiRobotA, i = 0 : 0 ->[nameB = "name"] = multiRobotA : [string, [string, string]] +>[nameB = "name"] = multiRobotA : MultiSkilledRobot >[nameB = "name"] : [string] >nameB = "name" : "name" >nameB : string >"name" : "name" ->multiRobotA : [string, [string, string]] +>multiRobotA : MultiSkilledRobot >i = 0 : 0 >i : number >0 : 0 @@ -379,13 +379,13 @@ for ([nameB = "name"] = multiRobotA, i = 0; i < 1; i++) { } for ([nameB = "name"] = getMultiRobot(), i = 0; i < 1; i++) { >[nameB = "name"] = getMultiRobot(), i = 0 : 0 ->[nameB = "name"] = getMultiRobot() : [string, [string, string]] +>[nameB = "name"] = getMultiRobot() : MultiSkilledRobot >[nameB = "name"] : [string] >nameB = "name" : "name" >nameB : string >"name" : "name" ->getMultiRobot() : [string, [string, string]] ->getMultiRobot : () => [string, [string, string]] +>getMultiRobot() : MultiSkilledRobot +>getMultiRobot : () => MultiSkilledRobot >i = 0 : 0 >i : number >0 : 0 @@ -433,7 +433,7 @@ for ([nameB = "name"] = ["trimmer", ["trimming", "edging"]], i = 0; i < 1; i++) for ([numberA2 = -1, nameA2 = "name", skillA2 = "skill"] = robotA, i = 0; i < 1; i++) { >[numberA2 = -1, nameA2 = "name", skillA2 = "skill"] = robotA, i = 0 : 0 ->[numberA2 = -1, nameA2 = "name", skillA2 = "skill"] = robotA : [number, string, string] +>[numberA2 = -1, nameA2 = "name", skillA2 = "skill"] = robotA : Robot >[numberA2 = -1, nameA2 = "name", skillA2 = "skill"] : [number, string, string] >numberA2 = -1 : -1 >numberA2 : number @@ -445,7 +445,7 @@ for ([numberA2 = -1, nameA2 = "name", skillA2 = "skill"] = robotA, i = 0; i < 1; >skillA2 = "skill" : "skill" >skillA2 : string >"skill" : "skill" ->robotA : [number, string, string] +>robotA : Robot >i = 0 : 0 >i : number >0 : 0 @@ -464,7 +464,7 @@ for ([numberA2 = -1, nameA2 = "name", skillA2 = "skill"] = robotA, i = 0; i < 1; } for ([numberA2 = -1, nameA2 = "name", skillA2 = "skill"] = getRobot(), i = 0; i < 1; i++) { >[numberA2 = -1, nameA2 = "name", skillA2 = "skill"] = getRobot(), i = 0 : 0 ->[numberA2 = -1, nameA2 = "name", skillA2 = "skill"] = getRobot() : [number, string, string] +>[numberA2 = -1, nameA2 = "name", skillA2 = "skill"] = getRobot() : Robot >[numberA2 = -1, nameA2 = "name", skillA2 = "skill"] : [number, string, string] >numberA2 = -1 : -1 >numberA2 : number @@ -476,8 +476,8 @@ for ([numberA2 = -1, nameA2 = "name", skillA2 = "skill"] = getRobot(), i = 0; i >skillA2 = "skill" : "skill" >skillA2 : string >"skill" : "skill" ->getRobot() : [number, string, string] ->getRobot : () => [number, string, string] +>getRobot() : Robot +>getRobot : () => Robot >i = 0 : 0 >i : number >0 : 0 @@ -548,7 +548,7 @@ for (let >"none" : "none" ] = multiRobotA, i = 0; i < 1; i++) { ->multiRobotA : [string, [string, string]] +>multiRobotA : MultiSkilledRobot >i : number >0 : 0 >i < 1 : boolean @@ -566,7 +566,7 @@ for (let } for ([nameMA = "noName", >[nameMA = "noName", [ primarySkillA = "primary", secondarySkillA = "secondary" ] = ["none", "none"]] = getMultiRobot(), i = 0 : 0 ->[nameMA = "noName", [ primarySkillA = "primary", secondarySkillA = "secondary" ] = ["none", "none"]] = getMultiRobot() : [string, [string, string]] +>[nameMA = "noName", [ primarySkillA = "primary", secondarySkillA = "secondary" ] = ["none", "none"]] = getMultiRobot() : MultiSkilledRobot >[nameMA = "noName", [ primarySkillA = "primary", secondarySkillA = "secondary" ] = ["none", "none"]] : [string, [string, string]] >nameMA = "noName" : "noName" >nameMA : string @@ -592,8 +592,8 @@ for ([nameMA = "noName", >"none" : "none" ] = getMultiRobot(), i = 0; i < 1; i++) { ->getMultiRobot() : [string, [string, string]] ->getMultiRobot : () => [string, [string, string]] +>getMultiRobot() : MultiSkilledRobot +>getMultiRobot : () => MultiSkilledRobot >i = 0 : 0 >i : number >0 : 0 @@ -662,7 +662,7 @@ for ([nameMA = "noName", for ([numberA3 = -1, ...robotAInfo] = robotA, i = 0; i < 1; i++) { >[numberA3 = -1, ...robotAInfo] = robotA, i = 0 : 0 ->[numberA3 = -1, ...robotAInfo] = robotA : [number, string, string] +>[numberA3 = -1, ...robotAInfo] = robotA : Robot >[numberA3 = -1, ...robotAInfo] : [number, ...(string | number)[]] >numberA3 = -1 : -1 >numberA3 : number @@ -670,7 +670,7 @@ for ([numberA3 = -1, ...robotAInfo] = robotA, i = 0; i < 1; i++) { >1 : 1 >...robotAInfo : string | number >robotAInfo : (string | number)[] ->robotA : [number, string, string] +>robotA : Robot >i = 0 : 0 >i : number >0 : 0 @@ -689,7 +689,7 @@ for ([numberA3 = -1, ...robotAInfo] = robotA, i = 0; i < 1; i++) { } for ([numberA3 = -1, ...robotAInfo] = getRobot(), i = 0; i < 1; i++) { >[numberA3 = -1, ...robotAInfo] = getRobot(), i = 0 : 0 ->[numberA3 = -1, ...robotAInfo] = getRobot() : [number, string, string] +>[numberA3 = -1, ...robotAInfo] = getRobot() : Robot >[numberA3 = -1, ...robotAInfo] : [number, ...(string | number)[]] >numberA3 = -1 : -1 >numberA3 : number @@ -697,8 +697,8 @@ for ([numberA3 = -1, ...robotAInfo] = getRobot(), i = 0; i < 1; i++) { >1 : 1 >...robotAInfo : string | number >robotAInfo : (string | number)[] ->getRobot() : [number, string, string] ->getRobot : () => [number, string, string] +>getRobot() : Robot +>getRobot : () => Robot >i = 0 : 0 >i : number >0 : 0 @@ -717,7 +717,7 @@ for ([numberA3 = -1, ...robotAInfo] = getRobot(), i = 0; i < 1; i++) { } for ([numberA3 = -1, ...robotAInfo] = [2, "trimmer", "trimming"], i = 0; i < 1; i++) { >[numberA3 = -1, ...robotAInfo] = [2, "trimmer", "trimming"], i = 0 : 0 ->[numberA3 = -1, ...robotAInfo] = [2, "trimmer", "trimming"] : [number, string, string] +>[numberA3 = -1, ...robotAInfo] = [2, "trimmer", "trimming"] : Robot >[numberA3 = -1, ...robotAInfo] : [number, ...(string | number)[]] >numberA3 = -1 : -1 >numberA3 : number @@ -725,7 +725,7 @@ for ([numberA3 = -1, ...robotAInfo] = [2, "trimmer", "trimming"], i = 0; >1 : 1 >...robotAInfo : string | number >robotAInfo : (string | number)[] ->[2, "trimmer", "trimming"] : [number, string, string] +>[2, "trimmer", "trimming"] : Robot >[2, "trimmer", "trimming"] : [number, string, string] >2 : 2 >"trimmer" : "trimmer" diff --git a/tests/baselines/reference/sourceMapValidationDestructuringForOfArrayBindingPattern.types b/tests/baselines/reference/sourceMapValidationDestructuringForOfArrayBindingPattern.types index 57fa951a2c7..f38bc8330ef 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringForOfArrayBindingPattern.types +++ b/tests/baselines/reference/sourceMapValidationDestructuringForOfArrayBindingPattern.types @@ -7,40 +7,40 @@ declare var console: { >msg : any } type Robot = [number, string, string]; ->Robot : [number, string, string] +>Robot : Robot type MultiSkilledRobot = [string, [string, string]]; ->MultiSkilledRobot : [string, [string, string]] +>MultiSkilledRobot : MultiSkilledRobot let robotA: Robot = [1, "mower", "mowing"]; ->robotA : [number, string, string] +>robotA : Robot >[1, "mower", "mowing"] : [number, string, string] >1 : 1 >"mower" : "mower" >"mowing" : "mowing" let robotB: Robot = [2, "trimmer", "trimming"]; ->robotB : [number, string, string] +>robotB : Robot >[2, "trimmer", "trimming"] : [number, string, string] >2 : 2 >"trimmer" : "trimmer" >"trimming" : "trimming" let robots = [robotA, robotB]; ->robots : [number, string, string][] ->[robotA, robotB] : [number, string, string][] ->robotA : [number, string, string] ->robotB : [number, string, string] +>robots : Robot[] +>[robotA, robotB] : Robot[] +>robotA : Robot +>robotB : Robot function getRobots() { ->getRobots : () => [number, string, string][] +>getRobots : () => Robot[] return robots; ->robots : [number, string, string][] +>robots : Robot[] } let multiRobotA: MultiSkilledRobot = ["mower", ["mowing", ""]]; ->multiRobotA : [string, [string, string]] +>multiRobotA : MultiSkilledRobot >["mower", ["mowing", ""]] : [string, [string, string]] >"mower" : "mower" >["mowing", ""] : [string, string] @@ -48,7 +48,7 @@ let multiRobotA: MultiSkilledRobot = ["mower", ["mowing", ""]]; >"" : "" let multiRobotB: MultiSkilledRobot = ["trimmer", ["trimming", "edging"]]; ->multiRobotB : [string, [string, string]] +>multiRobotB : MultiSkilledRobot >["trimmer", ["trimming", "edging"]] : [string, [string, string]] >"trimmer" : "trimmer" >["trimming", "edging"] : [string, string] @@ -56,22 +56,22 @@ let multiRobotB: MultiSkilledRobot = ["trimmer", ["trimming", "edging"]]; >"edging" : "edging" let multiRobots = [multiRobotA, multiRobotB]; ->multiRobots : [string, [string, string]][] ->[multiRobotA, multiRobotB] : [string, [string, string]][] ->multiRobotA : [string, [string, string]] ->multiRobotB : [string, [string, string]] +>multiRobots : MultiSkilledRobot[] +>[multiRobotA, multiRobotB] : MultiSkilledRobot[] +>multiRobotA : MultiSkilledRobot +>multiRobotB : MultiSkilledRobot function getMultiRobots() { ->getMultiRobots : () => [string, [string, string]][] +>getMultiRobots : () => MultiSkilledRobot[] return multiRobots; ->multiRobots : [string, [string, string]][] +>multiRobots : MultiSkilledRobot[] } for (let [, nameA] of robots) { > : undefined >nameA : string ->robots : [number, string, string][] +>robots : Robot[] console.log(nameA); >console.log(nameA) : void @@ -83,8 +83,8 @@ for (let [, nameA] of robots) { for (let [, nameA] of getRobots()) { > : undefined >nameA : string ->getRobots() : [number, string, string][] ->getRobots : () => [number, string, string][] +>getRobots() : Robot[] +>getRobots : () => Robot[] console.log(nameA); >console.log(nameA) : void @@ -96,9 +96,9 @@ for (let [, nameA] of getRobots()) { for (let [, nameA] of [robotA, robotB]) { > : undefined >nameA : string ->[robotA, robotB] : [number, string, string][] ->robotA : [number, string, string] ->robotB : [number, string, string] +>[robotA, robotB] : Robot[] +>robotA : Robot +>robotB : Robot console.log(nameA); >console.log(nameA) : void @@ -111,7 +111,7 @@ for (let [, [primarySkillA, secondarySkillA]] of multiRobots) { > : undefined >primarySkillA : string >secondarySkillA : string ->multiRobots : [string, [string, string]][] +>multiRobots : MultiSkilledRobot[] console.log(primarySkillA); >console.log(primarySkillA) : void @@ -124,8 +124,8 @@ for (let [, [primarySkillA, secondarySkillA]] of getMultiRobots()) { > : undefined >primarySkillA : string >secondarySkillA : string ->getMultiRobots() : [string, [string, string]][] ->getMultiRobots : () => [string, [string, string]][] +>getMultiRobots() : MultiSkilledRobot[] +>getMultiRobots : () => MultiSkilledRobot[] console.log(primarySkillA); >console.log(primarySkillA) : void @@ -138,9 +138,9 @@ for (let [, [primarySkillA, secondarySkillA]] of [multiRobotA, multiRobotB]) { > : undefined >primarySkillA : string >secondarySkillA : string ->[multiRobotA, multiRobotB] : [string, [string, string]][] ->multiRobotA : [string, [string, string]] ->multiRobotB : [string, [string, string]] +>[multiRobotA, multiRobotB] : MultiSkilledRobot[] +>multiRobotA : MultiSkilledRobot +>multiRobotB : MultiSkilledRobot console.log(primarySkillA); >console.log(primarySkillA) : void @@ -152,7 +152,7 @@ for (let [, [primarySkillA, secondarySkillA]] of [multiRobotA, multiRobotB]) { for (let [numberB] of robots) { >numberB : number ->robots : [number, string, string][] +>robots : Robot[] console.log(numberB); >console.log(numberB) : void @@ -163,8 +163,8 @@ for (let [numberB] of robots) { } for (let [numberB] of getRobots()) { >numberB : number ->getRobots() : [number, string, string][] ->getRobots : () => [number, string, string][] +>getRobots() : Robot[] +>getRobots : () => Robot[] console.log(numberB); >console.log(numberB) : void @@ -175,9 +175,9 @@ for (let [numberB] of getRobots()) { } for (let [numberB] of [robotA, robotB]) { >numberB : number ->[robotA, robotB] : [number, string, string][] ->robotA : [number, string, string] ->robotB : [number, string, string] +>[robotA, robotB] : Robot[] +>robotA : Robot +>robotB : Robot console.log(numberB); >console.log(numberB) : void @@ -188,7 +188,7 @@ for (let [numberB] of [robotA, robotB]) { } for (let [nameB] of multiRobots) { >nameB : string ->multiRobots : [string, [string, string]][] +>multiRobots : MultiSkilledRobot[] console.log(nameB); >console.log(nameB) : void @@ -199,8 +199,8 @@ for (let [nameB] of multiRobots) { } for (let [nameB] of getMultiRobots()) { >nameB : string ->getMultiRobots() : [string, [string, string]][] ->getMultiRobots : () => [string, [string, string]][] +>getMultiRobots() : MultiSkilledRobot[] +>getMultiRobots : () => MultiSkilledRobot[] console.log(nameB); >console.log(nameB) : void @@ -211,9 +211,9 @@ for (let [nameB] of getMultiRobots()) { } for (let [nameB] of [multiRobotA, multiRobotB]) { >nameB : string ->[multiRobotA, multiRobotB] : [string, [string, string]][] ->multiRobotA : [string, [string, string]] ->multiRobotB : [string, [string, string]] +>[multiRobotA, multiRobotB] : MultiSkilledRobot[] +>multiRobotA : MultiSkilledRobot +>multiRobotB : MultiSkilledRobot console.log(nameB); >console.log(nameB) : void @@ -227,7 +227,7 @@ for (let [numberA2, nameA2, skillA2] of robots) { >numberA2 : number >nameA2 : string >skillA2 : string ->robots : [number, string, string][] +>robots : Robot[] console.log(nameA2); >console.log(nameA2) : void @@ -240,8 +240,8 @@ for (let [numberA2, nameA2, skillA2] of getRobots()) { >numberA2 : number >nameA2 : string >skillA2 : string ->getRobots() : [number, string, string][] ->getRobots : () => [number, string, string][] +>getRobots() : Robot[] +>getRobots : () => Robot[] console.log(nameA2); >console.log(nameA2) : void @@ -254,9 +254,9 @@ for (let [numberA2, nameA2, skillA2] of [robotA, robotB]) { >numberA2 : number >nameA2 : string >skillA2 : string ->[robotA, robotB] : [number, string, string][] ->robotA : [number, string, string] ->robotB : [number, string, string] +>[robotA, robotB] : Robot[] +>robotA : Robot +>robotB : Robot console.log(nameA2); >console.log(nameA2) : void @@ -269,7 +269,7 @@ for (let [nameMA, [primarySkillA, secondarySkillA]] of multiRobots) { >nameMA : string >primarySkillA : string >secondarySkillA : string ->multiRobots : [string, [string, string]][] +>multiRobots : MultiSkilledRobot[] console.log(nameMA); >console.log(nameMA) : void @@ -282,8 +282,8 @@ for (let [nameMA, [primarySkillA, secondarySkillA]] of getMultiRobots()) { >nameMA : string >primarySkillA : string >secondarySkillA : string ->getMultiRobots() : [string, [string, string]][] ->getMultiRobots : () => [string, [string, string]][] +>getMultiRobots() : MultiSkilledRobot[] +>getMultiRobots : () => MultiSkilledRobot[] console.log(nameMA); >console.log(nameMA) : void @@ -296,9 +296,9 @@ for (let [nameMA, [primarySkillA, secondarySkillA]] of [multiRobotA, multiRobotB >nameMA : string >primarySkillA : string >secondarySkillA : string ->[multiRobotA, multiRobotB] : [string, [string, string]][] ->multiRobotA : [string, [string, string]] ->multiRobotB : [string, [string, string]] +>[multiRobotA, multiRobotB] : MultiSkilledRobot[] +>multiRobotA : MultiSkilledRobot +>multiRobotB : MultiSkilledRobot console.log(nameMA); >console.log(nameMA) : void @@ -311,7 +311,7 @@ for (let [nameMA, [primarySkillA, secondarySkillA]] of [multiRobotA, multiRobotB for (let [numberA3, ...robotAInfo] of robots) { >numberA3 : number >robotAInfo : [string, string] ->robots : [number, string, string][] +>robots : Robot[] console.log(numberA3); >console.log(numberA3) : void @@ -323,8 +323,8 @@ for (let [numberA3, ...robotAInfo] of robots) { for (let [numberA3, ...robotAInfo] of getRobots()) { >numberA3 : number >robotAInfo : [string, string] ->getRobots() : [number, string, string][] ->getRobots : () => [number, string, string][] +>getRobots() : Robot[] +>getRobots : () => Robot[] console.log(numberA3); >console.log(numberA3) : void @@ -336,9 +336,9 @@ for (let [numberA3, ...robotAInfo] of getRobots()) { for (let [numberA3, ...robotAInfo] of [robotA, robotB]) { >numberA3 : number >robotAInfo : [string, string] ->[robotA, robotB] : [number, string, string][] ->robotA : [number, string, string] ->robotB : [number, string, string] +>[robotA, robotB] : Robot[] +>robotA : Robot +>robotB : Robot console.log(numberA3); >console.log(numberA3) : void @@ -349,7 +349,7 @@ for (let [numberA3, ...robotAInfo] of [robotA, robotB]) { } for (let [...multiRobotAInfo] of multiRobots) { >multiRobotAInfo : [string, [string, string]] ->multiRobots : [string, [string, string]][] +>multiRobots : MultiSkilledRobot[] console.log(multiRobotAInfo); >console.log(multiRobotAInfo) : void @@ -360,8 +360,8 @@ for (let [...multiRobotAInfo] of multiRobots) { } for (let [...multiRobotAInfo] of getMultiRobots()) { >multiRobotAInfo : [string, [string, string]] ->getMultiRobots() : [string, [string, string]][] ->getMultiRobots : () => [string, [string, string]][] +>getMultiRobots() : MultiSkilledRobot[] +>getMultiRobots : () => MultiSkilledRobot[] console.log(multiRobotAInfo); >console.log(multiRobotAInfo) : void @@ -372,9 +372,9 @@ for (let [...multiRobotAInfo] of getMultiRobots()) { } for (let [...multiRobotAInfo] of [multiRobotA, multiRobotB]) { >multiRobotAInfo : [string, [string, string]] ->[multiRobotA, multiRobotB] : [string, [string, string]][] ->multiRobotA : [string, [string, string]] ->multiRobotB : [string, [string, string]] +>[multiRobotA, multiRobotB] : MultiSkilledRobot[] +>multiRobotA : MultiSkilledRobot +>multiRobotB : MultiSkilledRobot console.log(multiRobotAInfo); >console.log(multiRobotAInfo) : void diff --git a/tests/baselines/reference/sourceMapValidationDestructuringForOfArrayBindingPattern2.types b/tests/baselines/reference/sourceMapValidationDestructuringForOfArrayBindingPattern2.types index c6b57fb4f62..92797377d3a 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringForOfArrayBindingPattern2.types +++ b/tests/baselines/reference/sourceMapValidationDestructuringForOfArrayBindingPattern2.types @@ -7,40 +7,40 @@ declare var console: { >msg : any } type Robot = [number, string, string]; ->Robot : [number, string, string] +>Robot : Robot type MultiSkilledRobot = [string, [string, string]]; ->MultiSkilledRobot : [string, [string, string]] +>MultiSkilledRobot : MultiSkilledRobot let robotA: Robot = [1, "mower", "mowing"]; ->robotA : [number, string, string] +>robotA : Robot >[1, "mower", "mowing"] : [number, string, string] >1 : 1 >"mower" : "mower" >"mowing" : "mowing" let robotB: Robot = [2, "trimmer", "trimming"]; ->robotB : [number, string, string] +>robotB : Robot >[2, "trimmer", "trimming"] : [number, string, string] >2 : 2 >"trimmer" : "trimmer" >"trimming" : "trimming" let robots = [robotA, robotB]; ->robots : [number, string, string][] ->[robotA, robotB] : [number, string, string][] ->robotA : [number, string, string] ->robotB : [number, string, string] +>robots : Robot[] +>[robotA, robotB] : Robot[] +>robotA : Robot +>robotB : Robot function getRobots() { ->getRobots : () => [number, string, string][] +>getRobots : () => Robot[] return robots; ->robots : [number, string, string][] +>robots : Robot[] } let multiRobotA: MultiSkilledRobot = ["mower", ["mowing", ""]]; ->multiRobotA : [string, [string, string]] +>multiRobotA : MultiSkilledRobot >["mower", ["mowing", ""]] : [string, [string, string]] >"mower" : "mower" >["mowing", ""] : [string, string] @@ -48,7 +48,7 @@ let multiRobotA: MultiSkilledRobot = ["mower", ["mowing", ""]]; >"" : "" let multiRobotB: MultiSkilledRobot = ["trimmer", ["trimming", "edging"]]; ->multiRobotB : [string, [string, string]] +>multiRobotB : MultiSkilledRobot >["trimmer", ["trimming", "edging"]] : [string, [string, string]] >"trimmer" : "trimmer" >["trimming", "edging"] : [string, string] @@ -56,16 +56,16 @@ let multiRobotB: MultiSkilledRobot = ["trimmer", ["trimming", "edging"]]; >"edging" : "edging" let multiRobots = [multiRobotA, multiRobotB]; ->multiRobots : [string, [string, string]][] ->[multiRobotA, multiRobotB] : [string, [string, string]][] ->multiRobotA : [string, [string, string]] ->multiRobotB : [string, [string, string]] +>multiRobots : MultiSkilledRobot[] +>[multiRobotA, multiRobotB] : MultiSkilledRobot[] +>multiRobotA : MultiSkilledRobot +>multiRobotB : MultiSkilledRobot function getMultiRobots() { ->getMultiRobots : () => [string, [string, string]][] +>getMultiRobots : () => MultiSkilledRobot[] return multiRobots; ->multiRobots : [string, [string, string]][] +>multiRobots : MultiSkilledRobot[] } let nameA: string, primarySkillA: string, secondarySkillA: string; @@ -92,7 +92,7 @@ for ([, nameA] of robots) { >[, nameA] : [undefined, string] > : undefined >nameA : string ->robots : [number, string, string][] +>robots : Robot[] console.log(nameA); >console.log(nameA) : void @@ -105,8 +105,8 @@ for ([, nameA] of getRobots()) { >[, nameA] : [undefined, string] > : undefined >nameA : string ->getRobots() : [number, string, string][] ->getRobots : () => [number, string, string][] +>getRobots() : Robot[] +>getRobots : () => Robot[] console.log(nameA); >console.log(nameA) : void @@ -119,9 +119,9 @@ for ([, nameA] of [robotA, robotB]) { >[, nameA] : [undefined, string] > : undefined >nameA : string ->[robotA, robotB] : [number, string, string][] ->robotA : [number, string, string] ->robotB : [number, string, string] +>[robotA, robotB] : Robot[] +>robotA : Robot +>robotB : Robot console.log(nameA); >console.log(nameA) : void @@ -136,7 +136,7 @@ for ([, [primarySkillA, secondarySkillA]] of multiRobots) { >[primarySkillA, secondarySkillA] : [string, string] >primarySkillA : string >secondarySkillA : string ->multiRobots : [string, [string, string]][] +>multiRobots : MultiSkilledRobot[] console.log(primarySkillA); >console.log(primarySkillA) : void @@ -151,8 +151,8 @@ for ([, [primarySkillA, secondarySkillA]] of getMultiRobots()) { >[primarySkillA, secondarySkillA] : [string, string] >primarySkillA : string >secondarySkillA : string ->getMultiRobots() : [string, [string, string]][] ->getMultiRobots : () => [string, [string, string]][] +>getMultiRobots() : MultiSkilledRobot[] +>getMultiRobots : () => MultiSkilledRobot[] console.log(primarySkillA); >console.log(primarySkillA) : void @@ -167,9 +167,9 @@ for ([, [primarySkillA, secondarySkillA]] of [multiRobotA, multiRobotB]) { >[primarySkillA, secondarySkillA] : [string, string] >primarySkillA : string >secondarySkillA : string ->[multiRobotA, multiRobotB] : [string, [string, string]][] ->multiRobotA : [string, [string, string]] ->multiRobotB : [string, [string, string]] +>[multiRobotA, multiRobotB] : MultiSkilledRobot[] +>multiRobotA : MultiSkilledRobot +>multiRobotB : MultiSkilledRobot console.log(primarySkillA); >console.log(primarySkillA) : void @@ -182,7 +182,7 @@ for ([, [primarySkillA, secondarySkillA]] of [multiRobotA, multiRobotB]) { for ([numberB] of robots) { >[numberB] : [number] >numberB : number ->robots : [number, string, string][] +>robots : Robot[] console.log(numberB); >console.log(numberB) : void @@ -194,8 +194,8 @@ for ([numberB] of robots) { for ([numberB] of getRobots()) { >[numberB] : [number] >numberB : number ->getRobots() : [number, string, string][] ->getRobots : () => [number, string, string][] +>getRobots() : Robot[] +>getRobots : () => Robot[] console.log(numberB); >console.log(numberB) : void @@ -207,9 +207,9 @@ for ([numberB] of getRobots()) { for ([numberB] of [robotA, robotB]) { >[numberB] : [number] >numberB : number ->[robotA, robotB] : [number, string, string][] ->robotA : [number, string, string] ->robotB : [number, string, string] +>[robotA, robotB] : Robot[] +>robotA : Robot +>robotB : Robot console.log(numberB); >console.log(numberB) : void @@ -221,7 +221,7 @@ for ([numberB] of [robotA, robotB]) { for ([nameB] of multiRobots) { >[nameB] : [string] >nameB : string ->multiRobots : [string, [string, string]][] +>multiRobots : MultiSkilledRobot[] console.log(nameB); >console.log(nameB) : void @@ -233,8 +233,8 @@ for ([nameB] of multiRobots) { for ([nameB] of getMultiRobots()) { >[nameB] : [string] >nameB : string ->getMultiRobots() : [string, [string, string]][] ->getMultiRobots : () => [string, [string, string]][] +>getMultiRobots() : MultiSkilledRobot[] +>getMultiRobots : () => MultiSkilledRobot[] console.log(nameB); >console.log(nameB) : void @@ -246,9 +246,9 @@ for ([nameB] of getMultiRobots()) { for ([nameB] of [multiRobotA, multiRobotB]) { >[nameB] : [string] >nameB : string ->[multiRobotA, multiRobotB] : [string, [string, string]][] ->multiRobotA : [string, [string, string]] ->multiRobotB : [string, [string, string]] +>[multiRobotA, multiRobotB] : MultiSkilledRobot[] +>multiRobotA : MultiSkilledRobot +>multiRobotB : MultiSkilledRobot console.log(nameB); >console.log(nameB) : void @@ -263,7 +263,7 @@ for ([numberA2, nameA2, skillA2] of robots) { >numberA2 : number >nameA2 : string >skillA2 : string ->robots : [number, string, string][] +>robots : Robot[] console.log(nameA2); >console.log(nameA2) : void @@ -277,8 +277,8 @@ for ([numberA2, nameA2, skillA2] of getRobots()) { >numberA2 : number >nameA2 : string >skillA2 : string ->getRobots() : [number, string, string][] ->getRobots : () => [number, string, string][] +>getRobots() : Robot[] +>getRobots : () => Robot[] console.log(nameA2); >console.log(nameA2) : void @@ -292,9 +292,9 @@ for ([numberA2, nameA2, skillA2] of [robotA, robotB]) { >numberA2 : number >nameA2 : string >skillA2 : string ->[robotA, robotB] : [number, string, string][] ->robotA : [number, string, string] ->robotB : [number, string, string] +>[robotA, robotB] : Robot[] +>robotA : Robot +>robotB : Robot console.log(nameA2); >console.log(nameA2) : void @@ -309,7 +309,7 @@ for ([nameMA, [primarySkillA, secondarySkillA]] of multiRobots) { >[primarySkillA, secondarySkillA] : [string, string] >primarySkillA : string >secondarySkillA : string ->multiRobots : [string, [string, string]][] +>multiRobots : MultiSkilledRobot[] console.log(nameMA); >console.log(nameMA) : void @@ -324,8 +324,8 @@ for ([nameMA, [primarySkillA, secondarySkillA]] of getMultiRobots()) { >[primarySkillA, secondarySkillA] : [string, string] >primarySkillA : string >secondarySkillA : string ->getMultiRobots() : [string, [string, string]][] ->getMultiRobots : () => [string, [string, string]][] +>getMultiRobots() : MultiSkilledRobot[] +>getMultiRobots : () => MultiSkilledRobot[] console.log(nameMA); >console.log(nameMA) : void @@ -340,9 +340,9 @@ for ([nameMA, [primarySkillA, secondarySkillA]] of [multiRobotA, multiRobotB]) { >[primarySkillA, secondarySkillA] : [string, string] >primarySkillA : string >secondarySkillA : string ->[multiRobotA, multiRobotB] : [string, [string, string]][] ->multiRobotA : [string, [string, string]] ->multiRobotB : [string, [string, string]] +>[multiRobotA, multiRobotB] : MultiSkilledRobot[] +>multiRobotA : MultiSkilledRobot +>multiRobotB : MultiSkilledRobot console.log(nameMA); >console.log(nameMA) : void @@ -357,7 +357,7 @@ for ([numberA3, ...robotAInfo] of robots) { >numberA3 : number >...robotAInfo : string | number >robotAInfo : (string | number)[] ->robots : [number, string, string][] +>robots : Robot[] console.log(numberA3); >console.log(numberA3) : void @@ -371,8 +371,8 @@ for ([numberA3, ...robotAInfo] of getRobots()) { >numberA3 : number >...robotAInfo : string | number >robotAInfo : (string | number)[] ->getRobots() : [number, string, string][] ->getRobots : () => [number, string, string][] +>getRobots() : Robot[] +>getRobots : () => Robot[] console.log(numberA3); >console.log(numberA3) : void @@ -386,9 +386,9 @@ for ([numberA3, ...robotAInfo] of [robotA, robotB]) { >numberA3 : number >...robotAInfo : string | number >robotAInfo : (string | number)[] ->[robotA, robotB] : [number, string, string][] ->robotA : [number, string, string] ->robotB : [number, string, string] +>[robotA, robotB] : Robot[] +>robotA : Robot +>robotB : Robot console.log(numberA3); >console.log(numberA3) : void @@ -401,7 +401,7 @@ for ([...multiRobotAInfo] of multiRobots) { >[...multiRobotAInfo] : (string | [string, string])[] >...multiRobotAInfo : string | [string, string] >multiRobotAInfo : (string | [string, string])[] ->multiRobots : [string, [string, string]][] +>multiRobots : MultiSkilledRobot[] console.log(multiRobotAInfo); >console.log(multiRobotAInfo) : void @@ -414,8 +414,8 @@ for ([...multiRobotAInfo] of getMultiRobots()) { >[...multiRobotAInfo] : (string | [string, string])[] >...multiRobotAInfo : string | [string, string] >multiRobotAInfo : (string | [string, string])[] ->getMultiRobots() : [string, [string, string]][] ->getMultiRobots : () => [string, [string, string]][] +>getMultiRobots() : MultiSkilledRobot[] +>getMultiRobots : () => MultiSkilledRobot[] console.log(multiRobotAInfo); >console.log(multiRobotAInfo) : void @@ -428,9 +428,9 @@ for ([...multiRobotAInfo] of [multiRobotA, multiRobotB]) { >[...multiRobotAInfo] : (string | [string, string])[] >...multiRobotAInfo : string | [string, string] >multiRobotAInfo : (string | [string, string])[] ->[multiRobotA, multiRobotB] : [string, [string, string]][] ->multiRobotA : [string, [string, string]] ->multiRobotB : [string, [string, string]] +>[multiRobotA, multiRobotB] : MultiSkilledRobot[] +>multiRobotA : MultiSkilledRobot +>multiRobotB : MultiSkilledRobot console.log(multiRobotAInfo); >console.log(multiRobotAInfo) : void diff --git a/tests/baselines/reference/sourceMapValidationDestructuringForOfArrayBindingPatternDefaultValues.types b/tests/baselines/reference/sourceMapValidationDestructuringForOfArrayBindingPatternDefaultValues.types index 34689acf920..cab4cc5ba07 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringForOfArrayBindingPatternDefaultValues.types +++ b/tests/baselines/reference/sourceMapValidationDestructuringForOfArrayBindingPatternDefaultValues.types @@ -7,40 +7,40 @@ declare var console: { >msg : any } type Robot = [number, string, string]; ->Robot : [number, string, string] +>Robot : Robot type MultiSkilledRobot = [string, [string, string]]; ->MultiSkilledRobot : [string, [string, string]] +>MultiSkilledRobot : MultiSkilledRobot let robotA: Robot = [1, "mower", "mowing"]; ->robotA : [number, string, string] +>robotA : Robot >[1, "mower", "mowing"] : [number, string, string] >1 : 1 >"mower" : "mower" >"mowing" : "mowing" let robotB: Robot = [2, "trimmer", "trimming"]; ->robotB : [number, string, string] +>robotB : Robot >[2, "trimmer", "trimming"] : [number, string, string] >2 : 2 >"trimmer" : "trimmer" >"trimming" : "trimming" let robots = [robotA, robotB]; ->robots : [number, string, string][] ->[robotA, robotB] : [number, string, string][] ->robotA : [number, string, string] ->robotB : [number, string, string] +>robots : Robot[] +>[robotA, robotB] : Robot[] +>robotA : Robot +>robotB : Robot function getRobots() { ->getRobots : () => [number, string, string][] +>getRobots : () => Robot[] return robots; ->robots : [number, string, string][] +>robots : Robot[] } let multiRobotA: MultiSkilledRobot = ["mower", ["mowing", ""]]; ->multiRobotA : [string, [string, string]] +>multiRobotA : MultiSkilledRobot >["mower", ["mowing", ""]] : [string, [string, string]] >"mower" : "mower" >["mowing", ""] : [string, string] @@ -48,7 +48,7 @@ let multiRobotA: MultiSkilledRobot = ["mower", ["mowing", ""]]; >"" : "" let multiRobotB: MultiSkilledRobot = ["trimmer", ["trimming", "edging"]]; ->multiRobotB : [string, [string, string]] +>multiRobotB : MultiSkilledRobot >["trimmer", ["trimming", "edging"]] : [string, [string, string]] >"trimmer" : "trimmer" >["trimming", "edging"] : [string, string] @@ -56,23 +56,23 @@ let multiRobotB: MultiSkilledRobot = ["trimmer", ["trimming", "edging"]]; >"edging" : "edging" let multiRobots = [multiRobotA, multiRobotB]; ->multiRobots : [string, [string, string]][] ->[multiRobotA, multiRobotB] : [string, [string, string]][] ->multiRobotA : [string, [string, string]] ->multiRobotB : [string, [string, string]] +>multiRobots : MultiSkilledRobot[] +>[multiRobotA, multiRobotB] : MultiSkilledRobot[] +>multiRobotA : MultiSkilledRobot +>multiRobotB : MultiSkilledRobot function getMultiRobots() { ->getMultiRobots : () => [string, [string, string]][] +>getMultiRobots : () => MultiSkilledRobot[] return multiRobots; ->multiRobots : [string, [string, string]][] +>multiRobots : MultiSkilledRobot[] } for (let [, nameA = "noName"] of robots) { > : undefined >nameA : string >"noName" : "noName" ->robots : [number, string, string][] +>robots : Robot[] console.log(nameA); >console.log(nameA) : void @@ -85,8 +85,8 @@ for (let [, nameA = "noName"] of getRobots()) { > : undefined >nameA : string >"noName" : "noName" ->getRobots() : [number, string, string][] ->getRobots : () => [number, string, string][] +>getRobots() : Robot[] +>getRobots : () => Robot[] console.log(nameA); >console.log(nameA) : void @@ -99,9 +99,9 @@ for (let [, nameA = "noName"] of [robotA, robotB]) { > : undefined >nameA : string >"noName" : "noName" ->[robotA, robotB] : [number, string, string][] ->robotA : [number, string, string] ->robotB : [number, string, string] +>[robotA, robotB] : Robot[] +>robotA : Robot +>robotB : Robot console.log(nameA); >console.log(nameA) : void @@ -125,7 +125,7 @@ for (let [, [ >["skill1", "skill2"] : [string, string] >"skill1" : "skill1" >"skill2" : "skill2" ->multiRobots : [string, [string, string]][] +>multiRobots : MultiSkilledRobot[] console.log(primarySkillA); >console.log(primarySkillA) : void @@ -149,8 +149,8 @@ for (let [, [ >["skill1", "skill2"] : [string, string] >"skill1" : "skill1" >"skill2" : "skill2" ->getMultiRobots() : [string, [string, string]][] ->getMultiRobots : () => [string, [string, string]][] +>getMultiRobots() : MultiSkilledRobot[] +>getMultiRobots : () => MultiSkilledRobot[] console.log(primarySkillA); >console.log(primarySkillA) : void @@ -174,9 +174,9 @@ for (let [, [ >["skill1", "skill2"] : [string, string] >"skill1" : "skill1" >"skill2" : "skill2" ->[multiRobotA, multiRobotB] : [string, [string, string]][] ->multiRobotA : [string, [string, string]] ->multiRobotB : [string, [string, string]] +>[multiRobotA, multiRobotB] : MultiSkilledRobot[] +>multiRobotA : MultiSkilledRobot +>multiRobotB : MultiSkilledRobot console.log(primarySkillA); >console.log(primarySkillA) : void @@ -190,7 +190,7 @@ for (let [numberB = -1] of robots) { >numberB : number >-1 : -1 >1 : 1 ->robots : [number, string, string][] +>robots : Robot[] console.log(numberB); >console.log(numberB) : void @@ -203,8 +203,8 @@ for (let [numberB = -1] of getRobots()) { >numberB : number >-1 : -1 >1 : 1 ->getRobots() : [number, string, string][] ->getRobots : () => [number, string, string][] +>getRobots() : Robot[] +>getRobots : () => Robot[] console.log(numberB); >console.log(numberB) : void @@ -217,9 +217,9 @@ for (let [numberB = -1] of [robotA, robotB]) { >numberB : number >-1 : -1 >1 : 1 ->[robotA, robotB] : [number, string, string][] ->robotA : [number, string, string] ->robotB : [number, string, string] +>[robotA, robotB] : Robot[] +>robotA : Robot +>robotB : Robot console.log(numberB); >console.log(numberB) : void @@ -231,7 +231,7 @@ for (let [numberB = -1] of [robotA, robotB]) { for (let [nameB = "noName"] of multiRobots) { >nameB : string >"noName" : "noName" ->multiRobots : [string, [string, string]][] +>multiRobots : MultiSkilledRobot[] console.log(nameB); >console.log(nameB) : void @@ -243,8 +243,8 @@ for (let [nameB = "noName"] of multiRobots) { for (let [nameB = "noName"] of getMultiRobots()) { >nameB : string >"noName" : "noName" ->getMultiRobots() : [string, [string, string]][] ->getMultiRobots : () => [string, [string, string]][] +>getMultiRobots() : MultiSkilledRobot[] +>getMultiRobots : () => MultiSkilledRobot[] console.log(nameB); >console.log(nameB) : void @@ -256,9 +256,9 @@ for (let [nameB = "noName"] of getMultiRobots()) { for (let [nameB = "noName"] of [multiRobotA, multiRobotB]) { >nameB : string >"noName" : "noName" ->[multiRobotA, multiRobotB] : [string, [string, string]][] ->multiRobotA : [string, [string, string]] ->multiRobotB : [string, [string, string]] +>[multiRobotA, multiRobotB] : MultiSkilledRobot[] +>multiRobotA : MultiSkilledRobot +>multiRobotB : MultiSkilledRobot console.log(nameB); >console.log(nameB) : void @@ -276,7 +276,7 @@ for (let [numberA2 = -1, nameA2 = "noName", skillA2 = "skill"] of robots) { >"noName" : "noName" >skillA2 : string >"skill" : "skill" ->robots : [number, string, string][] +>robots : Robot[] console.log(nameA2); >console.log(nameA2) : void @@ -293,8 +293,8 @@ for (let [numberA2 = -1, nameA2 = "noName", skillA2 = "skill"] of getRobots()) { >"noName" : "noName" >skillA2 : string >"skill" : "skill" ->getRobots() : [number, string, string][] ->getRobots : () => [number, string, string][] +>getRobots() : Robot[] +>getRobots : () => Robot[] console.log(nameA2); >console.log(nameA2) : void @@ -311,9 +311,9 @@ for (let [numberA2 = -1, nameA2 = "noName", skillA2 = "skill"] of [robotA, robot >"noName" : "noName" >skillA2 : string >"skill" : "skill" ->[robotA, robotB] : [number, string, string][] ->robotA : [number, string, string] ->robotB : [number, string, string] +>[robotA, robotB] : Robot[] +>robotA : Robot +>robotB : Robot console.log(nameA2); >console.log(nameA2) : void @@ -338,7 +338,7 @@ for (let [nameMA = "noName", [ >["skill1", "skill2"] : [string, string] >"skill1" : "skill1" >"skill2" : "skill2" ->multiRobots : [string, [string, string]][] +>multiRobots : MultiSkilledRobot[] console.log(nameMA); >console.log(nameMA) : void @@ -363,8 +363,8 @@ for (let [nameMA = "noName", [ >["skill1", "skill2"] : [string, string] >"skill1" : "skill1" >"skill2" : "skill2" ->getMultiRobots() : [string, [string, string]][] ->getMultiRobots : () => [string, [string, string]][] +>getMultiRobots() : MultiSkilledRobot[] +>getMultiRobots : () => MultiSkilledRobot[] console.log(nameMA); >console.log(nameMA) : void @@ -389,9 +389,9 @@ for (let [nameMA = "noName", [ >["skill1", "skill2"] : [string, string] >"skill1" : "skill1" >"skill2" : "skill2" ->[multiRobotA, multiRobotB] : [string, [string, string]][] ->multiRobotA : [string, [string, string]] ->multiRobotB : [string, [string, string]] +>[multiRobotA, multiRobotB] : MultiSkilledRobot[] +>multiRobotA : MultiSkilledRobot +>multiRobotB : MultiSkilledRobot console.log(nameMA); >console.log(nameMA) : void @@ -406,7 +406,7 @@ for (let [numberA3 = -1, ...robotAInfo] of robots) { >-1 : -1 >1 : 1 >robotAInfo : [string, string] ->robots : [number, string, string][] +>robots : Robot[] console.log(numberA3); >console.log(numberA3) : void @@ -420,8 +420,8 @@ for (let [numberA3 = -1, ...robotAInfo] of getRobots()) { >-1 : -1 >1 : 1 >robotAInfo : [string, string] ->getRobots() : [number, string, string][] ->getRobots : () => [number, string, string][] +>getRobots() : Robot[] +>getRobots : () => Robot[] console.log(numberA3); >console.log(numberA3) : void @@ -435,9 +435,9 @@ for (let [numberA3 = -1, ...robotAInfo] of [robotA, robotB]) { >-1 : -1 >1 : 1 >robotAInfo : [string, string] ->[robotA, robotB] : [number, string, string][] ->robotA : [number, string, string] ->robotB : [number, string, string] +>[robotA, robotB] : Robot[] +>robotA : Robot +>robotB : Robot console.log(numberA3); >console.log(numberA3) : void diff --git a/tests/baselines/reference/sourceMapValidationDestructuringForOfArrayBindingPatternDefaultValues2.types b/tests/baselines/reference/sourceMapValidationDestructuringForOfArrayBindingPatternDefaultValues2.types index ffca2d37c89..14e0bbaa335 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringForOfArrayBindingPatternDefaultValues2.types +++ b/tests/baselines/reference/sourceMapValidationDestructuringForOfArrayBindingPatternDefaultValues2.types @@ -7,40 +7,40 @@ declare var console: { >msg : any } type Robot = [number, string, string]; ->Robot : [number, string, string] +>Robot : Robot type MultiSkilledRobot = [string, [string, string]]; ->MultiSkilledRobot : [string, [string, string]] +>MultiSkilledRobot : MultiSkilledRobot let robotA: Robot = [1, "mower", "mowing"]; ->robotA : [number, string, string] +>robotA : Robot >[1, "mower", "mowing"] : [number, string, string] >1 : 1 >"mower" : "mower" >"mowing" : "mowing" let robotB: Robot = [2, "trimmer", "trimming"]; ->robotB : [number, string, string] +>robotB : Robot >[2, "trimmer", "trimming"] : [number, string, string] >2 : 2 >"trimmer" : "trimmer" >"trimming" : "trimming" let robots = [robotA, robotB]; ->robots : [number, string, string][] ->[robotA, robotB] : [number, string, string][] ->robotA : [number, string, string] ->robotB : [number, string, string] +>robots : Robot[] +>[robotA, robotB] : Robot[] +>robotA : Robot +>robotB : Robot function getRobots() { ->getRobots : () => [number, string, string][] +>getRobots : () => Robot[] return robots; ->robots : [number, string, string][] +>robots : Robot[] } let multiRobotA: MultiSkilledRobot = ["mower", ["mowing", ""]]; ->multiRobotA : [string, [string, string]] +>multiRobotA : MultiSkilledRobot >["mower", ["mowing", ""]] : [string, [string, string]] >"mower" : "mower" >["mowing", ""] : [string, string] @@ -48,7 +48,7 @@ let multiRobotA: MultiSkilledRobot = ["mower", ["mowing", ""]]; >"" : "" let multiRobotB: MultiSkilledRobot = ["trimmer", ["trimming", "edging"]]; ->multiRobotB : [string, [string, string]] +>multiRobotB : MultiSkilledRobot >["trimmer", ["trimming", "edging"]] : [string, [string, string]] >"trimmer" : "trimmer" >["trimming", "edging"] : [string, string] @@ -56,16 +56,16 @@ let multiRobotB: MultiSkilledRobot = ["trimmer", ["trimming", "edging"]]; >"edging" : "edging" let multiRobots = [multiRobotA, multiRobotB]; ->multiRobots : [string, [string, string]][] ->[multiRobotA, multiRobotB] : [string, [string, string]][] ->multiRobotA : [string, [string, string]] ->multiRobotB : [string, [string, string]] +>multiRobots : MultiSkilledRobot[] +>[multiRobotA, multiRobotB] : MultiSkilledRobot[] +>multiRobotA : MultiSkilledRobot +>multiRobotB : MultiSkilledRobot function getMultiRobots() { ->getMultiRobots : () => [string, [string, string]][] +>getMultiRobots : () => MultiSkilledRobot[] return multiRobots; ->multiRobots : [string, [string, string]][] +>multiRobots : MultiSkilledRobot[] } let nameA: string, primarySkillA: string, secondarySkillA: string; @@ -94,7 +94,7 @@ for ([, nameA = "noName"] of robots) { >nameA = "noName" : "noName" >nameA : string >"noName" : "noName" ->robots : [number, string, string][] +>robots : Robot[] console.log(nameA); >console.log(nameA) : void @@ -109,8 +109,8 @@ for ([, nameA = "noName"] of getRobots()) { >nameA = "noName" : "noName" >nameA : string >"noName" : "noName" ->getRobots() : [number, string, string][] ->getRobots : () => [number, string, string][] +>getRobots() : Robot[] +>getRobots : () => Robot[] console.log(nameA); >console.log(nameA) : void @@ -125,9 +125,9 @@ for ([, nameA = "noName"] of [robotA, robotB]) { >nameA = "noName" : "noName" >nameA : string >"noName" : "noName" ->[robotA, robotB] : [number, string, string][] ->robotA : [number, string, string] ->robotB : [number, string, string] +>[robotA, robotB] : Robot[] +>robotA : Robot +>robotB : Robot console.log(nameA); >console.log(nameA) : void @@ -156,7 +156,7 @@ for ([, [ >["skill1", "skill2"] : [string, string] >"skill1" : "skill1" >"skill2" : "skill2" ->multiRobots : [string, [string, string]][] +>multiRobots : MultiSkilledRobot[] console.log(primarySkillA); >console.log(primarySkillA) : void @@ -185,8 +185,8 @@ for ([, [ >["skill1", "skill2"] : [string, string] >"skill1" : "skill1" >"skill2" : "skill2" ->getMultiRobots() : [string, [string, string]][] ->getMultiRobots : () => [string, [string, string]][] +>getMultiRobots() : MultiSkilledRobot[] +>getMultiRobots : () => MultiSkilledRobot[] console.log(primarySkillA); >console.log(primarySkillA) : void @@ -215,9 +215,9 @@ for ([, [ >["skill1", "skill2"] : [string, string] >"skill1" : "skill1" >"skill2" : "skill2" ->[multiRobotA, multiRobotB] : [string, [string, string]][] ->multiRobotA : [string, [string, string]] ->multiRobotB : [string, [string, string]] +>[multiRobotA, multiRobotB] : MultiSkilledRobot[] +>multiRobotA : MultiSkilledRobot +>multiRobotB : MultiSkilledRobot console.log(primarySkillA); >console.log(primarySkillA) : void @@ -233,7 +233,7 @@ for ([numberB = -1] of robots) { >numberB : number >-1 : -1 >1 : 1 ->robots : [number, string, string][] +>robots : Robot[] console.log(numberB); >console.log(numberB) : void @@ -248,8 +248,8 @@ for ([numberB = -1] of getRobots()) { >numberB : number >-1 : -1 >1 : 1 ->getRobots() : [number, string, string][] ->getRobots : () => [number, string, string][] +>getRobots() : Robot[] +>getRobots : () => Robot[] console.log(numberB); >console.log(numberB) : void @@ -264,9 +264,9 @@ for ([numberB = -1] of [robotA, robotB]) { >numberB : number >-1 : -1 >1 : 1 ->[robotA, robotB] : [number, string, string][] ->robotA : [number, string, string] ->robotB : [number, string, string] +>[robotA, robotB] : Robot[] +>robotA : Robot +>robotB : Robot console.log(numberB); >console.log(numberB) : void @@ -280,7 +280,7 @@ for ([nameB = "noName"] of multiRobots) { >nameB = "noName" : "noName" >nameB : string >"noName" : "noName" ->multiRobots : [string, [string, string]][] +>multiRobots : MultiSkilledRobot[] console.log(nameB); >console.log(nameB) : void @@ -294,8 +294,8 @@ for ([nameB = "noName"] of getMultiRobots()) { >nameB = "noName" : "noName" >nameB : string >"noName" : "noName" ->getMultiRobots() : [string, [string, string]][] ->getMultiRobots : () => [string, [string, string]][] +>getMultiRobots() : MultiSkilledRobot[] +>getMultiRobots : () => MultiSkilledRobot[] console.log(nameB); >console.log(nameB) : void @@ -309,9 +309,9 @@ for ([nameB = "noName"] of [multiRobotA, multiRobotB]) { >nameB = "noName" : "noName" >nameB : string >"noName" : "noName" ->[multiRobotA, multiRobotB] : [string, [string, string]][] ->multiRobotA : [string, [string, string]] ->multiRobotB : [string, [string, string]] +>[multiRobotA, multiRobotB] : MultiSkilledRobot[] +>multiRobotA : MultiSkilledRobot +>multiRobotB : MultiSkilledRobot console.log(nameB); >console.log(nameB) : void @@ -333,7 +333,7 @@ for ([numberA2 = -1, nameA2 = "noName", skillA2 = "skill"] of robots) { >skillA2 = "skill" : "skill" >skillA2 : string >"skill" : "skill" ->robots : [number, string, string][] +>robots : Robot[] console.log(nameA2); >console.log(nameA2) : void @@ -354,8 +354,8 @@ for ([numberA2 = -1, nameA2 = "noName", skillA2 = "skill"] of getRobots()) { >skillA2 = "skill" : "skill" >skillA2 : string >"skill" : "skill" ->getRobots() : [number, string, string][] ->getRobots : () => [number, string, string][] +>getRobots() : Robot[] +>getRobots : () => Robot[] console.log(nameA2); >console.log(nameA2) : void @@ -376,9 +376,9 @@ for ([numberA2 = -1, nameA2 = "noName", skillA2 = "skill"] of [robotA, robotB]) >skillA2 = "skill" : "skill" >skillA2 : string >"skill" : "skill" ->[robotA, robotB] : [number, string, string][] ->robotA : [number, string, string] ->robotB : [number, string, string] +>[robotA, robotB] : Robot[] +>robotA : Robot +>robotB : Robot console.log(nameA2); >console.log(nameA2) : void @@ -409,7 +409,7 @@ for ([nameMA = "noName", [ >["skill1", "skill2"] : [string, string] >"skill1" : "skill1" >"skill2" : "skill2" ->multiRobots : [string, [string, string]][] +>multiRobots : MultiSkilledRobot[] console.log(nameMA); >console.log(nameMA) : void @@ -440,8 +440,8 @@ for ([nameMA = "noName", [ >["skill1", "skill2"] : [string, string] >"skill1" : "skill1" >"skill2" : "skill2" ->getMultiRobots() : [string, [string, string]][] ->getMultiRobots : () => [string, [string, string]][] +>getMultiRobots() : MultiSkilledRobot[] +>getMultiRobots : () => MultiSkilledRobot[] console.log(nameMA); >console.log(nameMA) : void @@ -472,9 +472,9 @@ for ([nameMA = "noName", [ >["skill1", "skill2"] : [string, string] >"skill1" : "skill1" >"skill2" : "skill2" ->[multiRobotA, multiRobotB] : [string, [string, string]][] ->multiRobotA : [string, [string, string]] ->multiRobotB : [string, [string, string]] +>[multiRobotA, multiRobotB] : MultiSkilledRobot[] +>multiRobotA : MultiSkilledRobot +>multiRobotB : MultiSkilledRobot console.log(nameMA); >console.log(nameMA) : void @@ -492,7 +492,7 @@ for ([numberA3 = -1, ...robotAInfo] of robots) { >1 : 1 >...robotAInfo : string | number >robotAInfo : (string | number)[] ->robots : [number, string, string][] +>robots : Robot[] console.log(numberA3); >console.log(numberA3) : void @@ -509,8 +509,8 @@ for ([numberA3 = -1, ...robotAInfo] of getRobots()) { >1 : 1 >...robotAInfo : string | number >robotAInfo : (string | number)[] ->getRobots() : [number, string, string][] ->getRobots : () => [number, string, string][] +>getRobots() : Robot[] +>getRobots : () => Robot[] console.log(numberA3); >console.log(numberA3) : void @@ -527,9 +527,9 @@ for ([numberA3 = -1, ...robotAInfo] of [robotA, robotB]) { >1 : 1 >...robotAInfo : string | number >robotAInfo : (string | number)[] ->[robotA, robotB] : [number, string, string][] ->robotA : [number, string, string] ->robotB : [number, string, string] +>[robotA, robotB] : Robot[] +>robotA : Robot +>robotB : Robot console.log(numberA3); >console.log(numberA3) : void diff --git a/tests/baselines/reference/sourceMapValidationDestructuringParametertArrayBindingPattern.types b/tests/baselines/reference/sourceMapValidationDestructuringParametertArrayBindingPattern.types index 2758457edbe..ff955abe34b 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringParametertArrayBindingPattern.types +++ b/tests/baselines/reference/sourceMapValidationDestructuringParametertArrayBindingPattern.types @@ -7,17 +7,17 @@ declare var console: { >msg : any } type Robot = [number, string, string]; ->Robot : [number, string, string] +>Robot : Robot var robotA: Robot = [1, "mower", "mowing"]; ->robotA : [number, string, string] +>robotA : Robot >[1, "mower", "mowing"] : [number, string, string] >1 : 1 >"mower" : "mower" >"mowing" : "mowing" function foo1([, nameA]: Robot) { ->foo1 : ([, nameA]: [number, string, string]) => void +>foo1 : ([, nameA]: Robot) => void > : undefined >nameA : string @@ -30,7 +30,7 @@ function foo1([, nameA]: Robot) { } function foo2([numberB]: Robot) { ->foo2 : ([numberB]: [number, string, string]) => void +>foo2 : ([numberB]: Robot) => void >numberB : number console.log(numberB); @@ -42,7 +42,7 @@ function foo2([numberB]: Robot) { } function foo3([numberA2, nameA2, skillA2]: Robot) { ->foo3 : ([numberA2, nameA2, skillA2]: [number, string, string]) => void +>foo3 : ([numberA2, nameA2, skillA2]: Robot) => void >numberA2 : number >nameA2 : string >skillA2 : string @@ -56,7 +56,7 @@ function foo3([numberA2, nameA2, skillA2]: Robot) { } function foo4([numberA3, ...robotAInfo]: Robot) { ->foo4 : ([numberA3, ...robotAInfo]: [number, string, string]) => void +>foo4 : ([numberA3, ...robotAInfo]: Robot) => void >numberA3 : number >robotAInfo : [string, string] @@ -70,12 +70,12 @@ function foo4([numberA3, ...robotAInfo]: Robot) { foo1(robotA); >foo1(robotA) : void ->foo1 : ([, nameA]: [number, string, string]) => void ->robotA : [number, string, string] +>foo1 : ([, nameA]: Robot) => void +>robotA : Robot foo1([2, "trimmer", "trimming"]); >foo1([2, "trimmer", "trimming"]) : void ->foo1 : ([, nameA]: [number, string, string]) => void +>foo1 : ([, nameA]: Robot) => void >[2, "trimmer", "trimming"] : [number, string, string] >2 : 2 >"trimmer" : "trimmer" @@ -83,12 +83,12 @@ foo1([2, "trimmer", "trimming"]); foo2(robotA); >foo2(robotA) : void ->foo2 : ([numberB]: [number, string, string]) => void ->robotA : [number, string, string] +>foo2 : ([numberB]: Robot) => void +>robotA : Robot foo2([2, "trimmer", "trimming"]); >foo2([2, "trimmer", "trimming"]) : void ->foo2 : ([numberB]: [number, string, string]) => void +>foo2 : ([numberB]: Robot) => void >[2, "trimmer", "trimming"] : [number, string, string] >2 : 2 >"trimmer" : "trimmer" @@ -96,12 +96,12 @@ foo2([2, "trimmer", "trimming"]); foo3(robotA); >foo3(robotA) : void ->foo3 : ([numberA2, nameA2, skillA2]: [number, string, string]) => void ->robotA : [number, string, string] +>foo3 : ([numberA2, nameA2, skillA2]: Robot) => void +>robotA : Robot foo3([2, "trimmer", "trimming"]); >foo3([2, "trimmer", "trimming"]) : void ->foo3 : ([numberA2, nameA2, skillA2]: [number, string, string]) => void +>foo3 : ([numberA2, nameA2, skillA2]: Robot) => void >[2, "trimmer", "trimming"] : [number, string, string] >2 : 2 >"trimmer" : "trimmer" @@ -109,12 +109,12 @@ foo3([2, "trimmer", "trimming"]); foo4(robotA); >foo4(robotA) : void ->foo4 : ([numberA3, ...robotAInfo]: [number, string, string]) => void ->robotA : [number, string, string] +>foo4 : ([numberA3, ...robotAInfo]: Robot) => void +>robotA : Robot foo4([2, "trimmer", "trimming"]); >foo4([2, "trimmer", "trimming"]) : void ->foo4 : ([numberA3, ...robotAInfo]: [number, string, string]) => void +>foo4 : ([numberA3, ...robotAInfo]: Robot) => void >[2, "trimmer", "trimming"] : [number, string, string] >2 : 2 >"trimmer" : "trimmer" diff --git a/tests/baselines/reference/sourceMapValidationDestructuringParametertArrayBindingPattern2.types b/tests/baselines/reference/sourceMapValidationDestructuringParametertArrayBindingPattern2.types index 1cdced45404..aee226f8d83 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringParametertArrayBindingPattern2.types +++ b/tests/baselines/reference/sourceMapValidationDestructuringParametertArrayBindingPattern2.types @@ -7,10 +7,10 @@ declare var console: { >msg : any } type Robot = [string, [string, string]]; ->Robot : [string, [string, string]] +>Robot : Robot var robotA: Robot = ["trimmer", ["trimming", "edging"]]; ->robotA : [string, [string, string]] +>robotA : Robot >["trimmer", ["trimming", "edging"]] : [string, [string, string]] >"trimmer" : "trimmer" >["trimming", "edging"] : [string, string] @@ -18,7 +18,7 @@ var robotA: Robot = ["trimmer", ["trimming", "edging"]]; >"edging" : "edging" function foo1([, skillA]: Robot) { ->foo1 : ([, skillA]: [string, [string, string]]) => void +>foo1 : ([, skillA]: Robot) => void > : undefined >skillA : [string, string] @@ -31,7 +31,7 @@ function foo1([, skillA]: Robot) { } function foo2([nameMB]: Robot) { ->foo2 : ([nameMB]: [string, [string, string]]) => void +>foo2 : ([nameMB]: Robot) => void >nameMB : string console.log(nameMB); @@ -43,7 +43,7 @@ function foo2([nameMB]: Robot) { } function foo3([nameMA, [primarySkillA, secondarySkillA]]: Robot) { ->foo3 : ([nameMA, [primarySkillA, secondarySkillA]]: [string, [string, string]]) => void +>foo3 : ([nameMA, [primarySkillA, secondarySkillA]]: Robot) => void >nameMA : string >primarySkillA : string >secondarySkillA : string @@ -57,7 +57,7 @@ function foo3([nameMA, [primarySkillA, secondarySkillA]]: Robot) { } function foo4([...multiRobotAInfo]: Robot) { ->foo4 : ([...multiRobotAInfo]: [string, [string, string]]) => void +>foo4 : ([...multiRobotAInfo]: Robot) => void >multiRobotAInfo : [string, [string, string]] console.log(multiRobotAInfo); @@ -70,12 +70,12 @@ function foo4([...multiRobotAInfo]: Robot) { foo1(robotA); >foo1(robotA) : void ->foo1 : ([, skillA]: [string, [string, string]]) => void ->robotA : [string, [string, string]] +>foo1 : ([, skillA]: Robot) => void +>robotA : Robot foo1(["roomba", ["vaccum", "mopping"]]); >foo1(["roomba", ["vaccum", "mopping"]]) : void ->foo1 : ([, skillA]: [string, [string, string]]) => void +>foo1 : ([, skillA]: Robot) => void >["roomba", ["vaccum", "mopping"]] : [string, [string, string]] >"roomba" : "roomba" >["vaccum", "mopping"] : [string, string] @@ -84,12 +84,12 @@ foo1(["roomba", ["vaccum", "mopping"]]); foo2(robotA); >foo2(robotA) : void ->foo2 : ([nameMB]: [string, [string, string]]) => void ->robotA : [string, [string, string]] +>foo2 : ([nameMB]: Robot) => void +>robotA : Robot foo2(["roomba", ["vaccum", "mopping"]]); >foo2(["roomba", ["vaccum", "mopping"]]) : void ->foo2 : ([nameMB]: [string, [string, string]]) => void +>foo2 : ([nameMB]: Robot) => void >["roomba", ["vaccum", "mopping"]] : [string, [string, string]] >"roomba" : "roomba" >["vaccum", "mopping"] : [string, string] @@ -98,12 +98,12 @@ foo2(["roomba", ["vaccum", "mopping"]]); foo3(robotA); >foo3(robotA) : void ->foo3 : ([nameMA, [primarySkillA, secondarySkillA]]: [string, [string, string]]) => void ->robotA : [string, [string, string]] +>foo3 : ([nameMA, [primarySkillA, secondarySkillA]]: Robot) => void +>robotA : Robot foo3(["roomba", ["vaccum", "mopping"]]); >foo3(["roomba", ["vaccum", "mopping"]]) : void ->foo3 : ([nameMA, [primarySkillA, secondarySkillA]]: [string, [string, string]]) => void +>foo3 : ([nameMA, [primarySkillA, secondarySkillA]]: Robot) => void >["roomba", ["vaccum", "mopping"]] : [string, [string, string]] >"roomba" : "roomba" >["vaccum", "mopping"] : [string, string] @@ -112,12 +112,12 @@ foo3(["roomba", ["vaccum", "mopping"]]); foo4(robotA); >foo4(robotA) : void ->foo4 : ([...multiRobotAInfo]: [string, [string, string]]) => void ->robotA : [string, [string, string]] +>foo4 : ([...multiRobotAInfo]: Robot) => void +>robotA : Robot foo4(["roomba", ["vaccum", "mopping"]]); >foo4(["roomba", ["vaccum", "mopping"]]) : void ->foo4 : ([...multiRobotAInfo]: [string, [string, string]]) => void +>foo4 : ([...multiRobotAInfo]: Robot) => void >["roomba", ["vaccum", "mopping"]] : [string, [string, string]] >"roomba" : "roomba" >["vaccum", "mopping"] : [string, string] diff --git a/tests/baselines/reference/sourceMapValidationDestructuringParametertArrayBindingPatternDefaultValues.types b/tests/baselines/reference/sourceMapValidationDestructuringParametertArrayBindingPatternDefaultValues.types index 60345aa2b73..94106255a12 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringParametertArrayBindingPatternDefaultValues.types +++ b/tests/baselines/reference/sourceMapValidationDestructuringParametertArrayBindingPatternDefaultValues.types @@ -7,17 +7,17 @@ declare var console: { >msg : any } type Robot = [number, string, string]; ->Robot : [number, string, string] +>Robot : Robot var robotA: Robot = [1, "mower", "mowing"]; ->robotA : [number, string, string] +>robotA : Robot >[1, "mower", "mowing"] : [number, string, string] >1 : 1 >"mower" : "mower" >"mowing" : "mowing" function foo1([, nameA = "noName"]: Robot = [-1, "name", "skill"]) { ->foo1 : ([, nameA]?: [number, string, string]) => void +>foo1 : ([, nameA]?: Robot) => void > : undefined >nameA : string >"noName" : "noName" @@ -36,7 +36,7 @@ function foo1([, nameA = "noName"]: Robot = [-1, "name", "skill"]) { } function foo2([numberB = -1]: Robot = [-1, "name", "skill"]) { ->foo2 : ([numberB]?: [number, string, string]) => void +>foo2 : ([numberB]?: Robot) => void >numberB : number >-1 : -1 >1 : 1 @@ -55,7 +55,7 @@ function foo2([numberB = -1]: Robot = [-1, "name", "skill"]) { } function foo3([numberA2 = -1, nameA2 = "name", skillA2 = "skill"]: Robot = [-1, "name", "skill"]) { ->foo3 : ([numberA2, nameA2, skillA2]?: [number, string, string]) => void +>foo3 : ([numberA2, nameA2, skillA2]?: Robot) => void >numberA2 : number >-1 : -1 >1 : 1 @@ -78,7 +78,7 @@ function foo3([numberA2 = -1, nameA2 = "name", skillA2 = "skill"]: Robot = [-1, } function foo4([numberA3 = -1, ...robotAInfo]: Robot = [-1, "name", "skill"]) { ->foo4 : ([numberA3, ...robotAInfo]?: [number, string, string]) => void +>foo4 : ([numberA3, ...robotAInfo]?: Robot) => void >numberA3 : number >-1 : -1 >1 : 1 @@ -99,12 +99,12 @@ function foo4([numberA3 = -1, ...robotAInfo]: Robot = [-1, "name", "skill"]) { foo1(robotA); >foo1(robotA) : void ->foo1 : ([, nameA]?: [number, string, string]) => void ->robotA : [number, string, string] +>foo1 : ([, nameA]?: Robot) => void +>robotA : Robot foo1([2, "trimmer", "trimming"]); >foo1([2, "trimmer", "trimming"]) : void ->foo1 : ([, nameA]?: [number, string, string]) => void +>foo1 : ([, nameA]?: Robot) => void >[2, "trimmer", "trimming"] : [number, string, string] >2 : 2 >"trimmer" : "trimmer" @@ -112,12 +112,12 @@ foo1([2, "trimmer", "trimming"]); foo2(robotA); >foo2(robotA) : void ->foo2 : ([numberB]?: [number, string, string]) => void ->robotA : [number, string, string] +>foo2 : ([numberB]?: Robot) => void +>robotA : Robot foo2([2, "trimmer", "trimming"]); >foo2([2, "trimmer", "trimming"]) : void ->foo2 : ([numberB]?: [number, string, string]) => void +>foo2 : ([numberB]?: Robot) => void >[2, "trimmer", "trimming"] : [number, string, string] >2 : 2 >"trimmer" : "trimmer" @@ -125,12 +125,12 @@ foo2([2, "trimmer", "trimming"]); foo3(robotA); >foo3(robotA) : void ->foo3 : ([numberA2, nameA2, skillA2]?: [number, string, string]) => void ->robotA : [number, string, string] +>foo3 : ([numberA2, nameA2, skillA2]?: Robot) => void +>robotA : Robot foo3([2, "trimmer", "trimming"]); >foo3([2, "trimmer", "trimming"]) : void ->foo3 : ([numberA2, nameA2, skillA2]?: [number, string, string]) => void +>foo3 : ([numberA2, nameA2, skillA2]?: Robot) => void >[2, "trimmer", "trimming"] : [number, string, string] >2 : 2 >"trimmer" : "trimmer" @@ -138,12 +138,12 @@ foo3([2, "trimmer", "trimming"]); foo4(robotA); >foo4(robotA) : void ->foo4 : ([numberA3, ...robotAInfo]?: [number, string, string]) => void ->robotA : [number, string, string] +>foo4 : ([numberA3, ...robotAInfo]?: Robot) => void +>robotA : Robot foo4([2, "trimmer", "trimming"]); >foo4([2, "trimmer", "trimming"]) : void ->foo4 : ([numberA3, ...robotAInfo]?: [number, string, string]) => void +>foo4 : ([numberA3, ...robotAInfo]?: Robot) => void >[2, "trimmer", "trimming"] : [number, string, string] >2 : 2 >"trimmer" : "trimmer" diff --git a/tests/baselines/reference/sourceMapValidationDestructuringParametertArrayBindingPatternDefaultValues2.types b/tests/baselines/reference/sourceMapValidationDestructuringParametertArrayBindingPatternDefaultValues2.types index d9c991f65fb..f2773f2d252 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringParametertArrayBindingPatternDefaultValues2.types +++ b/tests/baselines/reference/sourceMapValidationDestructuringParametertArrayBindingPatternDefaultValues2.types @@ -7,10 +7,10 @@ declare var console: { >msg : any } type Robot = [string, string[]]; ->Robot : [string, string[]] +>Robot : Robot var robotA: Robot = ["trimmer", ["trimming", "edging"]]; ->robotA : [string, string[]] +>robotA : Robot >["trimmer", ["trimming", "edging"]] : [string, string[]] >"trimmer" : "trimmer" >["trimming", "edging"] : string[] @@ -18,7 +18,7 @@ var robotA: Robot = ["trimmer", ["trimming", "edging"]]; >"edging" : "edging" function foo1([, skillA = ["noSkill", "noSkill"]]: Robot= ["name", ["skill1", "skill2"]]) { ->foo1 : ([, skillA]?: [string, string[]]) => void +>foo1 : ([, skillA]?: Robot) => void > : undefined >skillA : string[] >["noSkill", "noSkill"] : string[] @@ -39,7 +39,7 @@ function foo1([, skillA = ["noSkill", "noSkill"]]: Robot= ["name", ["skill1", "s } function foo2([nameMB = "noName"]: Robot = ["name", ["skill1", "skill2"]]) { ->foo2 : ([nameMB]?: [string, string[]]) => void +>foo2 : ([nameMB]?: Robot) => void >nameMB : string >"noName" : "noName" >["name", ["skill1", "skill2"]] : [string, string[]] @@ -57,7 +57,7 @@ function foo2([nameMB = "noName"]: Robot = ["name", ["skill1", "skill2"]]) { } function foo3([nameMA = "noName", [ ->foo3 : ([nameMA, [primarySkillA, secondarySkillA]]: [string, string[]]) => void +>foo3 : ([nameMA, [primarySkillA, secondarySkillA]]: Robot) => void >nameMA : string >"noName" : "noName" @@ -84,12 +84,12 @@ function foo3([nameMA = "noName", [ foo1(robotA); >foo1(robotA) : void ->foo1 : ([, skillA]?: [string, string[]]) => void ->robotA : [string, string[]] +>foo1 : ([, skillA]?: Robot) => void +>robotA : Robot foo1(["roomba", ["vaccum", "mopping"]]); >foo1(["roomba", ["vaccum", "mopping"]]) : void ->foo1 : ([, skillA]?: [string, string[]]) => void +>foo1 : ([, skillA]?: Robot) => void >["roomba", ["vaccum", "mopping"]] : [string, string[]] >"roomba" : "roomba" >["vaccum", "mopping"] : string[] @@ -98,12 +98,12 @@ foo1(["roomba", ["vaccum", "mopping"]]); foo2(robotA); >foo2(robotA) : void ->foo2 : ([nameMB]?: [string, string[]]) => void ->robotA : [string, string[]] +>foo2 : ([nameMB]?: Robot) => void +>robotA : Robot foo2(["roomba", ["vaccum", "mopping"]]); >foo2(["roomba", ["vaccum", "mopping"]]) : void ->foo2 : ([nameMB]?: [string, string[]]) => void +>foo2 : ([nameMB]?: Robot) => void >["roomba", ["vaccum", "mopping"]] : [string, string[]] >"roomba" : "roomba" >["vaccum", "mopping"] : string[] @@ -112,12 +112,12 @@ foo2(["roomba", ["vaccum", "mopping"]]); foo3(robotA); >foo3(robotA) : void ->foo3 : ([nameMA, [primarySkillA, secondarySkillA]]: [string, string[]]) => void ->robotA : [string, string[]] +>foo3 : ([nameMA, [primarySkillA, secondarySkillA]]: Robot) => void +>robotA : Robot foo3(["roomba", ["vaccum", "mopping"]]); >foo3(["roomba", ["vaccum", "mopping"]]) : void ->foo3 : ([nameMA, [primarySkillA, secondarySkillA]]: [string, string[]]) => void +>foo3 : ([nameMA, [primarySkillA, secondarySkillA]]: Robot) => void >["roomba", ["vaccum", "mopping"]] : [string, string[]] >"roomba" : "roomba" >["vaccum", "mopping"] : string[] diff --git a/tests/baselines/reference/sourceMapValidationDestructuringVariableStatementArrayBindingPattern.types b/tests/baselines/reference/sourceMapValidationDestructuringVariableStatementArrayBindingPattern.types index 2ed0777aa80..61e7f7ab3e2 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringVariableStatementArrayBindingPattern.types +++ b/tests/baselines/reference/sourceMapValidationDestructuringVariableStatementArrayBindingPattern.types @@ -7,17 +7,17 @@ declare var console: { >msg : string } type Robot = [number, string, string]; ->Robot : [number, string, string] +>Robot : Robot var robotA: Robot = [1, "mower", "mowing"]; ->robotA : [number, string, string] +>robotA : Robot >[1, "mower", "mowing"] : [number, string, string] >1 : 1 >"mower" : "mower" >"mowing" : "mowing" var robotB: Robot = [2, "trimmer", "trimming"]; ->robotB : [number, string, string] +>robotB : Robot >[2, "trimmer", "trimming"] : [number, string, string] >2 : 2 >"trimmer" : "trimmer" @@ -27,17 +27,17 @@ var robotB: Robot = [2, "trimmer", "trimming"]; let [, nameA] = robotA; > : undefined >nameA : string ->robotA : [number, string, string] +>robotA : Robot let [numberB] = robotB; >numberB : number ->robotB : [number, string, string] +>robotB : Robot let [numberA2, nameA2, skillA2] = robotA; >numberA2 : number >nameA2 : string >skillA2 : string ->robotA : [number, string, string] +>robotA : Robot let [numberC2] = [3, "edging", "Trimming edges"]; >numberC2 : number @@ -58,7 +58,7 @@ let [numberC, nameC, skillC] = [3, "edging", "Trimming edges"]; let [numberA3, ...robotAInfo] = robotA; >numberA3 : number >robotAInfo : [string, string] ->robotA : [number, string, string] +>robotA : Robot if (nameA == nameA2) { >nameA == nameA2 : boolean diff --git a/tests/baselines/reference/sourceMapValidationDestructuringVariableStatementArrayBindingPattern2.types b/tests/baselines/reference/sourceMapValidationDestructuringVariableStatementArrayBindingPattern2.types index 94b0ff295a2..9027e3be196 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringVariableStatementArrayBindingPattern2.types +++ b/tests/baselines/reference/sourceMapValidationDestructuringVariableStatementArrayBindingPattern2.types @@ -7,10 +7,10 @@ declare var console: { >msg : string } type MultiSkilledRobot = [string, [string, string]]; ->MultiSkilledRobot : [string, [string, string]] +>MultiSkilledRobot : MultiSkilledRobot var multiRobotA: MultiSkilledRobot = ["mower", ["mowing", ""]]; ->multiRobotA : [string, [string, string]] +>multiRobotA : MultiSkilledRobot >["mower", ["mowing", ""]] : [string, [string, string]] >"mower" : "mower" >["mowing", ""] : [string, string] @@ -18,7 +18,7 @@ var multiRobotA: MultiSkilledRobot = ["mower", ["mowing", ""]]; >"" : "" var multiRobotB: MultiSkilledRobot = ["trimmer", ["trimming", "edging"]]; ->multiRobotB : [string, [string, string]] +>multiRobotB : MultiSkilledRobot >["trimmer", ["trimming", "edging"]] : [string, [string, string]] >"trimmer" : "trimmer" >["trimming", "edging"] : [string, string] @@ -28,17 +28,17 @@ var multiRobotB: MultiSkilledRobot = ["trimmer", ["trimming", "edging"]]; let [, skillA] = multiRobotA; > : undefined >skillA : [string, string] ->multiRobotA : [string, [string, string]] +>multiRobotA : MultiSkilledRobot let [nameMB] = multiRobotB; >nameMB : string ->multiRobotB : [string, [string, string]] +>multiRobotB : MultiSkilledRobot let [nameMA, [primarySkillA, secondarySkillA]] = multiRobotA; >nameMA : string >primarySkillA : string >secondarySkillA : string ->multiRobotA : [string, [string, string]] +>multiRobotA : MultiSkilledRobot let [nameMC] = ["roomba", ["vaccum", "mopping"]]; >nameMC : string @@ -60,7 +60,7 @@ let [nameMC2, [primarySkillC, secondarySkillC]] = ["roomba", ["vaccum", "mopping let [...multiRobotAInfo] = multiRobotA; >multiRobotAInfo : [string, [string, string]] ->multiRobotA : [string, [string, string]] +>multiRobotA : MultiSkilledRobot if (nameMB == nameMA) { >nameMB == nameMA : boolean diff --git a/tests/baselines/reference/sourceMapValidationDestructuringVariableStatementArrayBindingPattern3.types b/tests/baselines/reference/sourceMapValidationDestructuringVariableStatementArrayBindingPattern3.types index 10025aabc0a..1ee682f838a 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringVariableStatementArrayBindingPattern3.types +++ b/tests/baselines/reference/sourceMapValidationDestructuringVariableStatementArrayBindingPattern3.types @@ -7,27 +7,27 @@ declare var console: { >msg : any } type Robot = [number, string, string]; ->Robot : [number, string, string] +>Robot : Robot type MultiSkilledRobot = [string, [string, string]]; ->MultiSkilledRobot : [string, [string, string]] +>MultiSkilledRobot : MultiSkilledRobot var robotA: Robot = [1, "mower", "mowing"]; ->robotA : [number, string, string] +>robotA : Robot >[1, "mower", "mowing"] : [number, string, string] >1 : 1 >"mower" : "mower" >"mowing" : "mowing" var robotB: Robot = [2, "trimmer", "trimming"]; ->robotB : [number, string, string] +>robotB : Robot >[2, "trimmer", "trimming"] : [number, string, string] >2 : 2 >"trimmer" : "trimmer" >"trimming" : "trimming" var multiRobotA: MultiSkilledRobot = ["mower", ["mowing", ""]]; ->multiRobotA : [string, [string, string]] +>multiRobotA : MultiSkilledRobot >["mower", ["mowing", ""]] : [string, [string, string]] >"mower" : "mower" >["mowing", ""] : [string, string] @@ -35,7 +35,7 @@ var multiRobotA: MultiSkilledRobot = ["mower", ["mowing", ""]]; >"" : "" var multiRobotB: MultiSkilledRobot = ["trimmer", ["trimming", "edging"]]; ->multiRobotB : [string, [string, string]] +>multiRobotB : MultiSkilledRobot >["trimmer", ["trimming", "edging"]] : [string, [string, string]] >"trimmer" : "trimmer" >["trimming", "edging"] : [string, string] @@ -61,19 +61,19 @@ let multiRobotAInfo: (string | [string, string])[]; >multiRobotAInfo : (string | [string, string])[] [, nameA] = robotA; ->[, nameA] = robotA : [number, string, string] +>[, nameA] = robotA : Robot >[, nameA] : [undefined, string] > : undefined >nameA : string ->robotA : [number, string, string] +>robotA : Robot [, nameB] = getRobotB(); ->[, nameB] = getRobotB() : [number, string, string] +>[, nameB] = getRobotB() : Robot >[, nameB] : [undefined, string] > : undefined >nameB : string ->getRobotB() : [number, string, string] ->getRobotB : () => [number, string, string] +>getRobotB() : Robot +>getRobotB : () => Robot [, nameB] = [2, "trimmer", "trimming"]; >[, nameB] = [2, "trimmer", "trimming"] : [number, string, string] @@ -86,19 +86,19 @@ let multiRobotAInfo: (string | [string, string])[]; >"trimming" : "trimming" [, multiSkillB] = multiRobotB; ->[, multiSkillB] = multiRobotB : [string, [string, string]] +>[, multiSkillB] = multiRobotB : MultiSkilledRobot >[, multiSkillB] : [undefined, [string, string]] > : undefined >multiSkillB : [string, string] ->multiRobotB : [string, [string, string]] +>multiRobotB : MultiSkilledRobot [, multiSkillB] = getMultiRobotB(); ->[, multiSkillB] = getMultiRobotB() : [string, [string, string]] +>[, multiSkillB] = getMultiRobotB() : MultiSkilledRobot >[, multiSkillB] : [undefined, [string, string]] > : undefined >multiSkillB : [string, string] ->getMultiRobotB() : [string, [string, string]] ->getMultiRobotB : () => [string, [string, string]] +>getMultiRobotB() : MultiSkilledRobot +>getMultiRobotB : () => MultiSkilledRobot [, multiSkillB] = ["roomba", ["vaccum", "mopping"]]; >[, multiSkillB] = ["roomba", ["vaccum", "mopping"]] : [string, [string, string]] @@ -112,17 +112,17 @@ let multiRobotAInfo: (string | [string, string])[]; >"mopping" : "mopping" [numberB] = robotB; ->[numberB] = robotB : [number, string, string] +>[numberB] = robotB : Robot >[numberB] : [number] >numberB : number ->robotB : [number, string, string] +>robotB : Robot [numberB] = getRobotB(); ->[numberB] = getRobotB() : [number, string, string] +>[numberB] = getRobotB() : Robot >[numberB] : [number] >numberB : number ->getRobotB() : [number, string, string] ->getRobotB : () => [number, string, string] +>getRobotB() : Robot +>getRobotB : () => Robot [numberB] = [2, "trimmer", "trimming"]; >[numberB] = [2, "trimmer", "trimming"] : [number, string, string] @@ -134,17 +134,17 @@ let multiRobotAInfo: (string | [string, string])[]; >"trimming" : "trimming" [nameMB] = multiRobotB; ->[nameMB] = multiRobotB : [string, [string, string]] +>[nameMB] = multiRobotB : MultiSkilledRobot >[nameMB] : [string] >nameMB : string ->multiRobotB : [string, [string, string]] +>multiRobotB : MultiSkilledRobot [nameMB] = getMultiRobotB(); ->[nameMB] = getMultiRobotB() : [string, [string, string]] +>[nameMB] = getMultiRobotB() : MultiSkilledRobot >[nameMB] : [string] >nameMB : string ->getMultiRobotB() : [string, [string, string]] ->getMultiRobotB : () => [string, [string, string]] +>getMultiRobotB() : MultiSkilledRobot +>getMultiRobotB : () => MultiSkilledRobot [nameMB] = ["trimmer", ["trimming", "edging"]]; >[nameMB] = ["trimmer", ["trimming", "edging"]] : [string, string[]] @@ -157,21 +157,21 @@ let multiRobotAInfo: (string | [string, string])[]; >"edging" : "edging" [numberB, nameB, skillB] = robotB; ->[numberB, nameB, skillB] = robotB : [number, string, string] +>[numberB, nameB, skillB] = robotB : Robot >[numberB, nameB, skillB] : [number, string, string] >numberB : number >nameB : string >skillB : string ->robotB : [number, string, string] +>robotB : Robot [numberB, nameB, skillB] = getRobotB(); ->[numberB, nameB, skillB] = getRobotB() : [number, string, string] +>[numberB, nameB, skillB] = getRobotB() : Robot >[numberB, nameB, skillB] : [number, string, string] >numberB : number >nameB : string >skillB : string ->getRobotB() : [number, string, string] ->getRobotB : () => [number, string, string] +>getRobotB() : Robot +>getRobotB : () => Robot [numberB, nameB, skillB] = [2, "trimmer", "trimming"]; >[numberB, nameB, skillB] = [2, "trimmer", "trimming"] : [number, string, string] @@ -185,23 +185,23 @@ let multiRobotAInfo: (string | [string, string])[]; >"trimming" : "trimming" [nameMB, [primarySkillB, secondarySkillB]] = multiRobotB; ->[nameMB, [primarySkillB, secondarySkillB]] = multiRobotB : [string, [string, string]] +>[nameMB, [primarySkillB, secondarySkillB]] = multiRobotB : MultiSkilledRobot >[nameMB, [primarySkillB, secondarySkillB]] : [string, [string, string]] >nameMB : string >[primarySkillB, secondarySkillB] : [string, string] >primarySkillB : string >secondarySkillB : string ->multiRobotB : [string, [string, string]] +>multiRobotB : MultiSkilledRobot [nameMB, [primarySkillB, secondarySkillB]] = getMultiRobotB(); ->[nameMB, [primarySkillB, secondarySkillB]] = getMultiRobotB() : [string, [string, string]] +>[nameMB, [primarySkillB, secondarySkillB]] = getMultiRobotB() : MultiSkilledRobot >[nameMB, [primarySkillB, secondarySkillB]] : [string, [string, string]] >nameMB : string >[primarySkillB, secondarySkillB] : [string, string] >primarySkillB : string >secondarySkillB : string ->getMultiRobotB() : [string, [string, string]] ->getMultiRobotB : () => [string, [string, string]] +>getMultiRobotB() : MultiSkilledRobot +>getMultiRobotB : () => MultiSkilledRobot [nameMB, [primarySkillB, secondarySkillB]] = ["trimmer", ["trimming", "edging"]]; >[nameMB, [primarySkillB, secondarySkillB]] = ["trimmer", ["trimming", "edging"]] : [string, [string, string]] @@ -217,48 +217,48 @@ let multiRobotAInfo: (string | [string, string])[]; >"edging" : "edging" [numberB, ...robotAInfo] = robotB; ->[numberB, ...robotAInfo] = robotB : [number, string, string] +>[numberB, ...robotAInfo] = robotB : Robot >[numberB, ...robotAInfo] : [number, ...(string | number)[]] >numberB : number >...robotAInfo : string | number >robotAInfo : (string | number)[] ->robotB : [number, string, string] +>robotB : Robot [numberB, ...robotAInfo] = getRobotB(); ->[numberB, ...robotAInfo] = getRobotB() : [number, string, string] +>[numberB, ...robotAInfo] = getRobotB() : Robot >[numberB, ...robotAInfo] : [number, ...(string | number)[]] >numberB : number >...robotAInfo : string | number >robotAInfo : (string | number)[] ->getRobotB() : [number, string, string] ->getRobotB : () => [number, string, string] +>getRobotB() : Robot +>getRobotB : () => Robot [numberB, ...robotAInfo] = [2, "trimmer", "trimming"]; ->[numberB, ...robotAInfo] = [2, "trimmer", "trimming"] : [number, string, string] +>[numberB, ...robotAInfo] = [2, "trimmer", "trimming"] : Robot >[numberB, ...robotAInfo] : [number, ...(string | number)[]] >numberB : number >...robotAInfo : string | number >robotAInfo : (string | number)[] ->[2, "trimmer", "trimming"] : [number, string, string] +>[2, "trimmer", "trimming"] : Robot >[2, "trimmer", "trimming"] : [number, string, string] >2 : 2 >"trimmer" : "trimmer" >"trimming" : "trimming" [...multiRobotAInfo] = multiRobotA; ->[...multiRobotAInfo] = multiRobotA : [string, [string, string]] +>[...multiRobotAInfo] = multiRobotA : MultiSkilledRobot >[...multiRobotAInfo] : (string | [string, string])[] >...multiRobotAInfo : string | [string, string] >multiRobotAInfo : (string | [string, string])[] ->multiRobotA : [string, [string, string]] +>multiRobotA : MultiSkilledRobot [...multiRobotAInfo] = getMultiRobotB(); ->[...multiRobotAInfo] = getMultiRobotB() : [string, [string, string]] +>[...multiRobotAInfo] = getMultiRobotB() : MultiSkilledRobot >[...multiRobotAInfo] : (string | [string, string])[] >...multiRobotAInfo : string | [string, string] >multiRobotAInfo : (string | [string, string])[] ->getMultiRobotB() : [string, [string, string]] ->getMultiRobotB : () => [string, [string, string]] +>getMultiRobotB() : MultiSkilledRobot +>getMultiRobotB : () => MultiSkilledRobot [...multiRobotAInfo] = ["trimmer", ["trimming", "edging"]]; >[...multiRobotAInfo] = ["trimmer", ["trimming", "edging"]] : (string | [string, string])[] @@ -285,15 +285,15 @@ if (nameA == nameB) { } function getRobotB() { ->getRobotB : () => [number, string, string] +>getRobotB : () => Robot return robotB; ->robotB : [number, string, string] +>robotB : Robot } function getMultiRobotB() { ->getMultiRobotB : () => [string, [string, string]] +>getMultiRobotB : () => MultiSkilledRobot return multiRobotB; ->multiRobotB : [string, [string, string]] +>multiRobotB : MultiSkilledRobot } diff --git a/tests/baselines/reference/sourceMapValidationDestructuringVariableStatementArrayBindingPatternDefaultValues.types b/tests/baselines/reference/sourceMapValidationDestructuringVariableStatementArrayBindingPatternDefaultValues.types index 7e4ae19d394..0bdf495f09e 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringVariableStatementArrayBindingPatternDefaultValues.types +++ b/tests/baselines/reference/sourceMapValidationDestructuringVariableStatementArrayBindingPatternDefaultValues.types @@ -7,17 +7,17 @@ declare var console: { >msg : string } type Robot = [number, string, string]; ->Robot : [number, string, string] +>Robot : Robot var robotA: Robot = [1, "mower", "mowing"]; ->robotA : [number, string, string] +>robotA : Robot >[1, "mower", "mowing"] : [number, string, string] >1 : 1 >"mower" : "mower" >"mowing" : "mowing" var robotB: Robot = [2, "trimmer", "trimming"]; ->robotB : [number, string, string] +>robotB : Robot >[2, "trimmer", "trimming"] : [number, string, string] >2 : 2 >"trimmer" : "trimmer" @@ -27,13 +27,13 @@ let [, nameA = "noName"] = robotA; > : undefined >nameA : string >"noName" : "noName" ->robotA : [number, string, string] +>robotA : Robot let [numberB = -1] = robotB; >numberB : number >-1 : -1 >1 : 1 ->robotB : [number, string, string] +>robotB : Robot let [numberA2 = -1, nameA2 = "noName", skillA2 = "noSkill"] = robotA; >numberA2 : number @@ -43,7 +43,7 @@ let [numberA2 = -1, nameA2 = "noName", skillA2 = "noSkill"] = robotA; >"noName" : "noName" >skillA2 : string >"noSkill" : "noSkill" ->robotA : [number, string, string] +>robotA : Robot let [numberC2 = -1] = [3, "edging", "Trimming edges"]; >numberC2 : number @@ -72,7 +72,7 @@ let [numberA3 = -1, ...robotAInfo] = robotA; >-1 : -1 >1 : 1 >robotAInfo : [string, string] ->robotA : [number, string, string] +>robotA : Robot if (nameA == nameA2) { >nameA == nameA2 : boolean diff --git a/tests/baselines/reference/sourceMapValidationDestructuringVariableStatementArrayBindingPatternDefaultValues2.types b/tests/baselines/reference/sourceMapValidationDestructuringVariableStatementArrayBindingPatternDefaultValues2.types index 3781d10d069..44fbba0b1ad 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringVariableStatementArrayBindingPatternDefaultValues2.types +++ b/tests/baselines/reference/sourceMapValidationDestructuringVariableStatementArrayBindingPatternDefaultValues2.types @@ -7,10 +7,10 @@ declare var console: { >msg : string } type MultiSkilledRobot = [string, string[]]; ->MultiSkilledRobot : [string, string[]] +>MultiSkilledRobot : MultiSkilledRobot var multiRobotA: MultiSkilledRobot = ["mower", ["mowing", ""]]; ->multiRobotA : [string, string[]] +>multiRobotA : MultiSkilledRobot >["mower", ["mowing", ""]] : [string, string[]] >"mower" : "mower" >["mowing", ""] : string[] @@ -18,7 +18,7 @@ var multiRobotA: MultiSkilledRobot = ["mower", ["mowing", ""]]; >"" : "" var multiRobotB: MultiSkilledRobot = ["trimmer", ["trimming", "edging"]]; ->multiRobotB : [string, string[]] +>multiRobotB : MultiSkilledRobot >["trimmer", ["trimming", "edging"]] : [string, string[]] >"trimmer" : "trimmer" >["trimming", "edging"] : string[] @@ -31,12 +31,12 @@ let [, skillA = ["noSkill", "noSkill"]] = multiRobotA; >["noSkill", "noSkill"] : string[] >"noSkill" : "noSkill" >"noSkill" : "noSkill" ->multiRobotA : [string, string[]] +>multiRobotA : MultiSkilledRobot let [nameMB = "noName" ] = multiRobotB; >nameMB : string >"noName" : "noName" ->multiRobotB : [string, string[]] +>multiRobotB : MultiSkilledRobot let [nameMA = "noName", [primarySkillA = "noSkill", secondarySkillA = "noSkill"] = ["noSkill", "noSkill"]] = multiRobotA; >nameMA : string @@ -48,7 +48,7 @@ let [nameMA = "noName", [primarySkillA = "noSkill", secondarySkillA = "noSkill"] >["noSkill", "noSkill"] : [string, string] >"noSkill" : "noSkill" >"noSkill" : "noSkill" ->multiRobotA : [string, string[]] +>multiRobotA : MultiSkilledRobot let [nameMC = "noName" ] = ["roomba", ["vaccum", "mopping"]]; >nameMC : string diff --git a/tests/baselines/reference/sourceMapValidationDestructuringVariableStatementArrayBindingPatternDefaultValues3.types b/tests/baselines/reference/sourceMapValidationDestructuringVariableStatementArrayBindingPatternDefaultValues3.types index 2f9d1dac6e3..8968f49732e 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringVariableStatementArrayBindingPatternDefaultValues3.types +++ b/tests/baselines/reference/sourceMapValidationDestructuringVariableStatementArrayBindingPatternDefaultValues3.types @@ -7,27 +7,27 @@ declare var console: { >msg : any } type Robot = [number, string, string]; ->Robot : [number, string, string] +>Robot : Robot type MultiSkilledRobot = [string, string[]]; ->MultiSkilledRobot : [string, string[]] +>MultiSkilledRobot : MultiSkilledRobot var robotA: Robot = [1, "mower", "mowing"]; ->robotA : [number, string, string] +>robotA : Robot >[1, "mower", "mowing"] : [number, string, string] >1 : 1 >"mower" : "mower" >"mowing" : "mowing" var robotB: Robot = [2, "trimmer", "trimming"]; ->robotB : [number, string, string] +>robotB : Robot >[2, "trimmer", "trimming"] : [number, string, string] >2 : 2 >"trimmer" : "trimmer" >"trimming" : "trimming" var multiRobotA: MultiSkilledRobot = ["mower", ["mowing", ""]]; ->multiRobotA : [string, string[]] +>multiRobotA : MultiSkilledRobot >["mower", ["mowing", ""]] : [string, string[]] >"mower" : "mower" >["mowing", ""] : string[] @@ -35,7 +35,7 @@ var multiRobotA: MultiSkilledRobot = ["mower", ["mowing", ""]]; >"" : "" var multiRobotB: MultiSkilledRobot = ["trimmer", ["trimming", "edging"]]; ->multiRobotB : [string, string[]] +>multiRobotB : MultiSkilledRobot >["trimmer", ["trimming", "edging"]] : [string, string[]] >"trimmer" : "trimmer" >["trimming", "edging"] : string[] @@ -61,23 +61,23 @@ let multiRobotAInfo: (string | string[])[]; >multiRobotAInfo : (string | string[])[] [, nameA = "helloNoName"] = robotA; ->[, nameA = "helloNoName"] = robotA : [number, string, string] +>[, nameA = "helloNoName"] = robotA : Robot >[, nameA = "helloNoName"] : [undefined, string] > : undefined >nameA = "helloNoName" : "helloNoName" >nameA : string >"helloNoName" : "helloNoName" ->robotA : [number, string, string] +>robotA : Robot [, nameB = "helloNoName"] = getRobotB(); ->[, nameB = "helloNoName"] = getRobotB() : [number, string, string] +>[, nameB = "helloNoName"] = getRobotB() : Robot >[, nameB = "helloNoName"] : [undefined, string] > : undefined >nameB = "helloNoName" : "helloNoName" >nameB : string >"helloNoName" : "helloNoName" ->getRobotB() : [number, string, string] ->getRobotB : () => [number, string, string] +>getRobotB() : Robot +>getRobotB : () => Robot [, nameB = "helloNoName"] = [2, "trimmer", "trimming"]; >[, nameB = "helloNoName"] = [2, "trimmer", "trimming"] : [number, string, string] @@ -92,23 +92,23 @@ let multiRobotAInfo: (string | string[])[]; >"trimming" : "trimming" [, multiSkillB = []] = multiRobotB; ->[, multiSkillB = []] = multiRobotB : [string, string[]] +>[, multiSkillB = []] = multiRobotB : MultiSkilledRobot >[, multiSkillB = []] : [undefined, undefined[]] > : undefined >multiSkillB = [] : undefined[] >multiSkillB : string[] >[] : undefined[] ->multiRobotB : [string, string[]] +>multiRobotB : MultiSkilledRobot [, multiSkillB = []] = getMultiRobotB(); ->[, multiSkillB = []] = getMultiRobotB() : [string, string[]] +>[, multiSkillB = []] = getMultiRobotB() : MultiSkilledRobot >[, multiSkillB = []] : [undefined, undefined[]] > : undefined >multiSkillB = [] : undefined[] >multiSkillB : string[] >[] : undefined[] ->getMultiRobotB() : [string, string[]] ->getMultiRobotB : () => [string, string[]] +>getMultiRobotB() : MultiSkilledRobot +>getMultiRobotB : () => MultiSkilledRobot [, multiSkillB = []] = ["roomba", ["vaccum", "mopping"]]; >[, multiSkillB = []] = ["roomba", ["vaccum", "mopping"]] : [string, string[]] @@ -124,23 +124,23 @@ let multiRobotAInfo: (string | string[])[]; >"mopping" : "mopping" [numberB = -1] = robotB; ->[numberB = -1] = robotB : [number, string, string] +>[numberB = -1] = robotB : Robot >[numberB = -1] : [number] >numberB = -1 : -1 >numberB : number >-1 : -1 >1 : 1 ->robotB : [number, string, string] +>robotB : Robot [numberB = -1] = getRobotB(); ->[numberB = -1] = getRobotB() : [number, string, string] +>[numberB = -1] = getRobotB() : Robot >[numberB = -1] : [number] >numberB = -1 : -1 >numberB : number >-1 : -1 >1 : 1 ->getRobotB() : [number, string, string] ->getRobotB : () => [number, string, string] +>getRobotB() : Robot +>getRobotB : () => Robot [numberB = -1] = [2, "trimmer", "trimming"]; >[numberB = -1] = [2, "trimmer", "trimming"] : [number, string, string] @@ -155,21 +155,21 @@ let multiRobotAInfo: (string | string[])[]; >"trimming" : "trimming" [nameMB = "helloNoName"] = multiRobotB; ->[nameMB = "helloNoName"] = multiRobotB : [string, string[]] +>[nameMB = "helloNoName"] = multiRobotB : MultiSkilledRobot >[nameMB = "helloNoName"] : [string] >nameMB = "helloNoName" : "helloNoName" >nameMB : string >"helloNoName" : "helloNoName" ->multiRobotB : [string, string[]] +>multiRobotB : MultiSkilledRobot [nameMB = "helloNoName"] = getMultiRobotB(); ->[nameMB = "helloNoName"] = getMultiRobotB() : [string, string[]] +>[nameMB = "helloNoName"] = getMultiRobotB() : MultiSkilledRobot >[nameMB = "helloNoName"] : [string] >nameMB = "helloNoName" : "helloNoName" >nameMB : string >"helloNoName" : "helloNoName" ->getMultiRobotB() : [string, string[]] ->getMultiRobotB : () => [string, string[]] +>getMultiRobotB() : MultiSkilledRobot +>getMultiRobotB : () => MultiSkilledRobot [nameMB = "helloNoName"] = ["trimmer", ["trimming", "edging"]]; >[nameMB = "helloNoName"] = ["trimmer", ["trimming", "edging"]] : [string, string[]] @@ -184,7 +184,7 @@ let multiRobotAInfo: (string | string[])[]; >"edging" : "edging" [numberB = -1, nameB = "helloNoName", skillB = "noSkill"] = robotB; ->[numberB = -1, nameB = "helloNoName", skillB = "noSkill"] = robotB : [number, string, string] +>[numberB = -1, nameB = "helloNoName", skillB = "noSkill"] = robotB : Robot >[numberB = -1, nameB = "helloNoName", skillB = "noSkill"] : [number, string, string] >numberB = -1 : -1 >numberB : number @@ -196,10 +196,10 @@ let multiRobotAInfo: (string | string[])[]; >skillB = "noSkill" : "noSkill" >skillB : string >"noSkill" : "noSkill" ->robotB : [number, string, string] +>robotB : Robot [numberB = -1, nameB = "helloNoName", skillB = "noSkill"] = getRobotB(); ->[numberB = -1, nameB = "helloNoName", skillB = "noSkill"] = getRobotB() : [number, string, string] +>[numberB = -1, nameB = "helloNoName", skillB = "noSkill"] = getRobotB() : Robot >[numberB = -1, nameB = "helloNoName", skillB = "noSkill"] : [number, string, string] >numberB = -1 : -1 >numberB : number @@ -211,8 +211,8 @@ let multiRobotAInfo: (string | string[])[]; >skillB = "noSkill" : "noSkill" >skillB : string >"noSkill" : "noSkill" ->getRobotB() : [number, string, string] ->getRobotB : () => [number, string, string] +>getRobotB() : Robot +>getRobotB : () => Robot [numberB = -1, nameB = "helloNoName", skillB = "noSkill"] = [2, "trimmer", "trimming"]; >[numberB = -1, nameB = "helloNoName", skillB = "noSkill"] = [2, "trimmer", "trimming"] : [number, string, string] @@ -233,7 +233,7 @@ let multiRobotAInfo: (string | string[])[]; >"trimming" : "trimming" [nameMB = "helloNoName", [primarySkillB = "noSkill", secondarySkillB = "noSkill"] = []] = multiRobotB; ->[nameMB = "helloNoName", [primarySkillB = "noSkill", secondarySkillB = "noSkill"] = []] = multiRobotB : [string, string[]] +>[nameMB = "helloNoName", [primarySkillB = "noSkill", secondarySkillB = "noSkill"] = []] = multiRobotB : MultiSkilledRobot >[nameMB = "helloNoName", [primarySkillB = "noSkill", secondarySkillB = "noSkill"] = []] : [string, []] >nameMB = "helloNoName" : "helloNoName" >nameMB : string @@ -247,10 +247,10 @@ let multiRobotAInfo: (string | string[])[]; >secondarySkillB : string >"noSkill" : "noSkill" >[] : [] ->multiRobotB : [string, string[]] +>multiRobotB : MultiSkilledRobot [nameMB = "helloNoName", [primarySkillB = "noSkill", secondarySkillB = "noSkill"] = []] = getMultiRobotB(); ->[nameMB = "helloNoName", [primarySkillB = "noSkill", secondarySkillB = "noSkill"] = []] = getMultiRobotB() : [string, string[]] +>[nameMB = "helloNoName", [primarySkillB = "noSkill", secondarySkillB = "noSkill"] = []] = getMultiRobotB() : MultiSkilledRobot >[nameMB = "helloNoName", [primarySkillB = "noSkill", secondarySkillB = "noSkill"] = []] : [string, []] >nameMB = "helloNoName" : "helloNoName" >nameMB : string @@ -264,8 +264,8 @@ let multiRobotAInfo: (string | string[])[]; >secondarySkillB : string >"noSkill" : "noSkill" >[] : [] ->getMultiRobotB() : [string, string[]] ->getMultiRobotB : () => [string, string[]] +>getMultiRobotB() : MultiSkilledRobot +>getMultiRobotB : () => MultiSkilledRobot [nameMB = "helloNoName", [primarySkillB = "noSkill", secondarySkillB = "noSkill"] = []] = >[nameMB = "helloNoName", [primarySkillB = "noSkill", secondarySkillB = "noSkill"] = []] = ["trimmer", ["trimming", "edging"]] : [string, [string, string]] @@ -291,7 +291,7 @@ let multiRobotAInfo: (string | string[])[]; >"edging" : "edging" [numberB = -1, ...robotAInfo] = robotB; ->[numberB = -1, ...robotAInfo] = robotB : [number, string, string] +>[numberB = -1, ...robotAInfo] = robotB : Robot >[numberB = -1, ...robotAInfo] : [number, ...(string | number)[]] >numberB = -1 : -1 >numberB : number @@ -299,10 +299,10 @@ let multiRobotAInfo: (string | string[])[]; >1 : 1 >...robotAInfo : string | number >robotAInfo : (string | number)[] ->robotB : [number, string, string] +>robotB : Robot [numberB = -1, ...robotAInfo] = getRobotB(); ->[numberB = -1, ...robotAInfo] = getRobotB() : [number, string, string] +>[numberB = -1, ...robotAInfo] = getRobotB() : Robot >[numberB = -1, ...robotAInfo] : [number, ...(string | number)[]] >numberB = -1 : -1 >numberB : number @@ -310,11 +310,11 @@ let multiRobotAInfo: (string | string[])[]; >1 : 1 >...robotAInfo : string | number >robotAInfo : (string | number)[] ->getRobotB() : [number, string, string] ->getRobotB : () => [number, string, string] +>getRobotB() : Robot +>getRobotB : () => Robot [numberB = -1, ...robotAInfo] = [2, "trimmer", "trimming"]; ->[numberB = -1, ...robotAInfo] = [2, "trimmer", "trimming"] : [number, string, string] +>[numberB = -1, ...robotAInfo] = [2, "trimmer", "trimming"] : Robot >[numberB = -1, ...robotAInfo] : [number, ...(string | number)[]] >numberB = -1 : -1 >numberB : number @@ -322,7 +322,7 @@ let multiRobotAInfo: (string | string[])[]; >1 : 1 >...robotAInfo : string | number >robotAInfo : (string | number)[] ->[2, "trimmer", "trimming"] : [number, string, string] +>[2, "trimmer", "trimming"] : Robot >[2, "trimmer", "trimming"] : [number, string, string] >2 : 2 >"trimmer" : "trimmer" @@ -342,15 +342,15 @@ if (nameA == nameB) { } function getRobotB() { ->getRobotB : () => [number, string, string] +>getRobotB : () => Robot return robotB; ->robotB : [number, string, string] +>robotB : Robot } function getMultiRobotB() { ->getMultiRobotB : () => [string, string[]] +>getMultiRobotB : () => MultiSkilledRobot return multiRobotB; ->multiRobotB : [string, string[]] +>multiRobotB : MultiSkilledRobot } diff --git a/tests/baselines/reference/specedNoStackBlown.types b/tests/baselines/reference/specedNoStackBlown.types index 654f98941df..f2ef490fa80 100644 --- a/tests/baselines/reference/specedNoStackBlown.types +++ b/tests/baselines/reference/specedNoStackBlown.types @@ -26,10 +26,10 @@ type ErrorMsg = >field : string export type Spec = [Predicate, ErrorMsg]; ->Spec : [Predicate, ErrorMsg] +>Spec : Spec export type SpecArray = Array>; ->SpecArray : [Predicate, ErrorMsg][] +>SpecArray : Spec[] export type SpecFunction = [INPUT] extends [ReadonlyArray] >SpecFunction : SpecFunction diff --git a/tests/baselines/reference/spreadBooleanRespectsFreshness.types b/tests/baselines/reference/spreadBooleanRespectsFreshness.types index c607422b062..cd20dc31944 100644 --- a/tests/baselines/reference/spreadBooleanRespectsFreshness.types +++ b/tests/baselines/reference/spreadBooleanRespectsFreshness.types @@ -7,7 +7,7 @@ type FooBase = string | false; >false : false type FooArray = FooBase[]; ->FooArray : FooBase[] +>FooArray : FooArray declare let foo1: Foo; >foo1 : Foo @@ -20,13 +20,13 @@ foo1 = [...Array.isArray(foo2) ? foo2 : [foo2]]; >foo1 : Foo >[...Array.isArray(foo2) ? foo2 : [foo2]] : FooBase[] >...Array.isArray(foo2) ? foo2 : [foo2] : FooBase ->Array.isArray(foo2) ? foo2 : [foo2] : FooBase[] +>Array.isArray(foo2) ? foo2 : [foo2] : FooArray >Array.isArray(foo2) : boolean >Array.isArray : (arg: any) => arg is any[] >Array : ArrayConstructor >isArray : (arg: any) => arg is any[] >foo2 : Foo ->foo2 : FooBase[] +>foo2 : FooArray >[foo2] : FooBase[] >foo2 : FooBase diff --git a/tests/baselines/reference/spreadTypeVariable.types b/tests/baselines/reference/spreadTypeVariable.types index c5de712fb19..0e836355d42 100644 --- a/tests/baselines/reference/spreadTypeVariable.types +++ b/tests/baselines/reference/spreadTypeVariable.types @@ -37,7 +37,7 @@ function f4(arg: T) { } function f5(arg: T) { ->f5 : (arg: T) => T +>f5 : (arg: T) => T >key : string >arg : T diff --git a/tests/baselines/reference/tupleTypes.errors.txt b/tests/baselines/reference/tupleTypes.errors.txt index af76c872a6f..a3c2fc00eb4 100644 --- a/tests/baselines/reference/tupleTypes.errors.txt +++ b/tests/baselines/reference/tupleTypes.errors.txt @@ -9,7 +9,7 @@ tests/cases/compiler/tupleTypes.ts(18,1): error TS2322: Type '[number, string, n Type '3' is not assignable to type '2'. tests/cases/compiler/tupleTypes.ts(35,14): error TS2493: Tuple type '[number, string]' of length '2' has no element at index '2'. tests/cases/compiler/tupleTypes.ts(36,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'tt2' must be of type 'undefined', but here has type 'string | number'. -tests/cases/compiler/tupleTypes.ts(41,1): error TS2322: Type '[]' is not assignable to type '[number, string]'. +tests/cases/compiler/tupleTypes.ts(41,1): error TS2739: Type '[]' is missing the following properties from type '[number, string]': 0, 1 tests/cases/compiler/tupleTypes.ts(47,1): error TS2322: Type '[number, string]' is not assignable to type 'number[]'. Type 'string | number' is not assignable to type 'number'. Type 'string' is not assignable to type 'number'. @@ -87,7 +87,7 @@ tests/cases/compiler/tupleTypes.ts(51,1): error TS2322: Type '[number, {}]' is n tt = [undefined, undefined]; tt = []; // Error ~~ -!!! error TS2322: Type '[]' is not assignable to type '[number, string]'. +!!! error TS2739: Type '[]' is missing the following properties from type '[number, string]': 0, 1 var a: number[]; var a1: [number, string]; diff --git a/tests/baselines/reference/typeAliases.types b/tests/baselines/reference/typeAliases.types index 8790c043adf..3eff23307dc 100644 --- a/tests/baselines/reference/typeAliases.types +++ b/tests/baselines/reference/typeAliases.types @@ -183,22 +183,22 @@ f15(E.x).toLowerCase(); >toLowerCase : () => string type StringAndBoolean = [string, boolean] ->StringAndBoolean : [string, boolean] +>StringAndBoolean : StringAndBoolean declare function f16(s: StringAndBoolean): string; ->f16 : (s: [string, boolean]) => string ->s : [string, boolean] +>f16 : (s: StringAndBoolean) => string +>s : StringAndBoolean var x: [string, boolean]; >x : [string, boolean] f16(x); >f16(x) : string ->f16 : (s: [string, boolean]) => string +>f16 : (s: StringAndBoolean) => string >x : [string, boolean] var y: StringAndBoolean = ["1", false]; ->y : [string, boolean] +>y : StringAndBoolean >["1", false] : [string, false] >"1" : "1" >false : false @@ -207,7 +207,7 @@ y[0].toLowerCase(); >y[0].toLowerCase() : string >y[0].toLowerCase : () => string >y[0] : string ->y : [string, boolean] +>y : StringAndBoolean >0 : 0 >toLowerCase : () => string diff --git a/tests/baselines/reference/typeGuardNarrowsIndexedAccessOfKnownProperty.types b/tests/baselines/reference/typeGuardNarrowsIndexedAccessOfKnownProperty.types index 4e3d2e0743e..1f36901d437 100644 --- a/tests/baselines/reference/typeGuardNarrowsIndexedAccessOfKnownProperty.types +++ b/tests/baselines/reference/typeGuardNarrowsIndexedAccessOfKnownProperty.types @@ -208,10 +208,10 @@ interface Y { } type A = ["aa", number]; ->A : ["aa", number] +>A : A type B = ["bb", string]; ->B : ["bb", string] +>B : B type Z = X | Y; >Z : Z @@ -271,7 +271,7 @@ function check(z: Z, c: C) { var aa: number = c[1] // should be number >aa : number >c[1] : number ->c : ["aa", number] +>c : A >1 : 1 break; @@ -281,7 +281,7 @@ function check(z: Z, c: C) { var bb: string = c[1] // should be string >bb : string >c[1] : string ->c : ["bb", string] +>c : B >1 : 1 break; diff --git a/tests/baselines/reference/typeInferenceLiteralUnion.types b/tests/baselines/reference/typeInferenceLiteralUnion.types index de4637c52c5..84a65ccbc53 100644 --- a/tests/baselines/reference/typeInferenceLiteralUnion.types +++ b/tests/baselines/reference/typeInferenceLiteralUnion.types @@ -56,11 +56,11 @@ export function extent(array: Array): [T | Pri let extentMixed: [Primitive | NumCoercible, Primitive | NumCoercible] | [undefined, undefined]; ->extentMixed : [undefined, undefined] | [string | number | boolean | Date | NumCoercible, string | number | boolean | Date | NumCoercible] +>extentMixed : [string | number | boolean | Date | NumCoercible, string | number | boolean | Date | NumCoercible] | [undefined, undefined] extentMixed = extent([new NumCoercible(10), 13, '12', true]); >extentMixed = extent([new NumCoercible(10), 13, '12', true]) : [undefined, undefined] | [string | number | boolean | Date | NumCoercible, string | number | boolean | Date | NumCoercible] ->extentMixed : [undefined, undefined] | [string | number | boolean | Date | NumCoercible, string | number | boolean | Date | NumCoercible] +>extentMixed : [string | number | boolean | Date | NumCoercible, string | number | boolean | Date | NumCoercible] | [undefined, undefined] >extent([new NumCoercible(10), 13, '12', true]) : [undefined, undefined] | [string | number | boolean | Date | NumCoercible, string | number | boolean | Date | NumCoercible] >extent : (array: (string | number | boolean | Date | T)[]) => [string | number | boolean | Date | T, string | number | boolean | Date | T] | [undefined, undefined] >[new NumCoercible(10), 13, '12', true] : (string | number | true | NumCoercible)[] diff --git a/tests/baselines/reference/typePredicateStructuralMatch.types b/tests/baselines/reference/typePredicateStructuralMatch.types index b4f5dbea3f1..48cca07cf10 100644 --- a/tests/baselines/reference/typePredicateStructuralMatch.types +++ b/tests/baselines/reference/typePredicateStructuralMatch.types @@ -2,25 +2,25 @@ // Repro from #12235 getResults1([]); ->getResults1([]) : Result[] ->getResults1 : (value: Result[] | { data: Result[]; }) => Result[] +>getResults1([]) : Results +>getResults1 : (value: Results | { data: Results; }) => Results >[] : undefined[] getResults1({data: []}); ->getResults1({data: []}) : Result[] ->getResults1 : (value: Result[] | { data: Result[]; }) => Result[] +>getResults1({data: []}) : Results +>getResults1 : (value: Results | { data: Results; }) => Results >{data: []} : { data: undefined[]; } >data : undefined[] >[] : undefined[] getResults2([]); ->getResults2([]) : Result[] ->getResults2 : (value: Result[] | { data: Result[]; }) => Result[] +>getResults2([]) : Results +>getResults2 : (value: Results | { data: Results; }) => Results >[] : undefined[] getResults2({data: []}); ->getResults2({data: []}) : Result[] ->getResults2 : (value: Result[] | { data: Result[]; }) => Result[] +>getResults2({data: []}) : Results +>getResults2 : (value: Results | { data: Results; }) => Results >{data: []} : { data: undefined[]; } >data : undefined[] >[] : undefined[] @@ -30,7 +30,7 @@ type Result = { value: string }; >value : string type Results = Result[]; ->Results : Result[] +>Results : Results function isResponseInData(value: T | { data: T}): value is { data: T } { >isResponseInData : (value: T | { data: T; }) => value is { data: T; } @@ -47,19 +47,19 @@ function isResponseInData(value: T | { data: T}): value is { data: T } { } function getResults1(value: Results | { data: Results }): Results { ->getResults1 : (value: Result[] | { data: Result[]; }) => Result[] ->value : Result[] | { data: Result[]; } ->data : Result[] +>getResults1 : (value: Results | { data: Results; }) => Results +>value : Results | { data: Results; } +>data : Results return isResponseInData(value) ? value.data : value; ->isResponseInData(value) ? value.data : value : Result[] +>isResponseInData(value) ? value.data : value : Results >isResponseInData(value) : boolean >isResponseInData : (value: T | { data: T; }) => value is { data: T; } ->value : Result[] | { data: Result[]; } ->value.data : Result[] ->value : { data: Result[]; } ->data : Result[] ->value : Result[] +>value : Results | { data: Results; } +>value.data : Results +>value : { data: Results; } +>data : Results +>value : Results } function isPlainResponse(value: T | { data: T}): value is T { @@ -77,17 +77,17 @@ function isPlainResponse(value: T | { data: T}): value is T { } function getResults2(value: Results | { data: Results }): Results { ->getResults2 : (value: Result[] | { data: Result[]; }) => Result[] ->value : Result[] | { data: Result[]; } ->data : Result[] +>getResults2 : (value: Results | { data: Results; }) => Results +>value : Results | { data: Results; } +>data : Results return isPlainResponse(value) ? value : value.data; ->isPlainResponse(value) ? value : value.data : Result[] +>isPlainResponse(value) ? value : value.data : Results >isPlainResponse(value) : boolean >isPlainResponse : (value: T | { data: T; }) => value is T ->value : Result[] | { data: Result[]; } ->value : Result[] ->value.data : Result[] ->value : { data: Result[]; } ->data : Result[] +>value : Results | { data: Results; } +>value : Results +>value.data : Results +>value : { data: Results; } +>data : Results } diff --git a/tests/baselines/reference/unionTypeWithLeadingOperator.types b/tests/baselines/reference/unionTypeWithLeadingOperator.types index 930ff71f3f7..63d2e7c018d 100644 --- a/tests/baselines/reference/unionTypeWithLeadingOperator.types +++ b/tests/baselines/reference/unionTypeWithLeadingOperator.types @@ -12,7 +12,7 @@ type B = >type : "DECREMENT" type C = [| 0 | 1, | "foo" | "bar"]; ->C : [0 | 1, "foo" | "bar"] +>C : C export type D = >D : D diff --git a/tests/baselines/reference/unionsOfTupleTypes1.errors.txt b/tests/baselines/reference/unionsOfTupleTypes1.errors.txt index da997e988ee..344bd49f54f 100644 --- a/tests/baselines/reference/unionsOfTupleTypes1.errors.txt +++ b/tests/baselines/reference/unionsOfTupleTypes1.errors.txt @@ -1,10 +1,10 @@ -tests/cases/conformance/types/tuple/unionsOfTupleTypes1.ts(8,15): error TS2493: Tuple type '[string, number]' of length '2' has no element at index '2'. +tests/cases/conformance/types/tuple/unionsOfTupleTypes1.ts(8,15): error TS2493: Tuple type 'T1' of length '2' has no element at index '2'. tests/cases/conformance/types/tuple/unionsOfTupleTypes1.ts(13,15): error TS2339: Property '2' does not exist on type 'T2'. -tests/cases/conformance/types/tuple/unionsOfTupleTypes1.ts(27,20): error TS2493: Tuple type '[string, number]' of length '2' has no element at index '2'. +tests/cases/conformance/types/tuple/unionsOfTupleTypes1.ts(27,20): error TS2493: Tuple type 'T1' of length '2' has no element at index '2'. tests/cases/conformance/types/tuple/unionsOfTupleTypes1.ts(28,20): error TS2339: Property '2' does not exist on type 'T2'. -tests/cases/conformance/types/tuple/unionsOfTupleTypes1.ts(31,16): error TS2493: Tuple type '[string, number]' of length '2' has no element at index '2'. +tests/cases/conformance/types/tuple/unionsOfTupleTypes1.ts(31,16): error TS2493: Tuple type 'T1' of length '2' has no element at index '2'. tests/cases/conformance/types/tuple/unionsOfTupleTypes1.ts(32,16): error TS2339: Property '2' does not exist on type 'T2'. -tests/cases/conformance/types/tuple/unionsOfTupleTypes1.ts(37,18): error TS2493: Tuple type '[string, number]' of length '2' has no element at index '2'. +tests/cases/conformance/types/tuple/unionsOfTupleTypes1.ts(37,18): error TS2493: Tuple type 'T1' of length '2' has no element at index '2'. tests/cases/conformance/types/tuple/unionsOfTupleTypes1.ts(41,18): error TS2339: Property '2' does not exist on type 'T2'. @@ -18,7 +18,7 @@ tests/cases/conformance/types/tuple/unionsOfTupleTypes1.ts(41,18): error TS2339: type T11 = T1[1]; // number type T12 = T1[2]; // undefined ~ -!!! error TS2493: Tuple type '[string, number]' of length '2' has no element at index '2'. +!!! error TS2493: Tuple type 'T1' of length '2' has no element at index '2'. type T1N = T1[number]; // string | number type T20 = T2[0]; // string | boolean @@ -41,7 +41,7 @@ tests/cases/conformance/types/tuple/unionsOfTupleTypes1.ts(41,18): error TS2339: function f1(t1: T1, t2: T2, t3: T3, t4: T4, x: number) { let [d10, d11, d12] = t1; // string, number ~~~ -!!! error TS2493: Tuple type '[string, number]' of length '2' has no element at index '2'. +!!! error TS2493: Tuple type 'T1' of length '2' has no element at index '2'. let [d20, d21, d22] = t2; // string | boolean, number | undefined ~~~ !!! error TS2339: Property '2' does not exist on type 'T2'. @@ -49,7 +49,7 @@ tests/cases/conformance/types/tuple/unionsOfTupleTypes1.ts(41,18): error TS2339: let [d40, d41, d42] = t4; // string | boolean, number | undefined, number | undefined [d10, d11, d12] = t1; ~~~ -!!! error TS2493: Tuple type '[string, number]' of length '2' has no element at index '2'. +!!! error TS2493: Tuple type 'T1' of length '2' has no element at index '2'. [d20, d21, d22] = t2; ~~~ !!! error TS2339: Property '2' does not exist on type 'T2'. @@ -59,7 +59,7 @@ tests/cases/conformance/types/tuple/unionsOfTupleTypes1.ts(41,18): error TS2339: let t11 = t1[1]; // number let t12 = t1[2]; // undefined ~ -!!! error TS2493: Tuple type '[string, number]' of length '2' has no element at index '2'. +!!! error TS2493: Tuple type 'T1' of length '2' has no element at index '2'. let t1x = t1[x]; // string | number let t20 = t2[0]; // string | boolean let t21 = t2[1]; // number | undefined diff --git a/tests/baselines/reference/unionsOfTupleTypes1.types b/tests/baselines/reference/unionsOfTupleTypes1.types index e0867cd1045..f1142821d28 100644 --- a/tests/baselines/reference/unionsOfTupleTypes1.types +++ b/tests/baselines/reference/unionsOfTupleTypes1.types @@ -1,12 +1,12 @@ === tests/cases/conformance/types/tuple/unionsOfTupleTypes1.ts === type T1 = [string, number]; ->T1 : [string, number] +>T1 : T1 type T2 = [boolean] | [string, number]; >T2 : T2 type T3 = [string, ...number[]]; ->T3 : [string, ...number[]] +>T3 : T3 type T4 = [boolean] | [string, ...number[]]; >T4 : T4 @@ -60,10 +60,10 @@ type T4N = T4[number]; // string | number | boolean >T4N : string | number | boolean function f1(t1: T1, t2: T2, t3: T3, t4: T4, x: number) { ->f1 : (t1: [string, number], t2: T2, t3: [string, ...number[]], t4: T4, x: number) => void ->t1 : [string, number] +>f1 : (t1: T1, t2: T2, t3: T3, t4: T4, x: number) => void +>t1 : T1 >t2 : T2 ->t3 : [string, ...number[]] +>t3 : T3 >t4 : T4 >x : number @@ -71,7 +71,7 @@ function f1(t1: T1, t2: T2, t3: T3, t4: T4, x: number) { >d10 : string >d11 : number >d12 : undefined ->t1 : [string, number] +>t1 : T1 let [d20, d21, d22] = t2; // string | boolean, number | undefined >d20 : string | boolean @@ -83,7 +83,7 @@ function f1(t1: T1, t2: T2, t3: T3, t4: T4, x: number) { >d30 : string >d31 : number >d32 : number ->t3 : [string, ...number[]] +>t3 : T3 let [d40, d41, d42] = t4; // string | boolean, number | undefined, number | undefined >d40 : string | boolean @@ -92,12 +92,12 @@ function f1(t1: T1, t2: T2, t3: T3, t4: T4, x: number) { >t4 : T4 [d10, d11, d12] = t1; ->[d10, d11, d12] = t1 : [string, number] +>[d10, d11, d12] = t1 : T1 >[d10, d11, d12] : [string, number, undefined] >d10 : string >d11 : number >d12 : undefined ->t1 : [string, number] +>t1 : T1 [d20, d21, d22] = t2; >[d20, d21, d22] = t2 : T2 @@ -108,12 +108,12 @@ function f1(t1: T1, t2: T2, t3: T3, t4: T4, x: number) { >t2 : T2 [d30, d31, d32] = t3; ->[d30, d31, d32] = t3 : [string, ...number[]] +>[d30, d31, d32] = t3 : T3 >[d30, d31, d32] : [string, number, number] >d30 : string >d31 : number >d32 : number ->t3 : [string, ...number[]] +>t3 : T3 [d40, d41, d42] = t4; >[d40, d41, d42] = t4 : T4 @@ -126,25 +126,25 @@ function f1(t1: T1, t2: T2, t3: T3, t4: T4, x: number) { let t10 = t1[0]; // string >t10 : string >t1[0] : string ->t1 : [string, number] +>t1 : T1 >0 : 0 let t11 = t1[1]; // number >t11 : number >t1[1] : number ->t1 : [string, number] +>t1 : T1 >1 : 1 let t12 = t1[2]; // undefined >t12 : undefined >t1[2] : undefined ->t1 : [string, number] +>t1 : T1 >2 : 2 let t1x = t1[x]; // string | number >t1x : string | number >t1[x] : string | number ->t1 : [string, number] +>t1 : T1 >x : number let t20 = t2[0]; // string | boolean @@ -174,25 +174,25 @@ function f1(t1: T1, t2: T2, t3: T3, t4: T4, x: number) { let t30 = t3[0]; // string >t30 : string >t3[0] : string ->t3 : [string, ...number[]] +>t3 : T3 >0 : 0 let t31 = t3[1]; // number >t31 : number >t3[1] : number ->t3 : [string, ...number[]] +>t3 : T3 >1 : 1 let t32 = t3[2]; // number >t32 : number >t3[2] : number ->t3 : [string, ...number[]] +>t3 : T3 >2 : 2 let t3x = t3[x]; // string | number >t3x : string | number >t3[x] : string | number ->t3 : [string, ...number[]] +>t3 : T3 >x : number let t40 = t4[0]; // string | boolean @@ -222,7 +222,7 @@ function f1(t1: T1, t2: T2, t3: T3, t4: T4, x: number) { t1[1] = 42; >t1[1] = 42 : 42 >t1[1] : number ->t1 : [string, number] +>t1 : T1 >1 : 1 >42 : 42 @@ -236,7 +236,7 @@ function f1(t1: T1, t2: T2, t3: T3, t4: T4, x: number) { t3[1] = 42; >t3[1] = 42 : 42 >t3[1] : number ->t3 : [string, ...number[]] +>t3 : T3 >1 : 1 >42 : 42 From bf0debb883b2a07c39a43b6148a80f4d61234876 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 27 Aug 2019 07:16:51 -0400 Subject: [PATCH 045/140] Handle missing global array type --- src/compiler/checker.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e49e4492265..e403c2f964f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9620,7 +9620,8 @@ namespace ts { const target = getArrayOrTupleTargetType(node); const aliasSymbol = getAliasSymbolForTypeNode(node); const aliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol); - links.resolvedType = node.kind === SyntaxKind.TupleType && node.elementTypes.length === 0 ? target : + links.resolvedType = target === emptyGenericType ? emptyObjectType : + node.kind === SyntaxKind.TupleType && node.elementTypes.length === 0 ? target : createDeferredTypeReference(target, node, /*mapper*/ undefined, aliasSymbol, aliasTypeArguments); } return links.resolvedType; From b18c70f8c0a15328b292e4e7fe11afb14ea50f6c Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 27 Aug 2019 07:23:52 -0400 Subject: [PATCH 046/140] Fix fourslash test --- .../codeFixClassImplementInterfaceMemberTypeAlias.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cases/fourslash/codeFixClassImplementInterfaceMemberTypeAlias.ts b/tests/cases/fourslash/codeFixClassImplementInterfaceMemberTypeAlias.ts index 6fd8900d51b..8893d35b549 100644 --- a/tests/cases/fourslash/codeFixClassImplementInterfaceMemberTypeAlias.ts +++ b/tests/cases/fourslash/codeFixClassImplementInterfaceMemberTypeAlias.ts @@ -10,8 +10,8 @@ verify.codeFix({ `type MyType = [string, number]; interface I { x: MyType; test(a: MyType): void; } class C implements I { - x: [string, number]; - test(a: [string, number]): void { + x: MyType; + test(a: MyType): void { throw new Error("Method not implemented."); } }`, From d347b08a42bb705415fe8b859a69697c1d155a59 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 27 Aug 2019 13:13:58 -0700 Subject: [PATCH 047/140] Copied from old branch 1. Everything explodes! Out of stack space! 2. Results aren't used yet. 3. But call and construct use the new getSignatureFromCalls, so I expect some baseline changes after I get the infinite recursion fixed. --- src/compiler/checker.ts | 3 + src/compiler/types.ts | 1 + src/services/codefixes/inferFromUsage.ts | 85 ++++++++++++++++++++---- 3 files changed, 75 insertions(+), 14 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cfd83efeb31..1b6fee6f0de 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -524,6 +524,9 @@ namespace ts { }, getApparentType, getUnionType, + isTypeAssignableTo: (source, target) => { + return isTypeAssignableTo(source, target); + }, createAnonymousType, createSignature, createSymbol, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 2c8a882c164..6e92eba8ded 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3286,6 +3286,7 @@ namespace ts { /* @internal */ getElementTypeOfArrayType(arrayType: Type): Type | undefined; /* @internal */ createPromiseType(type: Type): Type; + /* @internal */ isTypeAssignableTo(source: Type, target: Type): boolean; /* @internal */ createAnonymousType(symbol: Symbol, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexInfo: IndexInfo | undefined, numberIndexInfo: IndexInfo | undefined): Type; /* @internal */ createSignature( declaration: SignatureDeclaration, diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index 2eb9eaca7b7..4b111dae25b 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -401,7 +401,7 @@ namespace ts.codefix { interface CallUsage { argumentTypes: Type[]; - returnType: Usage; + return_: Usage; } interface Usage { @@ -671,16 +671,17 @@ namespace ts.codefix { function inferTypeFromCallExpression(parent: CallExpression | NewExpression, usage: Usage): void { const call: CallUsage = { argumentTypes: [], - returnType: {} + return_: {} }; if (parent.arguments) { for (const argument of parent.arguments) { + // TODO: should recursively infer a usage here, right? call.argumentTypes.push(checker.getTypeAtLocation(argument)); } } - calculateUsageOfNode(parent, call.returnType); + calculateUsageOfNode(parent, call.return_); if (parent.kind === SyntaxKind.CallExpression) { (usage.calls || (usage.calls = [])).push(call); } @@ -830,6 +831,7 @@ namespace ts.codefix { } types.push(...(usage.candidateTypes || []).map(t => checker.getBaseTypeOfLiteralType(t))); + types.push(...findBuiltinType(usage)); if (usage.properties && hasCalls(usage.properties.get("then" as __String))) { const paramType = getParameterTypeFromCalls(0, usage.properties.get("then" as __String)!.calls!, /*isRestParameter*/ false)!; // TODO: GH#18217 @@ -858,15 +860,11 @@ namespace ts.codefix { } if (usage.calls) { - for (const call of usage.calls) { - callSignatures.push(getSignatureFromCall(call)); - } + callSignatures.push(getSignatureFromCalls(usage.calls)); } if (usage.constructs) { - for (const construct of usage.constructs) { - constructSignatures.push(getSignatureFromCall(construct)); - } + constructSignatures.push(getSignatureFromCalls(usage.constructs)); } if (usage.stringIndex) { @@ -882,6 +880,61 @@ namespace ts.codefix { } } + function combineUsages(usages: Usage[]): Usage { + return { + isNumber: usages.some(u => u.isNumber), + isString: usages.some(u => u.isString), + isNumberOrString: usages.some(u => u.isNumberOrString), + candidateTypes: flatMap(usages, u => u.candidateTypes) as Type[], + properties: undefined, // TODO + calls: flatMap(usages, u => u.calls) as CallUsage[], + constructs: flatMap(usages, u => u.constructs) as CallUsage[], + numberIndex: forEach(usages, u => u.numberIndex), + stringIndex: forEach(usages, u => u.stringIndex), + candidateThisTypes: flatMap(usages, u => u.candidateThisTypes) as Type[], + } + } + + function findBuiltinType(usage: Usage): Type[] { + const builtins = [ + checker.getStringType(), + checker.getNumberType(), + checker.createArrayType(checker.getAnyType()), + checker.createPromiseType(checker.getAnyType()), + // checker.getFunctionType() // not sure what this was supposed to be good for. + ]; + const matches = builtins.filter(t => matchesAllPropertiesOf(t, usage)); + if (false && 0 < matches.length && matches.length < 3) { + return matches; + } + return []; + } + + function matchesAllPropertiesOf(type: Type, usage: Usage) { + if (!usage.properties) return false; + let result = true; + usage.properties.forEach((prop, name) => { + const source = checker.getUnionType(inferFromUsage(prop)); + const target = checker.getTypeOfPropertyOfType(type, name as string); + if (target && prop.calls) { + const sigs = checker.getSignaturesOfType(target, ts.SignatureKind.Call); + result = result && !!sigs.length && sigs.some( + sig => checker.isTypeAssignableTo( + getFunctionFromCalls(prop.calls!), + checker.createAnonymousType(undefined!, createSymbolTable(), [sig], emptyArray, undefined, undefined))); + } + else { + result = result && !!source && !!target && checker.isTypeAssignableTo(source, target); + } + }); + return result; + } + + + function getFunctionFromCalls(calls: CallUsage[]) { + return checker.createAnonymousType(undefined!, createSymbolTable(), [getSignatureFromCalls(calls)], emptyArray, undefined, undefined); + } + function getParameterTypeFromCalls(parameterIndex: number, calls: CallUsage[], isRestParameter: boolean) { let types: Type[] = []; if (calls) { @@ -904,16 +957,20 @@ namespace ts.codefix { return undefined; } - function getSignatureFromCall(call: CallUsage): Signature { + function getSignatureFromCalls(calls: CallUsage[]): Signature { const parameters: Symbol[] = []; - for (let i = 0; i < call.argumentTypes.length; i++) { + const length = Math.max(...calls.map(c => c.argumentTypes.length)); + for (let i = 0; i < length; i++) { const symbol = checker.createSymbol(SymbolFlags.FunctionScopedVariable, escapeLeadingUnderscores(`arg${i}`)); - symbol.type = checker.getWidenedType(checker.getBaseTypeOfLiteralType(call.argumentTypes[i])); + symbol.type = unifyFromUsage(calls.map(call => call.argumentTypes[i] || checker.getUndefinedType())); + if (calls.some(call => call.argumentTypes[i] === undefined)) { + symbol.flags |= SymbolFlags.Optional; + } parameters.push(symbol); } - const returnType = unifyFromUsage(inferFromUsage(call.returnType), checker.getVoidType()); + const returnType = unifyFromUsage(inferFromUsage(combineUsages(calls.map(call => call.return_))), checker.getVoidType()); // TODO: GH#18217 - return checker.createSignature(/*declaration*/ undefined!, /*typeParameters*/ undefined, /*thisParameter*/ undefined, parameters, returnType, /*typePredicate*/ undefined, call.argumentTypes.length, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); + return checker.createSignature(/*declaration*/ undefined!, /*typeParameters*/ undefined, /*thisParameter*/ undefined, parameters, returnType, /*typePredicate*/ undefined, length, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); } function addCandidateType(usage: Usage, type: Type | undefined) { From c2d0aa8931a44e19f294db71facb710a84abd047 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 27 Aug 2019 16:18:20 -0400 Subject: [PATCH 048/140] Only defer aliased array and tuple types --- src/compiler/checker.ts | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e403c2f964f..1231d4b31f1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9614,15 +9614,40 @@ namespace ts { return getTupleTypeOfArity(node.elementTypes.length, minLength, !!restElement, readonly, /*associatedNames*/ undefined); } + function isAliasedType(node: Node): boolean { + const parent = node.parent; + switch (parent.kind) { + case SyntaxKind.ParenthesizedType: + case SyntaxKind.ArrayType: + case SyntaxKind.TupleType: + case SyntaxKind.RestType: + case SyntaxKind.UnionType: + case SyntaxKind.IntersectionType: + case SyntaxKind.IndexedAccessType: + return isAliasedType(parent); + case SyntaxKind.TypeAliasDeclaration: + return true; + } + return false; + } + function getTypeFromArrayOrTupleTypeNode(node: ArrayTypeNode | TupleTypeNode): Type { const links = getNodeLinks(node); if (!links.resolvedType) { const target = getArrayOrTupleTargetType(node); - const aliasSymbol = getAliasSymbolForTypeNode(node); - const aliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol); - links.resolvedType = target === emptyGenericType ? emptyObjectType : - node.kind === SyntaxKind.TupleType && node.elementTypes.length === 0 ? target : - createDeferredTypeReference(target, node, /*mapper*/ undefined, aliasSymbol, aliasTypeArguments); + if (target === emptyGenericType) { + links.resolvedType = emptyObjectType; + } + else if (isAliasedType(node)) { + const aliasSymbol = getAliasSymbolForTypeNode(node); + const aliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol); + links.resolvedType = node.kind === SyntaxKind.TupleType && node.elementTypes.length === 0 ? target : + createDeferredTypeReference(target, node, /*mapper*/ undefined, aliasSymbol, aliasTypeArguments); + } + else { + const elementTypes = node.kind === SyntaxKind.ArrayType ? [getTypeFromTypeNode(node.elementType)] : map(node.elementTypes, getTypeFromTypeNode); + links.resolvedType = createTypeReference(target, elementTypes); + } } return links.resolvedType; } From 8f3a91724e77f87e00923d2f505f004cc1d8e468 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 27 Aug 2019 16:29:50 -0400 Subject: [PATCH 049/140] Accept new baselines --- .../baselines/reference/arrayFrom.errors.txt | 2 -- .../reference/castingTuple.errors.txt | 2 -- .../reference/checkJsxChildrenProperty3.types | 4 ++-- .../checkJsxChildrenProperty4.errors.txt | 16 +++++++-------- .../reference/checkJsxChildrenProperty4.types | 4 ++-- .../complexRecursiveCollections.types | 16 +++++++-------- .../contextualSignatureInstantiation.types | 2 +- ...ectDependenceBetweenTypeAliases.errors.txt | 20 ++++++++++++++++++- .../directDependenceBetweenTypeAliases.types | 16 +++++++-------- .../recursiveResolveTypeMembers.errors.txt | 4 ++-- .../recursiveTypesWithTypeof.errors.txt | 7 +++---- .../reference/recursiveTypesWithTypeof.types | 6 +++--- .../reference/spreadTypeVariable.types | 2 +- .../baselines/reference/tupleTypes.errors.txt | 4 ++-- .../reference/typeInferenceLiteralUnion.types | 4 ++-- 15 files changed, 61 insertions(+), 48 deletions(-) diff --git a/tests/baselines/reference/arrayFrom.errors.txt b/tests/baselines/reference/arrayFrom.errors.txt index 7d9645f9420..615bd1bf769 100644 --- a/tests/baselines/reference/arrayFrom.errors.txt +++ b/tests/baselines/reference/arrayFrom.errors.txt @@ -1,7 +1,6 @@ tests/cases/compiler/arrayFrom.ts(20,7): error TS2322: Type 'A[]' is not assignable to type 'B[]'. Property 'b' is missing in type 'A' but required in type 'B'. tests/cases/compiler/arrayFrom.ts(23,7): error TS2322: Type 'A[]' is not assignable to type 'B[]'. - Type 'A' is not assignable to type 'B'. ==== tests/cases/compiler/arrayFrom.ts (2 errors) ==== @@ -34,7 +33,6 @@ tests/cases/compiler/arrayFrom.ts(23,7): error TS2322: Type 'A[]' is not assigna const result6: B[] = Array.from(inputALike); // expect error ~~~~~~~ !!! error TS2322: Type 'A[]' is not assignable to type 'B[]'. -!!! error TS2322: Type 'A' is not assignable to type 'B'. const result7: B[] = Array.from(inputALike, ({ a }): B => ({ b: a })); const result8: A[] = Array.from(inputARand); const result9: B[] = Array.from(inputARand, ({ a }): B => ({ b: a })); diff --git a/tests/baselines/reference/castingTuple.errors.txt b/tests/baselines/reference/castingTuple.errors.txt index 56941dfddd0..0a1d592e8b1 100644 --- a/tests/baselines/reference/castingTuple.errors.txt +++ b/tests/baselines/reference/castingTuple.errors.txt @@ -4,7 +4,6 @@ tests/cases/conformance/types/tuple/castingTuple.ts(14,15): error TS2352: Conver Types of property 'length' are incompatible. Type '3' is not comparable to type '2'. tests/cases/conformance/types/tuple/castingTuple.ts(15,14): error TS2352: Conversion of type '[number, string]' to type '[number, string, boolean]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. - Property '2' is missing in type '[number, string]' but required in type '[number, string, boolean]'. tests/cases/conformance/types/tuple/castingTuple.ts(18,21): error TS2352: Conversion of type '[C, D]' to type '[C, D, A]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. Property '2' is missing in type '[C, D]' but required in type '[C, D, A]'. tests/cases/conformance/types/tuple/castingTuple.ts(20,33): error TS2493: Tuple type '[C, D, A]' of length '3' has no element at index '5'. @@ -41,7 +40,6 @@ tests/cases/conformance/types/tuple/castingTuple.ts(33,1): error TS2304: Cannot var longer = numStrTuple as [number, string, boolean] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS2352: Conversion of type '[number, string]' to type '[number, string, boolean]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. -!!! error TS2352: Property '2' is missing in type '[number, string]' but required in type '[number, string, boolean]'. var classCDTuple: [C, D] = [new C(), new D()]; var interfaceIITuple = <[I, I]>classCDTuple; var classCDATuple = <[C, D, A]>classCDTuple; diff --git a/tests/baselines/reference/checkJsxChildrenProperty3.types b/tests/baselines/reference/checkJsxChildrenProperty3.types index 2d4380a1975..f2ed3dc8fd0 100644 --- a/tests/baselines/reference/checkJsxChildrenProperty3.types +++ b/tests/baselines/reference/checkJsxChildrenProperty3.types @@ -31,11 +31,11 @@ class FetchUser extends React.Component { ? this.props.children(this.state.result) >this.props.children(this.state.result) : JSX.Element ->this.props.children : ((user: IUser) => JSX.Element) | (((user: IUser) => JSX.Element) & string) | (((user: IUser) => JSX.Element) & number) | (((user: IUser) => JSX.Element) & false) | (((user: IUser) => JSX.Element) & true) | (((user: IUser) => JSX.Element) & React.ReactElement) | (((user: IUser) => JSX.Element) & (string | number | boolean | React.ReactElement | any[])[]) +>this.props.children : ((user: IUser) => JSX.Element) | (((user: IUser) => JSX.Element) & string) | (((user: IUser) => JSX.Element) & number) | (((user: IUser) => JSX.Element) & false) | (((user: IUser) => JSX.Element) & true) | (((user: IUser) => JSX.Element) & React.ReactElement) | (((user: IUser) => JSX.Element) & (string | number | boolean | any[] | React.ReactElement)[]) >this.props : IFetchUserProps & { children?: React.ReactNode; } >this : this >props : IFetchUserProps & { children?: React.ReactNode; } ->children : ((user: IUser) => JSX.Element) | (((user: IUser) => JSX.Element) & string) | (((user: IUser) => JSX.Element) & number) | (((user: IUser) => JSX.Element) & false) | (((user: IUser) => JSX.Element) & true) | (((user: IUser) => JSX.Element) & React.ReactElement) | (((user: IUser) => JSX.Element) & (string | number | boolean | React.ReactElement | any[])[]) +>children : ((user: IUser) => JSX.Element) | (((user: IUser) => JSX.Element) & string) | (((user: IUser) => JSX.Element) & number) | (((user: IUser) => JSX.Element) & false) | (((user: IUser) => JSX.Element) & true) | (((user: IUser) => JSX.Element) & React.ReactElement) | (((user: IUser) => JSX.Element) & (string | number | boolean | any[] | React.ReactElement)[]) >this.state.result : any >this.state : any >this : this diff --git a/tests/baselines/reference/checkJsxChildrenProperty4.errors.txt b/tests/baselines/reference/checkJsxChildrenProperty4.errors.txt index 40eb1d77677..34bd2189964 100644 --- a/tests/baselines/reference/checkJsxChildrenProperty4.errors.txt +++ b/tests/baselines/reference/checkJsxChildrenProperty4.errors.txt @@ -1,8 +1,8 @@ tests/cases/conformance/jsx/file.tsx(24,28): error TS2551: Property 'NAme' does not exist on type 'IUser'. Did you mean 'Name'? -tests/cases/conformance/jsx/file.tsx(36,15): error TS2322: Type '(user: IUser) => Element' is not assignable to type 'string | number | boolean | ReactElement | any[]'. - Type '(user: IUser) => Element' is missing the following properties from type 'any[]': push, pop, concat, join, and 15 more. -tests/cases/conformance/jsx/file.tsx(39,15): error TS2322: Type '(user: IUser) => Element' is not assignable to type 'string | number | boolean | ReactElement | any[]'. - Type '(user: IUser) => Element' is missing the following properties from type 'any[]': push, pop, concat, join, and 15 more. +tests/cases/conformance/jsx/file.tsx(36,15): error TS2322: Type '(user: IUser) => Element' is not assignable to type 'string | number | boolean | any[] | ReactElement'. + Type '(user: IUser) => Element' is missing the following properties from type 'ReactElement': type, props +tests/cases/conformance/jsx/file.tsx(39,15): error TS2322: Type '(user: IUser) => Element' is not assignable to type 'string | number | boolean | any[] | ReactElement'. + Type '(user: IUser) => Element' is missing the following properties from type 'ReactElement': type, props ==== tests/cases/conformance/jsx/file.tsx (3 errors) ==== @@ -50,8 +50,8 @@ tests/cases/conformance/jsx/file.tsx(39,15): error TS2322: Type '(user: IUser) = ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) } ~~~~~~~~~~~~~ -!!! error TS2322: Type '(user: IUser) => Element' is not assignable to type 'string | number | boolean | ReactElement | any[]'. -!!! error TS2322: Type '(user: IUser) => Element' is missing the following properties from type 'any[]': push, pop, concat, join, and 15 more. +!!! error TS2322: Type '(user: IUser) => Element' is not assignable to type 'string | number | boolean | any[] | ReactElement'. +!!! error TS2322: Type '(user: IUser) => Element' is missing the following properties from type 'ReactElement': type, props !!! related TS6212 tests/cases/conformance/jsx/file.tsx:36:15: Did you mean to call this expression? { user => ( ~~~~~~~~~ @@ -59,8 +59,8 @@ tests/cases/conformance/jsx/file.tsx(39,15): error TS2322: Type '(user: IUser) = ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) } ~~~~~~~~~~~~~ -!!! error TS2322: Type '(user: IUser) => Element' is not assignable to type 'string | number | boolean | ReactElement | any[]'. -!!! error TS2322: Type '(user: IUser) => Element' is missing the following properties from type 'any[]': push, pop, concat, join, and 15 more. +!!! error TS2322: Type '(user: IUser) => Element' is not assignable to type 'string | number | boolean | any[] | ReactElement'. +!!! error TS2322: Type '(user: IUser) => Element' is missing the following properties from type 'ReactElement': type, props !!! related TS6212 tests/cases/conformance/jsx/file.tsx:39:15: Did you mean to call this expression? ); diff --git a/tests/baselines/reference/checkJsxChildrenProperty4.types b/tests/baselines/reference/checkJsxChildrenProperty4.types index 4f753cf9f3b..067e8f2611a 100644 --- a/tests/baselines/reference/checkJsxChildrenProperty4.types +++ b/tests/baselines/reference/checkJsxChildrenProperty4.types @@ -31,11 +31,11 @@ class FetchUser extends React.Component { ? this.props.children(this.state.result) >this.props.children(this.state.result) : JSX.Element ->this.props.children : ((user: IUser) => JSX.Element) | (((user: IUser) => JSX.Element) & string) | (((user: IUser) => JSX.Element) & number) | (((user: IUser) => JSX.Element) & false) | (((user: IUser) => JSX.Element) & true) | (((user: IUser) => JSX.Element) & React.ReactElement) | (((user: IUser) => JSX.Element) & (string | number | boolean | React.ReactElement | any[])[]) +>this.props.children : ((user: IUser) => JSX.Element) | (((user: IUser) => JSX.Element) & string) | (((user: IUser) => JSX.Element) & number) | (((user: IUser) => JSX.Element) & false) | (((user: IUser) => JSX.Element) & true) | (((user: IUser) => JSX.Element) & React.ReactElement) | (((user: IUser) => JSX.Element) & (string | number | boolean | any[] | React.ReactElement)[]) >this.props : IFetchUserProps & { children?: React.ReactNode; } >this : this >props : IFetchUserProps & { children?: React.ReactNode; } ->children : ((user: IUser) => JSX.Element) | (((user: IUser) => JSX.Element) & string) | (((user: IUser) => JSX.Element) & number) | (((user: IUser) => JSX.Element) & false) | (((user: IUser) => JSX.Element) & true) | (((user: IUser) => JSX.Element) & React.ReactElement) | (((user: IUser) => JSX.Element) & (string | number | boolean | React.ReactElement | any[])[]) +>children : ((user: IUser) => JSX.Element) | (((user: IUser) => JSX.Element) & string) | (((user: IUser) => JSX.Element) & number) | (((user: IUser) => JSX.Element) & false) | (((user: IUser) => JSX.Element) & true) | (((user: IUser) => JSX.Element) & React.ReactElement) | (((user: IUser) => JSX.Element) & (string | number | boolean | any[] | React.ReactElement)[]) >this.state.result : any >this.state : any >this : this diff --git a/tests/baselines/reference/complexRecursiveCollections.types b/tests/baselines/reference/complexRecursiveCollections.types index 2450407e90d..feaff620486 100644 --- a/tests/baselines/reference/complexRecursiveCollections.types +++ b/tests/baselines/reference/complexRecursiveCollections.types @@ -1029,28 +1029,28 @@ declare module Immutable { >value : T[K] merge(...collections: Array | Iterable<[string, any]>>): this; ->merge : (...collections: (Partial | Iterable<[string, any]>)[]) => this ->collections : (Partial | Iterable<[string, any]>)[] +>merge : (...collections: (Iterable<[string, any]> | Partial)[]) => this +>collections : (Iterable<[string, any]> | Partial)[] mergeDeep(...collections: Array | Iterable<[string, any]>>): this; ->mergeDeep : (...collections: (Partial | Iterable<[string, any]>)[]) => this ->collections : (Partial | Iterable<[string, any]>)[] +>mergeDeep : (...collections: (Iterable<[string, any]> | Partial)[]) => this +>collections : (Iterable<[string, any]> | Partial)[] mergeWith(merger: (oldVal: any, newVal: any, key: keyof T) => any, ...collections: Array | Iterable<[string, any]>>): this; ->mergeWith : (merger: (oldVal: any, newVal: any, key: keyof T) => any, ...collections: (Partial | Iterable<[string, any]>)[]) => this +>mergeWith : (merger: (oldVal: any, newVal: any, key: keyof T) => any, ...collections: (Iterable<[string, any]> | Partial)[]) => this >merger : (oldVal: any, newVal: any, key: keyof T) => any >oldVal : any >newVal : any >key : keyof T ->collections : (Partial | Iterable<[string, any]>)[] +>collections : (Iterable<[string, any]> | Partial)[] mergeDeepWith(merger: (oldVal: any, newVal: any, key: any) => any, ...collections: Array | Iterable<[string, any]>>): this; ->mergeDeepWith : (merger: (oldVal: any, newVal: any, key: any) => any, ...collections: (Partial | Iterable<[string, any]>)[]) => this +>mergeDeepWith : (merger: (oldVal: any, newVal: any, key: any) => any, ...collections: (Iterable<[string, any]> | Partial)[]) => this >merger : (oldVal: any, newVal: any, key: any) => any >oldVal : any >newVal : any >key : any ->collections : (Partial | Iterable<[string, any]>)[] +>collections : (Iterable<[string, any]> | Partial)[] delete(key: K): this; >delete : (key: K) => this diff --git a/tests/baselines/reference/contextualSignatureInstantiation.types b/tests/baselines/reference/contextualSignatureInstantiation.types index 57e8f79a28f..ae5a4000537 100644 --- a/tests/baselines/reference/contextualSignatureInstantiation.types +++ b/tests/baselines/reference/contextualSignatureInstantiation.types @@ -108,7 +108,7 @@ var d = bar(1, "one", h); // Should be number[] | string[] var d = bar("one", 1, h); // Should be number[] | string[] >d : number[] | string[] ->bar("one", 1, h) : string[] | number[] +>bar("one", 1, h) : number[] | string[] >bar : (x: T, y: U, cb: (x: T, y: U) => V) => V >"one" : "one" >1 : 1 diff --git a/tests/baselines/reference/directDependenceBetweenTypeAliases.errors.txt b/tests/baselines/reference/directDependenceBetweenTypeAliases.errors.txt index d3960267177..15e654df9a7 100644 --- a/tests/baselines/reference/directDependenceBetweenTypeAliases.errors.txt +++ b/tests/baselines/reference/directDependenceBetweenTypeAliases.errors.txt @@ -4,9 +4,15 @@ tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts( tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(7,6): error TS2456: Type alias 'T0_3' circularly references itself. tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(11,6): error TS2456: Type alias 'T1' circularly references itself. tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(14,6): error TS2456: Type alias 'T2' circularly references itself. +tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(25,5): error TS2502: 'x' is referenced directly or indirectly in its own type annotation. +tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(26,6): error TS2456: Type alias 'T5' circularly references itself. +tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(29,6): error TS2456: Type alias 'T6' circularly references itself. +tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(30,6): error TS2456: Type alias 'T7' circularly references itself. +tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(31,5): error TS2502: 'yy' is referenced directly or indirectly in its own type annotation. +tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(32,6): error TS2456: Type alias 'T8' circularly references itself. -==== tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts (6 errors) ==== +==== tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts (12 errors) ==== // It is an error for the type specified in a type alias to depend on that type alias // A type alias directly depends on the type it aliases. @@ -44,13 +50,25 @@ tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts( // A type query directly depends on the type of the referenced entity. var x: T5[] = [] + ~ +!!! error TS2502: 'x' is referenced directly or indirectly in its own type annotation. type T5 = typeof x + ~~ +!!! error TS2456: Type alias 'T5' circularly references itself. class C1 {} type T6 = T7 | number + ~~ +!!! error TS2456: Type alias 'T6' circularly references itself. type T7 = typeof yy + ~~ +!!! error TS2456: Type alias 'T7' circularly references itself. var yy: [string, T8[]]; + ~~ +!!! error TS2502: 'yy' is referenced directly or indirectly in its own type annotation. type T8 = C + ~~ +!!! error TS2456: Type alias 'T8' circularly references itself. // legal cases type T9 = () => T9 diff --git a/tests/baselines/reference/directDependenceBetweenTypeAliases.types b/tests/baselines/reference/directDependenceBetweenTypeAliases.types index 431b65eea8c..1ddbeb019cf 100644 --- a/tests/baselines/reference/directDependenceBetweenTypeAliases.types +++ b/tests/baselines/reference/directDependenceBetweenTypeAliases.types @@ -39,28 +39,28 @@ type T4 = [number, T4] // A type query directly depends on the type of the referenced entity. var x: T5[] = [] ->x : any[][][][][][][][][][][] +>x : any >[] : undefined[] type T5 = typeof x ->T5 : any[][][][][][][][][][][] ->x : any[][][][][][][][][][][] +>T5 : any +>x : any class C1 {} >C1 : C1 type T6 = T7 | number ->T6 : T6 +>T6 : any type T7 = typeof yy ->T7 : [string, C[]] ->yy : [string, C[]] +>T7 : any +>yy : any var yy: [string, T8[]]; ->yy : [string, C[]] +>yy : any type T8 = C ->T8 : C +>T8 : any // legal cases type T9 = () => T9 diff --git a/tests/baselines/reference/recursiveResolveTypeMembers.errors.txt b/tests/baselines/reference/recursiveResolveTypeMembers.errors.txt index 7bb5c554984..ad5fe6dc1ae 100644 --- a/tests/baselines/reference/recursiveResolveTypeMembers.errors.txt +++ b/tests/baselines/reference/recursiveResolveTypeMembers.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/recursiveResolveTypeMembers.ts(4,49): error TS2589: Type instantiation is excessively deep and possibly infinite. +tests/cases/compiler/recursiveResolveTypeMembers.ts(4,49): error TS2577: Return type annotation circularly references itself. tests/cases/compiler/recursiveResolveTypeMembers.ts(4,58): error TS2304: Cannot find name 'H'. tests/cases/compiler/recursiveResolveTypeMembers.ts(4,62): error TS2574: A rest element type must be an array type. tests/cases/compiler/recursiveResolveTypeMembers.ts(4,79): error TS2304: Cannot find name 'R'. @@ -10,7 +10,7 @@ tests/cases/compiler/recursiveResolveTypeMembers.ts(4,79): error TS2304: Cannot type PromisedTuple void> = U extends (h: infer H, ...args: infer R) => [Promise, ...PromisedTuple] ? [] : [] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2589: Type instantiation is excessively deep and possibly infinite. +!!! error TS2577: Return type annotation circularly references itself. ~ !!! error TS2304: Cannot find name 'H'. ~~~~~~~~~~~~~~~~~~~ diff --git a/tests/baselines/reference/recursiveTypesWithTypeof.errors.txt b/tests/baselines/reference/recursiveTypesWithTypeof.errors.txt index 2807613c3d9..0604e38bd94 100644 --- a/tests/baselines/reference/recursiveTypesWithTypeof.errors.txt +++ b/tests/baselines/reference/recursiveTypesWithTypeof.errors.txt @@ -3,7 +3,7 @@ tests/cases/conformance/types/specifyingTypes/typeQueries/recursiveTypesWithType tests/cases/conformance/types/specifyingTypes/typeQueries/recursiveTypesWithTypeof.ts(6,5): error TS2502: 'e' is referenced directly or indirectly in its own type annotation. tests/cases/conformance/types/specifyingTypes/typeQueries/recursiveTypesWithTypeof.ts(10,5): error TS2502: 'f' is referenced directly or indirectly in its own type annotation. tests/cases/conformance/types/specifyingTypes/typeQueries/recursiveTypesWithTypeof.ts(12,5): error TS2502: 'f2' is referenced directly or indirectly in its own type annotation. -tests/cases/conformance/types/specifyingTypes/typeQueries/recursiveTypesWithTypeof.ts(15,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'f3' must be of type 'Foo[]>[]>[]>[]>[]>[]>[]>[]>[]>[]>[]', but here has type 'any'. +tests/cases/conformance/types/specifyingTypes/typeQueries/recursiveTypesWithTypeof.ts(14,5): error TS2502: 'f3' is referenced directly or indirectly in its own type annotation. tests/cases/conformance/types/specifyingTypes/typeQueries/recursiveTypesWithTypeof.ts(51,5): error TS2502: 'hy3' is referenced directly or indirectly in its own type annotation. @@ -32,10 +32,9 @@ tests/cases/conformance/types/specifyingTypes/typeQueries/recursiveTypesWithType !!! error TS2502: 'f2' is referenced directly or indirectly in its own type annotation. var f2: any; var f3: Foo[]; - var f3: any; ~~ -!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'f3' must be of type 'Foo[]>[]>[]>[]>[]>[]>[]>[]>[]>[]>[]', but here has type 'any'. -!!! related TS6203 tests/cases/conformance/types/specifyingTypes/typeQueries/recursiveTypesWithTypeof.ts:14:5: 'f3' was also declared here. +!!! error TS2502: 'f3' is referenced directly or indirectly in its own type annotation. + var f3: any; // None of these declarations should have any errors! // Truly recursive types diff --git a/tests/baselines/reference/recursiveTypesWithTypeof.types b/tests/baselines/reference/recursiveTypesWithTypeof.types index 1a527bfa470..5625e7919cd 100644 --- a/tests/baselines/reference/recursiveTypesWithTypeof.types +++ b/tests/baselines/reference/recursiveTypesWithTypeof.types @@ -37,11 +37,11 @@ var f2: any; >f2 : any var f3: Foo[]; ->f3 : Foo[]>[]>[]>[]>[]>[]>[]>[]>[]>[]>[] ->f3 : Foo[]>[]>[]>[]>[]>[]>[]>[]>[]>[]>[] +>f3 : any +>f3 : any var f3: any; ->f3 : Foo[]>[]>[]>[]>[]>[]>[]>[]>[]>[]>[] +>f3 : any // None of these declarations should have any errors! // Truly recursive types diff --git a/tests/baselines/reference/spreadTypeVariable.types b/tests/baselines/reference/spreadTypeVariable.types index 0e836355d42..c5de712fb19 100644 --- a/tests/baselines/reference/spreadTypeVariable.types +++ b/tests/baselines/reference/spreadTypeVariable.types @@ -37,7 +37,7 @@ function f4(arg: T) { } function f5(arg: T) { ->f5 : (arg: T) => T +>f5 : (arg: T) => T >key : string >arg : T diff --git a/tests/baselines/reference/tupleTypes.errors.txt b/tests/baselines/reference/tupleTypes.errors.txt index a3c2fc00eb4..af76c872a6f 100644 --- a/tests/baselines/reference/tupleTypes.errors.txt +++ b/tests/baselines/reference/tupleTypes.errors.txt @@ -9,7 +9,7 @@ tests/cases/compiler/tupleTypes.ts(18,1): error TS2322: Type '[number, string, n Type '3' is not assignable to type '2'. tests/cases/compiler/tupleTypes.ts(35,14): error TS2493: Tuple type '[number, string]' of length '2' has no element at index '2'. tests/cases/compiler/tupleTypes.ts(36,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'tt2' must be of type 'undefined', but here has type 'string | number'. -tests/cases/compiler/tupleTypes.ts(41,1): error TS2739: Type '[]' is missing the following properties from type '[number, string]': 0, 1 +tests/cases/compiler/tupleTypes.ts(41,1): error TS2322: Type '[]' is not assignable to type '[number, string]'. tests/cases/compiler/tupleTypes.ts(47,1): error TS2322: Type '[number, string]' is not assignable to type 'number[]'. Type 'string | number' is not assignable to type 'number'. Type 'string' is not assignable to type 'number'. @@ -87,7 +87,7 @@ tests/cases/compiler/tupleTypes.ts(51,1): error TS2322: Type '[number, {}]' is n tt = [undefined, undefined]; tt = []; // Error ~~ -!!! error TS2739: Type '[]' is missing the following properties from type '[number, string]': 0, 1 +!!! error TS2322: Type '[]' is not assignable to type '[number, string]'. var a: number[]; var a1: [number, string]; diff --git a/tests/baselines/reference/typeInferenceLiteralUnion.types b/tests/baselines/reference/typeInferenceLiteralUnion.types index 84a65ccbc53..de4637c52c5 100644 --- a/tests/baselines/reference/typeInferenceLiteralUnion.types +++ b/tests/baselines/reference/typeInferenceLiteralUnion.types @@ -56,11 +56,11 @@ export function extent(array: Array): [T | Pri let extentMixed: [Primitive | NumCoercible, Primitive | NumCoercible] | [undefined, undefined]; ->extentMixed : [string | number | boolean | Date | NumCoercible, string | number | boolean | Date | NumCoercible] | [undefined, undefined] +>extentMixed : [undefined, undefined] | [string | number | boolean | Date | NumCoercible, string | number | boolean | Date | NumCoercible] extentMixed = extent([new NumCoercible(10), 13, '12', true]); >extentMixed = extent([new NumCoercible(10), 13, '12', true]) : [undefined, undefined] | [string | number | boolean | Date | NumCoercible, string | number | boolean | Date | NumCoercible] ->extentMixed : [string | number | boolean | Date | NumCoercible, string | number | boolean | Date | NumCoercible] | [undefined, undefined] +>extentMixed : [undefined, undefined] | [string | number | boolean | Date | NumCoercible, string | number | boolean | Date | NumCoercible] >extent([new NumCoercible(10), 13, '12', true]) : [undefined, undefined] | [string | number | boolean | Date | NumCoercible, string | number | boolean | Date | NumCoercible] >extent : (array: (string | number | boolean | Date | T)[]) => [string | number | boolean | Date | T, string | number | boolean | Date | T] | [undefined, undefined] >[new NumCoercible(10), 13, '12', true] : (string | number | true | NumCoercible)[] From 842c588f3ef5b56bde3f71265d7bc7c243c539f6 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 28 Aug 2019 07:52:42 -0400 Subject: [PATCH 050/140] Exclude method symbols when relating tuple types --- src/compiler/checker.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1231d4b31f1..529a357e34d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14123,9 +14123,11 @@ namespace ts { // We only call this for union target types when we're attempting to do excess property checking - in those cases, we want to get _all possible props_ // from the target union, across all members const properties = target.flags & TypeFlags.Union ? getPossiblePropertiesOfUnionType(target as UnionType) : getPropertiesOfType(target); + const numericNamesOnly = isTupleType(source) && isTupleType(target); for (const targetProp of excludeProperties(properties, excludedProperties)) { - if (!(targetProp.flags & SymbolFlags.Prototype)) { - const sourceProp = getPropertyOfType(source, targetProp.escapedName); + const name = targetProp.escapedName; + if (!(targetProp.flags & SymbolFlags.Prototype) && (!numericNamesOnly || isNumericLiteralName(name) || name === "length")) { + const sourceProp = getPropertyOfType(source, name); if (sourceProp && sourceProp !== targetProp) { const related = propertyRelatedTo(source, target, sourceProp, targetProp, getTypeOfSymbol, reportErrors, isIntersectionConstituent); if (!related) { From 945d423ef5b511ae157b15849b2b822de4b48953 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Wed, 28 Aug 2019 14:12:21 -0700 Subject: [PATCH 051/140] Fix bugs in combineUsages/getSignatureFromCalls --- src/services/codefixes/inferFromUsage.ts | 76 +++++++++++++++++------- 1 file changed, 56 insertions(+), 20 deletions(-) diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index 4b111dae25b..92382c462fa 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -405,18 +405,19 @@ namespace ts.codefix { } interface Usage { - isNumber?: boolean; - isString?: boolean; + isNumber: boolean | undefined; + isString: boolean | undefined; /** Used ambiguously, eg x + ___ or object[___]; results in string | number if no other evidence exists */ - isNumberOrString?: boolean; + isNumberOrString: boolean | undefined; - candidateTypes?: Type[]; - properties?: UnderscoreEscapedMap; - calls?: CallUsage[]; - constructs?: CallUsage[]; - numberIndex?: Usage; - stringIndex?: Usage; - candidateThisTypes?: Type[]; + candidateTypes: Type[] | undefined; + properties: UnderscoreEscapedMap | undefined; + calls: CallUsage[] | undefined; + constructs: CallUsage[] | undefined; + numberIndex: Usage | undefined; + stringIndex: Usage | undefined; + candidateThisTypes: Type[] | undefined; + inferredTypes: Type[] | undefined; } function single(): Type { @@ -428,7 +429,7 @@ namespace ts.codefix { return undefined; } - const usage: Usage = {}; + const usage = createEmptyUsage(); for (const reference of references) { cancellationToken.throwIfCancellationRequested(); calculateUsageOfNode(reference, usage); @@ -466,7 +467,7 @@ namespace ts.codefix { } function thisParameter() { - const usage: Usage = {}; + const usage = createEmptyUsage(); for (const reference of references) { cancellationToken.throwIfCancellationRequested(); calculateUsageOfNode(reference, usage); @@ -476,7 +477,7 @@ namespace ts.codefix { } function inferTypesFromReferencesSingle(references: readonly Identifier[]): Type[] { - const usage: Usage = {}; + const usage: Usage = createEmptyUsage(); for (const reference of references) { cancellationToken.throwIfCancellationRequested(); calculateUsageOfNode(reference, usage); @@ -671,7 +672,7 @@ namespace ts.codefix { function inferTypeFromCallExpression(parent: CallExpression | NewExpression, usage: Usage): void { const call: CallUsage = { argumentTypes: [], - return_: {} + return_: createEmptyUsage() }; if (parent.arguments) { @@ -695,7 +696,7 @@ namespace ts.codefix { if (!usage.properties) { usage.properties = createUnderscoreEscapedMap(); } - const propertyUsage = usage.properties.get(name) || { }; + const propertyUsage = usage.properties.get(name) || createEmptyUsage(); calculateUsageOfNode(parent, propertyUsage); usage.properties.set(name, propertyUsage); } @@ -707,7 +708,7 @@ namespace ts.codefix { } else { const indexType = checker.getTypeAtLocation(parent.argumentExpression); - const indexUsage = {}; + const indexUsage = createEmptyUsage(); calculateUsageOfNode(parent, indexUsage); if (indexType.flags & TypeFlags.NumberLike) { usage.numberIndex = indexUsage; @@ -845,7 +846,10 @@ namespace ts.codefix { if (usage.numberIndex) { types.push(checker.createArrayType(recur(usage.numberIndex))); } - else if (usage.properties || usage.calls || usage.constructs || usage.stringIndex) { + else if (usage.properties && usage.properties.size + || usage.calls && usage.calls.length + || usage.constructs && usage.constructs.length + || usage.stringIndex) { const members = createUnderscoreEscapedMap(); const callSignatures: Signature[] = []; const constructSignatures: Signature[] = []; @@ -873,25 +877,57 @@ namespace ts.codefix { types.push(checker.createAnonymousType(/*symbol*/ undefined!, members, callSignatures, constructSignatures, stringIndexInfo, /*numberIndexInfo*/ undefined)); // TODO: GH#18217 } - return types; + return types; // TODO: Should cache this since I HOPE it doesn't change function recur(innerUsage: Usage): Type { return unifyFromUsage(inferFromUsage(innerUsage)); } } + function createEmptyUsage(): Usage { + return { + isNumber: undefined, + isString: undefined, + isNumberOrString: undefined, + candidateTypes: undefined, + properties: undefined, + calls: undefined, + constructs: undefined, + numberIndex: undefined, + stringIndex: undefined, + candidateThisTypes: undefined, + inferredTypes: undefined, + } + } + function combineUsages(usages: Usage[]): Usage { + const combinedProperties = createUnderscoreEscapedMap() + for (const u of usages) { + if (u.properties) { + u.properties.forEach((p,name) => { + if (!combinedProperties.has(name)) { + combinedProperties.set(name, []); + } + combinedProperties.get(name)!.push(p); + }); + } + } + const properties = createUnderscoreEscapedMap() + combinedProperties.forEach((ps,name) => { + properties.set(name, combineUsages(ps)); + }); return { isNumber: usages.some(u => u.isNumber), isString: usages.some(u => u.isString), isNumberOrString: usages.some(u => u.isNumberOrString), candidateTypes: flatMap(usages, u => u.candidateTypes) as Type[], - properties: undefined, // TODO + properties, calls: flatMap(usages, u => u.calls) as CallUsage[], constructs: flatMap(usages, u => u.constructs) as CallUsage[], numberIndex: forEach(usages, u => u.numberIndex), stringIndex: forEach(usages, u => u.stringIndex), candidateThisTypes: flatMap(usages, u => u.candidateThisTypes) as Type[], + inferredTypes: undefined, // clear type cache } } @@ -901,7 +937,7 @@ namespace ts.codefix { checker.getNumberType(), checker.createArrayType(checker.getAnyType()), checker.createPromiseType(checker.getAnyType()), - // checker.getFunctionType() // not sure what this was supposed to be good for. + // checker.getFunctionType() // TODO: not sure what this was supposed to be good for. ]; const matches = builtins.filter(t => matchesAllPropertiesOf(t, usage)); if (false && 0 < matches.length && matches.length < 3) { From fd8f9904490ec7cf93e1010604e7a4bec2a56756 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 29 Aug 2019 07:17:45 -0700 Subject: [PATCH 052/140] Fix instantiation of alias type arguments for deferred type references --- src/compiler/checker.ts | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 529a357e34d..85c3c10f150 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9115,13 +9115,15 @@ namespace ts { return type; } - function createDeferredTypeReference(target: GenericType, node: ArrayTypeNode | TupleTypeNode, mapper?: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: ReadonlyArray): DeferredTypeReference { + function createDeferredTypeReference(target: GenericType, node: ArrayTypeNode | TupleTypeNode, mapper?: TypeMapper): DeferredTypeReference { + const aliasSymbol = getAliasSymbolForTypeNode(node); + const aliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol); const type = createObjectType(ObjectFlags.Reference, target.symbol); type.target = target; type.node = node; type.mapper = mapper; type.aliasSymbol = aliasSymbol; - type.aliasTypeArguments = aliasTypeArguments; + type.aliasTypeArguments = mapper ? instantiateTypes(aliasTypeArguments, mapper) : aliasTypeArguments; return type; } @@ -9639,10 +9641,8 @@ namespace ts { links.resolvedType = emptyObjectType; } else if (isAliasedType(node)) { - const aliasSymbol = getAliasSymbolForTypeNode(node); - const aliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol); links.resolvedType = node.kind === SyntaxKind.TupleType && node.elementTypes.length === 0 ? target : - createDeferredTypeReference(target, node, /*mapper*/ undefined, aliasSymbol, aliasTypeArguments); + createDeferredTypeReference(target, node, /*mapper*/ undefined); } else { const elementTypes = node.kind === SyntaxKind.ArrayType ? [getTypeFromTypeNode(node.elementType)] : map(node.elementTypes, getTypeFromTypeNode); @@ -11504,7 +11504,7 @@ namespace ts { let result = links.instantiations!.get(id); if (!result) { const newMapper = createTypeMapper(typeParameters, typeArguments); - result = target.objectFlags & ObjectFlags.Reference ? instantiateDeferredTypeReference(type, newMapper) : + result = target.objectFlags & ObjectFlags.Reference ? createDeferredTypeReference((type).target, (type).node, newMapper) : target.objectFlags & ObjectFlags.Mapped ? instantiateMappedType(target, newMapper) : instantiateAnonymousType(target, newMapper); links.instantiations!.set(id, result); @@ -11638,10 +11638,6 @@ namespace ts { return result; } - function instantiateDeferredTypeReference(type: DeferredTypeReference, mapper: TypeMapper): TypeReference { - return createDeferredTypeReference(type.target, type.node, mapper, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper)); - } - function getConditionalTypeInstantiation(type: ConditionalType, mapper: TypeMapper): Type { const root = type.root; if (root.outerTypeParameters) { From 6270ccc4b064cb9b66316d22d11a276c327bf886 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 29 Aug 2019 07:31:34 -0700 Subject: [PATCH 053/140] Accept new baselines --- .../reference/contextualTypingOfOptionalMembers.types | 8 ++++---- tests/baselines/reference/inferTypes1.types | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/baselines/reference/contextualTypingOfOptionalMembers.types b/tests/baselines/reference/contextualTypingOfOptionalMembers.types index 9df692608c2..8978cb86e07 100644 --- a/tests/baselines/reference/contextualTypingOfOptionalMembers.types +++ b/tests/baselines/reference/contextualTypingOfOptionalMembers.types @@ -134,7 +134,7 @@ declare function app3>(obj: Optionsapp3({ state: 100, actions: [ s => s // Should be typed number => number ], view: (s, a) => undefined as any,}) : void >app3 : >(obj: Options) => void ->{ state: 100, actions: [ s => s // Should be typed number => number ], view: (s, a) => undefined as any,} : { state: number; actions: ((s: number) => number)[]; view: (s: number, a: ActionsArray) => any; } +>{ state: 100, actions: [ s => s // Should be typed number => number ], view: (s, a) => undefined as any,} : { state: number; actions: ((s: number) => number)[]; view: (s: number, a: ActionsArray) => any; } state: 100, >state : number @@ -151,10 +151,10 @@ app3({ ], view: (s, a) => undefined as any, ->view : (s: number, a: ActionsArray) => any ->(s, a) => undefined as any : (s: number, a: ActionsArray) => any +>view : (s: number, a: ActionsArray) => any +>(s, a) => undefined as any : (s: number, a: ActionsArray) => any >s : number ->a : ActionsArray +>a : ActionsArray >undefined as any : any >undefined : undefined diff --git a/tests/baselines/reference/inferTypes1.types b/tests/baselines/reference/inferTypes1.types index 02fa41fe4c8..f31c230620b 100644 --- a/tests/baselines/reference/inferTypes1.types +++ b/tests/baselines/reference/inferTypes1.types @@ -275,13 +275,13 @@ type Bar = T extends Foo ? Foo : never; >Bar : Bar type T90 = Bar<[string, string]>; // [string, string] ->T90 : Foo +>T90 : Foo type T91 = Bar<[string, "a"]>; // [string, "a"] ->T91 : Foo +>T91 : Foo type T92 = Bar<[string, "a"] & { x: string }>; // [string, "a"] ->T92 : Foo +>T92 : Foo >x : string type T93 = Bar<["a", string]>; // never From 37150d9cb548e6e7802b731e8c03a298434e18d7 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Thu, 29 Aug 2019 12:40:33 -0700 Subject: [PATCH 054/140] Turn on findBuiltinTypes Type parameter inference is special-cased, just moved from its previous place with no improvement. --- src/services/codefixes/inferFromUsage.ts | 103 +++++++++--------- .../codeFixInferFromFunctionUsage.ts | 4 +- .../codeFixInferFromPrimitiveUsage.ts | 9 ++ .../codeFixInferFromUsageCallBodyBoth.ts | 2 +- 4 files changed, 65 insertions(+), 53 deletions(-) create mode 100644 tests/cases/fourslash/codeFixInferFromPrimitiveUsage.ts diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index 92382c462fa..ab1c2a4a52d 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -421,7 +421,7 @@ namespace ts.codefix { } function single(): Type { - return unifyFromUsage(inferTypesFromReferencesSingle(references)); + return unifyTypes(inferTypesFromReferencesSingle(references)); } function parameters(declaration: FunctionLike): ParameterInference[] | undefined { @@ -457,7 +457,7 @@ namespace ts.codefix { const inferred = inferTypesFromReferencesSingle(getReferences(parameter.name, program, cancellationToken)); types.push(...(isRest ? mapDefined(inferred, checker.getElementTypeOfArrayType) : inferred)); } - const type = unifyFromUsage(types); + const type = unifyTypes(types); return { type: isRest ? checker.createArrayType(type) : type, isOptional: isOptional && !isRest, @@ -473,7 +473,7 @@ namespace ts.codefix { calculateUsageOfNode(reference, usage); } - return unifyFromUsage(usage.candidateThisTypes || emptyArray); + return unifyTypes(usage.candidateThisTypes || emptyArray); } function inferTypesFromReferencesSingle(references: readonly Identifier[]): Type[] { @@ -627,6 +627,9 @@ namespace ts.codefix { else if (otherOperandType.flags & TypeFlags.StringLike) { usage.isString = true; } + else if (otherOperandType.flags & TypeFlags.Any) { + // do nothing, maybe we'll learn something elsewhere + } else { usage.isNumberOrString = true; } @@ -748,7 +751,7 @@ namespace ts.codefix { return inferences.filter(i => toRemove.every(f => !f(i))); } - function unifyFromUsage(inferences: ReadonlyArray, fallback = checker.getAnyType()): Type { + function unifyTypes(inferences: ReadonlyArray, fallback = checker.getAnyType()): Type { if (!inferences.length) return fallback; // 1. string or number individually override string | number @@ -774,7 +777,7 @@ namespace ts.codefix { good = good.filter(i => !(checker.getObjectFlags(i) & ObjectFlags.Anonymous)); good.push(unifyAnonymousTypes(anons)); } - return checker.getWidenedType(checker.getUnionType(good)); + return checker.getWidenedType(checker.getUnionType(good, UnionReduction.Subtype)); } function unifyAnonymousTypes(anons: AnonymousType[]) { @@ -832,16 +835,7 @@ namespace ts.codefix { } types.push(...(usage.candidateTypes || []).map(t => checker.getBaseTypeOfLiteralType(t))); - types.push(...findBuiltinType(usage)); - - if (usage.properties && hasCalls(usage.properties.get("then" as __String))) { - const paramType = getParameterTypeFromCalls(0, usage.properties.get("then" as __String)!.calls!, /*isRestParameter*/ false)!; // TODO: GH#18217 - const types = paramType.getCallSignatures().map(sig => sig.getReturnType()); - types.push(checker.createPromiseType(types.length ? checker.getUnionType(types, UnionReduction.Subtype) : checker.getAnyType())); - } - else if (usage.properties && hasCalls(usage.properties.get("push" as __String))) { - types.push(checker.createArrayType(getParameterTypeFromCalls(0, usage.properties.get("push" as __String)!.calls!, /*isRestParameter*/ false)!)); - } + types.push(...findBuiltinTypes(usage)); if (usage.numberIndex) { types.push(checker.createArrayType(recur(usage.numberIndex))); @@ -864,11 +858,12 @@ namespace ts.codefix { } if (usage.calls) { - callSignatures.push(getSignatureFromCalls(usage.calls)); + callSignatures.push(getSignatureFromCalls(usage.calls, checker.getVoidType())); } if (usage.constructs) { - constructSignatures.push(getSignatureFromCalls(usage.constructs)); + // TODO: fallback return should maybe be {}? + constructSignatures.push(getSignatureFromCalls(usage.constructs, checker.getVoidType())); } if (usage.stringIndex) { @@ -880,7 +875,7 @@ namespace ts.codefix { return types; // TODO: Should cache this since I HOPE it doesn't change function recur(innerUsage: Usage): Type { - return unifyFromUsage(inferFromUsage(innerUsage)); + return unifyTypes(inferFromUsage(innerUsage)); } } @@ -931,7 +926,8 @@ namespace ts.codefix { } } - function findBuiltinType(usage: Usage): Type[] { + function findBuiltinTypes(usage: Usage): Type[] { + if (!usage.properties || !usage.properties.size) return []; const builtins = [ checker.getStringType(), checker.getNumberType(), @@ -939,9 +935,21 @@ namespace ts.codefix { checker.createPromiseType(checker.getAnyType()), // checker.getFunctionType() // TODO: not sure what this was supposed to be good for. ]; + // TODO: Still need to infer type parameters const matches = builtins.filter(t => matchesAllPropertiesOf(t, usage)); - if (false && 0 < matches.length && matches.length < 3) { - return matches; + if (0 < matches.length && matches.length < 3) { + return matches.map(m => { + // special-case array and promise for now + if (m === builtins[3] && hasCalls(usage.properties!.get("then" as __String))) { + const paramType = getParameterTypeFromCalls(0, usage.properties!.get("then" as __String)!.calls!, /*isRestParameter*/ false)!; // TODO: GH#18217 + const returns = paramType.getCallSignatures().map(sig => sig.getReturnType()); + return checker.createPromiseType(returns.length ? checker.getUnionType(returns, UnionReduction.Subtype) : checker.getAnyType()); + } + else if (m === builtins[2] && hasCalls(usage.properties!.get("push" as __String))) { + return checker.createArrayType(getParameterTypeFromCalls(0, usage.properties!.get("push" as __String)!.calls!, /*isRestParameter*/ false)!); + } + return m; + }); } return []; } @@ -949,18 +957,18 @@ namespace ts.codefix { function matchesAllPropertiesOf(type: Type, usage: Usage) { if (!usage.properties) return false; let result = true; - usage.properties.forEach((prop, name) => { - const source = checker.getUnionType(inferFromUsage(prop)); - const target = checker.getTypeOfPropertyOfType(type, name as string); - if (target && prop.calls) { - const sigs = checker.getSignaturesOfType(target, ts.SignatureKind.Call); - result = result && !!sigs.length && sigs.some( - sig => checker.isTypeAssignableTo( - getFunctionFromCalls(prop.calls!), - checker.createAnonymousType(undefined!, createSymbolTable(), [sig], emptyArray, undefined, undefined))); + usage.properties.forEach((propUsage, name) => { + const source = checker.getTypeOfPropertyOfType(type, name as string); + if (!source) { + result = false; + return; + } + if (propUsage.calls) { + const sigs = checker.getSignaturesOfType(source, ts.SignatureKind.Call); + result = result && !!sigs.length && checker.isTypeAssignableTo(source, getFunctionFromCalls(propUsage.calls)); } else { - result = result && !!source && !!target && checker.isTypeAssignableTo(source, target); + result = result && checker.isTypeAssignableTo(source, unifyTypes(inferFromUsage(propUsage))); } }); return result; @@ -968,43 +976,38 @@ namespace ts.codefix { function getFunctionFromCalls(calls: CallUsage[]) { - return checker.createAnonymousType(undefined!, createSymbolTable(), [getSignatureFromCalls(calls)], emptyArray, undefined, undefined); + return checker.createAnonymousType(undefined!, createSymbolTable(), [getSignatureFromCalls(calls, checker.getAnyType())], emptyArray, undefined, undefined); } function getParameterTypeFromCalls(parameterIndex: number, calls: CallUsage[], isRestParameter: boolean) { + // TODO: This is largely redundant with getSignatureFromCalls, I think. (though it handles rest parameters correctly, so that needs to be integrated there) let types: Type[] = []; - if (calls) { - for (const call of calls) { - if (call.argumentTypes.length > parameterIndex) { - if (isRestParameter) { - types = concatenate(types, map(call.argumentTypes.slice(parameterIndex), a => checker.getBaseTypeOfLiteralType(a))); - } - else { - types.push(checker.getBaseTypeOfLiteralType(call.argumentTypes[parameterIndex])); - } + for (const call of calls) { + if (call.argumentTypes.length > parameterIndex) { + if (isRestParameter) { + types = concatenate(types, map(call.argumentTypes.slice(parameterIndex), a => checker.getBaseTypeOfLiteralType(a))); + } + else { + types.push(checker.getBaseTypeOfLiteralType(call.argumentTypes[parameterIndex])); } } } - - if (types.length) { - const type = checker.getWidenedType(checker.getUnionType(types, UnionReduction.Subtype)); - return isRestParameter ? checker.createArrayType(type) : type; - } - return undefined; + const type = unifyTypes(types); + return isRestParameter ? checker.createArrayType(type) : type; } - function getSignatureFromCalls(calls: CallUsage[]): Signature { + function getSignatureFromCalls(calls: CallUsage[], fallbackReturn: Type): Signature { const parameters: Symbol[] = []; const length = Math.max(...calls.map(c => c.argumentTypes.length)); for (let i = 0; i < length; i++) { const symbol = checker.createSymbol(SymbolFlags.FunctionScopedVariable, escapeLeadingUnderscores(`arg${i}`)); - symbol.type = unifyFromUsage(calls.map(call => call.argumentTypes[i] || checker.getUndefinedType())); + symbol.type = unifyTypes(calls.map(call => call.argumentTypes[i] || checker.getUndefinedType())); if (calls.some(call => call.argumentTypes[i] === undefined)) { symbol.flags |= SymbolFlags.Optional; } parameters.push(symbol); } - const returnType = unifyFromUsage(inferFromUsage(combineUsages(calls.map(call => call.return_))), checker.getVoidType()); + const returnType = unifyTypes(inferFromUsage(combineUsages(calls.map(call => call.return_))), fallbackReturn); // TODO: GH#18217 return checker.createSignature(/*declaration*/ undefined!, /*typeParameters*/ undefined, /*thisParameter*/ undefined, parameters, returnType, /*typePredicate*/ undefined, length, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); } diff --git a/tests/cases/fourslash/codeFixInferFromFunctionUsage.ts b/tests/cases/fourslash/codeFixInferFromFunctionUsage.ts index 27a039878ba..f2dbad67b4b 100644 --- a/tests/cases/fourslash/codeFixInferFromFunctionUsage.ts +++ b/tests/cases/fourslash/codeFixInferFromFunctionUsage.ts @@ -2,8 +2,8 @@ // @noImplicitAny: true ////function wrap( [| arr |] ) { -//// arr.sort(function (a: number, b: number) { return a < b ? -1 : 1 }) +//// arr.other(function (a: number, b: number) { return a < b ? -1 : 1 }) //// } // https://github.com/Microsoft/TypeScript/issues/29330 -verify.rangeAfterCodeFix("arr: { sort: (arg0: (a: number, b: number) => 1 | -1) => void; }"); +verify.rangeAfterCodeFix("arr: { other: (arg0: (a: number, b: number) => 1 | -1) => void; }"); diff --git a/tests/cases/fourslash/codeFixInferFromPrimitiveUsage.ts b/tests/cases/fourslash/codeFixInferFromPrimitiveUsage.ts new file mode 100644 index 00000000000..81c25770085 --- /dev/null +++ b/tests/cases/fourslash/codeFixInferFromPrimitiveUsage.ts @@ -0,0 +1,9 @@ +/// + +// @noImplicitAny: true +////function wrap( [| s |] ) { +//// return s.length + s.toUpperCase() +//// } + +// https://github.com/Microsoft/TypeScript/issues/29330 +verify.rangeAfterCodeFix("s: string"); diff --git a/tests/cases/fourslash/codeFixInferFromUsageCallBodyBoth.ts b/tests/cases/fourslash/codeFixInferFromUsageCallBodyBoth.ts index 859d5ea2ce7..f59d1bc1907 100644 --- a/tests/cases/fourslash/codeFixInferFromUsageCallBodyBoth.ts +++ b/tests/cases/fourslash/codeFixInferFromUsageCallBodyBoth.ts @@ -1,7 +1,7 @@ /// ////class C { -//// +//// p = 2 ////} ////var c = new C() ////function f([|x, y |]) { From 2f0ac25a00e890004354b095f8bf5b1267222193 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 30 Aug 2019 07:57:55 -0700 Subject: [PATCH 055/140] Defer resolution of type arguments in aliased type references --- src/compiler/checker.ts | 46 ++++++++++++++++++++--------------------- src/compiler/types.ts | 6 +++--- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 85c3c10f150..17023d6e5b6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6382,7 +6382,6 @@ namespace ts { return type.resolvedBaseTypes = emptyArray; } const baseTypeNode = getBaseTypeNodeOfClass(type)!; - const typeArgs = typeArgumentsFromTypeReferenceNode(baseTypeNode); let baseType: Type; const originalBaseType = baseConstructorType.symbol ? getDeclaredTypeOfSymbol(baseConstructorType.symbol) : undefined; if (baseConstructorType.symbol && baseConstructorType.symbol.flags & SymbolFlags.Class && @@ -6390,7 +6389,7 @@ namespace ts { // When base constructor type is a class with no captured type arguments we know that the constructors all have the same type parameters as the // class and all return the instance type of the class. There is no need for further checks and we can apply the // type arguments in the same manner as a type reference to get the same error reporting experience. - baseType = getTypeFromClassOrInterfaceReference(baseTypeNode, baseConstructorType.symbol, typeArgs); + baseType = getTypeFromClassOrInterfaceReference(baseTypeNode, baseConstructorType.symbol); } else if (baseConstructorType.flags & TypeFlags.Any) { baseType = baseConstructorType; @@ -9115,7 +9114,7 @@ namespace ts { return type; } - function createDeferredTypeReference(target: GenericType, node: ArrayTypeNode | TupleTypeNode, mapper?: TypeMapper): DeferredTypeReference { + function createDeferredTypeReference(target: GenericType, node: TypeReferenceNode | ArrayTypeNode | TupleTypeNode, mapper?: TypeMapper): DeferredTypeReference { const aliasSymbol = getAliasSymbolForTypeNode(node); const aliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol); const type = createObjectType(ObjectFlags.Reference, target.symbol); @@ -9129,7 +9128,11 @@ namespace ts { function getTypeArguments(type: TypeReference): ReadonlyArray { if (!type.resolvedTypeArguments) { - const typeArguments = type.node ? map(type.node.kind === SyntaxKind.ArrayType ? [type.node.elementType] : type.node.elementTypes, getTypeFromTypeNode) : emptyArray; + const node = type.node; + const typeArguments = !node ? emptyArray : + node.kind === SyntaxKind.TypeReference ? concatenate(type.target.outerTypeParameters, getEffectiveTypeArguments(node, type.target.localTypeParameters!)) : + node.kind === SyntaxKind.ArrayType ? [getTypeFromTypeNode(node.elementType)] : + map(node.elementTypes, getTypeFromTypeNode); type.resolvedTypeArguments = type.mapper ? instantiateTypes(typeArguments, type.mapper) : typeArguments; } return type.resolvedTypeArguments; @@ -9139,10 +9142,11 @@ namespace ts { return length(type.target.typeParameters); } + /** * Get type from type-reference that reference to class or interface */ - function getTypeFromClassOrInterfaceReference(node: NodeWithTypeArguments, symbol: Symbol, typeArgs: Type[] | undefined): Type { + function getTypeFromClassOrInterfaceReference(node: NodeWithTypeArguments, symbol: Symbol): Type { const type = getDeclaredTypeOfSymbol(getMergedSymbol(symbol)); const typeParameters = type.localTypeParameters; if (typeParameters) { @@ -9166,10 +9170,13 @@ namespace ts { return errorType; } } + if (node.kind === SyntaxKind.TypeReference && isAliasedType(node)) { + return createDeferredTypeReference(type, node, /*mapper*/ undefined); + } // In a type reference, the outer type parameters of the referenced class or interface are automatically // supplied as type arguments and the type reference only specifies arguments for the local type parameters // of the class or interface. - const typeArguments = concatenate(type.outerTypeParameters, fillMissingTypeArguments(typeArgs, typeParameters, minTypeArgumentCount, isJs)); + const typeArguments = concatenate(type.outerTypeParameters, fillMissingTypeArguments(typeArgumentsFromTypeReferenceNode(node), typeParameters, minTypeArgumentCount, isJs)); return createTypeReference(type, typeArguments); } return checkNoTypeArguments(node, symbol) ? type : errorType; @@ -9192,7 +9199,7 @@ namespace ts { * references to the type parameters of the alias. We replace those with the actual type arguments by instantiating the * declared type. Instantiations are cached using the type identities of the type arguments as the key. */ - function getTypeFromTypeAliasReference(node: NodeWithTypeArguments, symbol: Symbol, typeArguments: Type[] | undefined): Type { + function getTypeFromTypeAliasReference(node: NodeWithTypeArguments, symbol: Symbol): Type { const type = getDeclaredTypeOfSymbol(symbol); const typeParameters = getSymbolLinks(symbol).typeParameters; if (typeParameters) { @@ -9208,7 +9215,7 @@ namespace ts { typeParameters.length); return errorType; } - return getTypeAliasInstantiation(symbol, typeArguments); + return getTypeAliasInstantiation(symbol, typeArgumentsFromTypeReferenceNode(node)); } return checkNoTypeArguments(node, symbol) ? type : errorType; } @@ -9239,19 +9246,16 @@ namespace ts { } function getTypeReferenceType(node: NodeWithTypeArguments, symbol: Symbol): Type { - const typeArguments = typeArgumentsFromTypeReferenceNode(node); // Do unconditionally so we mark type arguments as referenced. if (symbol === unknownSymbol) { return errorType; } symbol = getExpandoSymbol(symbol) || symbol; - if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { - return getTypeFromClassOrInterfaceReference(node, symbol, typeArguments); + return getTypeFromClassOrInterfaceReference(node, symbol); } if (symbol.flags & SymbolFlags.TypeAlias) { - return getTypeFromTypeAliasReference(node, symbol, typeArguments); + return getTypeFromTypeAliasReference(node, symbol); } - // Get type from reference to named type that cannot be generic (enum or type parameter) const res = tryGetDeclaredTypeOfSymbol(symbol); if (res) { @@ -9259,7 +9263,6 @@ namespace ts { res.flags & TypeFlags.TypeParameter ? getConstrainedTypeVariable(res, node) : getRegularTypeOfLiteralType(res) : errorType; } - if (symbol.flags & SymbolFlags.Value && isJSDocTypeReference(node)) { const jsdocType = getTypeFromJSAlias(node, symbol); if (jsdocType) { @@ -9271,7 +9274,6 @@ namespace ts { return getTypeOfSymbol(symbol); } } - return errorType; } @@ -26100,16 +26102,13 @@ namespace ts { if (node.kind === SyntaxKind.TypeReference && node.typeName.jsdocDotPos !== undefined && !isInJSFile(node) && !isInJSDoc(node)) { grammarErrorAtPos(node, node.typeName.jsdocDotPos, 1, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments); } + forEach(node.typeArguments, checkSourceElement); const type = getTypeFromTypeReference(node); if (type !== errorType) { - if (node.typeArguments) { - // Do type argument local checks only if referenced type is successfully resolved - forEach(node.typeArguments, checkSourceElement); - if (produceDiagnostics) { - const typeParameters = getTypeParametersForTypeReference(node); - if (typeParameters) { - checkTypeArgumentConstraints(node, typeParameters); - } + if (node.typeArguments && produceDiagnostics) { + const typeParameters = getTypeParametersForTypeReference(node); + if (typeParameters) { + checkTypeArgumentConstraints(node, typeParameters); } } if (type.flags & TypeFlags.Enum && getNodeLinks(node).resolvedSymbol!.flags & SymbolFlags.EnumMember) { @@ -29333,6 +29332,7 @@ namespace ts { const baseTypeNode = getEffectiveBaseTypeNode(node); if (baseTypeNode) { + forEach(baseTypeNode.typeArguments, checkSourceElement); if (languageVersion < ScriptTarget.ES2015) { checkExternalEmitHelpers(baseTypeNode.parent, ExternalEmitHelpers.Extends); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 21f09ffcd5c..0466e75b3c4 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4202,18 +4202,18 @@ namespace ts { */ export interface TypeReference extends ObjectType { target: GenericType; // Type reference target - node?: ArrayTypeNode | TupleTypeNode; + node?: TypeReferenceNode | ArrayTypeNode | TupleTypeNode; /* @internal */ mapper?: TypeMapper; /* @internal */ - resolvedTypeArguments?: ReadonlyArray; // Resolved ype reference type arguments + resolvedTypeArguments?: ReadonlyArray; // Resolved type reference type arguments /* @internal */ literalType?: TypeReference; // Clone of type with ObjectFlags.ArrayLiteral set } export interface DeferredTypeReference extends TypeReference { /* @internal */ - node: ArrayTypeNode | TupleTypeNode; + node: TypeReferenceNode | ArrayTypeNode | TupleTypeNode; /* @internal */ mapper?: TypeMapper; } From 81bfa6f2e054e06a60e8edb105a5275bea0088d9 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 30 Aug 2019 07:58:04 -0700 Subject: [PATCH 056/140] Accept new baselines --- .../reference/api/tsserverlibrary.d.ts | 2 +- tests/baselines/reference/api/typescript.d.ts | 2 +- .../reference/asyncAliasReturnType_es5.types | 4 +-- .../reference/asyncAliasReturnType_es6.types | 4 +-- .../reference/asyncAwait_es2017.types | 32 +++++++++---------- .../baselines/reference/asyncAwait_es5.types | 32 +++++++++---------- .../baselines/reference/asyncAwait_es6.types | 32 +++++++++---------- ...ndexesOfIntersectionsAreInferencable.types | 6 ++-- ...appedTypeWithConditionalIsResolvable.types | 4 +-- ...clarationsForIndirectTypeAliasReference.js | 4 +-- ...rationsForIndirectTypeAliasReference.types | 12 +++---- ...estructuringParameterDeclaration3ES5.types | 12 +++---- ...ringParameterDeclaration3ES5iterable.types | 12 +++---- ...estructuringParameterDeclaration3ES6.types | 12 +++---- .../destructuringParameterDeclaration4.types | 4 +-- ...ectDependenceBetweenTypeAliases.errors.txt | 17 +--------- .../directDependenceBetweenTypeAliases.types | 12 +++---- .../reference/genericDefaultsErrors.types | 4 +-- .../reference/genericTypeAliases.types | 2 +- .../reference/mappedTypesArraysTuples.types | 2 +- .../reactSFCAndFunctionResolvable.types | 20 ++++++------ .../reference/readonlyArraysAndTuples.types | 4 +-- .../reference/readonlyArraysAndTuples2.types | 4 +-- .../reference/specedNoStackBlown.types | 2 +- ...dexOnExistingReadonlyFieldIsNotNever.types | 26 +++++++-------- .../transformNestedGeneratorsWithTry.types | 16 +++++----- ...ropsInferenceSucceedsOnIntersections.types | 2 +- ...xStatelessFunctionComponentOverload5.types | 2 +- ...xStatelessFunctionComponentOverload6.types | 2 +- ...tiatedWithDefaultWhenCheckingDefault.types | 4 +-- 30 files changed, 139 insertions(+), 154 deletions(-) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index c70f389e210..c6601d8d37d 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2351,7 +2351,7 @@ declare namespace ts { */ export interface TypeReference extends ObjectType { target: GenericType; - node?: ArrayTypeNode | TupleTypeNode; + node?: TypeReferenceNode | ArrayTypeNode | TupleTypeNode; } export interface DeferredTypeReference extends TypeReference { } diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index c7b96ded9b2..de30e555988 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2351,7 +2351,7 @@ declare namespace ts { */ export interface TypeReference extends ObjectType { target: GenericType; - node?: ArrayTypeNode | TupleTypeNode; + node?: TypeReferenceNode | ArrayTypeNode | TupleTypeNode; } export interface DeferredTypeReference extends TypeReference { } diff --git a/tests/baselines/reference/asyncAliasReturnType_es5.types b/tests/baselines/reference/asyncAliasReturnType_es5.types index 87090b795e3..22ca9c932b3 100644 --- a/tests/baselines/reference/asyncAliasReturnType_es5.types +++ b/tests/baselines/reference/asyncAliasReturnType_es5.types @@ -1,7 +1,7 @@ === tests/cases/conformance/async/es5/asyncAliasReturnType_es5.ts === type PromiseAlias = Promise; ->PromiseAlias : Promise +>PromiseAlias : PromiseAlias async function f(): PromiseAlias { ->f : () => Promise +>f : () => PromiseAlias } diff --git a/tests/baselines/reference/asyncAliasReturnType_es6.types b/tests/baselines/reference/asyncAliasReturnType_es6.types index 85d74896056..943856611b5 100644 --- a/tests/baselines/reference/asyncAliasReturnType_es6.types +++ b/tests/baselines/reference/asyncAliasReturnType_es6.types @@ -1,7 +1,7 @@ === tests/cases/conformance/async/es6/asyncAliasReturnType_es6.ts === type PromiseAlias = Promise; ->PromiseAlias : Promise +>PromiseAlias : PromiseAlias async function f(): PromiseAlias { ->f : () => Promise +>f : () => PromiseAlias } diff --git a/tests/baselines/reference/asyncAwait_es2017.types b/tests/baselines/reference/asyncAwait_es2017.types index 4d657ab2ca3..c3fecf0f7c8 100644 --- a/tests/baselines/reference/asyncAwait_es2017.types +++ b/tests/baselines/reference/asyncAwait_es2017.types @@ -1,6 +1,6 @@ === tests/cases/conformance/async/es2017/asyncAwait_es2017.ts === type MyPromise = Promise; ->MyPromise : Promise +>MyPromise : MyPromise declare var MyPromise: typeof Promise; >MyPromise : PromiseConstructor @@ -10,7 +10,7 @@ declare var p: Promise; >p : Promise declare var mp: MyPromise; ->mp : Promise +>mp : MyPromise async function f0() { } >f0 : () => Promise @@ -19,7 +19,7 @@ async function f1(): Promise { } >f1 : () => Promise async function f3(): MyPromise { } ->f3 : () => Promise +>f3 : () => MyPromise let f4 = async function() { } >f4 : () => Promise @@ -30,8 +30,8 @@ let f5 = async function(): Promise { } >async function(): Promise { } : () => Promise let f6 = async function(): MyPromise { } ->f6 : () => Promise ->async function(): MyPromise { } : () => Promise +>f6 : () => MyPromise +>async function(): MyPromise { } : () => MyPromise let f7 = async () => { }; >f7 : () => Promise @@ -42,8 +42,8 @@ let f8 = async (): Promise => { }; >async (): Promise => { } : () => Promise let f9 = async (): MyPromise => { }; ->f9 : () => Promise ->async (): MyPromise => { } : () => Promise +>f9 : () => MyPromise +>async (): MyPromise => { } : () => MyPromise let f10 = async () => p; >f10 : () => Promise @@ -53,21 +53,21 @@ let f10 = async () => p; let f11 = async () => mp; >f11 : () => Promise >async () => mp : () => Promise ->mp : Promise +>mp : MyPromise let f12 = async (): Promise => mp; >f12 : () => Promise >async (): Promise => mp : () => Promise ->mp : Promise +>mp : MyPromise let f13 = async (): MyPromise => p; ->f13 : () => Promise ->async (): MyPromise => p : () => Promise +>f13 : () => MyPromise +>async (): MyPromise => p : () => MyPromise >p : Promise let o = { ->o : { m1(): Promise; m2(): Promise; m3(): Promise; } ->{ async m1() { }, async m2(): Promise { }, async m3(): MyPromise { }} : { m1(): Promise; m2(): Promise; m3(): Promise; } +>o : { m1(): Promise; m2(): Promise; m3(): MyPromise; } +>{ async m1() { }, async m2(): Promise { }, async m3(): MyPromise { }} : { m1(): Promise; m2(): Promise; m3(): MyPromise; } async m1() { }, >m1 : () => Promise @@ -76,7 +76,7 @@ let o = { >m2 : () => Promise async m3(): MyPromise { } ->m3 : () => Promise +>m3 : () => MyPromise }; @@ -90,7 +90,7 @@ class C { >m2 : () => Promise async m3(): MyPromise { } ->m3 : () => Promise +>m3 : () => MyPromise static async m4() { } >m4 : () => Promise @@ -99,7 +99,7 @@ class C { >m5 : () => Promise static async m6(): MyPromise { } ->m6 : () => Promise +>m6 : () => MyPromise } module M { diff --git a/tests/baselines/reference/asyncAwait_es5.types b/tests/baselines/reference/asyncAwait_es5.types index fb10a6dd043..be62067c301 100644 --- a/tests/baselines/reference/asyncAwait_es5.types +++ b/tests/baselines/reference/asyncAwait_es5.types @@ -1,6 +1,6 @@ === tests/cases/conformance/async/es5/asyncAwait_es5.ts === type MyPromise = Promise; ->MyPromise : Promise +>MyPromise : MyPromise declare var MyPromise: typeof Promise; >MyPromise : PromiseConstructor @@ -10,7 +10,7 @@ declare var p: Promise; >p : Promise declare var mp: MyPromise; ->mp : Promise +>mp : MyPromise async function f0() { } >f0 : () => Promise @@ -19,7 +19,7 @@ async function f1(): Promise { } >f1 : () => Promise async function f3(): MyPromise { } ->f3 : () => Promise +>f3 : () => MyPromise let f4 = async function() { } >f4 : () => Promise @@ -30,8 +30,8 @@ let f5 = async function(): Promise { } >async function(): Promise { } : () => Promise let f6 = async function(): MyPromise { } ->f6 : () => Promise ->async function(): MyPromise { } : () => Promise +>f6 : () => MyPromise +>async function(): MyPromise { } : () => MyPromise let f7 = async () => { }; >f7 : () => Promise @@ -42,8 +42,8 @@ let f8 = async (): Promise => { }; >async (): Promise => { } : () => Promise let f9 = async (): MyPromise => { }; ->f9 : () => Promise ->async (): MyPromise => { } : () => Promise +>f9 : () => MyPromise +>async (): MyPromise => { } : () => MyPromise let f10 = async () => p; >f10 : () => Promise @@ -53,21 +53,21 @@ let f10 = async () => p; let f11 = async () => mp; >f11 : () => Promise >async () => mp : () => Promise ->mp : Promise +>mp : MyPromise let f12 = async (): Promise => mp; >f12 : () => Promise >async (): Promise => mp : () => Promise ->mp : Promise +>mp : MyPromise let f13 = async (): MyPromise => p; ->f13 : () => Promise ->async (): MyPromise => p : () => Promise +>f13 : () => MyPromise +>async (): MyPromise => p : () => MyPromise >p : Promise let o = { ->o : { m1(): Promise; m2(): Promise; m3(): Promise; } ->{ async m1() { }, async m2(): Promise { }, async m3(): MyPromise { }} : { m1(): Promise; m2(): Promise; m3(): Promise; } +>o : { m1(): Promise; m2(): Promise; m3(): MyPromise; } +>{ async m1() { }, async m2(): Promise { }, async m3(): MyPromise { }} : { m1(): Promise; m2(): Promise; m3(): MyPromise; } async m1() { }, >m1 : () => Promise @@ -76,7 +76,7 @@ let o = { >m2 : () => Promise async m3(): MyPromise { } ->m3 : () => Promise +>m3 : () => MyPromise }; @@ -90,7 +90,7 @@ class C { >m2 : () => Promise async m3(): MyPromise { } ->m3 : () => Promise +>m3 : () => MyPromise static async m4() { } >m4 : () => Promise @@ -99,7 +99,7 @@ class C { >m5 : () => Promise static async m6(): MyPromise { } ->m6 : () => Promise +>m6 : () => MyPromise } module M { diff --git a/tests/baselines/reference/asyncAwait_es6.types b/tests/baselines/reference/asyncAwait_es6.types index cd9a05ee48e..3933b9ce7da 100644 --- a/tests/baselines/reference/asyncAwait_es6.types +++ b/tests/baselines/reference/asyncAwait_es6.types @@ -1,6 +1,6 @@ === tests/cases/conformance/async/es6/asyncAwait_es6.ts === type MyPromise = Promise; ->MyPromise : Promise +>MyPromise : MyPromise declare var MyPromise: typeof Promise; >MyPromise : PromiseConstructor @@ -10,7 +10,7 @@ declare var p: Promise; >p : Promise declare var mp: MyPromise; ->mp : Promise +>mp : MyPromise async function f0() { } >f0 : () => Promise @@ -19,7 +19,7 @@ async function f1(): Promise { } >f1 : () => Promise async function f3(): MyPromise { } ->f3 : () => Promise +>f3 : () => MyPromise let f4 = async function() { } >f4 : () => Promise @@ -30,8 +30,8 @@ let f5 = async function(): Promise { } >async function(): Promise { } : () => Promise let f6 = async function(): MyPromise { } ->f6 : () => Promise ->async function(): MyPromise { } : () => Promise +>f6 : () => MyPromise +>async function(): MyPromise { } : () => MyPromise let f7 = async () => { }; >f7 : () => Promise @@ -42,8 +42,8 @@ let f8 = async (): Promise => { }; >async (): Promise => { } : () => Promise let f9 = async (): MyPromise => { }; ->f9 : () => Promise ->async (): MyPromise => { } : () => Promise +>f9 : () => MyPromise +>async (): MyPromise => { } : () => MyPromise let f10 = async () => p; >f10 : () => Promise @@ -53,21 +53,21 @@ let f10 = async () => p; let f11 = async () => mp; >f11 : () => Promise >async () => mp : () => Promise ->mp : Promise +>mp : MyPromise let f12 = async (): Promise => mp; >f12 : () => Promise >async (): Promise => mp : () => Promise ->mp : Promise +>mp : MyPromise let f13 = async (): MyPromise => p; ->f13 : () => Promise ->async (): MyPromise => p : () => Promise +>f13 : () => MyPromise +>async (): MyPromise => p : () => MyPromise >p : Promise let o = { ->o : { m1(): Promise; m2(): Promise; m3(): Promise; } ->{ async m1() { }, async m2(): Promise { }, async m3(): MyPromise { }} : { m1(): Promise; m2(): Promise; m3(): Promise; } +>o : { m1(): Promise; m2(): Promise; m3(): MyPromise; } +>{ async m1() { }, async m2(): Promise { }, async m3(): MyPromise { }} : { m1(): Promise; m2(): Promise; m3(): MyPromise; } async m1() { }, >m1 : () => Promise @@ -76,7 +76,7 @@ let o = { >m2 : () => Promise async m3(): MyPromise { } ->m3 : () => Promise +>m3 : () => MyPromise }; @@ -90,7 +90,7 @@ class C { >m2 : () => Promise async m3(): MyPromise { } ->m3 : () => Promise +>m3 : () => MyPromise static async m4() { } >m4 : () => Promise @@ -99,7 +99,7 @@ class C { >m5 : () => Promise static async m6(): MyPromise { } ->m6 : () => Promise +>m6 : () => MyPromise } module M { diff --git a/tests/baselines/reference/complicatedIndexesOfIntersectionsAreInferencable.types b/tests/baselines/reference/complicatedIndexesOfIntersectionsAreInferencable.types index 64511cb9df2..55d6368e292 100644 --- a/tests/baselines/reference/complicatedIndexesOfIntersectionsAreInferencable.types +++ b/tests/baselines/reference/complicatedIndexesOfIntersectionsAreInferencable.types @@ -12,10 +12,10 @@ interface FormikConfig { } declare function Func( ->Func : (x: string extends "validate" | "initialValues" | keyof ExtraProps ? Readonly & ExtraProps> : Pick & ExtraProps>, "validate" | "initialValues" | Exclude> & Partial & ExtraProps>, "validateOnChange" | Extract>>) => void +>Func : (x: string extends keyof ExtraProps | "validate" | "initialValues" ? Readonly & ExtraProps> : Pick & ExtraProps>, Exclude | "validate" | "initialValues"> & Partial & ExtraProps>, "validateOnChange" | Extract>>) => void x: (string extends "validate" | "initialValues" | keyof ExtraProps ->x : string extends "validate" | "initialValues" | keyof ExtraProps ? Readonly & ExtraProps> : Pick & ExtraProps>, "validate" | "initialValues" | Exclude> & Partial & ExtraProps>, "validateOnChange" | Extract>> +>x : string extends keyof ExtraProps | "validate" | "initialValues" ? Readonly & ExtraProps> : Pick & ExtraProps>, Exclude | "validate" | "initialValues"> & Partial & ExtraProps>, "validateOnChange" | Extract>> ? Readonly & ExtraProps> : Pick & ExtraProps>, "validate" | "initialValues" | Exclude> @@ -24,7 +24,7 @@ declare function Func( Func({ >Func({ initialValues: { foo: "" }, validate: props => { props.foo; }}) : void ->Func : (x: string extends "validate" | "initialValues" | keyof ExtraProps ? Readonly & ExtraProps> : Pick & ExtraProps>, "validate" | "initialValues" | Exclude> & Partial & ExtraProps>, "validateOnChange" | Extract>>) => void +>Func : (x: string extends keyof ExtraProps | "validate" | "initialValues" ? Readonly & ExtraProps> : Pick & ExtraProps>, Exclude | "validate" | "initialValues"> & Partial & ExtraProps>, "validateOnChange" | Extract>>) => void >{ initialValues: { foo: "" }, validate: props => { props.foo; }} : { initialValues: { foo: string; }; validate: (props: { foo: string; }) => void; } initialValues: { diff --git a/tests/baselines/reference/constraintOfRecursivelyMappedTypeWithConditionalIsResolvable.types b/tests/baselines/reference/constraintOfRecursivelyMappedTypeWithConditionalIsResolvable.types index b3f5a0e9f91..1170aa71c48 100644 --- a/tests/baselines/reference/constraintOfRecursivelyMappedTypeWithConditionalIsResolvable.types +++ b/tests/baselines/reference/constraintOfRecursivelyMappedTypeWithConditionalIsResolvable.types @@ -6,7 +6,7 @@ interface Map { } export type ImmutableTypes = IImmutableMap; ->ImmutableTypes : IImmutableMap +>ImmutableTypes : ImmutableTypes export type ImmutableModel = { [K in keyof T]: T[K] extends ImmutableTypes ? T[K] : never }; >ImmutableModel : ImmutableModel @@ -19,7 +19,7 @@ export interface IImmutableMap> extends Map; ->ImmutableTypes2 : IImmutableMap2 +>ImmutableTypes2 : ImmutableTypes2 type isImmutableType = [T] extends [ImmutableTypes2] ? T : never; >isImmutableType : isImmutableType diff --git a/tests/baselines/reference/declarationsForIndirectTypeAliasReference.js b/tests/baselines/reference/declarationsForIndirectTypeAliasReference.js index 9e2f9ee4039..1563e2571cc 100644 --- a/tests/baselines/reference/declarationsForIndirectTypeAliasReference.js +++ b/tests/baselines/reference/declarationsForIndirectTypeAliasReference.js @@ -61,6 +61,6 @@ declare type StringHash = Hash; interface StringHash2 extends Hash { } //// [a.d.ts] -import { StringHash2 } from "./b"; +import { StringHash, StringHash2 } from "./b"; export { doSome }; -declare function doSome(arg1: string, arg2?: import("./b").Hash, arg3?: StringHash2): void; +declare function doSome(arg1: string, arg2?: StringHash, arg3?: StringHash2): void; diff --git a/tests/baselines/reference/declarationsForIndirectTypeAliasReference.types b/tests/baselines/reference/declarationsForIndirectTypeAliasReference.types index e527a8a3bfa..85ebfca651f 100644 --- a/tests/baselines/reference/declarationsForIndirectTypeAliasReference.types +++ b/tests/baselines/reference/declarationsForIndirectTypeAliasReference.types @@ -15,7 +15,7 @@ interface Hash { } type StringHash = Hash; ->StringHash : Hash +>StringHash : StringHash interface StringHash2 extends Hash {} === tests/cases/compiler/a.ts === @@ -25,11 +25,11 @@ import {StringHash, StringHash2} from "./b"; export { doSome ->doSome : (arg1: string, arg2?: import("tests/cases/compiler/b").Hash, arg3?: StringHash2) => void +>doSome : (arg1: string, arg2?: StringHash, arg3?: StringHash2) => void } const MAP: StringHash = { ->MAP : import("tests/cases/compiler/b").Hash +>MAP : StringHash >{ a: "a"} : { a: string; } a: "a" @@ -49,12 +49,12 @@ const MAP2: StringHash2 = { }; function doSome(arg1: string, ->doSome : (arg1: string, arg2?: import("tests/cases/compiler/b").Hash, arg3?: StringHash2) => void +>doSome : (arg1: string, arg2?: StringHash, arg3?: StringHash2) => void >arg1 : string arg2 = MAP, ->arg2 : import("tests/cases/compiler/b").Hash ->MAP : import("tests/cases/compiler/b").Hash +>arg2 : StringHash +>MAP : StringHash arg3 = MAP2) { >arg3 : StringHash2 diff --git a/tests/baselines/reference/destructuringParameterDeclaration3ES5.types b/tests/baselines/reference/destructuringParameterDeclaration3ES5.types index 96681054bd9..a18a2c4f0a9 100644 --- a/tests/baselines/reference/destructuringParameterDeclaration3ES5.types +++ b/tests/baselines/reference/destructuringParameterDeclaration3ES5.types @@ -6,13 +6,13 @@ // ... Identifier TypeAnnotation(opt) type arrayString = Array ->arrayString : String[] +>arrayString : arrayString type someArray = Array | number[]; >someArray : someArray type stringOrNumArray = Array; ->stringOrNumArray : (String | Number)[] +>stringOrNumArray : stringOrNumArray function a1(...x: (number|string)[]) { } >a1 : (...x: (string | number)[]) => void @@ -27,12 +27,12 @@ function a3(...a: Array) { } >a : String[] function a4(...a: arrayString) { } ->a4 : (...a: String[]) => void ->a : String[] +>a4 : (...a: arrayString) => void +>a : arrayString function a5(...a: stringOrNumArray) { } ->a5 : (...a: (String | Number)[]) => void ->a : (String | Number)[] +>a5 : (...a: stringOrNumArray) => void +>a : stringOrNumArray function a9([a, b, [[c]]]) { } >a9 : ([a, b, [[c]]]: [any, any, [[any]]]) => void diff --git a/tests/baselines/reference/destructuringParameterDeclaration3ES5iterable.types b/tests/baselines/reference/destructuringParameterDeclaration3ES5iterable.types index 441a079e4ab..e41c2e5d75a 100644 --- a/tests/baselines/reference/destructuringParameterDeclaration3ES5iterable.types +++ b/tests/baselines/reference/destructuringParameterDeclaration3ES5iterable.types @@ -6,13 +6,13 @@ // ... Identifier TypeAnnotation(opt) type arrayString = Array ->arrayString : String[] +>arrayString : arrayString type someArray = Array | number[]; >someArray : someArray type stringOrNumArray = Array; ->stringOrNumArray : (String | Number)[] +>stringOrNumArray : stringOrNumArray function a1(...x: (number|string)[]) { } >a1 : (...x: (string | number)[]) => void @@ -27,12 +27,12 @@ function a3(...a: Array) { } >a : String[] function a4(...a: arrayString) { } ->a4 : (...a: String[]) => void ->a : String[] +>a4 : (...a: arrayString) => void +>a : arrayString function a5(...a: stringOrNumArray) { } ->a5 : (...a: (String | Number)[]) => void ->a : (String | Number)[] +>a5 : (...a: stringOrNumArray) => void +>a : stringOrNumArray function a9([a, b, [[c]]]) { } >a9 : ([a, b, [[c]]]: [any, any, [[any]]]) => void diff --git a/tests/baselines/reference/destructuringParameterDeclaration3ES6.types b/tests/baselines/reference/destructuringParameterDeclaration3ES6.types index a7fcb861e4c..4adacfd11ff 100644 --- a/tests/baselines/reference/destructuringParameterDeclaration3ES6.types +++ b/tests/baselines/reference/destructuringParameterDeclaration3ES6.types @@ -6,13 +6,13 @@ // ... Identifier TypeAnnotation(opt) type arrayString = Array ->arrayString : String[] +>arrayString : arrayString type someArray = Array | number[]; >someArray : someArray type stringOrNumArray = Array; ->stringOrNumArray : (String | Number)[] +>stringOrNumArray : stringOrNumArray function a1(...x: (number|string)[]) { } >a1 : (...x: (string | number)[]) => void @@ -27,12 +27,12 @@ function a3(...a: Array) { } >a : String[] function a4(...a: arrayString) { } ->a4 : (...a: String[]) => void ->a : String[] +>a4 : (...a: arrayString) => void +>a : arrayString function a5(...a: stringOrNumArray) { } ->a5 : (...a: (String | Number)[]) => void ->a : (String | Number)[] +>a5 : (...a: stringOrNumArray) => void +>a : stringOrNumArray function a9([a, b, [[c]]]) { } >a9 : ([a, b, [[c]]]: [any, any, [[any]]]) => void diff --git a/tests/baselines/reference/destructuringParameterDeclaration4.types b/tests/baselines/reference/destructuringParameterDeclaration4.types index 444a70ff196..2c3a7dc5f95 100644 --- a/tests/baselines/reference/destructuringParameterDeclaration4.types +++ b/tests/baselines/reference/destructuringParameterDeclaration4.types @@ -6,13 +6,13 @@ // ... Identifier TypeAnnotation(opt) type arrayString = Array ->arrayString : String[] +>arrayString : arrayString type someArray = Array | number[]; >someArray : someArray type stringOrNumArray = Array; ->stringOrNumArray : (String | Number)[] +>stringOrNumArray : stringOrNumArray function a0(...x: [number, number, string]) { } // Error, rest parameter must be array type >a0 : (x_0: number, x_1: number, x_2: string) => void diff --git a/tests/baselines/reference/directDependenceBetweenTypeAliases.errors.txt b/tests/baselines/reference/directDependenceBetweenTypeAliases.errors.txt index 15e654df9a7..374cef0c1cb 100644 --- a/tests/baselines/reference/directDependenceBetweenTypeAliases.errors.txt +++ b/tests/baselines/reference/directDependenceBetweenTypeAliases.errors.txt @@ -2,17 +2,12 @@ tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts( tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(5,6): error TS2456: Type alias 'T0_1' circularly references itself. tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(6,6): error TS2456: Type alias 'T0_2' circularly references itself. tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(7,6): error TS2456: Type alias 'T0_3' circularly references itself. -tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(11,6): error TS2456: Type alias 'T1' circularly references itself. tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(14,6): error TS2456: Type alias 'T2' circularly references itself. tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(25,5): error TS2502: 'x' is referenced directly or indirectly in its own type annotation. tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(26,6): error TS2456: Type alias 'T5' circularly references itself. -tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(29,6): error TS2456: Type alias 'T6' circularly references itself. -tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(30,6): error TS2456: Type alias 'T7' circularly references itself. -tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(31,5): error TS2502: 'yy' is referenced directly or indirectly in its own type annotation. -tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts(32,6): error TS2456: Type alias 'T8' circularly references itself. -==== tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts (12 errors) ==== +==== tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts (7 errors) ==== // It is an error for the type specified in a type alias to depend on that type alias // A type alias directly depends on the type it aliases. @@ -32,8 +27,6 @@ tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts( // A type reference directly depends on the referenced type and each of the type arguments, if any. interface I {} type T1 = I - ~~ -!!! error TS2456: Type alias 'T1' circularly references itself. // A union type directly depends on each of the constituent types. type T2 = T2 | string @@ -58,17 +51,9 @@ tests/cases/conformance/types/typeAliases/directDependenceBetweenTypeAliases.ts( class C1 {} type T6 = T7 | number - ~~ -!!! error TS2456: Type alias 'T6' circularly references itself. type T7 = typeof yy - ~~ -!!! error TS2456: Type alias 'T7' circularly references itself. var yy: [string, T8[]]; - ~~ -!!! error TS2502: 'yy' is referenced directly or indirectly in its own type annotation. type T8 = C - ~~ -!!! error TS2456: Type alias 'T8' circularly references itself. // legal cases type T9 = () => T9 diff --git a/tests/baselines/reference/directDependenceBetweenTypeAliases.types b/tests/baselines/reference/directDependenceBetweenTypeAliases.types index 1ddbeb019cf..e1d6784b327 100644 --- a/tests/baselines/reference/directDependenceBetweenTypeAliases.types +++ b/tests/baselines/reference/directDependenceBetweenTypeAliases.types @@ -17,7 +17,7 @@ type T0_3 = T0_1 // A type reference directly depends on the referenced type and each of the type arguments, if any. interface I {} type T1 = I ->T1 : any +>T1 : T1 // A union type directly depends on each of the constituent types. type T2 = T2 | string @@ -50,17 +50,17 @@ class C1 {} >C1 : C1 type T6 = T7 | number ->T6 : any +>T6 : T6 type T7 = typeof yy ->T7 : any ->yy : any +>T7 : [string, T8[]] +>yy : [string, T8[]] var yy: [string, T8[]]; ->yy : any +>yy : [string, T8[]] type T8 = C ->T8 : any +>T8 : T8 // legal cases type T9 = () => T9 diff --git a/tests/baselines/reference/genericDefaultsErrors.types b/tests/baselines/reference/genericDefaultsErrors.types index 51b819f9d01..5eaf9af1cc1 100644 --- a/tests/baselines/reference/genericDefaultsErrors.types +++ b/tests/baselines/reference/genericDefaultsErrors.types @@ -70,10 +70,10 @@ type i09t01 = i09<1>; // error >i09t01 : any type i09t02 = i09<1, 2>; // ok ->i09t02 : i09<1, 2, number> +>i09t02 : i09t02 type i09t03 = i09<1, 2, 3>; // ok ->i09t03 : i09<1, 2, 3> +>i09t03 : i09t03 type i09t04 = i09<1, 2, 3, 4>; // error >i09t04 : any diff --git a/tests/baselines/reference/genericTypeAliases.types b/tests/baselines/reference/genericTypeAliases.types index 308c61da725..a092c7c8024 100644 --- a/tests/baselines/reference/genericTypeAliases.types +++ b/tests/baselines/reference/genericTypeAliases.types @@ -143,7 +143,7 @@ interface AB { } type Pair = AB; ->Pair : AB +>Pair : Pair interface TaggedPair extends Pair { tag: string; diff --git a/tests/baselines/reference/mappedTypesArraysTuples.types b/tests/baselines/reference/mappedTypesArraysTuples.types index 6b43cd510fb..2ec00ad565e 100644 --- a/tests/baselines/reference/mappedTypesArraysTuples.types +++ b/tests/baselines/reference/mappedTypesArraysTuples.types @@ -66,7 +66,7 @@ type B = { b: string }; >b : string type T40 = Boxified | [A, B] | string | string[]>; ->T40 : string | Box[] | Boxified | Box[] | readonly Box[] | [Box, Box] +>T40 : string | Box[] | Boxified | readonly Box[] | Box[] | [Box, Box] type ReadWrite = { -readonly [P in keyof T] : T[P] }; >ReadWrite : ReadWrite diff --git a/tests/baselines/reference/reactSFCAndFunctionResolvable.types b/tests/baselines/reference/reactSFCAndFunctionResolvable.types index d8061605b1f..d4949fe8850 100644 --- a/tests/baselines/reference/reactSFCAndFunctionResolvable.types +++ b/tests/baselines/reference/reactSFCAndFunctionResolvable.types @@ -14,7 +14,7 @@ declare const OtherRadio: () => React.ReactElement<{}>; >React : any declare const Checkbox: React.SFC; ->Checkbox : React.StatelessComponent<{}> +>Checkbox : React.SFC<{}> >React : any declare const condition1: boolean; @@ -27,43 +27,43 @@ declare const condition3: boolean; >condition3 : boolean const RandomComponent: React.SFC = () => { ->RandomComponent : React.StatelessComponent<{}> +>RandomComponent : React.SFC<{}> >React : any >() => { const Component = condition1 ? Radio : Checkbox; const OtherComponent = condition2 ? OtherRadio : Checkbox; return condition1 ? : ;} : () => JSX.Element const Component = ->Component : React.StatelessComponent<{}> | ((props: {}) => React.ReactElement<{}>) +>Component : ((props: {}) => React.ReactElement<{}>) | React.SFC<{}> condition1 ->condition1 ? Radio : Checkbox : React.StatelessComponent<{}> | ((props: {}) => React.ReactElement<{}>) +>condition1 ? Radio : Checkbox : ((props: {}) => React.ReactElement<{}>) | React.SFC<{}> >condition1 : boolean ? Radio >Radio : (props: {}) => React.ReactElement<{}> : Checkbox; ->Checkbox : React.StatelessComponent<{}> +>Checkbox : React.SFC<{}> const OtherComponent = ->OtherComponent : React.StatelessComponent<{}> | (() => React.ReactElement<{}>) +>OtherComponent : (() => React.ReactElement<{}>) | React.SFC<{}> condition2 ->condition2 ? OtherRadio : Checkbox : React.StatelessComponent<{}> | (() => React.ReactElement<{}>) +>condition2 ? OtherRadio : Checkbox : (() => React.ReactElement<{}>) | React.SFC<{}> >condition2 : boolean ? OtherRadio >OtherRadio : () => React.ReactElement<{}> : Checkbox; ->Checkbox : React.StatelessComponent<{}> +>Checkbox : React.SFC<{}> return condition1 ? : ; >condition1 ? : : JSX.Element >condition1 : boolean > : JSX.Element ->Component : React.StatelessComponent<{}> | ((props: {}) => React.ReactElement<{}>) +>Component : ((props: {}) => React.ReactElement<{}>) | React.SFC<{}> > : JSX.Element ->OtherComponent : React.StatelessComponent<{}> | (() => React.ReactElement<{}>) +>OtherComponent : (() => React.ReactElement<{}>) | React.SFC<{}> }; diff --git a/tests/baselines/reference/readonlyArraysAndTuples.types b/tests/baselines/reference/readonlyArraysAndTuples.types index 2d4086a0193..a0db326f35e 100644 --- a/tests/baselines/reference/readonlyArraysAndTuples.types +++ b/tests/baselines/reference/readonlyArraysAndTuples.types @@ -3,13 +3,13 @@ type T10 = string[]; >T10 : T10 type T11 = Array; ->T11 : string[] +>T11 : T11 type T12 = readonly string[]; >T12 : readonly string[] type T13 = ReadonlyArray; ->T13 : readonly string[] +>T13 : T13 type T20 = [number, number]; >T20 : T20 diff --git a/tests/baselines/reference/readonlyArraysAndTuples2.types b/tests/baselines/reference/readonlyArraysAndTuples2.types index 7b8c7124806..be75e046528 100644 --- a/tests/baselines/reference/readonlyArraysAndTuples2.types +++ b/tests/baselines/reference/readonlyArraysAndTuples2.types @@ -3,13 +3,13 @@ type T10 = string[]; >T10 : T10 type T11 = Array; ->T11 : string[] +>T11 : T11 type T12 = readonly string[]; >T12 : readonly string[] type T13 = ReadonlyArray; ->T13 : readonly string[] +>T13 : T13 type T20 = [number, number]; >T20 : T20 diff --git a/tests/baselines/reference/specedNoStackBlown.types b/tests/baselines/reference/specedNoStackBlown.types index f2ef490fa80..884c24151a0 100644 --- a/tests/baselines/reference/specedNoStackBlown.types +++ b/tests/baselines/reference/specedNoStackBlown.types @@ -29,7 +29,7 @@ export type Spec = [Predicate, ErrorMs >Spec : Spec export type SpecArray = Array>; ->SpecArray : Spec[] +>SpecArray : SpecArray export type SpecFunction = [INPUT] extends [ReadonlyArray] >SpecFunction : SpecFunction diff --git a/tests/baselines/reference/thisIndexOnExistingReadonlyFieldIsNotNever.types b/tests/baselines/reference/thisIndexOnExistingReadonlyFieldIsNotNever.types index 30dfd635724..8f1eff831e3 100644 --- a/tests/baselines/reference/thisIndexOnExistingReadonlyFieldIsNotNever.types +++ b/tests/baselines/reference/thisIndexOnExistingReadonlyFieldIsNotNever.types @@ -15,7 +15,7 @@ interface CoachMarkAnchorProps { >anchor : C } type AnchorType

= Component

; ->AnchorType : Component +>AnchorType : AnchorType

class CoachMarkAnchorDecorator { >CoachMarkAnchorDecorator : CoachMarkAnchorDecorator @@ -27,28 +27,28 @@ class CoachMarkAnchorDecorator { return class CoachMarkAnchor extends Component> & P, {}> { >class CoachMarkAnchor extends Component> & P, {}> { private _onAnchorRef = (anchor: AnchorType

) => { const anchorRef = this.props.anchorRef; if (anchorRef) { anchorRef(anchor); } } } : typeof CoachMarkAnchor >CoachMarkAnchor : typeof CoachMarkAnchor ->Component : Component> & P, {}> +>Component : Component> & P, {}> private _onAnchorRef = (anchor: AnchorType

) => { ->_onAnchorRef : (anchor: Component) => void ->(anchor: AnchorType

) => { const anchorRef = this.props.anchorRef; if (anchorRef) { anchorRef(anchor); } } : (anchor: Component) => void ->anchor : Component +>_onAnchorRef : (anchor: AnchorType

) => void +>(anchor: AnchorType

) => { const anchorRef = this.props.anchorRef; if (anchorRef) { anchorRef(anchor); } } : (anchor: AnchorType

) => void +>anchor : AnchorType

const anchorRef = this.props.anchorRef; ->anchorRef : (CoachMarkAnchorProps> & P)["anchorRef"] | undefined ->this.props.anchorRef : (CoachMarkAnchorProps> & P)["anchorRef"] | undefined ->this.props : Readonly<{ children?: unknown; }> & Readonly> & P> +>anchorRef : (CoachMarkAnchorProps> & P)["anchorRef"] | undefined +>this.props.anchorRef : (CoachMarkAnchorProps> & P)["anchorRef"] | undefined +>this.props : Readonly<{ children?: unknown; }> & Readonly> & P> >this : this ->props : Readonly<{ children?: unknown; }> & Readonly> & P> ->anchorRef : (CoachMarkAnchorProps> & P)["anchorRef"] | undefined +>props : Readonly<{ children?: unknown; }> & Readonly> & P> +>anchorRef : (CoachMarkAnchorProps> & P)["anchorRef"] | undefined if (anchorRef) { ->anchorRef : (CoachMarkAnchorProps> & P)["anchorRef"] | undefined +>anchorRef : (CoachMarkAnchorProps> & P)["anchorRef"] | undefined anchorRef(anchor); >anchorRef(anchor) : void ->anchorRef : (anchor: Component) => void ->anchor : Component +>anchorRef : (anchor: AnchorType

) => void +>anchor : AnchorType

} } }; diff --git a/tests/baselines/reference/transformNestedGeneratorsWithTry.types b/tests/baselines/reference/transformNestedGeneratorsWithTry.types index 0ea963bbe4a..061342eaf44 100644 --- a/tests/baselines/reference/transformNestedGeneratorsWithTry.types +++ b/tests/baselines/reference/transformNestedGeneratorsWithTry.types @@ -4,13 +4,13 @@ import * as Bluebird from 'bluebird'; >Bluebird : PromiseConstructor async function a(): Bluebird { ->a : () => Promise +>a : () => Bluebird try { const b = async function b(): Bluebird { ->b : () => Promise ->async function b(): Bluebird { try { await Bluebird.resolve(); // -- remove this and it compiles } catch (error) { } } : () => Promise ->b : () => Promise +>b : () => Bluebird +>async function b(): Bluebird { try { await Bluebird.resolve(); // -- remove this and it compiles } catch (error) { } } : () => Bluebird +>b : () => Bluebird try { await Bluebird.resolve(); // -- remove this and it compiles @@ -27,8 +27,8 @@ async function a(): Bluebird { await b(); // -- or remove this and it compiles >await b() : void ->b() : Promise ->b : () => Promise +>b() : Bluebird +>b : () => Bluebird } catch (error) { } >error : any @@ -39,12 +39,12 @@ declare module "bluebird" { >"bluebird" : typeof import("bluebird") type Bluebird = Promise; ->Bluebird : Promise +>Bluebird : Bluebird const Bluebird: typeof Promise; >Bluebird : PromiseConstructor >Promise : PromiseConstructor export = Bluebird; ->Bluebird : Promise +>Bluebird : Bluebird } diff --git a/tests/baselines/reference/tsxReactPropsInferenceSucceedsOnIntersections.types b/tests/baselines/reference/tsxReactPropsInferenceSucceedsOnIntersections.types index 16b5cd13636..3fa0b722aa4 100644 --- a/tests/baselines/reference/tsxReactPropsInferenceSucceedsOnIntersections.types +++ b/tests/baselines/reference/tsxReactPropsInferenceSucceedsOnIntersections.types @@ -25,7 +25,7 @@ interface CustomButtonProps extends ButtonProps { } const CustomButton: React.SFC = props =>