Skip to content

Commit d947de4

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 4ee4766 commit d947de4

File tree

8 files changed

+96
-110
lines changed

8 files changed

+96
-110
lines changed

src/compiler/moduleNameResolver.ts

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ import {
5959
hasProperty,
6060
hasTrailingDirectorySeparator,
6161
hostGetCanonicalFileName,
62+
identity,
6263
inferredTypesContainingFile,
6364
isArray,
6465
isDeclarationFileName,
@@ -1056,6 +1057,7 @@ function createPerDirectoryResolutionCache<T>(
10561057
getCanonicalFileName: GetCanonicalFileName,
10571058
options: CompilerOptions | undefined,
10581059
optionsToRedirectsKey: Map<CompilerOptions, RedirectsCacheKey>,
1060+
getValidResolution: (resolution: T | undefined) => T | undefined,
10591061
): PerDirectoryResolutionCache<T> {
10601062
const directoryToModuleNameMap = createCacheWithRedirects<Path, ModeAwareCache<T>>(options, optionsToRedirectsKey);
10611063
return {
@@ -1081,7 +1083,7 @@ function createPerDirectoryResolutionCache<T>(
10811083

10821084
function getFromDirectoryCache(name: string, mode: ResolutionMode, directoryName: string, redirectedReference: ResolvedProjectReference | undefined) {
10831085
const path = toPath(directoryName, currentDirectory, getCanonicalFileName);
1084-
return directoryToModuleNameMap.getMapOfCacheRedirects(redirectedReference)?.get(path)?.get(name, mode);
1086+
return getValidResolution(directoryToModuleNameMap.getMapOfCacheRedirects(redirectedReference)?.get(path)?.get(name, mode));
10851087
}
10861088
}
10871089

@@ -1145,6 +1147,7 @@ function createNonRelativeNameResolutionCache<T>(
11451147
options: CompilerOptions | undefined,
11461148
getResolvedFileName: (result: T) => string | undefined,
11471149
optionsToRedirectsKey: Map<CompilerOptions, RedirectsCacheKey>,
1150+
getValidResolution: (resolution: T | undefined) => T | undefined,
11481151
): NonRelativeNameResolutionCache<T> {
11491152
const moduleNameToDirectoryMap = createCacheWithRedirects<ModeAwareCacheKey, PerNonRelativeNameCache<T>>(options, optionsToRedirectsKey);
11501153
return {
@@ -1164,12 +1167,19 @@ function createNonRelativeNameResolutionCache<T>(
11641167

11651168
function getFromNonRelativeNameCache(nonRelativeModuleName: string, mode: ResolutionMode, directoryName: string, redirectedReference?: ResolvedProjectReference): T | undefined {
11661169
Debug.assert(!isExternalModuleNameRelative(nonRelativeModuleName));
1167-
return moduleNameToDirectoryMap.getMapOfCacheRedirects(redirectedReference)?.get(createModeAwareCacheKey(nonRelativeModuleName, mode))?.get(directoryName);
1170+
return moduleNameToDirectoryMap.getMapOfCacheRedirects(redirectedReference)?.get(
1171+
createModeAwareCacheKey(nonRelativeModuleName, mode),
1172+
)?.get(directoryName);
11681173
}
11691174

11701175
function getOrCreateCacheForNonRelativeName(nonRelativeModuleName: string, mode: ResolutionMode, redirectedReference?: ResolvedProjectReference): PerNonRelativeNameCache<T> {
11711176
Debug.assert(!isExternalModuleNameRelative(nonRelativeModuleName));
1172-
return getOrCreateCache(moduleNameToDirectoryMap, redirectedReference, createModeAwareCacheKey(nonRelativeModuleName, mode), createPerModuleNameCache);
1177+
return getOrCreateCache(
1178+
moduleNameToDirectoryMap,
1179+
redirectedReference,
1180+
createModeAwareCacheKey(nonRelativeModuleName, mode),
1181+
createPerModuleNameCache,
1182+
);
11731183
}
11741184

11751185
function createPerModuleNameCache(): PerNonRelativeNameCache<T> {
@@ -1178,7 +1188,11 @@ function createNonRelativeNameResolutionCache<T>(
11781188
return { get, set };
11791189

11801190
function get(directory: string): T | undefined {
1181-
return directoryPathMap.get(toPath(directory, currentDirectory, getCanonicalFileName));
1191+
return getByPath(toPath(directory, currentDirectory, getCanonicalFileName));
1192+
}
1193+
1194+
function getByPath(directoryPath: Path): T | undefined {
1195+
return getValidResolution(directoryPathMap.get(directoryPath));
11821196
}
11831197

11841198
/**
@@ -1195,32 +1209,45 @@ function createNonRelativeNameResolutionCache<T>(
11951209
function set(directory: string, result: T): void {
11961210
const path = toPath(directory, currentDirectory, getCanonicalFileName);
11971211
// if entry is already in cache do nothing
1198-
if (directoryPathMap.has(path)) {
1212+
if (getByPath(path)) {
11991213
return;
12001214
}
1215+
1216+
const existing = directoryPathMap.get(path);
1217+
// Remove invalidated result from parent
1218+
if (existing) {
1219+
const existingCommonPrefix = getCommonPrefix(path, existing);
1220+
withCommonPrefix(path, existingCommonPrefix, parent => directoryPathMap.delete(parent));
1221+
}
1222+
12011223
directoryPathMap.set(path, result);
12021224

1203-
const resolvedFileName = getResolvedFileName(result);
12041225
// find common prefix between directory and resolved file name
12051226
// this common prefix should be the shortest path that has the same resolution
12061227
// directory: /a/b/c/d/e
12071228
// resolvedFileName: /a/b/foo.d.ts
12081229
// commonPrefix: /a/b
12091230
// for failed lookups cache the result for every directory up to root
1210-
const commonPrefix = resolvedFileName && getCommonPrefix(path, resolvedFileName);
1231+
const commonPrefix = getCommonPrefix(path, result);
1232+
withCommonPrefix(path, commonPrefix, parent => directoryPathMap.set(parent, result));
1233+
}
1234+
1235+
function withCommonPrefix(path: Path, commonPrefix: Path | undefined, action: (parent: Path) => void) {
12111236
let current = path;
12121237
while (current !== commonPrefix) {
12131238
const parent = getDirectoryPath(current);
1214-
if (parent === current || directoryPathMap.has(parent)) {
1239+
if (parent === current || getByPath(parent)) {
12151240
break;
12161241
}
1217-
directoryPathMap.set(parent, result);
1242+
action(parent);
12181243
current = parent;
12191244
}
12201245
}
12211246

1222-
function getCommonPrefix(directory: Path, resolution: string) {
1223-
const resolutionDirectory = toPath(getDirectoryPath(resolution), currentDirectory, getCanonicalFileName);
1247+
function getCommonPrefix(directory: Path, resolution: T) {
1248+
const resolvedFileName = getResolvedFileName(resolution);
1249+
if (!resolvedFileName) return undefined;
1250+
const resolutionDirectory = toPath(getDirectoryPath(resolvedFileName), currentDirectory, getCanonicalFileName);
12241251

12251252
// find first position where directory and resolution differs
12261253
let i = 0;
@@ -1239,7 +1266,7 @@ function createNonRelativeNameResolutionCache<T>(
12391266
if (sep === -1) {
12401267
return undefined;
12411268
}
1242-
return directory.substr(0, Math.max(sep, rootLength));
1269+
return directory.substr(0, Math.max(sep, rootLength)) as Path;
12431270
}
12441271
}
12451272
}
@@ -1256,20 +1283,24 @@ function createModuleOrTypeReferenceResolutionCache<T>(
12561283
packageJsonInfoCache: PackageJsonInfoCache | undefined,
12571284
getResolvedFileName: (result: T) => string | undefined,
12581285
optionsToRedirectsKey: Map<CompilerOptions, RedirectsCacheKey> | undefined,
1286+
getValidResolution: ((resolution: T | undefined) => T | undefined) | undefined,
12591287
): ModuleOrTypeReferenceResolutionCache<T> {
12601288
optionsToRedirectsKey ??= new Map();
1289+
getValidResolution ??= identity;
12611290
const perDirectoryResolutionCache = createPerDirectoryResolutionCache<T>(
12621291
currentDirectory,
12631292
getCanonicalFileName,
12641293
options,
12651294
optionsToRedirectsKey,
1295+
getValidResolution,
12661296
);
12671297
const nonRelativeNameResolutionCache = createNonRelativeNameResolutionCache(
12681298
currentDirectory,
12691299
getCanonicalFileName,
12701300
options,
12711301
getResolvedFileName,
12721302
optionsToRedirectsKey,
1303+
getValidResolution,
12731304
);
12741305
packageJsonInfoCache ??= createPackageJsonInfoCache(currentDirectory, getCanonicalFileName);
12751306

@@ -1313,13 +1344,15 @@ export function createModuleResolutionCache(
13131344
options?: CompilerOptions,
13141345
packageJsonInfoCache?: PackageJsonInfoCache,
13151346
optionsToRedirectsKey?: Map<CompilerOptions, RedirectsCacheKey>,
1347+
getValidResolution?: (resolution: ResolvedModuleWithFailedLookupLocations | undefined) => ResolvedModuleWithFailedLookupLocations | undefined,
13161348
): ModuleResolutionCache;
13171349
export function createModuleResolutionCache(
13181350
currentDirectory: string,
13191351
getCanonicalFileName: (s: string) => string,
13201352
options?: CompilerOptions,
13211353
packageJsonInfoCache?: PackageJsonInfoCache,
13221354
optionsToRedirectsKey?: Map<CompilerOptions, RedirectsCacheKey>,
1355+
getValidResolution?: (resolution: ResolvedModuleWithFailedLookupLocations | undefined) => ResolvedModuleWithFailedLookupLocations | undefined,
13231356
): ModuleResolutionCache {
13241357
const result = createModuleOrTypeReferenceResolutionCache(
13251358
currentDirectory,
@@ -1328,6 +1361,7 @@ export function createModuleResolutionCache(
13281361
packageJsonInfoCache,
13291362
getOriginalOrResolvedModuleFileName,
13301363
optionsToRedirectsKey,
1364+
getValidResolution,
13311365
) as ModuleResolutionCache;
13321366
result.getOrCreateCacheForModuleName = (nonRelativeName, mode, redirectedReference) => result.getOrCreateCacheForNonRelativeName(nonRelativeName, mode, redirectedReference);
13331367
return result;
@@ -1346,13 +1380,15 @@ export function createTypeReferenceDirectiveResolutionCache(
13461380
options?: CompilerOptions,
13471381
packageJsonInfoCache?: PackageJsonInfoCache,
13481382
optionsToRedirectsKey?: Map<CompilerOptions, RedirectsCacheKey>,
1383+
getValidResolution?: (resolution: ResolvedTypeReferenceDirectiveWithFailedLookupLocations | undefined) => ResolvedTypeReferenceDirectiveWithFailedLookupLocations | undefined,
13491384
): TypeReferenceDirectiveResolutionCache;
13501385
export function createTypeReferenceDirectiveResolutionCache(
13511386
currentDirectory: string,
13521387
getCanonicalFileName: (s: string) => string,
13531388
options?: CompilerOptions,
13541389
packageJsonInfoCache?: PackageJsonInfoCache,
13551390
optionsToRedirectsKey?: Map<CompilerOptions, RedirectsCacheKey>,
1391+
getValidResolution?: (resolution: ResolvedTypeReferenceDirectiveWithFailedLookupLocations | undefined) => ResolvedTypeReferenceDirectiveWithFailedLookupLocations | undefined,
13561392
): TypeReferenceDirectiveResolutionCache {
13571393
return createModuleOrTypeReferenceResolutionCache(
13581394
currentDirectory,
@@ -1361,6 +1397,7 @@ export function createTypeReferenceDirectiveResolutionCache(
13611397
packageJsonInfoCache,
13621398
getOriginalOrResolvedTypeReferenceFileName,
13631399
optionsToRedirectsKey,
1400+
getValidResolution,
13641401
);
13651402
}
13661403

src/compiler/program.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,6 @@ import {
273273
removeSuffix,
274274
resolutionExtensionIsTSOrJson,
275275
ResolutionMode,
276-
ResolutionWithFailedLookupLocations,
277276
resolveConfigFileProjectName,
278277
ResolvedConfigFileName,
279278
ResolvedModuleFull,
@@ -4063,7 +4062,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
40634062
resolveModuleNamesReusingOldState(moduleNames, file);
40644063
Debug.assert(resolutions.length === moduleNames.length);
40654064
const optionsForFile = (useSourceOfProjectReferenceRedirect ? getRedirectReferenceForResolution(file)?.commandLine.options : undefined) || options;
4066-
const resolutionsInFile = createModeAwareCache<ResolutionWithFailedLookupLocations>();
4065+
const resolutionsInFile = createModeAwareCache<ResolvedModuleWithFailedLookupLocations>();
40674066
(resolvedModules ??= new Map()).set(file.path, resolutionsInFile);
40684067
for (let index = 0; index < moduleNames.length; index++) {
40694068
const resolution = resolutions[index].resolvedModule;

0 commit comments

Comments
 (0)