Skip to content

Commit a797369

Browse files
committed
Resolutions cache stays for lifetime..
But when do we gc Resolution caches esp for non relative names etc? Also TODO:: handle change in module reosolution options Postpone stopping watching resolutions as they can still be shared from different file
1 parent 76f2d6a commit a797369

File tree

8 files changed

+107
-110
lines changed

8 files changed

+107
-110
lines changed

src/compiler/moduleNameResolver.ts

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import {
5757
hasProperty,
5858
hasTrailingDirectorySeparator,
5959
hostGetCanonicalFileName,
60+
identity,
6061
inferredTypesContainingFile,
6162
isArray,
6263
isDeclarationFileName,
@@ -1074,6 +1075,7 @@ function createPerDirectoryResolutionCache<T>(
10741075
getCanonicalFileName: GetCanonicalFileName,
10751076
options: CompilerOptions | undefined,
10761077
optionsToRedirectsKey: Map<CompilerOptions, RedirectsCacheKey>,
1078+
getValidResolution: (resolution: T | undefined) => T | undefined,
10771079
): PerDirectoryResolutionCache<T> {
10781080
const directoryToModuleNameMap = createCacheWithRedirects<Path, ModeAwareCache<T>>(options, optionsToRedirectsKey);
10791081
return {
@@ -1099,7 +1101,7 @@ function createPerDirectoryResolutionCache<T>(
10991101

11001102
function getFromDirectoryCache(name: string, mode: ResolutionMode, directoryName: string, redirectedReference: ResolvedProjectReference | undefined) {
11011103
const path = toPath(directoryName, currentDirectory, getCanonicalFileName);
1102-
return directoryToModuleNameMap.getMapOfCacheRedirects(redirectedReference)?.get(path)?.get(name, mode);
1104+
return getValidResolution(directoryToModuleNameMap.getMapOfCacheRedirects(redirectedReference)?.get(path)?.get(name, mode));
11031105
}
11041106
}
11051107

@@ -1163,6 +1165,7 @@ function createNonRelativeNameResolutionCache<T>(
11631165
options: CompilerOptions | undefined,
11641166
getResolvedFileName: (result: T) => string | undefined,
11651167
optionsToRedirectsKey: Map<CompilerOptions, RedirectsCacheKey>,
1168+
getValidResolution: (resolution: T | undefined) => T | undefined,
11661169
): NonRelativeNameResolutionCache<T> {
11671170
const moduleNameToDirectoryMap = createCacheWithRedirects<ModeAwareCacheKey, PerNonRelativeNameCache<T>>(options, optionsToRedirectsKey);
11681171
return {
@@ -1182,12 +1185,19 @@ function createNonRelativeNameResolutionCache<T>(
11821185

11831186
function getFromNonRelativeNameCache(nonRelativeModuleName: string, mode: ResolutionMode, directoryName: string, redirectedReference?: ResolvedProjectReference): T | undefined {
11841187
Debug.assert(!isExternalModuleNameRelative(nonRelativeModuleName));
1185-
return moduleNameToDirectoryMap.getMapOfCacheRedirects(redirectedReference)?.get(createModeAwareCacheKey(nonRelativeModuleName, mode))?.get(directoryName);
1188+
return moduleNameToDirectoryMap.getMapOfCacheRedirects(redirectedReference)?.get(
1189+
createModeAwareCacheKey(nonRelativeModuleName, mode),
1190+
)?.get(directoryName);
11861191
}
11871192

11881193
function getOrCreateCacheForNonRelativeName(nonRelativeModuleName: string, mode: ResolutionMode, redirectedReference?: ResolvedProjectReference): PerNonRelativeNameCache<T> {
11891194
Debug.assert(!isExternalModuleNameRelative(nonRelativeModuleName));
1190-
return getOrCreateCache(moduleNameToDirectoryMap, redirectedReference, createModeAwareCacheKey(nonRelativeModuleName, mode), createPerModuleNameCache);
1195+
return getOrCreateCache(
1196+
moduleNameToDirectoryMap,
1197+
redirectedReference,
1198+
createModeAwareCacheKey(nonRelativeModuleName, mode),
1199+
createPerModuleNameCache,
1200+
);
11911201
}
11921202

11931203
function createPerModuleNameCache(): PerNonRelativeNameCache<T> {
@@ -1196,7 +1206,11 @@ function createNonRelativeNameResolutionCache<T>(
11961206
return { get, set };
11971207

11981208
function get(directory: string): T | undefined {
1199-
return directoryPathMap.get(toPath(directory, currentDirectory, getCanonicalFileName));
1209+
return getByPath(toPath(directory, currentDirectory, getCanonicalFileName));
1210+
}
1211+
1212+
function getByPath(directoryPath: Path): T | undefined {
1213+
return getValidResolution(directoryPathMap.get(directoryPath));
12001214
}
12011215

12021216
/**
@@ -1213,32 +1227,45 @@ function createNonRelativeNameResolutionCache<T>(
12131227
function set(directory: string, result: T): void {
12141228
const path = toPath(directory, currentDirectory, getCanonicalFileName);
12151229
// if entry is already in cache do nothing
1216-
if (directoryPathMap.has(path)) {
1230+
if (getByPath(path)) {
12171231
return;
12181232
}
1233+
1234+
const existing = directoryPathMap.get(path);
1235+
// Remove invalidated result from parent
1236+
if (existing) {
1237+
const existingCommonPrefix = getCommonPrefix(path, existing);
1238+
withCommonPrefix(path, existingCommonPrefix, parent => directoryPathMap.delete(parent));
1239+
}
1240+
12191241
directoryPathMap.set(path, result);
12201242

1221-
const resolvedFileName = getResolvedFileName(result);
12221243
// find common prefix between directory and resolved file name
12231244
// this common prefix should be the shortest path that has the same resolution
12241245
// directory: /a/b/c/d/e
12251246
// resolvedFileName: /a/b/foo.d.ts
12261247
// commonPrefix: /a/b
12271248
// for failed lookups cache the result for every directory up to root
1228-
const commonPrefix = resolvedFileName && getCommonPrefix(path, resolvedFileName);
1249+
const commonPrefix = getCommonPrefix(path, result);
1250+
withCommonPrefix(path, commonPrefix, parent => directoryPathMap.set(parent, result));
1251+
}
1252+
1253+
function withCommonPrefix(path: Path, commonPrefix: Path | undefined, action: (parent: Path) => void) {
12291254
let current = path;
12301255
while (current !== commonPrefix) {
12311256
const parent = getDirectoryPath(current);
1232-
if (parent === current || directoryPathMap.has(parent)) {
1257+
if (parent === current || getByPath(parent)) {
12331258
break;
12341259
}
1235-
directoryPathMap.set(parent, result);
1260+
action(parent);
12361261
current = parent;
12371262
}
12381263
}
12391264

1240-
function getCommonPrefix(directory: Path, resolution: string) {
1241-
const resolutionDirectory = toPath(getDirectoryPath(resolution), currentDirectory, getCanonicalFileName);
1265+
function getCommonPrefix(directory: Path, resolution: T) {
1266+
const resolvedFileName = getResolvedFileName(resolution);
1267+
if (!resolvedFileName) return undefined;
1268+
const resolutionDirectory = toPath(getDirectoryPath(resolvedFileName), currentDirectory, getCanonicalFileName);
12421269

12431270
// find first position where directory and resolution differs
12441271
let i = 0;
@@ -1257,7 +1284,7 @@ function createNonRelativeNameResolutionCache<T>(
12571284
if (sep === -1) {
12581285
return undefined;
12591286
}
1260-
return directory.substr(0, Math.max(sep, rootLength));
1287+
return directory.substr(0, Math.max(sep, rootLength)) as Path;
12611288
}
12621289
}
12631290
}
@@ -1274,20 +1301,24 @@ function createModuleOrTypeReferenceResolutionCache<T>(
12741301
packageJsonInfoCache: PackageJsonInfoCache | undefined,
12751302
getResolvedFileName: (result: T) => string | undefined,
12761303
optionsToRedirectsKey: Map<CompilerOptions, RedirectsCacheKey> | undefined,
1304+
getValidResolution: ((resolution: T | undefined) => T | undefined) | undefined,
12771305
): ModuleOrTypeReferenceResolutionCache<T> {
12781306
optionsToRedirectsKey ??= new Map();
1307+
getValidResolution ??= identity;
12791308
const perDirectoryResolutionCache = createPerDirectoryResolutionCache<T>(
12801309
currentDirectory,
12811310
getCanonicalFileName,
12821311
options,
12831312
optionsToRedirectsKey,
1313+
getValidResolution,
12841314
);
12851315
const nonRelativeNameResolutionCache = createNonRelativeNameResolutionCache(
12861316
currentDirectory,
12871317
getCanonicalFileName,
12881318
options,
12891319
getResolvedFileName,
12901320
optionsToRedirectsKey,
1321+
getValidResolution,
12911322
);
12921323
packageJsonInfoCache ??= createPackageJsonInfoCache(currentDirectory, getCanonicalFileName);
12931324

@@ -1330,14 +1361,18 @@ export function createModuleResolutionCache(
13301361
getCanonicalFileName: (s: string) => string,
13311362
options?: CompilerOptions,
13321363
packageJsonInfoCache?: PackageJsonInfoCache,
1333-
optionsToRedirectsKey?: Map<CompilerOptions, RedirectsCacheKey>, // eslint-disable-line @typescript-eslint/unified-signatures
1364+
optionsToRedirectsKey?: Map<CompilerOptions, RedirectsCacheKey>,
1365+
getValidResolution?: ( // eslint-disable-line @typescript-eslint/unified-signatures
1366+
resolution: ResolvedModuleWithFailedLookupLocations | undefined,
1367+
) => ResolvedModuleWithFailedLookupLocations | undefined,
13341368
): ModuleResolutionCache;
13351369
export function createModuleResolutionCache(
13361370
currentDirectory: string,
13371371
getCanonicalFileName: (s: string) => string,
13381372
options?: CompilerOptions,
13391373
packageJsonInfoCache?: PackageJsonInfoCache,
13401374
optionsToRedirectsKey?: Map<CompilerOptions, RedirectsCacheKey>,
1375+
getValidResolution?: (resolution: ResolvedModuleWithFailedLookupLocations | undefined) => ResolvedModuleWithFailedLookupLocations | undefined,
13411376
): ModuleResolutionCache {
13421377
const result = createModuleOrTypeReferenceResolutionCache(
13431378
currentDirectory,
@@ -1346,6 +1381,7 @@ export function createModuleResolutionCache(
13461381
packageJsonInfoCache,
13471382
getOriginalOrResolvedModuleFileName,
13481383
optionsToRedirectsKey,
1384+
getValidResolution,
13491385
) as ModuleResolutionCache;
13501386
result.getOrCreateCacheForModuleName = (nonRelativeName, mode, redirectedReference) => result.getOrCreateCacheForNonRelativeName(nonRelativeName, mode, redirectedReference);
13511387
return result;
@@ -1363,14 +1399,18 @@ export function createTypeReferenceDirectiveResolutionCache(
13631399
getCanonicalFileName: (s: string) => string,
13641400
options?: CompilerOptions,
13651401
packageJsonInfoCache?: PackageJsonInfoCache,
1366-
optionsToRedirectsKey?: Map<CompilerOptions, RedirectsCacheKey>, // eslint-disable-line @typescript-eslint/unified-signatures
1402+
optionsToRedirectsKey?: Map<CompilerOptions, RedirectsCacheKey>,
1403+
getValidResolution?: ( // eslint-disable-line @typescript-eslint/unified-signatures
1404+
resolution: ResolvedTypeReferenceDirectiveWithFailedLookupLocations | undefined,
1405+
) => ResolvedTypeReferenceDirectiveWithFailedLookupLocations | undefined,
13671406
): TypeReferenceDirectiveResolutionCache;
13681407
export function createTypeReferenceDirectiveResolutionCache(
13691408
currentDirectory: string,
13701409
getCanonicalFileName: (s: string) => string,
13711410
options?: CompilerOptions,
13721411
packageJsonInfoCache?: PackageJsonInfoCache,
13731412
optionsToRedirectsKey?: Map<CompilerOptions, RedirectsCacheKey>,
1413+
getValidResolution?: (resolution: ResolvedTypeReferenceDirectiveWithFailedLookupLocations | undefined) => ResolvedTypeReferenceDirectiveWithFailedLookupLocations | undefined,
13741414
): TypeReferenceDirectiveResolutionCache {
13751415
return createModuleOrTypeReferenceResolutionCache(
13761416
currentDirectory,
@@ -1379,6 +1419,7 @@ export function createTypeReferenceDirectiveResolutionCache(
13791419
packageJsonInfoCache,
13801420
getOriginalOrResolvedTypeReferenceFileName,
13811421
optionsToRedirectsKey,
1422+
getValidResolution,
13821423
);
13831424
}
13841425

src/compiler/program.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,6 @@ import {
275275
removeSuffix,
276276
resolutionExtensionIsTSOrJson,
277277
ResolutionMode,
278-
ResolutionWithFailedLookupLocations,
279278
resolveConfigFileProjectName,
280279
ResolvedConfigFileName,
281280
ResolvedModuleFull,
@@ -4179,7 +4178,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
41794178
resolveModuleNamesReusingOldState(moduleNames, file);
41804179
Debug.assert(resolutions.length === moduleNames.length);
41814180
const optionsForFile = redirectedReference?.commandLine.options || options;
4182-
const resolutionsInFile = createModeAwareCache<ResolutionWithFailedLookupLocations>();
4181+
const resolutionsInFile = createModeAwareCache<ResolvedModuleWithFailedLookupLocations>();
41834182
(resolvedModules ??= new Map()).set(file.path, resolutionsInFile);
41844183
for (let index = 0; index < moduleNames.length; index++) {
41854184
const resolution = resolutions[index].resolvedModule;

0 commit comments

Comments
 (0)