Skip to content

Commit 4087c69

Browse files
committed
Update cached import list update as part of resolving modules instead of another pass
1 parent 6c9662b commit 4087c69

3 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
@@ -81,6 +81,14 @@ export interface HasInvalidatedFromResolutionCache {
8181
hasInvalidatedResolutions: HasInvalidatedResolutions;
8282
hasInvalidatedLibResolutions: HasInvalidatedLibResolutions;
8383
}
84+
/** @internal */
85+
export type CallbackOnNewResolution<T extends ResolutionWithFailedLookupLocations> = (
86+
existing: T | undefined,
87+
current: T,
88+
path: Path,
89+
name: string,
90+
mode: ResolutionMode,
91+
) => void;
8492
/**
8593
* This is the cache of module/typedirectives resolution that can be retained across program
8694
*
@@ -100,8 +108,6 @@ export interface ResolutionCache {
100108
dirPathToSymlinkPackageRefCount: Map<Path, number>;
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[],
@@ -533,7 +540,8 @@ export function needsResolutionFromGlobalCache(moduleName: string, resolution: R
533540
return !isExternalModuleNameRelative(moduleName) && isUnresolvedOrResolvedToJs(resolution);
534541
}
535542

536-
function isUnresolvedOrResolvedToJs(resolution: ResolvedModuleWithFailedLookupLocations) {
543+
/** @internal */
544+
export function isUnresolvedOrResolvedToJs(resolution: ResolvedModuleWithFailedLookupLocations): boolean {
537545
return !resolution.resolvedModule || !resolutionExtensionIsTSOrJson(resolution.resolvedModule.extension);
538546
}
539547

