Skip to content

Commit 9f09d09

Browse files
committed
Make sure reused resolutions from file are accounted if all resolutions are reused/are resolved to ambient module names
1 parent a97ba1a commit 9f09d09

15 files changed

+280
-150
lines changed

src/compiler/program.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1591,6 +1591,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
15911591
options: CompilerOptions,
15921592
containingSourceFile: SourceFile,
15931593
reusedNames: readonly StringLiteralLike[] | undefined,
1594+
ambientModuleNames: readonly StringLiteralLike[] | undefined,
15941595
) => readonly ResolvedModuleWithFailedLookupLocations[];
15951596
const hasInvalidatedResolutions = host.hasInvalidatedResolutions || returnFalse;
15961597
if (host.resolveModuleNameLiterals) {
@@ -1795,6 +1796,9 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
17951796
}
17961797
tracing?.pop();
17971798
}
1799+
else {
1800+
host.onReusedTypeReferenceDirectiveResolutions?.(/*reusedNames*/ undefined, /*containingSourceFile*/ undefined);
1801+
}
17981802

17991803
// Do not process the default library if:
18001804
// - The '--noLib' flag is used.
@@ -2041,6 +2045,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
20412045
moduleNames: readonly StringLiteralLike[],
20422046
containingFile: SourceFile,
20432047
reusedNames: readonly StringLiteralLike[] | undefined,
2048+
ambientModuleNames: readonly StringLiteralLike[] | undefined,
20442049
): readonly ResolvedModuleWithFailedLookupLocations[] {
20452050
const containingFileName = getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory);
20462051
const redirectedReference = getRedirectReferenceForResolution(containingFile);
@@ -2053,6 +2058,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
20532058
options,
20542059
containingFile,
20552060
reusedNames,
2061+
ambientModuleNames,
20562062
);
20572063
performance.mark("afterResolveModule");
20582064
performance.measure("ResolveModule", "beforeResolveModule", "afterResolveModule");
@@ -2168,6 +2174,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
21682174
containingSourceFile: containingFile,
21692175
nameAndModeGetter: moduleResolutionNameAndModeGetter,
21702176
resolutionWorker: resolveModuleNamesWorker,
2177+
onReusedResolutions: maybeBind(host, host.onReusedModuleResolutions),
21712178
getReusableOldResolution: (name, mode) => oldProgram?.getResolvedModule(containingFile, name, mode),
21722179
getResolved: getResolvedModuleFromResolution,
21732180
canReuseResolutionsInFile: () => containingFile === oldProgram?.getSourceFile(containingFile.fileName) && !hasInvalidatedResolutions(containingFile.path),
@@ -2227,6 +2234,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
22272234
containingSourceFile,
22282235
nameAndModeGetter: typeReferenceResolutionNameAndModeGetter,
22292236
resolutionWorker: resolveTypeReferenceDirectiveNamesWorker,
2237+
onReusedResolutions: maybeBind(host, host.onReusedTypeReferenceDirectiveResolutions),
22302238
getReusableOldResolution: (name, mode) =>
22312239
containingSourceFile ?
22322240
oldProgram?.getResolvedTypeReferenceDirective(containingSourceFile, name, mode) :
@@ -2248,7 +2256,15 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
22482256
entries: readonly Entry[],
22492257
containingFile: SourceFileOrString,
22502258
reusedNames: readonly Entry[] | undefined,
2259+
ambientEntries: readonly Entry[] | undefined,
22512260
) => readonly Resolution[];
2261+
onReusedResolutions:
2262+
| ((
2263+
resuedEntries: readonly Entry[] | undefined,
2264+
containingSourceFile: SourceFileOrUndefined,
2265+
ambientEntries: readonly Entry[] | undefined,
2266+
) => void)
2267+
| undefined;
22522268
getReusableOldResolution: (name: string, mode: ResolutionMode) => Resolution | undefined;
22532269
getResolved: (oldResolution: Resolution) => ResolutionWithResolvedFileName | undefined;
22542270
canReuseResolutionsInFile: () => boolean;
@@ -2261,12 +2277,14 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
22612277
containingSourceFile,
22622278
nameAndModeGetter,
22632279
resolutionWorker,
2280+
onReusedResolutions,
22642281
getReusableOldResolution,
22652282
getResolved,
22662283
canReuseResolutionsInFile,
22672284
isEntryResolvingToAmbientModule,
22682285
}: ResolveNamesReusingOldStateInput<Entry, SourceFileOrString, SourceFileOrUndefined, Resolution>): readonly Resolution[] {
22692286
if (!entries.length) {
2287+
onReusedResolutions?.(entries, containingSourceFile, /*ambientEntries*/ undefined);
22702288
return emptyArray;
22712289
}
22722290
if (structureIsReused === StructureIsReused.Not && (!isEntryResolvingToAmbientModule || !containingSourceFile!.ambientModuleNames.length)) {
@@ -2276,6 +2294,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
22762294
entries,
22772295
containingFile,
22782296
/*reusedNames*/ undefined,
2297+
/*ambientEntries*/ undefined,
22792298
);
22802299
}
22812300

