mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Add incremental test where cache should have same resolutions as whats in the program
This shows cache is holding onto resolutions that are no longer needed by program because either those modules arent present in file or is determined to be ambient resolution
This commit is contained in:
+13
-5
@@ -1022,7 +1022,8 @@ export function getResolutionModeOverride(node: ImportAttributes | undefined, gr
|
||||
return elem.value.text === "import" ? ModuleKind.ESNext : ModuleKind.CommonJS;
|
||||
}
|
||||
|
||||
const emptyResolution: ResolvedModuleWithFailedLookupLocations & ResolvedTypeReferenceDirectiveWithFailedLookupLocations = {
|
||||
/** @internal */
|
||||
export const emptyResolution: ResolvedModuleWithFailedLookupLocations & ResolvedTypeReferenceDirectiveWithFailedLookupLocations = {
|
||||
resolvedModule: undefined,
|
||||
resolvedTypeReferenceDirective: undefined,
|
||||
};
|
||||
@@ -1201,6 +1202,13 @@ function forEachProjectReference<T>(
|
||||
/** @internal */
|
||||
export const inferredTypesContainingFile = "__inferred type names__.ts";
|
||||
|
||||
/** @internal */
|
||||
export function getAutomaticTypeDirectiveContainingFile(options: CompilerOptions, currentDirectory: string): string {
|
||||
// This containingFilename needs to match with the one used in managed-side
|
||||
const containingDirectory = options.configFilePath ? getDirectoryPath(options.configFilePath) : currentDirectory;
|
||||
return combinePaths(containingDirectory, inferredTypesContainingFile);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getInferredLibraryNameResolveFrom(options: CompilerOptions, currentDirectory: string, libFileName: string): string {
|
||||
const containingDirectory = options.configFilePath ? getDirectoryPath(options.configFilePath) : currentDirectory;
|
||||
@@ -1874,10 +1882,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
automaticTypeDirectiveResolutions = createModeAwareCache();
|
||||
if (automaticTypeDirectiveNames.length) {
|
||||
tracing?.push(tracing.Phase.Program, "processTypeReferences", { count: automaticTypeDirectiveNames.length });
|
||||
// This containingFilename needs to match with the one used in managed-side
|
||||
const containingDirectory = options.configFilePath ? getDirectoryPath(options.configFilePath) : currentDirectory;
|
||||
const containingFilename = combinePaths(containingDirectory, inferredTypesContainingFile);
|
||||
const resolutions = resolveTypeReferenceDirectiveNamesReusingOldState(automaticTypeDirectiveNames, containingFilename);
|
||||
const resolutions = resolveTypeReferenceDirectiveNamesReusingOldState(
|
||||
automaticTypeDirectiveNames,
|
||||
getAutomaticTypeDirectiveContainingFile(options, currentDirectory),
|
||||
);
|
||||
for (let i = 0; i < automaticTypeDirectiveNames.length; i++) {
|
||||
// under node16/nodenext module resolution, load `types`/ata include names as cjs resolution results by passing an `undefined` mode
|
||||
automaticTypeDirectiveResolutions.set(automaticTypeDirectiveNames[i], /*mode*/ undefined, resolutions[i]);
|
||||
|
||||
@@ -204,6 +204,7 @@ export function verifyResolutionCache(
|
||||
actualProgram: ts.Program,
|
||||
resolutionHostCacheHost: ts.ResolutionCacheHost,
|
||||
projectName: string,
|
||||
userResolvedModuleNames?: true,
|
||||
): void {
|
||||
const currentDirectory = resolutionHostCacheHost.getCurrentDirectory!();
|
||||
const expected = ts.createResolutionCache(resolutionHostCacheHost, actual.rootDirForResolution);
|
||||
@@ -214,6 +215,12 @@ export function verifyResolutionCache(
|
||||
const expectedToResolution = new Map<ExpectedResolution, ts.ResolutionWithFailedLookupLocations>();
|
||||
const resolutionToExpected = new Map<ts.ResolutionWithFailedLookupLocations, ExpectedResolution>();
|
||||
const resolutionToRefs = new Map<ts.ResolutionWithFailedLookupLocations, ResolutionInfo[]>();
|
||||
const inferredTypesPath = resolutionHostCacheHost.toPath(
|
||||
ts.getAutomaticTypeDirectiveContainingFile(
|
||||
actualProgram.getCompilerOptions(),
|
||||
currentDirectory,
|
||||
),
|
||||
);
|
||||
actual.resolvedModuleNames.forEach((resolutions, path) =>
|
||||
collectResolutionToRefFromCache(
|
||||
"Modules",
|
||||
@@ -222,6 +229,7 @@ export function verifyResolutionCache(
|
||||
getResolvedModuleFileName,
|
||||
/*deferWatchingNonRelativeResolution*/ true,
|
||||
expected.resolvedModuleNames,
|
||||
(name, mode) => actualProgram.getResolvedModule(actualProgram.getSourceFileByPath(path)!, name, mode),
|
||||
)
|
||||
);
|
||||
actual.resolvedTypeReferenceDirectives.forEach((resolutions, path) =>
|
||||
@@ -232,6 +240,10 @@ export function verifyResolutionCache(
|
||||
getResolvedTypeRefFileName,
|
||||
/*deferWatchingNonRelativeResolution*/ false,
|
||||
expected.resolvedTypeReferenceDirectives,
|
||||
(name, mode) =>
|
||||
path !== inferredTypesPath ?
|
||||
actualProgram.getResolvedTypeReferenceDirective(actualProgram.getSourceFileByPath(path)!, name, mode) :
|
||||
actualProgram.getAutomaticTypeDirectiveResolutions().get(name, mode),
|
||||
)
|
||||
);
|
||||
actual.resolvedLibraries.forEach((resolved, libFileName) => {
|
||||
@@ -248,6 +260,39 @@ export function verifyResolutionCache(
|
||||
);
|
||||
expected.resolvedLibraries.set(libFileName, expectedResolution);
|
||||
});
|
||||
// Check for resolutions in program but not in cache to empty resolutions
|
||||
if (!userResolvedModuleNames) {
|
||||
actualProgram.forEachResolvedModule((resolution, name, mode, filePath) =>
|
||||
verifyResolutionIsInCache(
|
||||
"Modules",
|
||||
actual.resolvedModuleNames.get(filePath),
|
||||
resolution,
|
||||
name,
|
||||
mode,
|
||||
filePath,
|
||||
)
|
||||
);
|
||||
}
|
||||
actualProgram.forEachResolvedTypeReferenceDirective((resolution, name, mode, filePath) =>
|
||||
verifyResolutionIsInCache(
|
||||
"TypeRefs",
|
||||
actual.resolvedTypeReferenceDirectives.get(filePath),
|
||||
resolution,
|
||||
name,
|
||||
mode,
|
||||
filePath,
|
||||
)
|
||||
);
|
||||
actualProgram.getAutomaticTypeDirectiveResolutions().forEach((resolution, name, mode) =>
|
||||
verifyResolutionIsInCache(
|
||||
"AutoTypeRefs",
|
||||
actual.resolvedTypeReferenceDirectives.get(inferredTypesPath),
|
||||
resolution,
|
||||
name,
|
||||
mode,
|
||||
inferredTypesPath,
|
||||
)
|
||||
);
|
||||
|
||||
expected.finishCachingPerDirectoryResolution(actualProgram, /*oldProgram*/ undefined);
|
||||
|
||||
@@ -260,6 +305,10 @@ export function verifyResolutionCache(
|
||||
`Expected from:: ${JSON.stringify(info, undefined, " ")}` +
|
||||
`Actual from: ${resolution.files?.size}`,
|
||||
);
|
||||
ts.Debug.assert(
|
||||
!resolution.isInvalidated,
|
||||
`${projectName}:: Resolution should not be invalidated`,
|
||||
);
|
||||
verifySet(resolutionToExpected.get(resolution)!.files, resolution.files, `${projectName}:: Resolution files`);
|
||||
});
|
||||
verifyMapOfResolutionSet(expected.resolvedFileToResolution, actual.resolvedFileToResolution, `resolvedFileToResolution`);
|
||||
@@ -295,24 +344,54 @@ export function verifyResolutionCache(
|
||||
ts.Debug.assert(expected.countResolutionsResolvedWithGlobalCache() === 0, `${projectName}:: ResolutionsResolvedWithGlobalCache should be cleared`);
|
||||
ts.Debug.assert(expected.countResolutionsResolvedWithoutGlobalCache() === 0, `${projectName}:: ResolutionsResolvedWithoutGlobalCache should be cleared`);
|
||||
|
||||
function verifyResolutionIsInCache<T extends ts.ResolutionWithFailedLookupLocations>(
|
||||
cacheType: string,
|
||||
cache: ts.ModeAwareCache<T> | undefined,
|
||||
resolution: T,
|
||||
name: string,
|
||||
mode: ts.ResolutionMode,
|
||||
fileName: string,
|
||||
) {
|
||||
if (resolution as unknown !== ts.emptyResolution) {
|
||||
// Resolutions should match
|
||||
ts.Debug.assert(
|
||||
cache?.get(name, mode) === resolution,
|
||||
`${projectName}:: ${cacheType}:: ${name}:: ${mode} Expected resolution in program to be in cache ${fileName}`,
|
||||
);
|
||||
}
|
||||
else {
|
||||
// EmptyResolution is place holder and shouldnt be in the cache
|
||||
ts.Debug.assert(
|
||||
!cache?.has(name, mode),
|
||||
`${projectName}:: ${cacheType}:: ${name}:: ${mode} Ambient moduleResolution, should not be in cache or watched ${fileName}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function collectResolutionToRefFromCache<T extends ts.ResolutionWithFailedLookupLocations>(
|
||||
cacheType: string,
|
||||
fileName: ts.Path,
|
||||
cache: ts.ModeAwareCache<T> | undefined,
|
||||
getResolvedFileName: (resolution: T) => string | undefined,
|
||||
deferWatchingNonRelativeResolution: boolean,
|
||||
storeExpcted: Map<ts.Path, ts.ModeAwareCache<ts.ResolutionWithFailedLookupLocations>>,
|
||||
storeExpected: Map<ts.Path, ts.ModeAwareCache<ts.ResolutionWithFailedLookupLocations>>,
|
||||
getProgramResolutions: (name: string, mode: ts.ResolutionMode) => T | undefined,
|
||||
) {
|
||||
ts.Debug.assert(
|
||||
actualProgram.getSourceFileByPath(fileName) || ts.endsWith(fileName, ts.inferredTypesContainingFile),
|
||||
actualProgram.getSourceFileByPath(fileName) || inferredTypesPath === fileName,
|
||||
`${projectName}:: ${cacheType} ${fileName} Expect cache for file in program or auto type ref`,
|
||||
);
|
||||
let expectedCache: ts.ModeAwareCache<ts.ResolutionWithFailedLookupLocations> | undefined;
|
||||
cache?.forEach((resolved, name, mode) => {
|
||||
const resolvedFileName = getResolvedFileName(resolved);
|
||||
const expected = collectResolution(cacheType, fileName, resolved, resolvedFileName, name, mode, deferWatchingNonRelativeResolution);
|
||||
if (!expectedCache) storeExpcted.set(fileName, expectedCache = ts.createModeAwareCache());
|
||||
if (!expectedCache) storeExpected.set(fileName, expectedCache = ts.createModeAwareCache());
|
||||
expectedCache.set(name, mode, expected);
|
||||
// Resolution in cache should be same as that is in program
|
||||
ts.Debug.assert(
|
||||
resolved === getProgramResolutions(name, mode),
|
||||
`${projectName}:: ${cacheType} ${fileName} ${name} ${mode} Expected resolution in cache to be matched to that in the program`,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -133,6 +133,7 @@ export interface RunWatchBaseline<T extends ts.BuilderProgram> extends BaselineB
|
||||
getPrograms: () => readonly CommandLineProgram[];
|
||||
watchOrSolution: WatchOrSolution<T>;
|
||||
useSourceOfProjectReferenceRedirect?: () => boolean;
|
||||
userResolvedModuleNames?: true;
|
||||
}
|
||||
export function runWatchBaseline<T extends ts.BuilderProgram = ts.EmitAndSemanticDiagnosticsBuilderProgram>({
|
||||
scenario,
|
||||
@@ -146,6 +147,7 @@ export function runWatchBaseline<T extends ts.BuilderProgram = ts.EmitAndSemanti
|
||||
edits,
|
||||
watchOrSolution,
|
||||
useSourceOfProjectReferenceRedirect,
|
||||
userResolvedModuleNames,
|
||||
}: RunWatchBaseline<T>): void {
|
||||
baseline.push(`${sys.getExecutingFilePath()} ${commandLineArgs.join(" ")}`);
|
||||
let programs = watchBaseline({
|
||||
@@ -171,6 +173,7 @@ export function runWatchBaseline<T extends ts.BuilderProgram = ts.EmitAndSemanti
|
||||
caption,
|
||||
resolutionCache: (watchOrSolution as ts.WatchOfConfigFile<T> | undefined)?.getResolutionCache?.(),
|
||||
useSourceOfProjectReferenceRedirect,
|
||||
userResolvedModuleNames,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -183,6 +186,7 @@ export interface WatchBaseline extends BaselineBase, TscWatchCheckOptions {
|
||||
caption?: string;
|
||||
resolutionCache?: ts.ResolutionCache;
|
||||
useSourceOfProjectReferenceRedirect?: () => boolean;
|
||||
userResolvedModuleNames?: true;
|
||||
}
|
||||
export function watchBaseline({
|
||||
baseline,
|
||||
@@ -194,6 +198,7 @@ export function watchBaseline({
|
||||
caption,
|
||||
resolutionCache,
|
||||
useSourceOfProjectReferenceRedirect,
|
||||
userResolvedModuleNames,
|
||||
}: WatchBaseline): readonly CommandLineProgram[] {
|
||||
const programs = baselineAfterTscCompile(
|
||||
sys,
|
||||
@@ -213,6 +218,7 @@ export function watchBaseline({
|
||||
programs[0][0],
|
||||
resolutionCache,
|
||||
useSourceOfProjectReferenceRedirect,
|
||||
userResolvedModuleNames,
|
||||
);
|
||||
}
|
||||
return programs;
|
||||
@@ -222,7 +228,8 @@ function verifyProgramStructureAndResolutionCache(
|
||||
sys: TscWatchSystem,
|
||||
program: ts.Program,
|
||||
resolutionCache: ts.ResolutionCache,
|
||||
useSourceOfProjectReferenceRedirect?: () => boolean,
|
||||
useSourceOfProjectReferenceRedirect: (() => boolean) | undefined,
|
||||
userResolvedModuleNames: true | undefined,
|
||||
) {
|
||||
const options = program.getCompilerOptions();
|
||||
const compilerHost = ts.createCompilerHostWorker(options, /*setParentNodes*/ undefined, sys);
|
||||
@@ -239,25 +246,30 @@ function verifyProgramStructureAndResolutionCache(
|
||||
program,
|
||||
caption,
|
||||
);
|
||||
verifyResolutionCache(resolutionCache, program, {
|
||||
...compilerHost,
|
||||
verifyResolutionCache(
|
||||
resolutionCache,
|
||||
program,
|
||||
{
|
||||
...compilerHost,
|
||||
getCompilerHost: () => compilerHost,
|
||||
toPath: fileName => sys.toPath(fileName),
|
||||
getCompilationSettings: () => options,
|
||||
fileIsOpen: ts.returnFalse,
|
||||
getCurrentProgram: () => program,
|
||||
preferNonRecursiveWatch: sys.preferNonRecursiveWatch,
|
||||
|
||||
getCompilerHost: () => compilerHost,
|
||||
toPath: fileName => sys.toPath(fileName),
|
||||
getCompilationSettings: () => options,
|
||||
fileIsOpen: ts.returnFalse,
|
||||
getCurrentProgram: () => program,
|
||||
preferNonRecursiveWatch: sys.preferNonRecursiveWatch,
|
||||
|
||||
watchDirectoryOfFailedLookupLocation: ts.returnNoopFileWatcher,
|
||||
watchAffectingFileLocation: ts.returnNoopFileWatcher,
|
||||
onInvalidatedResolution: ts.noop,
|
||||
watchTypeRootsDirectory: ts.returnNoopFileWatcher,
|
||||
onChangedAutomaticTypeDirectiveNames: ts.noop,
|
||||
scheduleInvalidateResolutionsOfFailedLookupLocations: ts.noop,
|
||||
getCachedDirectoryStructureHost: ts.returnUndefined,
|
||||
writeLog: ts.noop,
|
||||
}, caption);
|
||||
watchDirectoryOfFailedLookupLocation: ts.returnNoopFileWatcher,
|
||||
watchAffectingFileLocation: ts.returnNoopFileWatcher,
|
||||
onInvalidatedResolution: ts.noop,
|
||||
watchTypeRootsDirectory: ts.returnNoopFileWatcher,
|
||||
onChangedAutomaticTypeDirectiveNames: ts.noop,
|
||||
scheduleInvalidateResolutionsOfFailedLookupLocations: ts.noop,
|
||||
getCachedDirectoryStructureHost: ts.returnUndefined,
|
||||
writeLog: ts.noop,
|
||||
},
|
||||
caption,
|
||||
userResolvedModuleNames,
|
||||
);
|
||||
}
|
||||
export interface VerifyTscWatch extends TscWatchCompile {
|
||||
baselineIncremental?: boolean;
|
||||
|
||||
@@ -118,6 +118,7 @@ describe("unittests:: tscWatch:: watchAPI:: tsc-watch with custom module resolut
|
||||
},
|
||||
],
|
||||
watchOrSolution: watch,
|
||||
userResolvedModuleNames: true,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user