Skip to content

Commit 816af71

Browse files
Fix incremental emit issue where dependency relations implied by synthesized imports would not be detected (#41346)
* Fix incremental emit issue where dependency relations implies by synthesized imports would not be detected * Update src/compiler/program.ts Co-authored-by: Daniel Rosenwasser <[email protected]>
1 parent 6bef0cb commit 816af71

10 files changed

+1258
-8
lines changed

src/compiler/program.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2207,6 +2207,10 @@ namespace ts {
22072207
addEmitFlags(importDecl, EmitFlags.NeverApplyImportHelper);
22082208
setParent(externalHelpersModuleReference, importDecl);
22092209
setParent(importDecl, file);
2210+
// explicitly unset the synthesized flag on these declarations so the checker API will answer questions about them
2211+
// (which is required to build the dependency graph for incremental emit)
2212+
(externalHelpersModuleReference as Mutable<Node>).flags &= ~NodeFlags.Synthesized;
2213+
(importDecl as Mutable<Node>).flags &= ~NodeFlags.Synthesized;
22102214
return externalHelpersModuleReference;
22112215
}
22122216

src/testRunner/unittests/tscWatch/incremental.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,5 +304,51 @@ export const Fragment: unique symbol;
304304
],
305305
modifyFs: host => host.writeFile(configFile.path, JSON.stringify({ compilerOptions: { ...jsxImportSourceOptions, jsxImportSource: "preact" } }))
306306
});
307+
308+
verifyIncrementalWatchEmit({
309+
subScenario: "jsxImportSource backing types added",
310+
files: () => [
311+
{ path: libFile.path, content: libContent },
312+
{ path: `${project}/index.tsx`, content: `export const App = () => <div propA={true}></div>;` },
313+
{ path: configFile.path, content: JSON.stringify({ compilerOptions: jsxImportSourceOptions }) }
314+
],
315+
modifyFs: host => {
316+
host.createDirectory(`${project}/node_modules`);
317+
host.createDirectory(`${project}/node_modules/react`);
318+
host.createDirectory(`${project}/node_modules/react/jsx-runtime`);
319+
host.writeFile(`${project}/node_modules/react/jsx-runtime/index.d.ts`, jsxLibraryContent);
320+
host.writeFile(`${project}/node_modules/react/package.json`, JSON.stringify({ name: "react", version: "0.0.1" }));
321+
}
322+
});
323+
324+
verifyIncrementalWatchEmit({
325+
subScenario: "jsxImportSource backing types removed",
326+
files: () => [
327+
{ path: libFile.path, content: libContent },
328+
{ path: `${project}/node_modules/react/jsx-runtime/index.d.ts`, content: jsxLibraryContent },
329+
{ path: `${project}/node_modules/react/package.json`, content: JSON.stringify({ name: "react", version: "0.0.1" }) },
330+
{ path: `${project}/index.tsx`, content: `export const App = () => <div propA={true}></div>;` },
331+
{ path: configFile.path, content: JSON.stringify({ compilerOptions: jsxImportSourceOptions }) }
332+
],
333+
modifyFs: host => {
334+
host.deleteFile(`${project}/node_modules/react/jsx-runtime/index.d.ts`);
335+
host.deleteFile(`${project}/node_modules/react/package.json`);
336+
}
337+
});
338+
339+
verifyIncrementalWatchEmit({
340+
subScenario: "importHelpers backing types removed",
341+
files: () => [
342+
{ path: libFile.path, content: libContent },
343+
{ path: `${project}/node_modules/tslib/index.d.ts`, content: "export function __assign(...args: any[]): any;" },
344+
{ path: `${project}/node_modules/tslib/package.json`, content: JSON.stringify({ name: "tslib", version: "0.0.1" }) },
345+
{ path: `${project}/index.tsx`, content: `export const x = {...{}};` },
346+
{ path: configFile.path, content: JSON.stringify({ compilerOptions: { importHelpers: true } }) }
347+
],
348+
modifyFs: host => {
349+
host.deleteFile(`${project}/node_modules/tslib/index.d.ts`);
350+
host.deleteFile(`${project}/node_modules/tslib/package.json`);
351+
}
352+
});
307353
});
308354
}
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
Input::
2+
//// [/a/lib/lib.d.ts]
3+
/// <reference no-default-lib="true"/>
4+
interface Boolean {}
5+
interface Function {}
6+
interface CallableFunction {}
7+
interface NewableFunction {}
8+
interface IArguments {}
9+
interface Number { toExponential: any; }
10+
interface Object {}
11+
interface RegExp {}
12+
interface String { charAt: any; }
13+
interface Array<T> { length: number; [n: number]: T; }
14+
interface ReadonlyArray<T> {}
15+
declare const console: { log(msg: any): void; };
16+
17+
//// [/users/username/projects/project/node_modules/tslib/index.d.ts]
18+
export function __assign(...args: any[]): any;
19+
20+
//// [/users/username/projects/project/node_modules/tslib/package.json]
21+
{"name":"tslib","version":"0.0.1"}
22+
23+
//// [/users/username/projects/project/index.tsx]
24+
export const x = {...{}};
25+
26+
//// [/users/username/projects/project/tsconfig.json]
27+
{"compilerOptions":{"importHelpers":true}}
28+
29+
30+
/a/lib/tsc.js -i
31+
Output::
32+
33+
34+
Program root files: ["/users/username/projects/project/index.tsx"]
35+
Program options: {"importHelpers":true,"incremental":true,"configFilePath":"/users/username/projects/project/tsconfig.json"}
36+
Program structureReused: Not
37+
Program files::
38+
/a/lib/lib.d.ts
39+
/users/username/projects/project/node_modules/tslib/index.d.ts
40+
/users/username/projects/project/index.tsx
41+
42+
Semantic diagnostics in builder refreshed for::
43+
/a/lib/lib.d.ts
44+
/users/username/projects/project/node_modules/tslib/index.d.ts
45+
/users/username/projects/project/index.tsx
46+
47+
WatchedFiles::
48+
49+
FsWatches::
50+
51+
FsWatchesRecursive::
52+
53+
exitCode:: ExitStatus.Success
54+
55+
//// [/users/username/projects/project/index.js]
56+
"use strict";
57+
exports.__esModule = true;
58+
exports.x = void 0;
59+
var tslib_1 = require("tslib");
60+
exports.x = tslib_1.__assign({});
61+
62+
63+
//// [/users/username/projects/project/tsconfig.tsbuildinfo]
64+
{
65+
"program": {
66+
"fileInfos": {
67+
"../../../../a/lib/lib.d.ts": {
68+
"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; };",
69+
"signature": "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; };",
70+
"affectsGlobalScope": true
71+
},
72+
"./node_modules/tslib/index.d.ts": {
73+
"version": "1620578607-export function __assign(...args: any[]): any;",
74+
"signature": "1620578607-export function __assign(...args: any[]): any;",
75+
"affectsGlobalScope": false
76+
},
77+
"./index.tsx": {
78+
"version": "-14168389096-export const x = {...{}};",
79+
"signature": "-6508651827-export declare const x: {};\n",
80+
"affectsGlobalScope": false
81+
}
82+
},
83+
"options": {
84+
"importHelpers": true,
85+
"incremental": true,
86+
"configFilePath": "./tsconfig.json"
87+
},
88+
"referencedMap": {
89+
"./index.tsx": [
90+
"./node_modules/tslib/index.d.ts"
91+
]
92+
},
93+
"exportedModulesMap": {},
94+
"semanticDiagnosticsPerFile": [
95+
"../../../../a/lib/lib.d.ts",
96+
"./index.tsx",
97+
"./node_modules/tslib/index.d.ts"
98+
]
99+
},
100+
"version": "FakeTSVersion"
101+
}
102+
103+
104+
Change::
105+
106+
Input::
107+
//// [/users/username/projects/project/node_modules/tslib/index.d.ts] deleted
108+
//// [/users/username/projects/project/node_modules/tslib/package.json] deleted
109+
110+
Output::
111+
index.tsx:1:19 - error TS2354: This syntax requires an imported helper but module 'tslib' cannot be found.
112+
113+
1 export const x = {...{}};
114+
   ~~~~~
