Skip to content

Commit e638aec

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 5604503 commit e638aec

File tree

3 files changed

+103
-19
lines changed

3 files changed

+103
-19
lines changed

src/compiler/builder.ts

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -540,18 +540,48 @@ namespace ts {
540540
return newSignature !== oldSignature;
541541
}
542542

543-
function forEachKeyOfExportedModulesMap(state: BuilderProgramState, filePath: Path, fn: (exportedFromPath: Path) => void) {
543+
function forEachKeyOfExportedModulesMap<T>(
544+
state: BuilderProgramState,
545+
filePath: Path,
546+
fn: (exportedFromPath: Path) => T | undefined,
547+
): T | undefined {
544548
// Go through exported modules from cache first
545-
state.currentAffectedFilesExportedModulesMap!.getKeys(filePath)?.forEach(fn);
549+
let keys = state.currentAffectedFilesExportedModulesMap!.getKeys(filePath);
550+
const result = keys && forEachKey(keys, fn);
551+
if (result) return result;
552+
546553
// If exported from path is not from cache and exported modules has path, all files referencing file exported from are affected
547-
state.exportedModulesMap!.getKeys(filePath)?.forEach(exportedFromPath =>
554+
keys = state.exportedModulesMap!.getKeys(filePath);
555+
return keys && forEachKey(keys, exportedFromPath =>
548556
// If the cache had an updated value, skip
549557
!state.currentAffectedFilesExportedModulesMap!.hasKey(exportedFromPath) &&
550-
!state.currentAffectedFilesExportedModulesMap!.deletedKeys()?.has(exportedFromPath) &&
551-
fn(exportedFromPath)
558+
!state.currentAffectedFilesExportedModulesMap!.deletedKeys()?.has(exportedFromPath) ?
559+
fn(exportedFromPath) :
560+
undefined
552561
);
553562
}
554563

564+
function handleDtsMayChangeOfGlobalScope(
565+
state: BuilderProgramState,
566+
filePath: Path,
567+
cancellationToken: CancellationToken | undefined,
568+
computeHash: BuilderState.ComputeHash,
569+
host: BuilderProgramHost,
570+
): boolean {
571+
if (!state.fileInfos.get(filePath)?.affectsGlobalScope) return false;
572+
// Every file needs to be handled
573+
BuilderState.getAllFilesExcludingDefaultLibraryFile(state, state.program!, /*firstSourceFile*/ undefined)
574+
.forEach(file => handleDtsMayChangeOf(
575+
state,
576+
file.resolvedPath,
577+
cancellationToken,
578+
computeHash,
579+
host,
580+
));
581+
removeDiagnosticsOfLibraryFiles(state);
582+
return true;
583+
}
584+
555585
/**
556586
* Iterate on referencing modules that export entities from affected file and delete diagnostics and add pending emit
557587
*/
@@ -577,6 +607,7 @@ namespace ts {
577607
const currentPath = queue.pop()!;
578608
if (!seenFileNamesMap.has(currentPath)) {
579609
seenFileNamesMap.set(currentPath, true);
610+
if (handleDtsMayChangeOfGlobalScope(state, currentPath, cancellationToken, computeHash, host)) return;
580611
handleDtsMayChangeOf(state, currentPath, cancellationToken, computeHash, host);
581612
if (isChangedSignature(state, currentPath)) {
582613
const currentSourceFile = Debug.checkDefined(state.program).getSourceFileByPath(currentPath)!;
@@ -590,8 +621,10 @@ namespace ts {
590621
const seenFileAndExportsOfFile = new Set<string>();
591622
// Go through exported modules from cache first
592623
// If exported modules has path, all files referencing file exported from are affected
593-
forEachKeyOfExportedModulesMap(state, affectedFile.resolvedPath, exportedFromPath =>
594-
state.referencedMap!.getKeys(exportedFromPath)?.forEach(filePath =>
624+
forEachKeyOfExportedModulesMap(state, affectedFile.resolvedPath, exportedFromPath => {
625+
if (handleDtsMayChangeOfGlobalScope(state, exportedFromPath, cancellationToken, computeHash, host)) return true;
626+
const references = state.referencedMap!.getKeys(exportedFromPath);
627+
return references && forEachKey(references, filePath =>
595628
handleDtsMayChangeOfFileAndExportsOfFile(
596629
state,
597630
filePath,
@@ -600,12 +633,13 @@ namespace ts {
600633
computeHash,
601634
host,
602635
)
603-
)
604-
);
636+
);
637+
});
605638
}
606639

607640
/**
608641
* handle dts and semantic diagnostics on file and iterate on anything that exports this file
642+
* return true when all work is done and we can exit handling dts emit and semantic diagnostics
609643
*/
610644
function handleDtsMayChangeOfFileAndExportsOfFile(
611645
state: BuilderProgramState,
@@ -614,9 +648,10 @@ namespace ts {
614648
cancellationToken: CancellationToken | undefined,
615649
computeHash: BuilderState.ComputeHash,
616650
host: BuilderProgramHost,
617-
): void {
618-
if (!tryAddToSet(seenFileAndExportsOfFile, filePath)) return;
651+
): boolean | undefined {
652+
if (!tryAddToSet(seenFileAndExportsOfFile, filePath)) return undefined;
619653

654+
if (handleDtsMayChangeOfGlobalScope(state, filePath, cancellationToken, computeHash, host)) return true;
620655
handleDtsMayChangeOf(state, filePath, cancellationToken, computeHash, host);
621656
Debug.assert(!!state.currentAffectedFilesExportedModulesMap);
622657

@@ -643,6 +678,7 @@ namespace ts {
643678
host,
644679
)
645680
);
681+
return undefined;
646682
}
647683

648684
/**

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)