@@ -592,7 +600,6 @@ export function createResolutionCache(
592600
resolutionHost: ResolutionCacheHost,
593601
rootDirForResolution: string,
594602
): ResolutionCache {
595-
let filesWithChangedSetOfUnresolvedImports: Path[] | undefined;
596603
let filesWithInvalidatedResolutions: Set<Path> | undefined;
597604
const nonRelativeExternalModuleResolutions = new Set<ResolutionWithFailedLookupLocations>();
598605

@@ -675,8 +682,6 @@ export function createResolutionCache(
675682
countResolutionsResolvedWithoutGlobalCache: () => resolutionsResolvedWithoutGlobalCache,
676683
watchFailedLookupLocationsOfExternalModuleResolutions,
677684
getModuleResolutionCache: () => moduleResolutionCache,
678-
startRecordingFilesWithChangedResolutions,
679-
finishRecordingFilesWithChangedResolutions,
680685
// perDirectoryResolvedModuleNames and perDirectoryResolvedTypeReferenceDirectives could be non empty if there was exception during program update
681686
// (between startCachingPerDirectoryResolution and finishCachingPerDirectoryResolution)
682687
startCachingPerDirectoryResolution,
@@ -742,16 +747,6 @@ export function createResolutionCache(
742747
typeReferenceDirectiveResolutionCache.update(resolutionHost.getCompilationSettings());
743748
}
744749

745-
function startRecordingFilesWithChangedResolutions() {
746-
filesWithChangedSetOfUnresolvedImports = [];
747-
}
748-
749-
function finishRecordingFilesWithChangedResolutions() {
750-
const collected = filesWithChangedSetOfUnresolvedImports;
751-
filesWithChangedSetOfUnresolvedImports = undefined;
752-
return collected;
753-
}
754-
755750
function createHasInvalidatedResolutions(
756751
customHasInvalidatedResolutions: HasInvalidatedResolutions,
757752
customHasInvalidatedLibResolutions: HasInvalidatedLibResolutions,
@@ -880,8 +875,8 @@ export function createResolutionCache(
880875
perFileCache: Map<Path, ModeAwareCache<T>>;
881876
loader: ResolutionLoader<Entry, T, SourceFile>;
882877
getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName<T, R>;
883-
logChanges?: boolean;
884878
deferWatchingNonRelativeResolution: boolean;
879+
onNewResolution?: CallbackOnNewResolution<T>;
885880
}
886881
function resolveNamesWithLocalCache<Entry, SourceFile, T extends ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName>({
887882
entries,
@@ -894,7 +889,7 @@ export function createResolutionCache(
894889
loader,
895890
getResolutionWithResolvedFileName,
896891
deferWatchingNonRelativeResolution,
897-
logChanges,
892+
onNewResolution,
898893
}: ResolveNamesWithLocalCacheInput<Entry, SourceFile, T, R>): readonly T[] {
899894
const path = resolutionHost.toPath(containingFile);
900895
const resolutionsInFile = perFileCache.get(path) || perFileCache.set(path, createModeAwareCache()).get(path)!;
@@ -935,12 +930,7 @@ export function createResolutionCache(
935930
stopWatchFailedLookupLocationOfResolution(existingResolution, path, getResolutionWithResolvedFileName);
936931
}
937932
}
938-
939-
if (logChanges && filesWithChangedSetOfUnresolvedImports && !resolutionIsEqualTo(existingResolution, resolution)) {
940-
filesWithChangedSetOfUnresolvedImports.push(path);
941-
// reset log changes to avoid recording the same file multiple times
942-
logChanges = false;
943-
}
933+
onNewResolution?.(existingResolution, resolution, path, name, mode);
944934
}
945935
else {
946936
const host = getModuleResolutionHost(resolutionHost);
@@ -987,24 +977,6 @@ export function createResolutionCache(
987977
});
988978
}
989979
return resolvedModules;
990-
991-
function resolutionIsEqualTo(oldResolution: T | undefined, newResolution: T | undefined): boolean {
992-
if (oldResolution === newResolution) {
993-
return true;
994-
}
995-
if (!oldResolution || !newResolution) {
996-
return false;
997-
}
998-
const oldResult = getResolutionWithResolvedFileName(oldResolution);
999-
const newResult = getResolutionWithResolvedFileName(newResolution);
1000-
if (oldResult === newResult) {
1001-
return true;
1002-
}
1003-
if (!oldResult || !newResult) {
1004-
return false;
1005-
}
1006-
return oldResult.resolvedFileName === newResult.resolvedFileName;
1007-
}
1008980
}
1009981

1010982
function resolveTypeReferenceDirectiveReferences<T extends FileReference | string>(
@@ -1042,6 +1014,7 @@ export function createResolutionCache(
10421014
options: CompilerOptions,
10431015
containingSourceFile: SourceFile,
10441016
reusedNames: readonly StringLiteralLike[] | undefined,
1017+
onNewResolution?: CallbackOnNewResolution<ResolvedModuleWithFailedLookupLocations>,
10451018
): readonly ResolvedModuleWithFailedLookupLocations[] {
10461019
return resolveNamesWithLocalCache({
10471020
entries: moduleLiterals,
@@ -1059,8 +1032,8 @@ export function createResolutionCache(
10591032
moduleResolutionCache,
10601033
),
10611034
getResolutionWithResolvedFileName: getResolvedModuleFromResolution,
1062-
logChanges: !!resolutionHost.getGlobalTypingsCacheLocation,
10631035
deferWatchingNonRelativeResolution: true, // Defer non relative resolution watch because we could be using ambient modules
1036+
onNewResolution,
10641037
});
10651038
}
10661039

src/server/project.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,9 @@ import {
7676
InstallPackageOptions,
7777
IScriptSnapshot,
7878
isDeclarationFileName,
79+
isExternalModuleNameRelative,
7980
isInsideNodeModules,
81+
isUnresolvedOrResolvedToJs,
8082
JSDocParsingMode,
8183
JsTyping,
8284
LanguageService,
@@ -390,6 +392,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
390392
* @internal
391393
*/
392394
cachedUnresolvedImportsPerFile: Map<Path, readonly string[]> = new Map();
395+
private recordChangesToUnresolvedImports = false;
393396

394397
/** @internal */
395398
lastCachedUnresolvedImportsList: SortedReadonlyArray<string> | undefined;
@@ -796,13 +799,22 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
796799

797800
/** @internal */
798801
resolveModuleNameLiterals(moduleLiterals: readonly StringLiteralLike[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile: SourceFile, reusedNames: readonly StringLiteralLike[] | undefined): readonly ResolvedModuleWithFailedLookupLocations[] {
802+
let needsUpdate = this.recordChangesToUnresolvedImports && this.cachedUnresolvedImportsPerFile.has(this.toPath(containingFile));
799803
return this.resolutionCache.resolveModuleNameLiterals(
800804
moduleLiterals,
801805
containingFile,
802806
redirectedReference,
803807
options,
804808
containingSourceFile,
805809
reusedNames,
810+
needsUpdate ? (existing, current, path, name) => {
811+
if (!needsUpdate || isExternalModuleNameRelative(name)) return;
812+
// If only unresolved flag is changed, update
813+
if ((existing && isUnresolvedOrResolvedToJs(existing)) === isUnresolvedOrResolvedToJs(current)) return;
814+
needsUpdate = false;
815+
this.cachedUnresolvedImportsPerFile.delete(path);
816+
this.lastCachedUnresolvedImportsList = undefined;
817+
} : undefined,
806818
);
807819
}
808820

@@ -1448,26 +1460,22 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
14481460
const useTypingsFromGlobalCache = this.useTypingsFromGlobalCache();
14491461
if (!useTypingsFromGlobalCache) this.resolutionCache.invalidateResolutionsWithGlobalCachePass();
14501462
else this.resolutionCache.invalidateResolutionsWithoutGlobalCachePass();
1451-
if (useTypingsFromGlobalCache && this.cachedUnresolvedImportsPerFile.size) this.resolutionCache.startRecordingFilesWithChangedResolutions();
1463+
if (useTypingsFromGlobalCache && this.cachedUnresolvedImportsPerFile.size) this.recordChangesToUnresolvedImports = true;
14521464

14531465
const hasNewProgram = this.updateGraphWorker();
14541466
const hasAddedorRemovedFiles = this.hasAddedorRemovedFiles;
14551467
this.hasAddedorRemovedFiles = false;
14561468
this.hasAddedOrRemovedSymlinks = false;
1469+
this.recordChangesToUnresolvedImports = false;
14571470

14581471
if (useTypingsFromGlobalCache) {
1459-
const changedFiles: readonly Path[] = this.resolutionCache.finishRecordingFilesWithChangedResolutions() || emptyArray;
1460-
for (const file of changedFiles) {
1461-
// delete cached information for changed files
1462-
this.cachedUnresolvedImportsPerFile.delete(file);
1463-
}
14641472
// 1. no changes in structure, no changes in unresolved imports - do nothing
14651473
// 2. no changes in structure, unresolved imports were changed - collect unresolved imports for all files
14661474
// (can reuse cached imports for files that were not changed)
14671475
// 3. new files were added/removed, but compilation settings stays the same - collect unresolved imports for all new/modified files
14681476
// (can reuse cached imports for files that were not changed)
14691477
// 4. compilation settings were changed in the way that might affect module resolution - drop all caches and collect all data from the scratch
1470-
if (!this.lastCachedUnresolvedImportsList || hasNewProgram || changedFiles.length) {
1478+
if (!this.lastCachedUnresolvedImportsList || hasNewProgram) {
14711479
this.lastCachedUnresolvedImportsList = getUnresolvedImports(
14721480
this.program!,
14731481
this.cachedUnresolvedImportsPerFile,

tests/baselines/reference/api/typescript.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2861,6 +2861,7 @@ declare namespace ts {
28612861
private externalFiles;
28622862
private missingFilesMap;
28632863
private generatedFilesMap;
2864+
private recordChangesToUnresolvedImports;
28642865
private hasAddedorRemovedFiles;
28652866
private hasAddedOrRemovedSymlinks;
28662867
protected languageService: LanguageService;

0 commit comments

Comments
 (0)