@@ -2284,6 +2303,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
22842303
let unknownEntryIndices: number[] | undefined;
22852304
let result: Resolution[] | undefined;
22862305
let reusedNames: Entry[] | undefined;
2306+
let ambientEntries: Entry[] | undefined;
22872307
const reuseResolutions = canReuseResolutionsInFile();
22882308
for (let i = 0; i < entries.length; i++) {
22892309
const entry = entries[i];
@@ -2315,6 +2335,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
23152335
}
23162336
}
23172337
if (isEntryResolvingToAmbientModule?.(entry, containingFile)) {
2338+
(ambientEntries ??= []).push(entry);
23182339
(result || (result = new Array(entries.length)))[i] = emptyResolution;
23192340
}
23202341
else {
@@ -2325,12 +2346,14 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
23252346
}
23262347

23272348
if (!unknownEntries) {
2349+
onReusedResolutions?.(reusedNames, containingSourceFile, ambientEntries);
23282350
return result!;
23292351
}
23302352
const resolutions = resolutionWorker(
23312353
unknownEntries,
23322354
containingFile,
23332355
reusedNames,
2356+
ambientEntries,
23342357
);
23352358
if (!result) return resolutions;
23362359
resolutions.forEach((resolution, index) => {
@@ -3860,7 +3883,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
38603883

38613884
function processTypeReferenceDirectives(file: SourceFile) {
38623885
const typeDirectives = file.typeReferenceDirectives;
3863-
if (!typeDirectives.length) return;
3886+
if (!typeDirectives.length) {
3887+
host.onReusedTypeReferenceDirectiveResolutions?.(/*reusedNames*/ undefined, file);
3888+
return;
3889+
}
38643890

38653891
const resolutions = resolvedTypeReferenceDirectiveNamesProcessing?.get(file.path) ||
38663892
resolveTypeReferenceDirectiveNamesReusingOldState(typeDirectives, file);
@@ -4091,6 +4117,9 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
40914117
}
40924118
}
40934119
}
4120+
else {
4121+
host.onReusedModuleResolutions?.(/*reusedNames*/ undefined, file, /*ambientModuleNames*/ undefined);
4122+
}
40944123
}
40954124

