Skip to content

Commit a4bce9e

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
1 parent ba00137 commit a4bce9e

File tree

31 files changed

+276
-275
lines changed

31 files changed

+276
-275
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,
@@ -1073,6 +1074,7 @@ function createPerDirectoryResolutionCache<T>(
10731074
getCanonicalFileName: GetCanonicalFileName,
10741075
options: CompilerOptions | undefined,
10751076
optionsToRedirectsKey: Map<CompilerOptions, RedirectsCacheKey>,
1077+
getValidResolution: (resolution: T | undefined) => T | undefined,
10761078
): PerDirectoryResolutionCache<T> {
10771079
const directoryToModuleNameMap = createCacheWithRedirects<Path, ModeAwareCache<T>>(options, optionsToRedirectsKey);
10781080
return {
@@ -1098,7 +1100,7 @@ function createPerDirectoryResolutionCache<T>(
10981100

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

@@ -1162,6 +1164,7 @@ function createNonRelativeNameResolutionCache<T>(
11621164
options: CompilerOptions | undefined,
11631165
getResolvedFileName: (result: T) => string | undefined,
11641166
optionsToRedirectsKey: Map<CompilerOptions, RedirectsCacheKey>,
1167+
getValidResolution: (resolution: T | undefined) => T | undefined,
11651168
): NonRelativeNameResolutionCache<T> {
11661169
const moduleNameToDirectoryMap = createCacheWithRedirects<ModeAwareCacheKey, PerNonRelativeNameCache<T>>(options, optionsToRedirectsKey);
11671170
return {
@@ -1181,12 +1184,19 @@ function createNonRelativeNameResolutionCache<T>(
11811184

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

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

11921202
function createPerModuleNameCache(): PerNonRelativeNameCache<T> {
@@ -1195,7 +1205,11 @@ function createNonRelativeNameResolutionCache<T>(
11951205
return { get, set };
11961206

11971207
function get(directory: string): T | undefined {
1198-
return directoryPathMap.get(toPath(directory, currentDirectory, getCanonicalFileName));
1208+
return getByPath(toPath(directory, currentDirectory, getCanonicalFileName));
1209+
}
1210+
1211+
function getByPath(directoryPath: Path): T | undefined {
1212+
return getValidResolution(directoryPathMap.get(directoryPath));
11991213
}
12001214

12011215
/**
@@ -1212,32 +1226,45 @@ function createNonRelativeNameResolutionCache<T>(
12121226
function set(directory: string, result: T): void {
12131227
const path = toPath(directory, currentDirectory, getCanonicalFileName);
12141228
// if entry is already in cache do nothing
1215-
if (directoryPathMap.has(path)) {
1229+
if (getByPath(path)) {
12161230
return;
12171231
}
1232+
1233+
const existing = directoryPathMap.get(path);
1234+
// Remove invalidated result from parent
1235+
if (existing) {
1236+
const existingCommonPrefix = getCommonPrefix(path, existing);
1237+
withCommonPrefix(path, existingCommonPrefix, parent => directoryPathMap.delete(parent));
1238+
}
1239+
12181240
directoryPathMap.set(path, result);
12191241

1220-
const resolvedFileName = getResolvedFileName(result);
12211242
// find common prefix between directory and resolved file name
12221243
// this common prefix should be the shortest path that has the same resolution
12231244
// directory: /a/b/c/d/e
12241245
// resolvedFileName: /a/b/foo.d.ts
12251246
// commonPrefix: /a/b
12261247
// for failed lookups cache the result for every directory up to root
1227-
const commonPrefix = resolvedFileName && getCommonPrefix(path, resolvedFileName);
1248+
const commonPrefix = getCommonPrefix(path, result);
1249+
withCommonPrefix(path, commonPrefix, parent => directoryPathMap.set(parent, result));
1250+
}
1251+
1252+
function withCommonPrefix(path: Path, commonPrefix: Path | undefined, action: (parent: Path) => void) {
12281253
let current = path;
12291254
while (current !== commonPrefix) {
12301255
const parent = getDirectoryPath(current);
1231-
if (parent === current || directoryPathMap.has(parent)) {
1256+
if (parent === current || getByPath(parent)) {
12321257
break;
12331258
}
1234-
directoryPathMap.set(parent, result);
1259+
action(parent);
12351260
current = parent;
12361261
}
12371262
}
12381263

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

12421269
// find first position where directory and resolution differs
12431270
let i = 0;
@@ -1256,7 +1283,7 @@ function createNonRelativeNameResolutionCache<T>(
12561283
if (sep === -1) {
12571284
return undefined;
12581285
}
1259-
return directory.substr(0, Math.max(sep, rootLength));
1286+
return directory.substr(0, Math.max(sep, rootLength)) as Path;
12601287
}
12611288
}
12621289
}
@@ -1273,20 +1300,24 @@ function createModuleOrTypeReferenceResolutionCache<T>(
12731300
packageJsonInfoCache: PackageJsonInfoCache | undefined,
12741301
getResolvedFileName: (result: T) => string | undefined,
12751302
optionsToRedirectsKey: Map<CompilerOptions, RedirectsCacheKey> | undefined,
1303+
getValidResolution: ((resolution: T | undefined) => T | undefined) | undefined,
12761304
): ModuleOrTypeReferenceResolutionCache<T> {
12771305
optionsToRedirectsKey ??= new Map();
1306+
getValidResolution ??= identity;
12781307
const perDirectoryResolutionCache = createPerDirectoryResolutionCache<T>(
12791308
currentDirectory,
12801309
getCanonicalFileName,
12811310
options,
12821311
optionsToRedirectsKey,
1312+
getValidResolution,
12831313
);
12841314
const nonRelativeNameResolutionCache = createNonRelativeNameResolutionCache(
12851315
currentDirectory,
12861316
getCanonicalFileName,
12871317
options,
12881318
getResolvedFileName,
12891319
optionsToRedirectsKey,
1320+
getValidResolution,
12901321
);
12911322
packageJsonInfoCache ??= createPackageJsonInfoCache(currentDirectory, getCanonicalFileName);
12921323

@@ -1329,14 +1360,18 @@ export function createModuleResolutionCache(
13291360
getCanonicalFileName: (s: string) => string,
13301361
options?: CompilerOptions,
13311362
packageJsonInfoCache?: PackageJsonInfoCache,
1332-
optionsToRedirectsKey?: Map<CompilerOptions, RedirectsCacheKey>, // eslint-disable-line @typescript-eslint/unified-signatures
1363+
optionsToRedirectsKey?: Map<CompilerOptions, RedirectsCacheKey>,
1364+
getValidResolution?: ( // eslint-disable-line @typescript-eslint/unified-signatures
1365+
resolution: ResolvedModuleWithFailedLookupLocations | undefined,
1366+
) => ResolvedModuleWithFailedLookupLocations | undefined,
13331367
): ModuleResolutionCache;
13341368
export function createModuleResolutionCache(
13351369
currentDirectory: string,
13361370
getCanonicalFileName: (s: string) => string,
13371371
options?: CompilerOptions,
13381372
packageJsonInfoCache?: PackageJsonInfoCache,
13391373
optionsToRedirectsKey?: Map<CompilerOptions, RedirectsCacheKey>,
1374+
getValidResolution?: (resolution: ResolvedModuleWithFailedLookupLocations | undefined) => ResolvedModuleWithFailedLookupLocations | undefined,
13401375
): ModuleResolutionCache {
13411376
const result = createModuleOrTypeReferenceResolutionCache(
13421377
currentDirectory,
@@ -1345,6 +1380,7 @@ export function createModuleResolutionCache(
13451380
packageJsonInfoCache,
13461381
getOriginalOrResolvedModuleFileName,
13471382
optionsToRedirectsKey,
1383+
getValidResolution,
13481384
) as ModuleResolutionCache;
13491385
result.getOrCreateCacheForModuleName = (nonRelativeName, mode, redirectedReference) => result.getOrCreateCacheForNonRelativeName(nonRelativeName, mode, redirectedReference);
13501386
return result;
@@ -1362,14 +1398,18 @@ export function createTypeReferenceDirectiveResolutionCache(
13621398
getCanonicalFileName: (s: string) => string,
13631399
options?: CompilerOptions,
13641400
packageJsonInfoCache?: PackageJsonInfoCache,
1365-
optionsToRedirectsKey?: Map<CompilerOptions, RedirectsCacheKey>, // eslint-disable-line @typescript-eslint/unified-signatures
1401+
optionsToRedirectsKey?: Map<CompilerOptions, RedirectsCacheKey>,
1402+
getValidResolution?: ( // eslint-disable-line @typescript-eslint/unified-signatures
1403+
resolution: ResolvedTypeReferenceDirectiveWithFailedLookupLocations | undefined,
1404+
) => ResolvedTypeReferenceDirectiveWithFailedLookupLocations | undefined,
13661405
): TypeReferenceDirectiveResolutionCache;
13671406
export function createTypeReferenceDirectiveResolutionCache(
13681407
currentDirectory: string,
13691408
getCanonicalFileName: (s: string) => string,
13701409
options?: CompilerOptions,
13711410
packageJsonInfoCache?: PackageJsonInfoCache,
13721411
optionsToRedirectsKey?: Map<CompilerOptions, RedirectsCacheKey>,
1412+
getValidResolution?: (resolution: ResolvedTypeReferenceDirectiveWithFailedLookupLocations | undefined) => ResolvedTypeReferenceDirectiveWithFailedLookupLocations | undefined,
13731413
): TypeReferenceDirectiveResolutionCache {
13741414
return createModuleOrTypeReferenceResolutionCache(
13751415
currentDirectory,
@@ -1378,6 +1418,7 @@ export function createTypeReferenceDirectiveResolutionCache(
13781418
packageJsonInfoCache,
13791419
getOriginalOrResolvedTypeReferenceFileName,
13801420
optionsToRedirectsKey,
1421+
getValidResolution,
13811422
);
13821423
}
13831424

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,
@@ -4156,7 +4155,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
41564155
resolveModuleNamesReusingOldState(moduleNames, file);
41574156
Debug.assert(resolutions.length === moduleNames.length);
41584157
const optionsForFile = redirectedReference?.commandLine.options || options;
4159-
const resolutionsInFile = createModeAwareCache<ResolutionWithFailedLookupLocations>();
4158+
const resolutionsInFile = createModeAwareCache<ResolvedModuleWithFailedLookupLocations>();
41604159
(resolvedModules ??= new Map()).set(file.path, resolutionsInFile);
41614160
for (let index = 0; index < moduleNames.length; index++) {
41624161
const resolution = resolutions[index].resolvedModule;

0 commit comments

Comments
 (0)