From b536f9dadedd2ea279ba6dabe007cd3033984e6d Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 12 Sep 2017 12:09:06 -0700 Subject: [PATCH] Should not remove the reused resolutions in the file when file contents have not changed. --- src/compiler/program.ts | 8 +++++--- src/compiler/resolutionCache.ts | 11 ++++++----- src/compiler/types.ts | 2 +- src/compiler/watchedProgram.ts | 4 ++-- src/server/project.ts | 4 ++-- src/services/services.ts | 2 +- src/services/types.ts | 2 +- 7 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index f1683d1e4db..5ff1c1e2b3b 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -595,11 +595,11 @@ namespace ts { let _compilerOptionsObjectLiteralSyntax: ObjectLiteralExpression; let moduleResolutionCache: ModuleResolutionCache; - let resolveModuleNamesWorker: (moduleNames: string[], containingFile: string) => ResolvedModuleFull[]; + let resolveModuleNamesWorker: (moduleNames: string[], containingFile: string, reusedNames?: string[]) => ResolvedModuleFull[]; const hasInvalidatedResolution = host.hasInvalidatedResolution || returnFalse; const hasChangedAutomaticTypeDirectiveNames = host.hasChangedAutomaticTypeDirectiveNames && host.hasChangedAutomaticTypeDirectiveNames.bind(host) || returnFalse; if (host.resolveModuleNames) { - resolveModuleNamesWorker = (moduleNames, containingFile) => host.resolveModuleNames(checkAllDefined(moduleNames), containingFile).map(resolved => { + resolveModuleNamesWorker = (moduleNames, containingFile, reusedNames) => host.resolveModuleNames(checkAllDefined(moduleNames), containingFile, reusedNames).map(resolved => { // An older host may have omitted extension, in which case we should infer it from the file extension of resolvedFileName. if (!resolved || (resolved as ResolvedModuleFull).extension !== undefined) { return resolved as ResolvedModuleFull; @@ -820,6 +820,7 @@ namespace ts { * * ResolvedModuleFull instance: can be reused. */ let result: ResolvedModuleFull[]; + let reusedNames: string[]; /** A transient placeholder used to mark predicted resolution in the result list. */ const predictedToResolveToAmbientModuleMarker: ResolvedModuleFull = {}; @@ -835,6 +836,7 @@ namespace ts { trace(host, Diagnostics.Reusing_resolution_of_module_0_to_file_1_from_old_program, moduleName, containingFile); } (result || (result = new Array(moduleNames.length)))[i] = oldResolvedModule; + (reusedNames || (reusedNames = [])).push(moduleName); continue; } } @@ -863,7 +865,7 @@ namespace ts { } const resolutions = unknownModuleNames && unknownModuleNames.length - ? resolveModuleNamesWorker(unknownModuleNames, containingFile) + ? resolveModuleNamesWorker(unknownModuleNames, containingFile, reusedNames) : emptyArray; // Combine results of resolutions and predicted results diff --git a/src/compiler/resolutionCache.ts b/src/compiler/resolutionCache.ts index 71ef37a9a37..c69caf15f07 100644 --- a/src/compiler/resolutionCache.ts +++ b/src/compiler/resolutionCache.ts @@ -8,7 +8,7 @@ namespace ts { startRecordingFilesWithChangedResolutions(): void; finishRecordingFilesWithChangedResolutions(): Path[]; - resolveModuleNames(moduleNames: string[], containingFile: string, logChanges: boolean): ResolvedModuleFull[]; + resolveModuleNames(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, logChanges: boolean): ResolvedModuleFull[]; resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[]; invalidateResolutionOfFile(filePath: Path): void; @@ -207,6 +207,7 @@ namespace ts { perDirectoryCache: Map>, loader: (name: string, containingFile: string, options: CompilerOptions, host: ModuleResolutionHost) => T, getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName, + reusedNames: string[] | undefined, logChanges: boolean): R[] { const path = resolutionHost.toPath(containingFile); @@ -253,7 +254,7 @@ namespace ts { // Stop watching and remove the unused name resolutionsInFile.forEach((resolution, name) => { - if (!seenNamesInFile.has(name)) { + if (!seenNamesInFile.has(name) && !contains(reusedNames, name)) { stopWatchFailedLookupLocationOfResolution(resolution); resolutionsInFile.delete(name); } @@ -285,16 +286,16 @@ namespace ts { typeDirectiveNames, containingFile, resolvedTypeReferenceDirectives, perDirectoryResolvedTypeReferenceDirectives, resolveTypeReferenceDirective, getResolvedTypeReferenceDirective, - /*logChanges*/ false + /*reusedNames*/ undefined, /*logChanges*/ false ); } - function resolveModuleNames(moduleNames: string[], containingFile: string, logChanges: boolean): ResolvedModuleFull[] { + function resolveModuleNames(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, logChanges: boolean): ResolvedModuleFull[] { return resolveNamesWithLocalCache( moduleNames, containingFile, resolvedModuleNames, perDirectoryResolvedModuleNames, resolveModuleName, getResolvedModule, - logChanges + reusedNames, logChanges ); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ef15e3fdd1e..d473f2441bd 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4138,7 +4138,7 @@ namespace ts { * If resolveModuleNames is implemented then implementation for members from ModuleResolutionHost can be just * 'throw new Error("NotImplemented")' */ - resolveModuleNames?(moduleNames: string[], containingFile: string): ResolvedModule[]; + resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModule[]; /** * This method is a companion for 'resolveModuleNames' and is used to resolve 'types' references to actual type declaration files */ diff --git a/src/compiler/watchedProgram.ts b/src/compiler/watchedProgram.ts index 67a1a943bf6..7d7b4b1b1d3 100644 --- a/src/compiler/watchedProgram.ts +++ b/src/compiler/watchedProgram.ts @@ -396,8 +396,8 @@ namespace ts { return partialSystem.getDirectories(path); } - function resolveModuleNames(moduleNames: string[], containingFile: string) { - return resolutionCache.resolveModuleNames(moduleNames, containingFile, /*logChanges*/ false); + function resolveModuleNames(moduleNames: string[], containingFile: string, reusedNames?: string[]) { + return resolutionCache.resolveModuleNames(moduleNames, containingFile, reusedNames, /*logChanges*/ false); } function resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string) { diff --git a/src/server/project.ts b/src/server/project.ts index c52f520b8a4..4a66a4064e0 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -325,8 +325,8 @@ namespace ts.server { return !this.isWatchedMissingFile(path) && this.partialSystem.fileExists(file); } - resolveModuleNames(moduleNames: string[], containingFile: string): ResolvedModuleFull[] { - return this.resolutionCache.resolveModuleNames(moduleNames, containingFile, /*logChanges*/ true); + resolveModuleNames(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModuleFull[] { + return this.resolutionCache.resolveModuleNames(moduleNames, containingFile, reusedNames, /*logChanges*/ true); } resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[] { diff --git a/src/services/services.ts b/src/services/services.ts index e8f073f4a17..08d5b007e87 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1177,7 +1177,7 @@ namespace ts { } if (host.resolveModuleNames) { - compilerHost.resolveModuleNames = (moduleNames, containingFile) => host.resolveModuleNames(moduleNames, containingFile); + compilerHost.resolveModuleNames = (moduleNames, containingFile, reusedNames) => host.resolveModuleNames(moduleNames, containingFile, reusedNames); } if (host.resolveTypeReferenceDirectives) { compilerHost.resolveTypeReferenceDirectives = (typeReferenceDirectiveNames, containingFile) => { diff --git a/src/services/types.ts b/src/services/types.ts index e63651b3371..1fa06796065 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -183,7 +183,7 @@ namespace ts { * if implementation is omitted then language service will use built-in module resolution logic and get answers to * host specific questions using 'getScriptSnapshot'. */ - resolveModuleNames?(moduleNames: string[], containingFile: string): ResolvedModule[]; + resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModule[]; resolveTypeReferenceDirectives?(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[]; hasInvalidatedResolution?: HasInvalidatedResolution; hasChangedAutomaticTypeDirectiveNames?(): boolean;