Skip to content

Commit 87918f5

Browse files
authored
Compact the tsbuild info by encoding info differently for some of the situations (#58641)
1 parent cffc425 commit 87918f5

File tree

608 files changed

+3824
-12763
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

608 files changed

+3824
-12763
lines changed

src/compiler/builder.ts

Lines changed: 84 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ import {
6060
isNumber,
6161
isString,
6262
map,
63+
mapDefinedIterator,
6364
maybeBind,
6465
noop,
6566
notImplemented,
@@ -102,7 +103,7 @@ export interface ReusableDiagnostic extends ReusableDiagnosticRelatedInformation
102103
export interface ReusableDiagnosticRelatedInformation {
103104
category: DiagnosticCategory;
104105
code: number;
105-
file: string | undefined;
106+
file: string | undefined | false;
106107
start: number | undefined;
107108
length: number | undefined;
108109
messageText: string | ReusableDiagnosticMessageChain;
@@ -384,7 +385,7 @@ function createBuilderProgramState(newProgram: Program, oldState: Readonly<Reusa
384385
(state.emitDiagnosticsPerFile ??= new Map()).set(
385386
sourceFilePath,
386387
oldState!.hasReusableDiagnostic ?
387-
convertToDiagnostics(emitDiagnostics as readonly ReusableDiagnostic[], newProgram) :
388+
convertToDiagnostics(emitDiagnostics as readonly ReusableDiagnostic[], sourceFilePath, newProgram) :
388389
repopulateDiagnostics(emitDiagnostics as readonly Diagnostic[], newProgram),
389390
);
390391
}
@@ -399,7 +400,7 @@ function createBuilderProgramState(newProgram: Program, oldState: Readonly<Reusa
399400
state.semanticDiagnosticsPerFile!.set(
400401
sourceFilePath,
401402
oldState!.hasReusableDiagnostic ?
402-
convertToDiagnostics(diagnostics as readonly ReusableDiagnostic[], newProgram) :
403+
convertToDiagnostics(diagnostics as readonly ReusableDiagnostic[], sourceFilePath, newProgram) :
403404
repopulateDiagnostics(diagnostics as readonly Diagnostic[], newProgram),
404405
);
405406
(state.semanticDiagnosticsFromOldState ??= new Set()).add(sourceFilePath);
@@ -516,19 +517,19 @@ function convertOrRepopulateDiagnosticMessageChainArray<T extends DiagnosticMess
516517
return sameMap(array, chain => convertOrRepopulateDiagnosticMessageChain(chain, sourceFile, newProgram, repopulateInfo));
517518
}
518519

519-
function convertToDiagnostics(diagnostics: readonly ReusableDiagnostic[], newProgram: Program): readonly Diagnostic[] {
520+
function convertToDiagnostics(diagnostics: readonly ReusableDiagnostic[], diagnosticFilePath: Path, newProgram: Program): readonly Diagnostic[] {
520521
if (!diagnostics.length) return emptyArray;
521522
let buildInfoDirectory: string | undefined;
522523
return diagnostics.map(diagnostic => {
523-
const result: Diagnostic = convertToDiagnosticRelatedInformation(diagnostic, newProgram, toPathInBuildInfoDirectory);
524+
const result: Diagnostic = convertToDiagnosticRelatedInformation(diagnostic, diagnosticFilePath, newProgram, toPathInBuildInfoDirectory);
524525
result.reportsUnnecessary = diagnostic.reportsUnnecessary;
525526
result.reportsDeprecated = diagnostic.reportDeprecated;
526527
result.source = diagnostic.source;
527528
result.skippedOn = diagnostic.skippedOn;
528529
const { relatedInformation } = diagnostic;
529530
result.relatedInformation = relatedInformation ?
530531
relatedInformation.length ?
531-
relatedInformation.map(r => convertToDiagnosticRelatedInformation(r, newProgram, toPathInBuildInfoDirectory)) :
532+
relatedInformation.map(r => convertToDiagnosticRelatedInformation(r, diagnosticFilePath, newProgram, toPathInBuildInfoDirectory)) :
532533
[] :
533534
undefined;
534535
return result;
@@ -540,9 +541,11 @@ function convertToDiagnostics(diagnostics: readonly ReusableDiagnostic[], newPro
540541
}
541542
}
542543

543-
function convertToDiagnosticRelatedInformation(diagnostic: ReusableDiagnosticRelatedInformation, newProgram: Program, toPath: (path: string) => Path): DiagnosticRelatedInformation {
544+
function convertToDiagnosticRelatedInformation(diagnostic: ReusableDiagnosticRelatedInformation, diagnosticFilePath: Path, newProgram: Program, toPath: (path: string) => Path): DiagnosticRelatedInformation {
544545
const { file } = diagnostic;
545-
const sourceFile = file ? newProgram.getSourceFileByPath(toPath(file)) : undefined;
546+
const sourceFile = file !== false ?
547+
newProgram.getSourceFileByPath(file ? toPath(file) : diagnosticFilePath) :
548+
undefined;
546549
return {
547550
...diagnostic,
548551
file: sourceFile,
@@ -981,7 +984,14 @@ export type ProgramBuildInfoFileId = number & { __programBuildInfoFileIdBrand: a
981984
/** @internal */
982985
export type ProgramBuildInfoFileIdListId = number & { __programBuildInfoFileIdListIdBrand: any; };
983986
/** @internal */
984-
export type ProgramBuildInfoDiagnostic = ProgramBuildInfoFileId | [fileId: ProgramBuildInfoFileId, diagnostics: readonly ReusableDiagnostic[]];
987+
export type ProgramBuildInfoDiagnosticOfFile = [fileId: ProgramBuildInfoFileId, diagnostics: readonly ReusableDiagnostic[]];
988+
/** @internal */
989+
export type ProgramBuildInfoDiagnostic =
990+
| ProgramBuildInfoFileId // File is not in changedSet and still doesnt have cached diagnostics
991+
| ProgramBuildInfoDiagnosticOfFile; // Diagnostics for file
992+
/** @internal */
993+
export type ProgramBuildInfoEmitDiagnostic = ProgramBuildInfoDiagnosticOfFile; // Diagnostics for the file
994+
985995
/**
986996
* fileId if pending emit is same as what compilerOptions suggest
987997
* [fileId] if pending emit is only dts file emit
@@ -1034,7 +1044,7 @@ export interface ProgramMultiFileEmitBuildInfo {
10341044
fileIdsList: readonly (readonly ProgramBuildInfoFileId[])[] | undefined;
10351045
referencedMap: ProgramBuildInfoReferencedMap | undefined;
10361046
semanticDiagnosticsPerFile: ProgramBuildInfoDiagnostic[] | undefined;
1037-
emitDiagnosticsPerFile: ProgramBuildInfoDiagnostic[] | undefined;
1047+
emitDiagnosticsPerFile: ProgramBuildInfoEmitDiagnostic[] | undefined;
10381048
affectedFilesPendingEmit: ProgramBuilderInfoFilePendingEmit[] | undefined;
10391049
changeFileSet: readonly ProgramBuildInfoFileId[] | undefined;
10401050
emitSignatures: readonly ProgramBuildInfoEmitSignature[] | undefined;
@@ -1156,14 +1166,14 @@ function getBuildInfo(state: BuilderProgramState): BuildInfo {
11561166
});
11571167

11581168
let referencedMap: ProgramBuildInfoReferencedMap | undefined;
1159-
if (state.referencedMap) {
1169+
if (state.referencedMap?.size()) {
11601170
referencedMap = arrayFrom(state.referencedMap.keys()).sort(compareStringsCaseSensitive).map(key => [
11611171
toFileId(key),
11621172
toFileIdListId(state.referencedMap!.getValues(key)!),
11631173
]);
11641174
}
11651175

1166-
const semanticDiagnosticsPerFile = convertToProgramBuildInfoDiagnostics(state.semanticDiagnosticsPerFile);
1176+
const semanticDiagnosticsPerFile = convertToProgramBuildInfoDiagnostics();
11671177
let affectedFilesPendingEmit: ProgramBuilderInfoFilePendingEmit[] | undefined;
11681178
if (state.affectedFilesPendingEmit?.size) {
11691179
const fullEmitForOptions = getBuilderFileEmit(state.compilerOptions);
@@ -1191,7 +1201,7 @@ function getBuildInfo(state: BuilderProgramState): BuildInfo {
11911201
changeFileSet = append(changeFileSet, toFileId(path));
11921202
}
11931203
}
1194-
const emitDiagnosticsPerFile = convertToProgramBuildInfoDiagnostics(state.emitDiagnosticsPerFile);
1204+
const emitDiagnosticsPerFile = convertToProgramBuildInfoEmitDiagnostics();
11951205
const program: ProgramMultiFileEmitBuildInfo = {
11961206
fileNames,
11971207
fileInfos,
@@ -1301,48 +1311,63 @@ function getBuildInfo(state: BuilderProgramState): BuildInfo {
13011311
return value;
13021312
}
13031313

1304-
function convertToProgramBuildInfoDiagnostics(diagnostics: Map<Path, readonly Diagnostic[]> | undefined) {
1314+
function convertToProgramBuildInfoDiagnostics() {
13051315
let result: ProgramBuildInfoDiagnostic[] | undefined;
1306-
if (diagnostics) {
1307-
for (const key of arrayFrom(diagnostics.keys()).sort(compareStringsCaseSensitive)) {
1308-
const value = diagnostics.get(key)!;
1309-
result = append(
1310-
result,
1311-
value.length ?
1312-
[
1313-
toFileId(key),
1314-
convertToReusableDiagnostics(value),
1315-
] :
1316-
toFileId(key),
1317-
);
1316+
state.fileInfos.forEach((_value, key) => {
1317+
const value = state.semanticDiagnosticsPerFile?.get(key);
1318+
if (!value) {
1319+
if (!state.changedFilesSet.has(key)) result = append(result, toFileId(key));
13181320
}
1321+
else if (value.length) {
1322+
result = append(result, [
1323+
toFileId(key),
1324+
convertToReusableDiagnostics(value, key),
1325+
]);
1326+
}
1327+
});
1328+
return result;
1329+
}
1330+
1331+
function convertToProgramBuildInfoEmitDiagnostics() {
1332+
let result: ProgramBuildInfoEmitDiagnostic[] | undefined;
1333+
if (!state.emitDiagnosticsPerFile?.size) return result;
1334+
for (const key of arrayFrom(state.emitDiagnosticsPerFile.keys()).sort(compareStringsCaseSensitive)) {
1335+
const value = state.emitDiagnosticsPerFile.get(key)!;
1336+
result = append(result, [
1337+
toFileId(key),
1338+
convertToReusableDiagnostics(value, key),
1339+
]);
13191340
}
13201341
return result;
13211342
}
13221343

1323-
function convertToReusableDiagnostics(diagnostics: readonly Diagnostic[]): readonly ReusableDiagnostic[] {
1344+
function convertToReusableDiagnostics(diagnostics: readonly Diagnostic[], diagnosticFilePath: Path): readonly ReusableDiagnostic[] {
13241345
Debug.assert(!!diagnostics.length);
13251346
return diagnostics.map(diagnostic => {
1326-
const result: ReusableDiagnostic = convertToReusableDiagnosticRelatedInformation(diagnostic);
1347+
const result: ReusableDiagnostic = convertToReusableDiagnosticRelatedInformation(diagnostic, diagnosticFilePath);
13271348
result.reportsUnnecessary = diagnostic.reportsUnnecessary;
13281349
result.reportDeprecated = diagnostic.reportsDeprecated;
13291350
result.source = diagnostic.source;
13301351
result.skippedOn = diagnostic.skippedOn;
13311352
const { relatedInformation } = diagnostic;
13321353
result.relatedInformation = relatedInformation ?
13331354
relatedInformation.length ?
1334-
relatedInformation.map(r => convertToReusableDiagnosticRelatedInformation(r)) :
1355+
relatedInformation.map(r => convertToReusableDiagnosticRelatedInformation(r, diagnosticFilePath)) :
13351356
[] :
13361357
undefined;
13371358
return result;
13381359
});
13391360
}
13401361

1341-
function convertToReusableDiagnosticRelatedInformation(diagnostic: DiagnosticRelatedInformation): ReusableDiagnosticRelatedInformation {
1362+
function convertToReusableDiagnosticRelatedInformation(diagnostic: DiagnosticRelatedInformation, diagnosticFilePath: Path): ReusableDiagnosticRelatedInformation {
13421363
const { file } = diagnostic;
13431364
return {
13441365
...diagnostic,
1345-
file: file ? relativeToBuildInfo(file.resolvedPath) : undefined,
1366+
file: file ?
1367+
file.resolvedPath === diagnosticFilePath ?
1368+
undefined :
1369+
relativeToBuildInfo(file.resolvedPath) :
1370+
false,
13461371
messageText: isString(diagnostic.messageText) ? diagnostic.messageText : convertToReusableDiagnosticMessageChain(diagnostic.messageText),
13471372
};
13481373
}
@@ -1881,16 +1906,17 @@ export function createBuilderProgramUsingProgramBuildInfo(buildInfo: BuildInfo,
18811906
);
18821907
}
18831908
});
1909+
const changedFilesSet = new Set(map(program.changeFileSet, toFilePath));
18841910
const fullEmitForOptions = program.affectedFilesPendingEmit ? getBuilderFileEmit(program.options || {}) : undefined;
18851911
state = {
18861912
fileInfos,
18871913
compilerOptions: program.options ? convertToOptionsWithAbsolutePaths(program.options, toAbsolutePath) : {},
1888-
referencedMap: toManyToManyPathMap(program.referencedMap),
1889-
semanticDiagnosticsPerFile: toPerFileDiagnostics(program.semanticDiagnosticsPerFile),
1890-
emitDiagnosticsPerFile: toPerFileDiagnostics(program.emitDiagnosticsPerFile),
1914+
referencedMap: toManyToManyPathMap(program.referencedMap, program.options ?? {}),
1915+
semanticDiagnosticsPerFile: toPerFileSemanticDiagnostics(program.semanticDiagnosticsPerFile, fileInfos, changedFilesSet),
1916+
emitDiagnosticsPerFile: toPerFileEmitDiagnostics(program.emitDiagnosticsPerFile),
18911917
hasReusableDiagnostic: true,
18921918
affectedFilesPendingEmit: program.affectedFilesPendingEmit && arrayToMap(program.affectedFilesPendingEmit, value => toFilePath(isNumber(value) ? value : value[0]), value => toBuilderFileEmit(value, fullEmitForOptions!)),
1893-
changedFilesSet: new Set(map(program.changeFileSet, toFilePath)),
1919+
changedFilesSet,
18941920
latestChangedDtsFile,
18951921
emitSignatures: emitSignatures?.size ? emitSignatures : undefined,
18961922
};
@@ -1938,18 +1964,33 @@ export function createBuilderProgramUsingProgramBuildInfo(buildInfo: BuildInfo,
19381964
return filePathsSetList![fileIdsListId - 1];
19391965
}
19401966

1941-
function toManyToManyPathMap(referenceMap: ProgramBuildInfoReferencedMap | undefined): BuilderState.ManyToManyPathMap | undefined {
1942-
if (!referenceMap) {
1943-
return undefined;
1944-
}
1945-
1946-
const map = BuilderState.createManyToManyPathMap();
1967+
function toManyToManyPathMap(referenceMap: ProgramBuildInfoReferencedMap | undefined, options: CompilerOptions): BuilderState.ManyToManyPathMap | undefined {
1968+
const map = BuilderState.createReferencedMap(options);
1969+
if (!map || !referenceMap) return map;
19471970
referenceMap.forEach(([fileId, fileIdListId]) => map.set(toFilePath(fileId), toFilePathsSet(fileIdListId)));
19481971
return map;
19491972
}
19501973

1951-
function toPerFileDiagnostics(diagnostics: readonly ProgramBuildInfoDiagnostic[] | undefined): Map<Path, readonly ReusableDiagnostic[]> | undefined {
1952-
return diagnostics && arrayToMap(diagnostics, value => toFilePath(isNumber(value) ? value : value[0]), value => isNumber(value) ? emptyArray : value[1]);
1974+
function toPerFileSemanticDiagnostics(
1975+
diagnostics: readonly ProgramBuildInfoDiagnostic[] | undefined,
1976+
fileInfos: Map<Path, BuilderState.FileInfo>,
1977+
changedFilesSet: Set<Path>,
1978+
): Map<Path, readonly ReusableDiagnostic[]> | undefined {
1979+
const semanticDiagnostics = new Map<Path, readonly ReusableDiagnostic[]>(
1980+
mapDefinedIterator(
1981+
fileInfos.keys(),
1982+
key => !changedFilesSet.has(key) ? [key, emptyArray] : undefined,
1983+
),
1984+
);
1985+
diagnostics?.forEach(value => {
1986+
if (isNumber(value)) semanticDiagnostics.delete(toFilePath(value));
1987+
else semanticDiagnostics.set(toFilePath(value[0]), value[1]);
1988+
});
1989+
return semanticDiagnostics.size ? semanticDiagnostics : undefined;
1990+
}
1991+
1992+
function toPerFileEmitDiagnostics(diagnostics: readonly ProgramBuildInfoEmitDiagnostic[] | undefined): Map<Path, readonly ReusableDiagnostic[]> | undefined {
1993+
return diagnostics && arrayToMap(diagnostics, value => toFilePath(value[0]), value => value[1]);
19531994
}
19541995
}
19551996

src/compiler/builderState.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
arrayFrom,
33
CancellationToken,
4+
CompilerOptions,
45
computeSignatureWithDiagnostics,
56
CustomTransformers,
67
Debug,
@@ -110,6 +111,7 @@ export namespace BuilderState {
110111
getKeys(v: Path): ReadonlySet<Path> | undefined;
111112
getValues(k: Path): ReadonlySet<Path> | undefined;
112113
keys(): IterableIterator<Path>;
114+
size(): number;
113115
}
114116

115117
export interface ManyToManyPathMap extends ReadonlyManyToManyPathMap {
@@ -123,6 +125,7 @@ export namespace BuilderState {
123125
getKeys: v => reverse.get(v),
124126
getValues: k => forward.get(k),
125127
keys: () => forward.keys(),
128+
size: () => forward.size,
126129

127130
deleteKey: k => {
128131
(deleted ||= new Set<Path>()).add(k);
@@ -292,15 +295,19 @@ export namespace BuilderState {
292295
return oldState && !oldState.referencedMap === !newReferencedMap;
293296
}
294297

298+
export function createReferencedMap(options: CompilerOptions) {
299+
return options.module !== ModuleKind.None && !options.outFile ?
300+
createManyToManyPathMap() :
301+
undefined;
302+
}
303+
295304
/**
296305
* Creates the state of file references and signature for the new program from oldState if it is safe
297306
*/
298307
export function create(newProgram: Program, oldState: Readonly<BuilderState> | undefined, disableUseFileVersionAsSignature: boolean): BuilderState {
299308
const fileInfos = new Map<Path, FileInfo>();
300309
const options = newProgram.getCompilerOptions();
301-
const isOutFile = options.outFile;
302-
const referencedMap = options.module !== ModuleKind.None && !isOutFile ?
303-
createManyToManyPathMap() : undefined;
310+
const referencedMap = createReferencedMap(options);
304311
const useOldState = canReuseOldState(referencedMap, oldState);
305312

306313
// Ensure source files have parent pointers set
@@ -323,7 +330,7 @@ export namespace BuilderState {
323330
version,
324331
signature,
325332
// No need to calculate affectsGlobalScope with --out since its not used at all
326-
affectsGlobalScope: !isOutFile ? isFileAffectingGlobalScope(sourceFile) || undefined : undefined,
333+
affectsGlobalScope: !options.outFile ? isFileAffectingGlobalScope(sourceFile) || undefined : undefined,
327334
impliedFormat: sourceFile.impliedNodeFormat,
328335
});
329336
}

src/compiler/tsbuildPublic.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ import {
7171
getWatchErrorSummaryDiagnosticMessage,
7272
hasProperty,
7373
identity,
74-
isArray,
7574
isIgnoredFileFromWildCardWatching,
7675
isIncrementalCompilation,
7776
isPackageJsonInfo,
@@ -105,7 +104,6 @@ import {
105104
SemanticDiagnosticsBuilderProgram,
106105
setGetSourceFileAsHashVersioned,
107106
SharedExtendedConfigFileWatcher,
108-
some,
109107
SourceFile,
110108
Status,
111109
sys,
@@ -1698,7 +1696,7 @@ function getUpToDateStatusWorker<T extends BuilderProgram>(state: SolutionBuilde
16981696
(!project.options.noEmit ?
16991697
(buildInfo.program as ProgramMultiFileEmitBuildInfo).affectedFilesPendingEmit?.length ||
17001698
(buildInfo.program as ProgramMultiFileEmitBuildInfo).emitDiagnosticsPerFile?.length :
1701-
some((buildInfo.program as ProgramMultiFileEmitBuildInfo).semanticDiagnosticsPerFile, isArray))
1699+
(buildInfo.program as ProgramMultiFileEmitBuildInfo).semanticDiagnosticsPerFile?.length)
17021700
) {
17031701
return {
17041702
type: UpToDateStatusType.OutOfDateBuildInfo,

0 commit comments

Comments
 (0)