115+
116+
117+
Found 1 error.
118+
119+
120+
121+
Program root files: ["/users/username/projects/project/index.tsx"]
122+
Program options: {"importHelpers":true,"incremental":true,"configFilePath":"/users/username/projects/project/tsconfig.json"}
123+
Program structureReused: Not
124+
Program files::
125+
/a/lib/lib.d.ts
126+
/users/username/projects/project/index.tsx
127+
128+
Semantic diagnostics in builder refreshed for::
129+
/users/username/projects/project/index.tsx
130+
131+
WatchedFiles::
132+
133+
FsWatches::
134+
135+
FsWatchesRecursive::
136+
137+
exitCode:: ExitStatus.DiagnosticsPresent_OutputsGenerated
138+
139+
//// [/users/username/projects/project/index.js] file written with same contents
140+
//// [/users/username/projects/project/tsconfig.tsbuildinfo]
141+
{
142+
"program": {
143+
"fileInfos": {
144+
"../../../../a/lib/lib.d.ts": {
145+
"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; };",
146+
"signature": "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; };",
147+
"affectsGlobalScope": true
148+
},
149+
"./index.tsx": {
150+
"version": "-14168389096-export const x = {...{}};",
151+
"signature": "-6508651827-export declare const x: {};\n",
152+
"affectsGlobalScope": false
153+
}
154+
},
155+
"options": {
156+
"importHelpers": true,
157+
"incremental": true,
158+
"configFilePath": "./tsconfig.json"
159+
},
160+
"referencedMap": {},
161+
"exportedModulesMap": {},
162+
"semanticDiagnosticsPerFile": [
163+
"../../../../a/lib/lib.d.ts",
164+
[
165+
"./index.tsx",
166+
[
167+
{
168+
"file": "./index.tsx",
169+
"start": 18,
170+
"length": 5,
171+
"messageText": "This syntax requires an imported helper but module 'tslib' cannot be found.",
172+
"category": 1,
173+
"code": 2354
174+
}
175+
]
176+
]
177+
]
178+
},
179+
"version": "FakeTSVersion"
180+
}
181+
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
Input::
2+
//// [/a/lib/lib.d.ts]
3+
/// <reference no-default-lib="true"/>
4+
interface Boolean {}
5+
interface Function {}
6+
interface CallableFunction {}
7+
interface NewableFunction {}
8+
interface IArguments {}
9+
interface Number { toExponential: any; }
10+
interface Object {}
11+
interface RegExp {}
12+
interface String { charAt: any; }
13+
interface Array<T> { length: number; [n: number]: T; }
14+
interface ReadonlyArray<T> {}
15+
declare const console: { log(msg: any): void; };
16+
17+
//// [/users/username/projects/project/node_modules/tslib/index.d.ts]
18+
export function __assign(...args: any[]): any;
19+
20+
//// [/users/username/projects/project/node_modules/tslib/package.json]
21+
{"name":"tslib","version":"0.0.1"}
22+
23+
//// [/users/username/projects/project/index.tsx]
24+
export const x = {...{}};
25+
26+
//// [/users/username/projects/project/tsconfig.json]
27+
{"compilerOptions":{"importHelpers":true}}
28+
29+
30+
/a/lib/tsc.js -w
31+
Output::
32+
>> Screen clear
33+
[12:00:29 AM] Starting compilation in watch mode...
34+
35+
[12:00:32 AM] Found 0 errors. Watching for file changes.
36+
37+
38+
39+
Program root files: ["/users/username/projects/project/index.tsx"]
40+
Program options: {"importHelpers":true,"watch":true,"configFilePath":"/users/username/projects/project/tsconfig.json"}
41+
Program structureReused: Not
42+
Program files::
43+
/a/lib/lib.d.ts
44+
/users/username/projects/project/node_modules/tslib/index.d.ts
45+
/users/username/projects/project/index.tsx
46+
47+
Semantic diagnostics in builder refreshed for::
48+
/a/lib/lib.d.ts
49+
/users/username/projects/project/node_modules/tslib/index.d.ts
50+
/users/username/projects/project/index.tsx
51+
52+
WatchedFiles::
53+
/users/username/projects/project/tsconfig.json:
54+
{"fileName":"/users/username/projects/project/tsconfig.json","pollingInterval":250}
55+
/users/username/projects/project/index.tsx:
56+
{"fileName":"/users/username/projects/project/index.tsx","pollingInterval":250}
57+
/users/username/projects/project/node_modules/tslib/index.d.ts:
58+
{"fileName":"/users/username/projects/project/node_modules/tslib/index.d.ts","pollingInterval":250}
59+
/a/lib/lib.d.ts:
60+
{"fileName":"/a/lib/lib.d.ts","pollingInterval":250}
61+
62+
FsWatches::
63+
64+
FsWatchesRecursive::
65+
/users/username/projects/project/node_modules:
66+
{"directoryName":"/users/username/projects/project/node_modules","fallbackPollingInterval":500,"fallbackOptions":{"watchFile":"PriorityPollingInterval"}}
67+
/users/username/projects/project/node_modules/@types:
68+
{"directoryName":"/users/username/projects/project/node_modules/@types","fallbackPollingInterval":500,"fallbackOptions":{"watchFile":"PriorityPollingInterval"}}
69+
/users/username/projects/project:
70+
{"directoryName":"/users/username/projects/project","fallbackPollingInterval":500,"fallbackOptions":{"watchFile":"PriorityPollingInterval"}}
71+
72+
exitCode:: ExitStatus.undefined
73+
74+
//// [/users/username/projects/project/index.js]
75+
"use strict";
76+
exports.__esModule = true;
77+
exports.x = void 0;
78+
var tslib_1 = require("tslib");
79+
exports.x = tslib_1.__assign({});
80+
81+
82+
83+
Change::
84+
85+
Input::
86+
//// [/users/username/projects/project/node_modules/tslib/index.d.ts] deleted
87+
//// [/users/username/projects/project/node_modules/tslib/package.json] deleted
88+
89+
Output::
90+
>> Screen clear
91+
[12:00:35 AM] Starting compilation in watch mode...
92+
93+
index.tsx:1:19 - error TS2354: This syntax requires an imported helper but module 'tslib' cannot be found.
94+
95+
1 export const x = {...{}};
96+
   ~~~~~