40964125
function checkSourceFilesBelongToPath(sourceFiles: readonly SourceFile[], rootDirectory: string): boolean {

src/compiler/resolutionCache.ts

Lines changed: 96 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
clearMap,
55
closeFileWatcher,
66
closeFileWatcherOf,
7+
CompilerHostSupportingResolutionCache,
78
CompilerOptions,
89
createModeAwareCache,
910
createModuleResolutionCache,
@@ -21,6 +22,7 @@ import {
2122
FileWatcher,
2223
FileWatcherCallback,
2324
firstDefinedIterator,
25+
getAutomaticTypeDirectiveContainingFile,
2426
GetCanonicalFileName,
2527
getDirectoryPath,
2628
getEffectiveTypeRoots,
@@ -63,6 +65,7 @@ import {
6365
resolutionExtensionIsTSOrJson,
6466
ResolutionLoader,
6567
ResolutionMode,
68+
ResolutionNameAndModeGetter,
6669
ResolutionWithResolvedFileName,
6770
ResolvedModuleWithFailedLookupLocations,
6871
ResolvedProjectReference,
@@ -75,6 +78,7 @@ import {
7578
startsWith,
7679
StringLiteralLike,
7780
trace,
81+
typeReferenceResolutionNameAndModeGetter,
7882
updateResolutionField,
7983
WatchDirectoryFlags,
8084
} from "./_namespaces/ts";
@@ -97,7 +101,7 @@ export type CallbackOnNewResolution<T extends ResolutionWithFailedLookupLocation
97101
*
98102
* @internal
99103
*/
100-
export interface ResolutionCache {
104+
export interface ResolutionCache extends Required<CompilerHostSupportingResolutionCache> {
101105
rootDirForResolution: string;
102106
resolvedModuleNames: Map<Path, ModeAwareCache<CachedResolvedModuleWithFailedLookupLocations>>;
103107
resolvedTypeReferenceDirectives: Map<Path, ModeAwareCache<CachedResolvedTypeReferenceDirectiveWithFailedLookupLocations>>;
@@ -125,6 +129,7 @@ export interface ResolutionCache {
125129
options: CompilerOptions,
126130
containingSourceFile: SourceFile,
127131
reusedNames: readonly StringLiteralLike[] | undefined,
132+
ambientModuleNames: readonly StringLiteralLike[] | undefined,
128133
onNewResolution?: CallbackOnNewResolution<ResolvedModuleWithFailedLookupLocations>,
129134
): readonly ResolvedModuleWithFailedLookupLocations[];
130135
resolveTypeReferenceDirectiveReferences<T extends FileReference | string>(
@@ -630,6 +635,8 @@ export function createResolutionCache(
630635
finishCachingPerDirectoryResolution,
631636
resolveModuleNameLiterals,
632637
resolveTypeReferenceDirectiveReferences,
638+
onReusedModuleResolutions,
639+
onReusedTypeReferenceDirectiveResolutions,
633640
resolveLibrary,
634641
resolveSingleModuleNameWithoutWatching,
635642
removeResolutionsFromProjectReferenceRedirects,
@@ -801,6 +808,7 @@ export function createResolutionCache(
801808
redirectedReference: ResolvedProjectReference | undefined;
802809
options: CompilerOptions;
803810
reusedNames?: readonly Entry[];
811+
ambientEntries?: readonly Entry[];
804812
perFileCache: Map<Path, ModeAwareCache<T>>;
805813
loader: ResolutionLoader<Entry, T, SourceFile>;
806814
getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName<T, R>;
@@ -815,6 +823,7 @@ export function createResolutionCache(
815823
options,
816824
perFileCache,
817825
reusedNames,
826+
ambientEntries,
818827
loader,
819828
getResolutionWithResolvedFileName,
820829
deferWatchingNonRelativeResolution,
@@ -889,23 +898,102 @@ export function createResolutionCache(
889898
seenNamesInFile.set(name, mode, true);
890899
resolvedModules.push(resolution);
891900
}
901+
onReusedResolutions({
902+
reusedNames,
903+
containingSourceFile,
904+
ambientEntries,
905+
path,
906+
resolutionsInFile,
907+
seenNamesInFile,
908+
nameAndModeGetter: loader.nameAndMode,
909+
getResolutionWithResolvedFileName,
910+
});
911+
return resolvedModules;
912+
}
913+
914+
interface OnReusedResolutionsInput<Entry, SourceFile, T extends ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName> {
915+
reusedNames: readonly Entry[] | undefined;
916+
containingSourceFile: SourceFile;
917+
ambientEntries?: readonly Entry[];
918+
path: Path;
919+
resolutionsInFile: ModeAwareCache<T> | undefined;
920+
seenNamesInFile?: ModeAwareCache<true>;
921+
nameAndModeGetter: ResolutionNameAndModeGetter<Entry, SourceFile>;
922+
getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName<T, R>;
923+
}
924+
function onReusedResolutions<Entry, SourceFile, T extends ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName>({
925+
reusedNames,
926+
containingSourceFile,
927+
path,
928+
resolutionsInFile,
929+
seenNamesInFile,
930+
nameAndModeGetter,
931+
getResolutionWithResolvedFileName,
932+
ambientEntries,
933+
}: OnReusedResolutionsInput<Entry, SourceFile, T, R>) {
934+
if (!resolutionsInFile) return;
935+
if (!seenNamesInFile) seenNamesInFile = createModeAwareCache();
892936
reusedNames?.forEach(entry =>
893-
seenNamesInFile.set(
894-
loader.nameAndMode.getName(entry),
895-
loader.nameAndMode.getMode(entry, containingSourceFile),
937+
seenNamesInFile!.set(
938+
nameAndModeGetter.getName(entry),
939+
nameAndModeGetter.getMode(entry, containingSourceFile),
896940
true,
897941
)
898942
);
943+
// For ambient module names, if its not invalidated keep it
944+
ambientEntries?.forEach(entry => {
945+
const name = nameAndModeGetter.getName(entry);
946+
const mode = nameAndModeGetter.getMode(entry, containingSourceFile);
947+
if (!seenNamesInFile!.has(name, mode)) {
948+
const resolution = resolutionsInFile.get(name, mode);
949+
// Keep this resolution from old time for ambient module names
950+
if (resolution && !resolution.isInvalidated) {
951+
seenNamesInFile!.set(name, mode, true);
952+
}
953+
}
954+
});
899955
if (resolutionsInFile.size() !== seenNamesInFile.size()) {
900956
// Stop watching and remove the unused name
901957
resolutionsInFile.forEach((resolution, name, mode) => {
902-
if (!seenNamesInFile.has(name, mode)) {
958+
if (!seenNamesInFile!.has(name, mode)) {
903959
stopWatchFailedLookupLocationOfResolution(resolution, path, getResolutionWithResolvedFileName);
904960
resolutionsInFile.delete(name, mode);
905961
}
906962
});
907963
}
908-
return resolvedModules;
964+
}
965+
966+
function onReusedModuleResolutions(
967+
reusedNames: readonly StringLiteralLike[] | undefined,
968+
containingSourceFile: SourceFile,
969+
ambientModuleNames: readonly StringLiteralLike[] | undefined,
970+
) {
971+
onReusedResolutions({
972+
reusedNames,
973+
containingSourceFile,
974+
ambientEntries: ambientModuleNames,
975+
path: containingSourceFile.path,
976+
resolutionsInFile: resolvedModuleNames.get(containingSourceFile.path),
977+
nameAndModeGetter: moduleResolutionNameAndModeGetter,
978+
getResolutionWithResolvedFileName: getResolvedModuleFromResolution,
979+
});
980+
}
981+
982+
function onReusedTypeReferenceDirectiveResolutions<T extends FileReference | string>(
983+
reusedNames: readonly T[] | undefined,
984+
containingSourceFile: SourceFile | undefined,
985+
) {
986+
const path = containingSourceFile ?
987+
containingSourceFile.path :
988+
resolutionHost.toPath(getAutomaticTypeDirectiveContainingFile(resolutionHost.getCompilationSettings(), getCurrentDirectory()));
989+
onReusedResolutions({
990+
reusedNames,
991+
containingSourceFile,
992+
path,
993+
resolutionsInFile: resolvedTypeReferenceDirectives.get(path),
994+
nameAndModeGetter: typeReferenceResolutionNameAndModeGetter,
995+
getResolutionWithResolvedFileName: getResolvedTypeReferenceDirectiveFromResolution,
996+
});
909997
}
910998

911999
function resolveTypeReferenceDirectiveReferences<T extends FileReference | string>(
@@ -943,6 +1031,7 @@ export function createResolutionCache(
9431031
options: CompilerOptions,
9441032
containingSourceFile: SourceFile,
9451033
reusedNames: readonly StringLiteralLike[] | undefined,
1034+
ambientModuleNames: readonly StringLiteralLike[] | undefined,
9461035
onNewResolution?: CallbackOnNewResolution<ResolvedModuleWithFailedLookupLocations>,
9471036
): readonly ResolvedModuleWithFailedLookupLocations[] {
9481037
return resolveNamesWithLocalCache({
@@ -952,6 +1041,7 @@ export function createResolutionCache(
9521041
redirectedReference,
9531042
options,
9541043
reusedNames,
1044+
ambientEntries: ambientModuleNames,
9551045
perFileCache: resolvedModuleNames,
9561046
loader: createModuleResolutionLoaderUsingGlobalCache(
9571047
containingFile,

src/compiler/types.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7786,6 +7786,7 @@ export interface CompilerHost extends ModuleResolutionHost {
77867786
options: CompilerOptions,
77877787
containingSourceFile: SourceFile,
77887788
reusedNames: readonly StringLiteralLike[] | undefined,
7789+
ambientModuleNames: readonly StringLiteralLike[] | undefined,
77897790
): readonly ResolvedModuleWithFailedLookupLocations[];
77907791
resolveTypeReferenceDirectiveReferences?<T extends FileReference | string>(
77917792
typeDirectiveReferences: readonly T[],
@@ -7828,6 +7829,22 @@ export interface CompilerHost extends ModuleResolutionHost {
78287829
jsDocParsingMode?: JSDocParsingMode;
78297830
}
78307831

7832+
/** @internal */
7833+
export interface CompilerHostSupportingResolutionCache {
7834+
onReusedModuleResolutions?(
7835+
reusedNames: readonly StringLiteralLike[] | undefined,
7836+
containingSourceFile: SourceFile,
7837+
ambientModuleNames: readonly StringLiteralLike[] | undefined,
7838+
): void;
7839+
onReusedTypeReferenceDirectiveResolutions?<T extends FileReference | string>(
7840+
reusedNames: readonly T[] | undefined,
7841+
containingSourceFile: SourceFile | undefined,
7842+
): void;
7843+
}
7844+
/** @internal */
7845+
export interface CompilerHost extends CompilerHostSupportingResolutionCache {
7846+
}
7847+
78317848
/** true if --out otherwise source file name *
78327849
* @internal
78337850
*/

src/compiler/watchPublic.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ export interface ProgramHost<T extends BuilderProgram> {
228228
options: CompilerOptions,
229229
containingSourceFile: SourceFile,
230230
reusedNames: readonly StringLiteralLike[] | undefined,
231+
ambientModuleNames: readonly StringLiteralLike[] | undefined,
231232
): readonly ResolvedModuleWithFailedLookupLocations[];
232233
resolveTypeReferenceDirectiveReferences?<T extends FileReference | string>(
233234
typeDirectiveReferences: readonly T[],
@@ -522,11 +523,13 @@ export function createWatchProgram<T extends BuilderProgram>(host: WatchCompiler
522523
compilerHost.resolveModuleNames = maybeBind(host, host.resolveModuleNames);
523524
if (!compilerHost.resolveModuleNameLiterals && !compilerHost.resolveModuleNames) {
524525
compilerHost.resolveModuleNameLiterals = resolutionCache.resolveModuleNameLiterals.bind(resolutionCache);
526+
compilerHost.onReusedModuleResolutions = resolutionCache.onReusedModuleResolutions.bind(resolutionCache);
525527
}
526528
compilerHost.resolveTypeReferenceDirectiveReferences = maybeBind(host, host.resolveTypeReferenceDirectiveReferences);
527529
compilerHost.resolveTypeReferenceDirectives = maybeBind(host, host.resolveTypeReferenceDirectives);
528530
if (!compilerHost.resolveTypeReferenceDirectiveReferences && !compilerHost.resolveTypeReferenceDirectives) {
529531
compilerHost.resolveTypeReferenceDirectiveReferences = resolutionCache.resolveTypeReferenceDirectiveReferences.bind(resolutionCache);
532+
compilerHost.onReusedTypeReferenceDirectiveResolutions = resolutionCache.onReusedTypeReferenceDirectiveResolutions.bind(resolutionCache);
530533
}
531534
compilerHost.resolveLibrary = !host.resolveLibrary ?
532535
resolutionCache.resolveLibrary.bind(resolutionCache) :

0 commit comments

Comments
 (0)