Skip to content

Commit b32d2eb

Browse files
committed
Only copy emit state fields when backing up to restore if emit fails
1 parent 21a6806 commit b32d2eb

File tree

6 files changed

+60
-63
lines changed

6 files changed

+60
-63
lines changed

src/compiler/builder.ts

+54-41
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,18 @@ namespace ts {
142142
filesChangingSignature?: Set<Path>;
143143
}
144144

145+
type BackupEmitState = Pick<BuilderProgramState,
146+
"affectedFilesPendingEmit" |
147+
"affectedFilesPendingEmitIndex" |
148+
"affectedFilesPendingEmitKind" |
149+
"seenEmittedFiles" |
150+
"programEmitComplete" |
151+
"emitSignatures" |
152+
"outSignature" |
153+
"dtsChangeTime" |
154+
"hasChangedEmitSignature"
155+
> & { changedFilesSet: BuilderProgramState["changedFilesSet"] | undefined };
156+
145157
function hasSameKeys(map1: ReadonlyCollection<string> | undefined, map2: ReadonlyCollection<string> | undefined): boolean {
146158
// Has same size and every key is present in both maps
147159
return map1 === map2 || map1 !== undefined && map2 !== undefined && map1.size === map2.size && !forEachKey(map1, key => !map2.has(key));
@@ -296,34 +308,35 @@ namespace ts {
296308
state.program = undefined;
297309
}
298310

299-
/**
300-
* Creates a clone of the state
301-
*/
302-
function cloneBuilderProgramState(state: Readonly<BuilderProgramState>): BuilderProgramState {
303-
const newState = BuilderState.clone(state) as BuilderProgramState;
304-
newState.semanticDiagnosticsPerFile = state.semanticDiagnosticsPerFile && new Map(state.semanticDiagnosticsPerFile);
305-
newState.changedFilesSet = new Set(state.changedFilesSet);
306-
newState.affectedFiles = state.affectedFiles;
307-
newState.affectedFilesIndex = state.affectedFilesIndex;
308-
newState.currentChangedFilePath = state.currentChangedFilePath;
309-
newState.currentAffectedFilesSignatures = state.currentAffectedFilesSignatures && new Map(state.currentAffectedFilesSignatures);
310-
newState.currentAffectedFilesExportedModulesMap = state.currentAffectedFilesExportedModulesMap?.clone();
311-
newState.seenAffectedFiles = state.seenAffectedFiles && new Set(state.seenAffectedFiles);
312-
newState.cleanedDiagnosticsOfLibFiles = state.cleanedDiagnosticsOfLibFiles;
313-
newState.semanticDiagnosticsFromOldState = state.semanticDiagnosticsFromOldState && new Set(state.semanticDiagnosticsFromOldState);
314-
newState.program = state.program;
315-
newState.compilerOptions = state.compilerOptions;
316-
newState.affectedFilesPendingEmit = state.affectedFilesPendingEmit && state.affectedFilesPendingEmit.slice();
317-
newState.affectedFilesPendingEmitKind = state.affectedFilesPendingEmitKind && new Map(state.affectedFilesPendingEmitKind);
318-
newState.affectedFilesPendingEmitIndex = state.affectedFilesPendingEmitIndex;
319-
newState.seenEmittedFiles = state.seenEmittedFiles && new Map(state.seenEmittedFiles);
320-
newState.programEmitComplete = state.programEmitComplete;
321-
newState.filesChangingSignature = state.filesChangingSignature && new Set(state.filesChangingSignature);
322-
newState.emitSignatures = state.emitSignatures && new Map(state.emitSignatures);
323-
newState.outSignature = state.outSignature;
324-
newState.dtsChangeTime = state.dtsChangeTime;
325-
newState.hasChangedEmitSignature = state.hasChangedEmitSignature;
326-
return newState;
311+
function backupEmitBuilderProgramState(state: Readonly<BuilderProgramState>): BackupEmitState {
312+
const outFilePath = outFile(state.compilerOptions);
313+
// Only in --out changeFileSet is kept around till emit
314+
Debug.assert(!state.changedFilesSet.size || outFilePath);
315+
return {
316+
affectedFilesPendingEmit: state.affectedFilesPendingEmit && state.affectedFilesPendingEmit.slice(),
317+
affectedFilesPendingEmitKind: state.affectedFilesPendingEmitKind && new Map(state.affectedFilesPendingEmitKind),
318+
affectedFilesPendingEmitIndex: state.affectedFilesPendingEmitIndex,
319+
seenEmittedFiles: state.seenEmittedFiles && new Map(state.seenEmittedFiles),
320+
programEmitComplete: state.programEmitComplete,
321+
emitSignatures: state.emitSignatures && new Map(state.emitSignatures),
322+
outSignature: state.outSignature,
323+
dtsChangeTime: state.dtsChangeTime,
324+
hasChangedEmitSignature: state.hasChangedEmitSignature,
325+
changedFilesSet: outFilePath ? new Set(state.changedFilesSet) : undefined,
326+
};
327+
}
328+
329+
function restoreEmitBuilderProgramState(state: BuilderProgramState, backupEmitState: BackupEmitState) {
330+
state.affectedFilesPendingEmit = backupEmitState.affectedFilesPendingEmit;
331+
state.affectedFilesPendingEmitKind = backupEmitState.affectedFilesPendingEmitKind;
332+
state.affectedFilesPendingEmitIndex = backupEmitState.affectedFilesPendingEmitIndex;
333+
state.seenEmittedFiles = backupEmitState.seenEmittedFiles;
334+
state.programEmitComplete = backupEmitState.programEmitComplete;
335+
state.emitSignatures = backupEmitState.emitSignatures;
336+
state.outSignature = backupEmitState.outSignature;
337+
state.dtsChangeTime = backupEmitState.dtsChangeTime;
338+
state.hasChangedEmitSignature = backupEmitState.hasChangedEmitSignature;
339+
if (backupEmitState.changedFilesSet) state.changedFilesSet = backupEmitState.changedFilesSet;
327340
}
328341

329342
/**
@@ -1090,8 +1103,8 @@ namespace ts {
10901103
* Computing hash to for signature verification
10911104
*/
10921105
const computeHash = maybeBind(host, host.createHash);
1093-
let state = createBuilderProgramState(newProgram, getCanonicalFileName, oldState, host.disableUseFileVersionAsSignature);
1094-
let backupState: BuilderProgramState | undefined;
1106+
const state = createBuilderProgramState(newProgram, getCanonicalFileName, oldState, host.disableUseFileVersionAsSignature);
1107+
let backupEmitState: BackupEmitState | undefined;
10951108
newProgram.getProgramBuildInfo = () => getProgramBuildInfo(state, getCanonicalFileName, host);
10961109

10971110
// To ensure that we arent storing any references to old program or new program without state
@@ -1102,20 +1115,20 @@ namespace ts {
11021115
const getState = () => state;
11031116
const builderProgram = createRedirectedBuilderProgram(getState, configFileParsingDiagnostics);
11041117
builderProgram.getState = getState;
1105-
builderProgram.backupState = () => {
1106-
Debug.assert(backupState === undefined);
1107-
backupState = cloneBuilderProgramState(state);
1118+
builderProgram.backupEmitState = () => {
1119+
Debug.assert(backupEmitState === undefined);
1120+
backupEmitState = backupEmitBuilderProgramState(state);
11081121
};
1109-
builderProgram.restoreState = () => {
1110-
state = Debug.checkDefined(backupState);
1111-
backupState = undefined;
1122+
builderProgram.restoreEmitState = () => {
1123+
restoreEmitBuilderProgramState(state, Debug.checkDefined(backupEmitState));
1124+
backupEmitState = undefined;
11121125
};
11131126
builderProgram.getAllDependencies = sourceFile => BuilderState.getAllDependencies(state, Debug.checkDefined(state.program), sourceFile);
11141127
builderProgram.getSemanticDiagnostics = getSemanticDiagnostics;
11151128
builderProgram.emit = emit;
11161129
builderProgram.releaseProgram = () => {
11171130
releaseCache(state);
1118-
backupState = undefined;
1131+
backupEmitState = undefined;
11191132
};
11201133

11211134
if (kind === BuilderProgramKind.SemanticDiagnosticsBuilderProgram) {
@@ -1451,8 +1464,8 @@ namespace ts {
14511464
};
14521465
return {
14531466
getState: () => state,
1454-
backupState: noop,
1455-
restoreState: noop,
1467+
backupEmitState: noop,
1468+
restoreEmitState: noop,
14561469
getProgram: notImplemented,
14571470
getProgramOrUndefined: returnUndefined,
14581471
releaseProgram: noop,
@@ -1506,8 +1519,8 @@ namespace ts {
15061519
export function createRedirectedBuilderProgram(getState: () => { program?: Program | undefined; compilerOptions: CompilerOptions; }, configFileParsingDiagnostics: readonly Diagnostic[]): BuilderProgram {
15071520
return {
15081521
getState: notImplemented,
1509-
backupState: noop,
1510-
restoreState: noop,
1522+
backupEmitState: noop,
1523+
restoreEmitState: noop,
15111524
getProgram,
15121525
getProgramOrUndefined: () => getState().program,
15131526
releaseProgram: () => getState().program = undefined,

src/compiler/builderPublic.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ namespace ts {
3939
/*@internal*/
4040
getState(): ReusableBuilderProgramState;
4141
/*@internal*/
42-
backupState(): void;
42+
backupEmitState(): void;
4343
/*@internal*/
44-
restoreState(): void;
44+
restoreEmitState(): void;
4545
/**
4646
* Returns current program
4747
*/

src/compiler/builderState.ts

-16
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ namespace ts {
6161
}
6262

6363
export interface ReadonlyManyToManyPathMap {
64-
clone(): ManyToManyPathMap;
6564
forEach(action: (v: ReadonlySet<Path>, k: Path) => void): void;
6665
getKeys(v: Path): ReadonlySet<Path> | undefined;
6766
getValues(k: Path): ReadonlySet<Path> | undefined;
@@ -85,7 +84,6 @@ namespace ts {
8584
export function createManyToManyPathMap(): ManyToManyPathMap {
8685
function create(forward: ESMap<Path, ReadonlySet<Path>>, reverse: ESMap<Path, Set<Path>>, deleted: Set<Path> | undefined): ManyToManyPathMap {
8786
const map: ManyToManyPathMap = {
88-
clone: () => create(new Map(forward), new Map(reverse), deleted && new Set(deleted)),
8987
forEach: fn => forward.forEach(fn),
9088
getKeys: v => reverse.get(v),
9189
getValues: k => forward.get(k),
@@ -324,20 +322,6 @@ namespace ts {
324322
state.allFileNames = undefined;
325323
}
326324

327-
/**
328-
* Creates a clone of the state
329-
*/
330-
export function clone(state: Readonly<BuilderState>): BuilderState {
331-
// Dont need to backup allFiles info since its cache anyway
332-
return {
333-
fileInfos: new Map(state.fileInfos),
334-
referencedMap: state.referencedMap?.clone(),
335-
exportedModulesMap: state.exportedModulesMap?.clone(),
336-
hasCalledUpdateShapeSignature: state.hasCalledUpdateShapeSignature && new Set(state.hasCalledUpdateShapeSignature),
337-
useFileVersionAsSignature: state.useFileVersionAsSignature,
338-
};
339-
}
340-
341325
/**
342326
* Gets the files affected by the path from the program
343327
*/

src/compiler/tsbuildPublic.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -948,7 +948,7 @@ namespace ts {
948948
Debug.assertIsDefined(program);
949949
Debug.assert(step === BuildStep.Emit);
950950
// Before emitting lets backup state, so we can revert it back if there are declaration errors to handle emit and declaration errors correctly
951-
program.backupState();
951+
program.backupEmitState();
952952
let declDiagnostics: Diagnostic[] | undefined;
953953
const reportDeclarationDiagnostics = (d: Diagnostic) => (declDiagnostics || (declDiagnostics = [])).push(d);
954954
const outputFiles: OutputFile[] = [];
@@ -964,7 +964,7 @@ namespace ts {
964964
);
965965
// Don't emit .d.ts if there are decl file errors
966966
if (declDiagnostics) {
967-
program.restoreState();
967+
program.restoreEmitState();
968968
({ buildResult, step } = buildErrors(
969969
state,
970970
projectPath,

tests/baselines/reference/tsbuildWatch/programUpdates/reportErrors/declarationEmitErrors/when-file-with-no-error-changes.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ Semantic diagnostics in builder refreshed for::
5555
Shape signatures in builder refreshed for::
5656
/a/lib/lib.d.ts (used version)
5757
/user/username/projects/solution/app/filewitherror.ts (used version)
58-
/user/username/projects/solution/app/filewithouterror.ts (computed .d.ts)
58+
/user/username/projects/solution/app/filewithouterror.ts (computed .d.ts during emit)
5959

6060
WatchedFiles::
6161
/user/username/projects/solution/app/tsconfig.json:

tests/baselines/reference/tsbuildWatch/programUpdates/reportErrors/declarationEmitErrors/when-fixing-error-files-all-files-are-emitted.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ Semantic diagnostics in builder refreshed for::
5555
Shape signatures in builder refreshed for::
5656
/a/lib/lib.d.ts (used version)
5757
/user/username/projects/solution/app/filewitherror.ts (used version)
58-
/user/username/projects/solution/app/filewithouterror.ts (computed .d.ts)
58+
/user/username/projects/solution/app/filewithouterror.ts (computed .d.ts during emit)
5959

6060
WatchedFiles::
6161
/user/username/projects/solution/app/tsconfig.json:

0 commit comments

Comments
 (0)