97+
98+
[12:00:39 AM] Found 1 error. Watching for file changes.
99+
100+
101+
102+
Program root files: ["/users/username/projects/project/index.tsx"]
103+
Program options: {"importHelpers":true,"watch":true,"configFilePath":"/users/username/projects/project/tsconfig.json"}
104+
Program structureReused: Not
105+
Program files::
106+
/a/lib/lib.d.ts
107+
/users/username/projects/project/index.tsx
108+
109+
Semantic diagnostics in builder refreshed for::
110+
/a/lib/lib.d.ts
111+
/users/username/projects/project/index.tsx
112+
113+
WatchedFiles::
114+
/users/username/projects/project/tsconfig.json:
115+
{"fileName":"/users/username/projects/project/tsconfig.json","pollingInterval":250}
116+
/users/username/projects/project/index.tsx:
117+
{"fileName":"/users/username/projects/project/index.tsx","pollingInterval":250}
118+
/a/lib/lib.d.ts:
119+
{"fileName":"/a/lib/lib.d.ts","pollingInterval":250}
120+
121+
FsWatches::
122+
123+
FsWatchesRecursive::
124+
/users/username/projects/project/node_modules:
125+
{"directoryName":"/users/username/projects/project/node_modules","fallbackPollingInterval":500,"fallbackOptions":{"watchFile":"PriorityPollingInterval"}}
126+
/users/username/projects/project/node_modules/@types:
127+
{"directoryName":"/users/username/projects/project/node_modules/@types","fallbackPollingInterval":500,"fallbackOptions":{"watchFile":"PriorityPollingInterval"}}
128+
/users/username/projects/project:
129+
{"directoryName":"/users/username/projects/project","fallbackPollingInterval":500,"fallbackOptions":{"watchFile":"PriorityPollingInterval"}}
130+
131+
exitCode:: ExitStatus.undefined
132+
133+
//// [/users/username/projects/project/index.js] file written with same contents

0 commit comments

Comments
 (0)