Skip to content

Commit 73e6924

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 34a2cb3 commit 73e6924

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
@@ -58,6 +58,7 @@ import {
5858
hasProperty,
5959
hasTrailingDirectorySeparator,
6060
hostGetCanonicalFileName,
61+
identity,
6162
inferredTypesContainingFile,
6263
isArray,
6364
isDeclarationFileName,
@@ -1064,6 +1065,7 @@ function createPerDirectoryResolutionCache<T>(
10641065
getCanonicalFileName: GetCanonicalFileName,
10651066
options: CompilerOptions | undefined,
10661067
optionsToRedirectsKey: Map<CompilerOptions, RedirectsCacheKey>,
1068+
getValidResolution: (resolution: T | undefined) => T | undefined,
10671069
): PerDirectoryResolutionCache<T> {
10681070
const directoryToModuleNameMap = createCacheWithRedirects<Path, ModeAwareCache<T>>(options, optionsToRedirectsKey);
10691071
return {
@@ -1089,7 +1091,7 @@ function createPerDirectoryResolutionCache<T>(
10891091

10901092
function getFromDirectoryCache(name: string, mode: ResolutionMode, directoryName: string, redirectedReference: ResolvedProjectReference | undefined) {
10911093
const path = toPath(directoryName, currentDirectory, getCanonicalFileName);
1092-
return directoryToModuleNameMap.getMapOfCacheRedirects(redirectedReference)?.get(path)?.get(name, mode);
1094+
return getValidResolution(directoryToModuleNameMap.getMapOfCacheRedirects(redirectedReference)?.get(path)?.get(name, mode));
10931095
}
10941096
}
10951097

@@ -1153,6 +1155,7 @@ function createNonRelativeNameResolutionCache<T>(
11531155
options: CompilerOptions | undefined,
11541156
getResolvedFileName: (result: T) => string | undefined,
11551157
optionsToRedirectsKey: Map<CompilerOptions, RedirectsCacheKey>,
1158+
getValidResolution: (resolution: T | undefined) => T | undefined,
11561159
): NonRelativeNameResolutionCache<T> {
11571160
const moduleNameToDirectoryMap = createCacheWithRedirects<ModeAwareCacheKey, PerNonRelativeNameCache<T>>(options, optionsToRedirectsKey);
11581161
return {
@@ -1172,12 +1175,19 @@ function createNonRelativeNameResolutionCache<T>(
11721175

11731176
function getFromNonRelativeNameCache(nonRelativeModuleName: string, mode: ResolutionMode, directoryName: string, redirectedReference?: ResolvedProjectReference): T | undefined {
11741177
Debug.assert(!isExternalModuleNameRelative(nonRelativeModuleName));
1175-
return moduleNameToDirectoryMap.getMapOfCacheRedirects(redirectedReference)?.get(createModeAwareCacheKey(nonRelativeModuleName, mode))?.get(directoryName);
1178+
return moduleNameToDirectoryMap.getMapOfCacheRedirects(redirectedReference)?.get(
1179+
createModeAwareCacheKey(nonRelativeModuleName, mode),
1180+
)?.get(directoryName);
11761181
}
11771182

11781183
function getOrCreateCacheForNonRelativeName(nonRelativeModuleName: string, mode: ResolutionMode, redirectedReference?: ResolvedProjectReference): PerNonRelativeNameCache<T> {
11791184
Debug.assert(!isExternalModuleNameRelative(nonRelativeModuleName));
1180-
return getOrCreateCache(moduleNameToDirectoryMap, redirectedReference, createModeAwareCacheKey(nonRelativeModuleName, mode), createPerModuleNameCache);
1185+
return getOrCreateCache(
1186+
moduleNameToDirectoryMap,
1187+
redirectedReference,
1188+
createModeAwareCacheKey(nonRelativeModuleName, mode),
1189+
createPerModuleNameCache,
1190+
);
11811191
}
11821192

11831193
function createPerModuleNameCache(): PerNonRelativeNameCache<T> {
@@ -1186,7 +1196,11 @@ function createNonRelativeNameResolutionCache<T>(
11861196
return { get, set };
11871197

11881198
function get(directory: string): T | undefined {
1189-
return directoryPathMap.get(toPath(directory, currentDirectory, getCanonicalFileName));
1199+
return getByPath(toPath(directory, currentDirectory, getCanonicalFileName));
1200+
}
1201+
1202+
function getByPath(directoryPath: Path): T | undefined {
1203+
return getValidResolution(directoryPathMap.get(directoryPath));
11901204
}
11911205

11921206
/**
@@ -1203,32 +1217,45 @@ function createNonRelativeNameResolutionCache<T>(
12031217
function set(directory: string, result: T): void {
12041218
const path = toPath(directory, currentDirectory, getCanonicalFileName);
12051219
// if entry is already in cache do nothing
1206-
if (directoryPathMap.has(path)) {
1220+
if (getByPath(path)) {
12071221
return;
12081222
}
1223+
1224+
const existing = directoryPathMap.get(path);
1225+
// Remove invalidated result from parent
1226+
if (existing) {
1227+
const existingCommonPrefix = getCommonPrefix(path, existing);
1228+
withCommonPrefix(path, existingCommonPrefix, parent => directoryPathMap.delete(parent));
1229+
}
1230+
12091231
directoryPathMap.set(path, result);
12101232

1211-
const resolvedFileName = getResolvedFileName(result);
12121233
// find common prefix between directory and resolved file name
12131234
// this common prefix should be the shortest path that has the same resolution
12141235
// directory: /a/b/c/d/e
12151236
// resolvedFileName: /a/b/foo.d.ts
12161237
// commonPrefix: /a/b
12171238
// for failed lookups cache the result for every directory up to root
1218-
const commonPrefix = resolvedFileName && getCommonPrefix(path, resolvedFileName);
1239+
const commonPrefix = getCommonPrefix(path, result);
1240+
withCommonPrefix(path, commonPrefix, parent => directoryPathMap.set(parent, result));
1241+
}
1242+
1243+
function withCommonPrefix(path: Path, commonPrefix: Path | undefined, action: (parent: Path) => void) {
12191244
let current = path;
12201245
while (current !== commonPrefix) {
12211246
const parent = getDirectoryPath(current);
1222-
if (parent === current || directoryPathMap.has(parent)) {
1247+
if (parent === current || getByPath(parent)) {
12231248
break;
12241249
}
1225-
directoryPathMap.set(parent, result);
1250+
action(parent);
12261251
current = parent;
12271252
}
12281253
}
12291254

1230-
function getCommonPrefix(directory: Path, resolution: string) {
1231-
const resolutionDirectory = toPath(getDirectoryPath(resolution), currentDirectory, getCanonicalFileName);
1255+
function getCommonPrefix(directory: Path, resolution: T) {
1256+
const resolvedFileName = getResolvedFileName(resolution);
1257+
if (!resolvedFileName) return undefined;
1258+
const resolutionDirectory = toPath(getDirectoryPath(resolvedFileName), currentDirectory, getCanonicalFileName);
12321259

12331260
// find first position where directory and resolution differs
12341261
let i = 0;
@@ -1247,7 +1274,7 @@ function createNonRelativeNameResolutionCache<T>(
12471274
if (sep === -1) {
12481275
return undefined;
12491276
}
1250-
return directory.substr(0, Math.max(sep, rootLength));
1277+
return directory.substr(0, Math.max(sep, rootLength)) as Path;
12511278
}
12521279
}
12531280
}
@@ -1264,20 +1291,24 @@ function createModuleOrTypeReferenceResolutionCache<T>(
12641291
packageJsonInfoCache: PackageJsonInfoCache | undefined,
12651292
getResolvedFileName: (result: T) => string | undefined,
12661293
optionsToRedirectsKey: Map<CompilerOptions, RedirectsCacheKey> | undefined,
1294+
getValidResolution: ((resolution: T | undefined) => T | undefined) | undefined,
12671295
): ModuleOrTypeReferenceResolutionCache<T> {
12681296
optionsToRedirectsKey ??= new Map();
1297+
getValidResolution ??= identity;
12691298
const perDirectoryResolutionCache = createPerDirectoryResolutionCache<T>(
12701299
currentDirectory,
12711300
getCanonicalFileName,
12721301
options,
12731302
optionsToRedirectsKey,
1303+
getValidResolution,
12741304
);
12751305
const nonRelativeNameResolutionCache = createNonRelativeNameResolutionCache(
12761306
currentDirectory,
12771307
getCanonicalFileName,
12781308
options,
12791309
getResolvedFileName,
12801310
optionsToRedirectsKey,
1311+
getValidResolution,
12811312
);
12821313
packageJsonInfoCache ??= createPackageJsonInfoCache(currentDirectory, getCanonicalFileName);
12831314

@@ -1321,13 +1352,15 @@ export function createModuleResolutionCache(
13211352
options?: CompilerOptions,
13221353
packageJsonInfoCache?: PackageJsonInfoCache,
13231354
optionsToRedirectsKey?: Map<CompilerOptions, RedirectsCacheKey>,
1355+
getValidResolution?: (resolution: ResolvedModuleWithFailedLookupLocations | undefined) => ResolvedModuleWithFailedLookupLocations | undefined,
13241356
): ModuleResolutionCache;
13251357
export function createModuleResolutionCache(
13261358
currentDirectory: string,
13271359
getCanonicalFileName: (s: string) => string,
13281360
options?: CompilerOptions,
13291361
packageJsonInfoCache?: PackageJsonInfoCache,
13301362
optionsToRedirectsKey?: Map<CompilerOptions, RedirectsCacheKey>,
1363+
getValidResolution?: (resolution: ResolvedModuleWithFailedLookupLocations | undefined) => ResolvedModuleWithFailedLookupLocations | undefined,
13311364
): ModuleResolutionCache {
13321365
const result = createModuleOrTypeReferenceResolutionCache(
13331366
currentDirectory,
@@ -1336,6 +1369,7 @@ export function createModuleResolutionCache(
13361369
packageJsonInfoCache,
13371370
getOriginalOrResolvedModuleFileName,
13381371
optionsToRedirectsKey,
1372+
getValidResolution,
13391373
) as ModuleResolutionCache;
13401374
result.getOrCreateCacheForModuleName = (nonRelativeName, mode, redirectedReference) => result.getOrCreateCacheForNonRelativeName(nonRelativeName, mode, redirectedReference);
13411375
return result;
@@ -1354,13 +1388,15 @@ export function createTypeReferenceDirectiveResolutionCache(
13541388
options?: CompilerOptions,
13551389
packageJsonInfoCache?: PackageJsonInfoCache,
13561390
optionsToRedirectsKey?: Map<CompilerOptions, RedirectsCacheKey>,
1391+
getValidResolution?: (resolution: ResolvedTypeReferenceDirectiveWithFailedLookupLocations | undefined) => ResolvedTypeReferenceDirectiveWithFailedLookupLocations | undefined,
13571392
): TypeReferenceDirectiveResolutionCache;
13581393
export function createTypeReferenceDirectiveResolutionCache(
13591394
currentDirectory: string,
13601395
getCanonicalFileName: (s: string) => string,
13611396
options?: CompilerOptions,
13621397
packageJsonInfoCache?: PackageJsonInfoCache,
13631398
optionsToRedirectsKey?: Map<CompilerOptions, RedirectsCacheKey>,
1399+
getValidResolution?: (resolution: ResolvedTypeReferenceDirectiveWithFailedLookupLocations | undefined) => ResolvedTypeReferenceDirectiveWithFailedLookupLocations | undefined,
13641400
): TypeReferenceDirectiveResolutionCache {
13651401
return createModuleOrTypeReferenceResolutionCache(
13661402
currentDirectory,
@@ -1369,6 +1405,7 @@ export function createTypeReferenceDirectiveResolutionCache(
13691405
packageJsonInfoCache,
13701406
getOriginalOrResolvedTypeReferenceFileName,
13711407
optionsToRedirectsKey,
1408+
getValidResolution,
13721409
);
13731410
}
13741411

src/compiler/program.ts

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

0 commit comments

Comments
 (0)