Skip to content

Commit 768f7ef

Browse files
committed
If we are updating dts of any of the file and it affects global scope, everything needs update in signature and dts emit
Fixes #42769
1 parent 034521a commit 768f7ef

File tree

3 files changed

+88
-19
lines changed

3 files changed

+88
-19
lines changed

src/compiler/builder.ts

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -524,16 +524,31 @@ namespace ts {
524524
return newSignature !== oldSignature;
525525
}
526526

527-
function forEachKeyOfExportedModulesMap(state: BuilderProgramState, filePath: Path, fn: (exportedFromPath: Path) => void) {
527+
function forEachKeyOfExportedModulesMap<T>(state: BuilderProgramState, filePath: Path, fn: (exportedFromPath: Path) => T | undefined): T | undefined {
528528
// Go through exported modules from cache first
529-
state.currentAffectedFilesExportedModulesMap!.getKeys(filePath)?.forEach(fn);
529+
let keys = state.currentAffectedFilesExportedModulesMap!.getKeys(filePath);
530+
const result = keys && forEachKey(keys, fn);
531+
if (result) return result;
532+
530533
// If exported from path is not from cache and exported modules has path, all files referencing file exported from are affected
531-
state.exportedModulesMap!.getKeys(filePath)?.forEach(exportedFromPath =>
534+
keys = state.exportedModulesMap!.getKeys(filePath);
535+
return keys && forEachKey(keys, exportedFromPath =>
532536
// If the cache had an updated value, skip
533537
!state.currentAffectedFilesExportedModulesMap!.hasKey(exportedFromPath) &&
534-
!state.currentAffectedFilesExportedModulesMap!.deletedKeys()?.has(exportedFromPath) &&
535-
fn(exportedFromPath)
538+
!state.currentAffectedFilesExportedModulesMap!.deletedKeys()?.has(exportedFromPath) ?
539+
fn(exportedFromPath) :
540+
undefined
541+
);
542+
}
543+
544+
function handleDtsMayChangeOfGlobalScope(state: BuilderProgramState, filePath: Path, cancellationToken: CancellationToken | undefined, computeHash: BuilderState.ComputeHash): boolean {
545+
if (!state.fileInfos.get(filePath)?.affectsGlobalScope) return false;
546+
// Every file needs to be handled
547+
BuilderState.getAllFilesExcludingDefaultLibraryFile(state, state.program!, /*firstSourceFile*/ undefined).forEach(
548+
file => handleDtsMayChangeOf(state, file.resolvedPath, cancellationToken, computeHash)
536549
);
550+
removeDiagnosticsOfLibraryFiles(state);
551+
return true;
537552
}
538553

539554
/**
@@ -556,6 +571,7 @@ namespace ts {
556571
if (!seenFileNamesMap.has(currentPath)) {
557572
seenFileNamesMap.set(currentPath, true);
558573
handleDtsMayChangeOf(state, currentPath, cancellationToken, computeHash);
574+
if (handleDtsMayChangeOfGlobalScope(state, currentPath, cancellationToken, computeHash)) return;
559575
if (isChangedSignature(state, currentPath)) {
560576
const currentSourceFile = Debug.checkDefined(state.program).getSourceFileByPath(currentPath)!;
561577
queue.push(...BuilderState.getReferencedByPaths(state, currentSourceFile.resolvedPath));
@@ -568,19 +584,23 @@ namespace ts {
568584
const seenFileAndExportsOfFile = new Set<string>();
569585
// Go through exported modules from cache first
570586
// If exported modules has path, all files referencing file exported from are affected
571-
forEachKeyOfExportedModulesMap(state, affectedFile.resolvedPath, exportedFromPath =>
572-
state.referencedMap!.getKeys(exportedFromPath)?.forEach(filePath =>
587+
forEachKeyOfExportedModulesMap(state, affectedFile.resolvedPath, exportedFromPath => {
588+
if (handleDtsMayChangeOfGlobalScope(state, exportedFromPath, cancellationToken, computeHash)) return true;
589+
const references = state.referencedMap!.getKeys(exportedFromPath);
590+
return references && forEachKey(references, filePath =>
573591
handleDtsMayChangeOfFileAndExportsOfFile(state, filePath, seenFileAndExportsOfFile, cancellationToken, computeHash)
574-
)
575-
);
592+
);
593+
});
576594
}
577595

578596
/**
579597
* handle dts and semantic diagnostics on file and iterate on anything that exports this file
598+
* return true when all work is done and we can exit handling dts emit and semantic diagnostics
580599
*/
581-
function handleDtsMayChangeOfFileAndExportsOfFile(state: BuilderProgramState, filePath: Path, seenFileAndExportsOfFile: Set<string>, cancellationToken: CancellationToken | undefined, computeHash: BuilderState.ComputeHash): void {
582-
if (!tryAddToSet(seenFileAndExportsOfFile, filePath)) return;
600+
function handleDtsMayChangeOfFileAndExportsOfFile(state: BuilderProgramState, filePath: Path, seenFileAndExportsOfFile: Set<string>, cancellationToken: CancellationToken | undefined, computeHash: BuilderState.ComputeHash): boolean | undefined {
601+
if (!tryAddToSet(seenFileAndExportsOfFile, filePath)) return undefined;
583602

603+
if (handleDtsMayChangeOfGlobalScope(state, filePath, cancellationToken, computeHash)) return true;
584604
handleDtsMayChangeOf(state, filePath, cancellationToken, computeHash);
585605
Debug.assert(!!state.currentAffectedFilesExportedModulesMap);
586606

@@ -594,6 +614,7 @@ namespace ts {
594614
!seenFileAndExportsOfFile.has(referencingFilePath) && // Not already removed diagnostic file
595615
handleDtsMayChangeOf(state, referencingFilePath, cancellationToken, computeHash) // Dont add to seen since this is not yet done with the export removal
596616
);
617+
return undefined;
597618
}
598619

599620
/**

tests/baselines/reference/tsc/incremental/change-to-type-that-gets-used-as-global-through-export-in-another-file-through-indirect-import.js

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,21 @@ export default 2;
168168

169169
Output::
170170
/lib/tsc -p src/project
171-
exitCode:: ExitStatus.Success
171+
src/project/class1.ts:1:7 - error TS2322: Type '1' is not assignable to type '2'.
172+
173+
1 const a: MagicNumber = 1;
174+
   ~
175+
176+
177+
Found 1 error in src/project/class1.ts:1
178+
179+
exitCode:: ExitStatus.DiagnosticsPresent_OutputsGenerated
172180

173181

182+
//// [/src/project/class1.d.ts]
183+
declare const a = 2;
184+
185+
174186
//// [/src/project/constants.d.ts]
175187
declare const _default: 2;
176188
export default _default;
@@ -185,7 +197,7 @@ exports["default"] = 2;
185197
//// [/src/project/reexport.d.ts] file written with same contents
186198
//// [/src/project/reexport.js] file written with same contents
187199
//// [/src/project/tsconfig.tsbuildinfo]
188-
{"program":{"fileNames":["../../lib/lib.d.ts","./class1.ts","./constants.ts","./reexport.ts","./types.d.ts"],"fileInfos":[{"version":"3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true},{"version":"4085502068-const a: MagicNumber = 1;\nconsole.log(a);","affectsGlobalScope":true},{"version":"-2659799015-export default 2;","signature":"1573564507-declare const _default: 2;\r\nexport default _default;\r\n"},{"version":"-1476032387-export { default as ConstantNumber } from \"./constants\"","signature":"-1329721329-export { default as ConstantNumber } from \"./constants\";\r\n"},{"version":"2093085814-type MagicNumber = typeof import('./reexport').ConstantNumber","affectsGlobalScope":true}],"options":{"composite":true},"fileIdsList":[[3],[4]],"referencedMap":[[4,1],[5,2]],"exportedModulesMap":[[4,1],[5,2]],"semanticDiagnosticsPerFile":[1,2,3,4,5]},"version":"FakeTSVersion"}
200+
{"program":{"fileNames":["../../lib/lib.d.ts","./class1.ts","./constants.ts","./reexport.ts","./types.d.ts"],"fileInfos":[{"version":"3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true},{"version":"4085502068-const a: MagicNumber = 1;\nconsole.log(a);","affectsGlobalScope":true},{"version":"-2659799015-export default 2;","signature":"1573564507-declare const _default: 2;\r\nexport default _default;\r\n"},{"version":"-1476032387-export { default as ConstantNumber } from \"./constants\"","signature":"-1329721329-export { default as ConstantNumber } from \"./constants\";\r\n"},{"version":"2093085814-type MagicNumber = typeof import('./reexport').ConstantNumber","affectsGlobalScope":true}],"options":{"composite":true},"fileIdsList":[[3],[4]],"referencedMap":[[4,1],[5,2]],"exportedModulesMap":[[4,1],[5,2]],"semanticDiagnosticsPerFile":[1,[2,[{"file":"./class1.ts","start":6,"length":1,"code":2322,"category":1,"messageText":"Type '1' is not assignable to type '2'."}]],3,4,5]},"version":"FakeTSVersion"}
189201

190202
//// [/src/project/tsconfig.tsbuildinfo.readable.baseline.txt]
191203
{
@@ -251,13 +263,25 @@ exports["default"] = 2;
251263
},
252264
"semanticDiagnosticsPerFile": [
253265
"../../lib/lib.d.ts",
254-
"./class1.ts",
266+
[
267+
"./class1.ts",
268+
[
269+
{
270+
"file": "./class1.ts",
271+
"start": 6,
272+
"length": 1,
273+
"code": 2322,
274+
"category": 1,
275+
"messageText": "Type '1' is not assignable to type '2'."
276+
}
277+
]
278+
],
255279
"./constants.ts",
256280
"./reexport.ts",
257281
"./types.d.ts"
258282
]
259283
},
260284
"version": "FakeTSVersion",
261-
"size": 1296
285+
"size": 1425
262286
}
263287

tests/baselines/reference/tsc/incremental/change-to-type-that-gets-used-as-global-through-export-in-another-file.js

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,21 @@ export default 2;
127127

128128
Output::
129129
/lib/tsc -p src/project
130-
exitCode:: ExitStatus.Success
130+
src/project/class1.ts:1:7 - error TS2322: Type '1' is not assignable to type '2'.
131+
132+
1 const a: MagicNumber = 1;
133+
   ~
134+
135+
136+
Found 1 error in src/project/class1.ts:1
137+
138+
exitCode:: ExitStatus.DiagnosticsPresent_OutputsGenerated
131139

132140

141+
//// [/src/project/class1.d.ts]
142+
declare const a = 2;
143+
144+
133145
//// [/src/project/constants.d.ts]
134146
declare const _default: 2;
135147
export default _default;
@@ -142,7 +154,7 @@ exports["default"] = 2;
142154

143155

144156
//// [/src/project/tsconfig.tsbuildinfo]
145-
{"program":{"fileNames":["../../lib/lib.d.ts","./class1.ts","./constants.ts","./types.d.ts"],"fileInfos":[{"version":"3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true},{"version":"4085502068-const a: MagicNumber = 1;\nconsole.log(a);","affectsGlobalScope":true},{"version":"-2659799015-export default 2;","signature":"1573564507-declare const _default: 2;\r\nexport default _default;\r\n"},{"version":"-2080821236-type MagicNumber = typeof import('./constants').default","affectsGlobalScope":true}],"options":{"composite":true},"fileIdsList":[[3]],"referencedMap":[[4,1]],"exportedModulesMap":[[4,1]],"semanticDiagnosticsPerFile":[1,2,3,4]},"version":"FakeTSVersion"}
157+
{"program":{"fileNames":["../../lib/lib.d.ts","./class1.ts","./constants.ts","./types.d.ts"],"fileInfos":[{"version":"3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true},{"version":"4085502068-const a: MagicNumber = 1;\nconsole.log(a);","affectsGlobalScope":true},{"version":"-2659799015-export default 2;","signature":"1573564507-declare const _default: 2;\r\nexport default _default;\r\n"},{"version":"-2080821236-type MagicNumber = typeof import('./constants').default","affectsGlobalScope":true}],"options":{"composite":true},"fileIdsList":[[3]],"referencedMap":[[4,1]],"exportedModulesMap":[[4,1]],"semanticDiagnosticsPerFile":[1,[2,[{"file":"./class1.ts","start":6,"length":1,"code":2322,"category":1,"messageText":"Type '1' is not assignable to type '2'."}]],3,4]},"version":"FakeTSVersion"}
146158

147159
//// [/src/project/tsconfig.tsbuildinfo.readable.baseline.txt]
148160
{
@@ -194,12 +206,24 @@ exports["default"] = 2;
194206
},
195207
"semanticDiagnosticsPerFile": [
196208
"../../lib/lib.d.ts",
197-
"./class1.ts",
209+
[
210+
"./class1.ts",
211+
[
212+
{
213+
"file": "./class1.ts",
214+
"start": 6,
215+
"length": 1,
216+
"code": 2322,
217+
"category": 1,
218+
"messageText": "Type '1' is not assignable to type '2'."
219+
}
220+
]
221+
],
198222
"./constants.ts",
199223
"./types.d.ts"
200224
]
201225
},
202226
"version": "FakeTSVersion",
203-
"size": 1084
227+
"size": 1213
204228
}
205229

0 commit comments

Comments
 (0)