Skip to content

Commit b93051a

Browse files
committed
Update cached import list update as part of resolving modules instead of another pass
1 parent f6dd3bf commit b93051a

2 files changed

Lines changed: 32 additions & 50 deletions

File tree

src/compiler/resolutionCache.ts

Lines changed: 16 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,14 @@ export interface HasInvalidatedFromResolutionCache {
8383
hasInvalidatedResolutions: HasInvalidatedResolutions;
8484
hasInvalidatedLibResolutions: HasInvalidatedLibResolutions;
8585
}
86+
/** @internal */
87+
export type CallbackOnNewResolution<T extends ResolutionWithFailedLookupLocations> = (
88+
existing: T | undefined,
89+
current: T,
90+
path: Path,
91+
name: string,
92+
mode: ResolutionMode,
93+
) => void;
8694
/**
8795
* This is the cache of module/typedirectives resolution that can be retained across program
8896
*
@@ -100,8 +108,6 @@ export interface ResolutionCache {
100108
fileWatchesOfAffectingLocations: Map<string, FileWatcherOfAffectingLocation>;
101109
countResolutionsResolvedWithGlobalCache(): number;
102110
countResolutionsResolvedWithoutGlobalCache(): number;
103-
startRecordingFilesWithChangedResolutions(): void;
104-
finishRecordingFilesWithChangedResolutions(): Path[] | undefined;
105111

106112
watchFailedLookupLocationsOfExternalModuleResolutions<T extends ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName>(
107113
name: string,
@@ -118,6 +124,7 @@ export interface ResolutionCache {
118124
options: CompilerOptions,
119125
containingSourceFile: SourceFile,
120126
reusedNames: readonly StringLiteralLike[] | undefined,
127+
onNewResolution?: CallbackOnNewResolution<ResolvedModuleWithFailedLookupLocations>,
121128
): readonly ResolvedModuleWithFailedLookupLocations[];
122129
resolveTypeReferenceDirectiveReferences<T extends FileReference | string>(
123130
typeDirectiveReferences: readonly T[],
@@ -486,7 +493,8 @@ export function needsResolutionFromGlobalCache(moduleName: string, resolution: R
486493
return !isExternalModuleNameRelative(moduleName) && isUnresolvedOrResolvedToJs(resolution);
487494
}
488495

489-
function isUnresolvedOrResolvedToJs(resolution: ResolvedModuleWithFailedLookupLocations) {
496+
/** @internal */
497+
export function isUnresolvedOrResolvedToJs(resolution: ResolvedModuleWithFailedLookupLocations) {
490498
return !resolution.resolvedModule || !resolutionExtensionIsTSOrJson(resolution.resolvedModule.extension);
491499
}
492500

@@ -546,7 +554,6 @@ export function createResolutionCache(
546554
resolutionHost: ResolutionCacheHost,
547555
rootDirForResolution: string,
548556
): ResolutionCache {
549-
let filesWithChangedSetOfUnresolvedImports: Path[] | undefined;
550557
let filesWithInvalidatedResolutions: Set<Path> | undefined;
551558
const nonRelativeExternalModuleResolutions = createMultiMap<string, ResolutionWithFailedLookupLocations>();
552559

@@ -622,8 +629,6 @@ export function createResolutionCache(
622629
countResolutionsResolvedWithoutGlobalCache: () => resolutionsResolvedWithoutGlobalCache,
623630
watchFailedLookupLocationsOfExternalModuleResolutions,
624631
getModuleResolutionCache: () => moduleResolutionCache,
625-
startRecordingFilesWithChangedResolutions,
626-
finishRecordingFilesWithChangedResolutions,
627632
// perDirectoryResolvedModuleNames and perDirectoryResolvedTypeReferenceDirectives could be non empty if there was exception during program update
628633
// (between startCachingPerDirectoryResolution and finishCachingPerDirectoryResolution)
629634
startCachingPerDirectoryResolution,
@@ -694,16 +699,6 @@ export function createResolutionCache(
694699
typeReferenceDirectiveResolutionCache.update(resolutionHost.getCompilationSettings());
695700
}
696701

697-
function startRecordingFilesWithChangedResolutions() {
698-
filesWithChangedSetOfUnresolvedImports = [];
699-
}
700-
701-
function finishRecordingFilesWithChangedResolutions() {
702-
const collected = filesWithChangedSetOfUnresolvedImports;
703-
filesWithChangedSetOfUnresolvedImports = undefined;
704-
return collected;
705-
}
706-
707702
function createHasInvalidatedResolutions(
708703
customHasInvalidatedResolutions: HasInvalidatedResolutions,
709704
customHasInvalidatedLibResolutions: HasInvalidatedLibResolutions,
@@ -824,8 +819,8 @@ export function createResolutionCache(
824819
perFileCache: Map<Path, ModeAwareCache<T>>;
825820
loader: ResolutionLoader<Entry, T, SourceFile>;
826821
getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName<T, R>;
827-
logChanges?: boolean;
828822
deferWatchingNonRelativeResolution: boolean;
823+
onNewResolution?: CallbackOnNewResolution<T>;
829824
}
830825
function resolveNamesWithLocalCache<Entry, SourceFile, T extends ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName>({
831826
entries,
@@ -838,7 +833,7 @@ export function createResolutionCache(
838833
loader,
839834
getResolutionWithResolvedFileName,
840835
deferWatchingNonRelativeResolution,
841-
logChanges,
836+
onNewResolution,
842837
}: ResolveNamesWithLocalCacheInput<Entry, SourceFile, T, R>): readonly T[] {
843838
const path = resolutionHost.toPath(containingFile);
844839
const resolutionsInFile = perFileCache.get(path) || perFileCache.set(path, createModeAwareCache()).get(path)!;
@@ -879,12 +874,7 @@ export function createResolutionCache(
879874
stopWatchFailedLookupLocationOfResolution(existingResolution, path, getResolutionWithResolvedFileName);
880875
}
881876
}
882-
883-
if (logChanges && filesWithChangedSetOfUnresolvedImports && !resolutionIsEqualTo(existingResolution, resolution)) {
884-
filesWithChangedSetOfUnresolvedImports.push(path);
885-
// reset log changes to avoid recording the same file multiple times
886-
logChanges = false;
887-
}
877+
onNewResolution?.(existingResolution, resolution, path, name, mode);
888878
}
889879
else {
890880
const host = getModuleResolutionHost(resolutionHost);
@@ -931,24 +921,6 @@ export function createResolutionCache(
931921
});
932922
}
933923
return resolvedModules;
934-
935-
function resolutionIsEqualTo(oldResolution: T | undefined, newResolution: T | undefined): boolean {
936-
if (oldResolution === newResolution) {
937-
return true;
938-
}
939-
if (!oldResolution || !newResolution) {
940-
return false;
941-
}
942-
const oldResult = getResolutionWithResolvedFileName(oldResolution);
943-
const newResult = getResolutionWithResolvedFileName(newResolution);
944-
if (oldResult === newResult) {
945-
return true;
946-
}
947-
if (!oldResult || !newResult) {
948-
return false;
949-
}
950-
return oldResult.resolvedFileName === newResult.resolvedFileName;
951-
}
952924
}
953925

954926
function resolveTypeReferenceDirectiveReferences<T extends FileReference | string>(
@@ -986,6 +958,7 @@ export function createResolutionCache(
986958
options: CompilerOptions,
987959
containingSourceFile: SourceFile,
988960
reusedNames: readonly StringLiteralLike[] | undefined,
961+
onNewResolution?: CallbackOnNewResolution<ResolvedModuleWithFailedLookupLocations>,
989962
): readonly ResolvedModuleWithFailedLookupLocations[] {
990963
return resolveNamesWithLocalCache({
991964
entries: moduleLiterals,
@@ -1003,8 +976,8 @@ export function createResolutionCache(
1003976
moduleResolutionCache,
1004977
),
1005978
getResolutionWithResolvedFileName: getResolvedModule,
1006-
logChanges: !!resolutionHost.getGlobalCache,
1007979
deferWatchingNonRelativeResolution: true, // Defer non relative resolution watch because we could be using ambient modules
980+
onNewResolution,
1008981
});
1009982
}
1010983

src/server/project.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ import {
7272
InstallPackageOptions,
7373
IScriptSnapshot,
7474
isDeclarationFileName,
75+
isExternalModuleNameRelative,
7576
isInsideNodeModules,
77+
isUnresolvedOrResolvedToJs,
7678
JSDocParsingMode,
7779
JsTyping,
7880
LanguageService,
@@ -388,6 +390,8 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
388390
* @internal
389391
*/
390392
cachedUnresolvedImportsPerFile = new Map<Path, readonly string[]>();
393+
/** @internal */
394+
private recordChangesToUnresolvedImports = false;
391395

392396
/** @internal */
393397
lastCachedUnresolvedImportsList: SortedReadonlyArray<string> | undefined;
@@ -782,13 +786,22 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
782786

783787
/** @internal */
784788
resolveModuleNameLiterals(moduleLiterals: readonly StringLiteralLike[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile: SourceFile, reusedNames: readonly StringLiteralLike[] | undefined): readonly ResolvedModuleWithFailedLookupLocations[] {
789+
let needsUpdate = this.recordChangesToUnresolvedImports && this.cachedUnresolvedImportsPerFile.has(this.toPath(containingFile));
785790
return this.resolutionCache.resolveModuleNameLiterals(
786791
moduleLiterals,
787792
containingFile,
788793
redirectedReference,
789794
options,
790795
containingSourceFile,
791796
reusedNames,
797+
needsUpdate ? (existing, current, path, name) => {
798+
if (!needsUpdate || isExternalModuleNameRelative(name)) return;
799+
// If only unresolved flag is changed, update
800+
if ((existing && isUnresolvedOrResolvedToJs(existing)) === isUnresolvedOrResolvedToJs(current)) return;
801+
needsUpdate = false;
802+
this.cachedUnresolvedImportsPerFile.delete(path);
803+
this.lastCachedUnresolvedImportsList = undefined;
804+
} : undefined,
792805
);
793806
}
794807

@@ -1424,26 +1437,22 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
14241437
const useTypingsFromGlobalCache = this.useTypingsFromGlobalCache();
14251438
if (!useTypingsFromGlobalCache) this.resolutionCache.invalidateResolutionsWithGlobalCachePass();
14261439
else this.resolutionCache.invalidateResolutionsWithoutGlobalCachePass();
1427-
if (useTypingsFromGlobalCache && this.cachedUnresolvedImportsPerFile.size) this.resolutionCache.startRecordingFilesWithChangedResolutions();
1440+
if (useTypingsFromGlobalCache && this.cachedUnresolvedImportsPerFile.size) this.recordChangesToUnresolvedImports = true;
14281441

14291442
const hasNewProgram = this.updateGraphWorker();
14301443
const hasAddedorRemovedFiles = this.hasAddedorRemovedFiles;
14311444
this.hasAddedorRemovedFiles = false;
14321445
this.hasAddedOrRemovedSymlinks = false;
1446+
this.recordChangesToUnresolvedImports = false;
14331447

14341448
if (useTypingsFromGlobalCache) {
1435-
const changedFiles: readonly Path[] = this.resolutionCache.finishRecordingFilesWithChangedResolutions() || emptyArray;
1436-
for (const file of changedFiles) {
1437-
// delete cached information for changed files
1438-
this.cachedUnresolvedImportsPerFile.delete(file);
1439-
}
14401449
// 1. no changes in structure, no changes in unresolved imports - do nothing
14411450
// 2. no changes in structure, unresolved imports were changed - collect unresolved imports for all files
14421451
// (can reuse cached imports for files that were not changed)
14431452
// 3. new files were added/removed, but compilation settings stays the same - collect unresolved imports for all new/modified files
14441453
// (can reuse cached imports for files that were not changed)
14451454
// 4. compilation settings were changed in the way that might affect module resolution - drop all caches and collect all data from the scratch
1446-
if (!this.lastCachedUnresolvedImportsList || hasNewProgram || changedFiles.length) {
1455+
if (!this.lastCachedUnresolvedImportsList || hasNewProgram) {
14471456
this.lastCachedUnresolvedImportsList = getUnresolvedImports(
14481457
this.program!,
14491458
this.cachedUnresolvedImportsPerFile,

0 commit comments

Comments
 (0)