tsc-ts 0.0.8 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/api/compiler/ast.d.ts +2 -0
- package/dist/api/compiler/ast.js +3 -0
- package/dist/api/compiler/checker-calls.js +5 -1
- package/dist/api/compiler/checker-grammar.js +3 -2
- package/dist/api/compiler/checker-inference.js +8 -2
- package/dist/api/compiler/checker-members.js +8 -3
- package/dist/api/compiler/checker-source-file.d.ts +12 -0
- package/dist/api/compiler/checker-source-file.js +35 -0
- package/dist/api/compiler/checker-symbols.js +2 -1
- package/dist/api/compiler/checker-type-factory.js +8 -2
- package/dist/api/compiler/checker.d.ts +17 -1
- package/dist/api/compiler/checker.js +49 -1
- package/dist/api/compiler/compile-program.d.ts +26 -2
- package/dist/api/compiler/compile-program.js +100 -7
- package/dist/api/compiler/diagnostics.d.ts +22 -0
- package/dist/api/compiler/diagnostics.js +86 -4
- package/dist/api/compiler/file-loader.d.ts +13 -3
- package/dist/api/compiler/file-loader.js +106 -30
- package/dist/api/compiler/link-tables.d.ts +7 -0
- package/dist/api/compiler/link-tables.js +22 -0
- package/dist/api/compiler/parallel-parse.d.ts +3 -2
- package/dist/api/compiler/parallel-parse.js +17 -5
- package/dist/api/compiler/parser.js +15 -14
- package/dist/api/compiler/printer/emit-context.d.ts +2 -0
- package/dist/api/compiler/printer/emit-context.js +4 -0
- package/dist/api/compiler/printer/printer.d.ts +48 -2
- package/dist/api/compiler/printer/printer.js +238 -14
- package/dist/api/compiler/program-checker.d.ts +22 -0
- package/dist/api/compiler/program-checker.js +39 -2
- package/dist/api/compiler/program.d.ts +2 -6
- package/dist/api/compiler/program.js +5 -30
- package/dist/api/compiler/relations.js +10 -0
- package/dist/api/compiler/symbol.d.ts +1 -1
- package/dist/api/compiler/symbol.js +8 -10
- package/dist/api/library/diagnostics.d.ts +10 -0
- package/dist/api/library/diagnostics.js +20 -0
- package/package.json +9 -9
- package/src/compiler/ast.ts +3 -0
- package/src/compiler/checker-calls.ts +3 -1
- package/src/compiler/checker-grammar.ts +3 -2
- package/src/compiler/checker-inference.ts +7 -2
- package/src/compiler/checker-members.ts +9 -3
- package/src/compiler/checker-source-file.ts +34 -0
- package/src/compiler/checker-symbols.ts +2 -1
- package/src/compiler/checker-type-factory.ts +4 -2
- package/src/compiler/checker.ts +45 -1
- package/src/compiler/compile-program.ts +121 -7
- package/src/compiler/diagnostics.ts +84 -3
- package/src/compiler/file-loader.ts +106 -29
- package/src/compiler/incremental.ts +80 -13
- package/src/compiler/link-tables.ts +32 -0
- package/src/compiler/parallel-check.ts +326 -62
- package/src/compiler/parallel-emit.ts +320 -0
- package/src/compiler/parallel-parse.ts +16 -5
- package/src/compiler/parse-thread.ts +3 -0
- package/src/compiler/parser.ts +15 -16
- package/src/compiler/printer/emit-context.ts +5 -0
- package/src/compiler/printer/printer.ts +231 -16
- package/src/compiler/program-checker.ts +40 -2
- package/src/compiler/program.ts +5 -25
- package/src/compiler/relations.ts +7 -0
- package/src/compiler/symbol.ts +15 -10
- package/src/compiler/thread-entry.ts +61 -3
- package/src/compiler/tsc-build.ts +63 -9
- package/src/compiler/tsc-cli.ts +5 -0
- package/src/compiler/tsc-compile.ts +278 -3
- package/src/library/diagnostics.ts +23 -0
|
@@ -33,7 +33,14 @@ import {
|
|
|
33
33
|
type OutputWriter,
|
|
34
34
|
ProgramEmitter,
|
|
35
35
|
} from './compile-program.js';
|
|
36
|
-
import {
|
|
36
|
+
import {
|
|
37
|
+
Diagnostic,
|
|
38
|
+
DiagnosticFile,
|
|
39
|
+
type DiagnosticFormatOptions,
|
|
40
|
+
formatDiagnostic,
|
|
41
|
+
formattedReports,
|
|
42
|
+
RepopulateInfo,
|
|
43
|
+
} from './diagnostics.js';
|
|
37
44
|
import { EmitOnly, EmitResult } from './emitter.js';
|
|
38
45
|
import { getEmitDeclarations, isIncremental } from './options.js';
|
|
39
46
|
import { DeclarationSignatureWriter } from './incremental.js';
|
|
@@ -65,7 +72,8 @@ export function residentMB(): number[] {
|
|
|
65
72
|
* (`CheckerResult.reserved`). With `emits` false the thread doesn't emit the files it checks, where
|
|
66
73
|
* the main thread emits the program (`checkersEmit`). `emitKinds`, by file index, is what the emit of
|
|
67
74
|
* each file includes (an `EmitOnly`, or -1 for none) where not every output of every file is emitted
|
|
68
|
-
* (an incremental program's rebuild); `undefined` for all of them.
|
|
75
|
+
* (an incremental program's rebuild); `undefined` for all of them. `units` are the statement ranges of
|
|
76
|
+
* declaration files the order has positions for (`CheckPlan.units`).
|
|
69
77
|
*/
|
|
70
78
|
export type CheckerSpawn = (
|
|
71
79
|
program: Program | undefined,
|
|
@@ -78,6 +86,7 @@ export type CheckerSpawn = (
|
|
|
78
86
|
emits: boolean,
|
|
79
87
|
emitKinds: number[] | undefined,
|
|
80
88
|
checking: boolean,
|
|
89
|
+
units: number[],
|
|
81
90
|
) => Worker;
|
|
82
91
|
|
|
83
92
|
export class ParallelCheck {
|
|
@@ -113,6 +122,10 @@ export class CheckerResult {
|
|
|
113
122
|
/** The positions of a group the thread took and had not checked when it stopped at its file limit. */
|
|
114
123
|
readonly reserved: number[] = [],
|
|
115
124
|
readonly emits: EmitResult[] = [],
|
|
125
|
+
/** The statement ranges of declaration files it checked (`rangeUnits`). */
|
|
126
|
+
readonly units: number[] = [],
|
|
127
|
+
/** Those of `units` after which its checker had diagnostics in their file (`checkSourceFileRange`). */
|
|
128
|
+
readonly reportingUnits: number[] = [],
|
|
116
129
|
) {}
|
|
117
130
|
}
|
|
118
131
|
|
|
@@ -138,10 +151,13 @@ export const recycleFiles: number = Math.max(0, Number(process.env.TSC_TS_RECYCL
|
|
|
138
151
|
* text (index, -1 when the program has the file), pos, end, code, category, message,
|
|
139
152
|
* skippedOnNoEmit, the argument count and indices, its repopulate kind (0 for none) followed by the
|
|
140
153
|
* module reference (index), mode and package name (index) of other kinds, then its message chain and
|
|
141
|
-
* related information as lists.
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
154
|
+
* related information as lists. A diagnostic of a reported list (the files' diagnostic and declaration
|
|
155
|
+
* diagnostic lists, the global diagnostics and an emit result's diagnostics) is followed by its text in
|
|
156
|
+
* the main thread's report format (`Diagnostic.formatted`, an index, -1 for none). An emit result is
|
|
157
|
+
* emitSkipped, the emitted files, errors and unsupported files as lists of indices, then its
|
|
158
|
+
* diagnostics and its declaration signatures as a list of indices. `files` and `nums` are typed
|
|
159
|
+
* arrays, which postMessage copies as one block of memory each; it copies an array of numbers element
|
|
160
|
+
* by element.
|
|
145
161
|
*/
|
|
146
162
|
export type PackedResult = {
|
|
147
163
|
readonly index: number;
|
|
@@ -152,6 +168,8 @@ export type PackedResult = {
|
|
|
152
168
|
readonly stats: number[];
|
|
153
169
|
readonly more: boolean;
|
|
154
170
|
readonly reserved: number[];
|
|
171
|
+
readonly units: Int32Array;
|
|
172
|
+
readonly reportingUnits: Int32Array;
|
|
155
173
|
};
|
|
156
174
|
|
|
157
175
|
class ResultPacker {
|
|
@@ -159,7 +177,11 @@ class ResultPacker {
|
|
|
159
177
|
readonly strs: string[] = [];
|
|
160
178
|
private readonly indices = new Map<string, number>();
|
|
161
179
|
|
|
162
|
-
constructor(
|
|
180
|
+
constructor(
|
|
181
|
+
private readonly program: Program,
|
|
182
|
+
/** The main thread's report format, which this thread formats the reported diagnostics in. */
|
|
183
|
+
private readonly format: DiagnosticFormatOptions | undefined,
|
|
184
|
+
) {}
|
|
163
185
|
|
|
164
186
|
private str(text: string): number {
|
|
165
187
|
let k = this.indices.get(text);
|
|
@@ -176,6 +198,21 @@ class ResultPacker {
|
|
|
176
198
|
for (const d of diagnostics) this.diagnostic(d);
|
|
177
199
|
}
|
|
178
200
|
|
|
201
|
+
/** A list the main thread reports: each diagnostic with its text in the report format. */
|
|
202
|
+
reported(diagnostics: readonly Diagnostic[]): void {
|
|
203
|
+
const nums = this.nums;
|
|
204
|
+
const format = this.format;
|
|
205
|
+
nums.push(diagnostics.length);
|
|
206
|
+
for (const d of diagnostics) {
|
|
207
|
+
this.diagnostic(d);
|
|
208
|
+
if (format === undefined) nums.push(-1);
|
|
209
|
+
else {
|
|
210
|
+
nums.push(this.strs.length);
|
|
211
|
+
this.strs.push(formatDiagnostic(d, format));
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
179
216
|
private strList(texts: readonly string[]): void {
|
|
180
217
|
this.nums.push(texts.length);
|
|
181
218
|
for (const text of texts) this.nums.push(this.str(text));
|
|
@@ -186,7 +223,7 @@ class ResultPacker {
|
|
|
186
223
|
this.strList(result.emittedFiles);
|
|
187
224
|
this.strList(result.errors);
|
|
188
225
|
this.strList(result.unsupported);
|
|
189
|
-
this.
|
|
226
|
+
this.reported(result.diagnostics);
|
|
190
227
|
this.strList(result.declarationSignatures);
|
|
191
228
|
this.strList(result.heldOutputs);
|
|
192
229
|
}
|
|
@@ -218,11 +255,11 @@ class ResultPacker {
|
|
|
218
255
|
|
|
219
256
|
/** Packs `result` (on the checker thread) for `postMessage`. */
|
|
220
257
|
export function packResult(result: CheckerResult, program: Program): PackedResult {
|
|
221
|
-
const packer = new ResultPacker(program);
|
|
222
|
-
for (const list of result.diagnostics) packer.
|
|
258
|
+
const packer = new ResultPacker(program, formattedReports.format);
|
|
259
|
+
for (const list of result.diagnostics) packer.reported(list);
|
|
223
260
|
packer.nums.push(result.declarations.length);
|
|
224
|
-
for (const list of result.declarations) packer.
|
|
225
|
-
packer.
|
|
261
|
+
for (const list of result.declarations) packer.reported(list);
|
|
262
|
+
packer.reported(result.globals);
|
|
226
263
|
packer.nums.push(result.emits.length);
|
|
227
264
|
for (const emit of result.emits) packer.emit(emit);
|
|
228
265
|
return {
|
|
@@ -234,6 +271,8 @@ export function packResult(result: CheckerResult, program: Program): PackedResul
|
|
|
234
271
|
stats: result.stats,
|
|
235
272
|
more: result.more,
|
|
236
273
|
reserved: result.reserved,
|
|
274
|
+
units: Int32Array.from(result.units),
|
|
275
|
+
reportingUnits: Int32Array.from(result.reportingUnits),
|
|
237
276
|
};
|
|
238
277
|
}
|
|
239
278
|
|
|
@@ -262,6 +301,19 @@ class ResultUnpacker {
|
|
|
262
301
|
return result;
|
|
263
302
|
}
|
|
264
303
|
|
|
304
|
+
/** A list `ResultPacker.reported` packed. */
|
|
305
|
+
reported(): Diagnostic[] {
|
|
306
|
+
const n = this.next();
|
|
307
|
+
const result: Diagnostic[] = [];
|
|
308
|
+
for (let k = 0; k < n; k++) {
|
|
309
|
+
const d = this.diagnostic();
|
|
310
|
+
const text = this.next();
|
|
311
|
+
if (text >= 0) d.formatted = this.packed.strs[text]!;
|
|
312
|
+
result.push(d);
|
|
313
|
+
}
|
|
314
|
+
return result;
|
|
315
|
+
}
|
|
316
|
+
|
|
265
317
|
private diagnostic(): Diagnostic {
|
|
266
318
|
const strs = this.packed.strs;
|
|
267
319
|
const name = this.next();
|
|
@@ -315,7 +367,7 @@ class ResultUnpacker {
|
|
|
315
367
|
this.strList(result.emittedFiles);
|
|
316
368
|
this.strList(result.errors);
|
|
317
369
|
this.strList(result.unsupported);
|
|
318
|
-
for (const d of this.
|
|
370
|
+
for (const d of this.reported()) result.diagnostics.push(d);
|
|
319
371
|
this.strList(result.declarationSignatures);
|
|
320
372
|
this.strList(result.heldOutputs);
|
|
321
373
|
return result;
|
|
@@ -329,11 +381,11 @@ export function unpackResult(
|
|
|
329
381
|
): CheckerResult {
|
|
330
382
|
const unpacker = new ResultUnpacker(packed, program, files);
|
|
331
383
|
const diagnostics: Diagnostic[][] = [];
|
|
332
|
-
for (let k = 0; k < packed.files.length; k++) diagnostics.push(unpacker.
|
|
384
|
+
for (let k = 0; k < packed.files.length; k++) diagnostics.push(unpacker.reported());
|
|
333
385
|
const declarations: Diagnostic[][] = [];
|
|
334
386
|
const nd = unpacker.count();
|
|
335
|
-
for (let k = 0; k < nd; k++) declarations.push(unpacker.
|
|
336
|
-
const globals = unpacker.
|
|
387
|
+
for (let k = 0; k < nd; k++) declarations.push(unpacker.reported());
|
|
388
|
+
const globals = unpacker.reported();
|
|
337
389
|
const emits: EmitResult[] = [];
|
|
338
390
|
const ne = unpacker.count();
|
|
339
391
|
for (let k = 0; k < ne; k++) emits.push(unpacker.emit());
|
|
@@ -348,6 +400,8 @@ export function unpackResult(
|
|
|
348
400
|
packed.more,
|
|
349
401
|
packed.reserved,
|
|
350
402
|
emits,
|
|
403
|
+
Array.from(packed.units),
|
|
404
|
+
Array.from(packed.reportingUnits),
|
|
351
405
|
);
|
|
352
406
|
}
|
|
353
407
|
|
|
@@ -638,8 +692,8 @@ class CheckCosts {
|
|
|
638
692
|
readonly libraries: number[][],
|
|
639
693
|
/** What resolving a library costs a checker the first time (`libraryFirstUseShare` of the text it reaches), by index. */
|
|
640
694
|
readonly libraryCost: number[],
|
|
641
|
-
/** The program files (indices) each file
|
|
642
|
-
readonly imports: (number[]
|
|
695
|
+
/** The program files (indices) each file imports (`ProcessedFiles.addedFiles`), by index. */
|
|
696
|
+
readonly imports: readonly (readonly number[])[],
|
|
643
697
|
) {}
|
|
644
698
|
}
|
|
645
699
|
|
|
@@ -684,34 +738,18 @@ function checkCosts(checked: CheckedProgram, order: number[]): CheckCosts {
|
|
|
684
738
|
}
|
|
685
739
|
const length = textLengths(program);
|
|
686
740
|
for (const i of order) cost[i] = length[i]!;
|
|
687
|
-
const indexOf = new Map<SourceFile, number>();
|
|
688
|
-
for (let i = 0; i < files.length; i++) indexOf.set(files[i]!, i);
|
|
689
|
-
// A file resolved by its own file name is that file (its path is the path of that name).
|
|
690
|
-
const byFileName = new Map<string, SourceFile>();
|
|
691
|
-
for (const file of files) byFileName.set(file.fileName, file);
|
|
692
741
|
const checkedFile: boolean[] = [];
|
|
693
742
|
for (let i = 0; i < files.length; i++) checkedFile.push(false);
|
|
694
743
|
for (const i of order) checkedFile[i] = true;
|
|
695
744
|
// Libraries: unchecked modules that are not default libraries (globals every checker has).
|
|
696
745
|
const isLibrary = (i: number): boolean =>
|
|
697
746
|
!checkedFile[i]! && !program.isSourceFileDefaultLibrary(files[i]!.path) && isExternalModuleFile(files[i]!);
|
|
698
|
-
|
|
699
|
-
const
|
|
700
|
-
let result = edges[i];
|
|
701
|
-
if (result === undefined) {
|
|
702
|
-
result = [];
|
|
703
|
-
for (const target of program.getResolvedFilesOf(files[i]!, byFileName)) {
|
|
704
|
-
const k = indexOf.get(target);
|
|
705
|
-
if (k !== undefined && k !== i) result.push(k);
|
|
706
|
-
}
|
|
707
|
-
edges[i] = result;
|
|
708
|
-
}
|
|
709
|
-
return result;
|
|
710
|
-
};
|
|
747
|
+
// The files each file imports: those it added to the program (`ProcessedFiles.addedFiles`).
|
|
748
|
+
const edges = program.addedFiles();
|
|
711
749
|
const importers = new Map<number, number>();
|
|
712
750
|
for (const i of order) {
|
|
713
751
|
const libraries: number[] = [];
|
|
714
|
-
for (const k of
|
|
752
|
+
for (const k of edges[i]!) if (isLibrary(k) && libraries.indexOf(k) < 0) libraries.push(k);
|
|
715
753
|
librariesOf[i] = libraries;
|
|
716
754
|
for (const k of libraries) importers.set(k, (importers.get(k) ?? 0) + 1);
|
|
717
755
|
}
|
|
@@ -726,7 +764,7 @@ function checkCosts(checked: CheckedProgram, order: number[]): CheckCosts {
|
|
|
726
764
|
while (stack.length > 0) {
|
|
727
765
|
const k = stack.pop()!;
|
|
728
766
|
total += length[k]!;
|
|
729
|
-
for (const t of
|
|
767
|
+
for (const t of edges[k]!)
|
|
730
768
|
if (!seen.has(t) && isLibrary(t)) {
|
|
731
769
|
seen.add(t);
|
|
732
770
|
stack.push(t);
|
|
@@ -1161,6 +1199,12 @@ export class CheckPlan {
|
|
|
1161
1199
|
readonly references: number,
|
|
1162
1200
|
/** For each position, the number of files of the group starting there (0 elsewhere). */
|
|
1163
1201
|
readonly groups: number[] = [],
|
|
1202
|
+
/**
|
|
1203
|
+
* The statement ranges of declaration files that several checkers check (`rangeUnits`): for each,
|
|
1204
|
+
* the file's index and its first and end statement. Position `k` of `order` is range `u` where
|
|
1205
|
+
* `order[k]` is `-1 - u`.
|
|
1206
|
+
*/
|
|
1207
|
+
readonly units: number[] = [],
|
|
1164
1208
|
) {}
|
|
1165
1209
|
}
|
|
1166
1210
|
|
|
@@ -1310,16 +1354,100 @@ export function checkGroups(
|
|
|
1310
1354
|
return groups;
|
|
1311
1355
|
}
|
|
1312
1356
|
|
|
1357
|
+
/**
|
|
1358
|
+
* How many ranges a declaration file checked in statement ranges (`rangeUnits`) has per checker's share
|
|
1359
|
+
* of the program's estimated cost, and at most per checker.
|
|
1360
|
+
*/
|
|
1361
|
+
const rangesPerShare = 2;
|
|
1362
|
+
const rangesPerChecker = 2;
|
|
1363
|
+
|
|
1364
|
+
/**
|
|
1365
|
+
* The statement ranges that `count` checkers check declaration files in, as `CheckPlan.units`: those of
|
|
1366
|
+
* the files of `costs` whose estimated cost is more than a checker's share, which one checker would
|
|
1367
|
+
* finish long after the others. lib.dom.d.ts (2.4 MB) is such a file in a small program: one checker
|
|
1368
|
+
* took 150 ms on it while 15 waited. Each range is about half a share, of about equal text, and the
|
|
1369
|
+
* last one ends the file (`checkSourceFileRange`). `grouped` files (`checkGroups`) are checked whole.
|
|
1370
|
+
* TSC_TS_RANGES=0 checks every file whole; TSC_TS_RANGES=all checks every checked declaration file in
|
|
1371
|
+
* ranges, `count` of them.
|
|
1372
|
+
*/
|
|
1373
|
+
export function rangeUnits(
|
|
1374
|
+
checked: CheckedProgram,
|
|
1375
|
+
count: number,
|
|
1376
|
+
costs: CheckCosts,
|
|
1377
|
+
grouped: ReadonlySet<number> = new Set<number>(),
|
|
1378
|
+
): number[] {
|
|
1379
|
+
const units: number[] = [];
|
|
1380
|
+
const mode = process.env.TSC_TS_RANGES;
|
|
1381
|
+
if (count < 2 || mode === '0') return units;
|
|
1382
|
+
const files = checked.program.getSourceFiles();
|
|
1383
|
+
const cost = costs.cost;
|
|
1384
|
+
let all = 0;
|
|
1385
|
+
for (const i of costs.order) all += cost[i]!;
|
|
1386
|
+
const share = all / count;
|
|
1387
|
+
for (const i of costs.order) {
|
|
1388
|
+
const file = files[i]!;
|
|
1389
|
+
if (!file.isDeclarationFile || grouped.has(i) || (mode !== 'all' && cost[i]! <= share)) continue;
|
|
1390
|
+
const statements = file.statements.nodes;
|
|
1391
|
+
const n = Math.min(
|
|
1392
|
+
statements.length,
|
|
1393
|
+
mode === 'all' ? count : Math.min(rangesPerChecker * count, Math.ceil((rangesPerShare * cost[i]!) / share)),
|
|
1394
|
+
);
|
|
1395
|
+
if (n < 2) continue;
|
|
1396
|
+
const text = file.text.length;
|
|
1397
|
+
let start = 0;
|
|
1398
|
+
for (let r = 1; r <= n && start < statements.length; r++) {
|
|
1399
|
+
let end = statements.length;
|
|
1400
|
+
if (r < n) {
|
|
1401
|
+
const target = (text * r) / n;
|
|
1402
|
+
end = start + 1;
|
|
1403
|
+
while (end < statements.length && statements[end - 1]!.end < target) end++;
|
|
1404
|
+
}
|
|
1405
|
+
units.push(i, start, end);
|
|
1406
|
+
start = end;
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
return units;
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
/** The estimated cost of range `u` of `units`, its file's share by text. */
|
|
1413
|
+
function unitCost(checked: CheckedProgram, costs: CheckCosts, units: readonly number[], u: number): number {
|
|
1414
|
+
const file = checked.program.getSourceFiles()[units[3 * u]!]!;
|
|
1415
|
+
return (costs.cost[units[3 * u]!]! * unitLength(file, units, u)) / Math.max(1, file.text.length);
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
/** The text length of the statements of range `u` of `units` of `file`. */
|
|
1419
|
+
function unitLength(file: SourceFile, units: readonly number[], u: number): number {
|
|
1420
|
+
const statements = file.statements.nodes;
|
|
1421
|
+
return statements[units[3 * u + 2]! - 1]!.end - statements[units[3 * u + 1]!]!.pos;
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1313
1424
|
/**
|
|
1314
1425
|
* Plans checking with `count` checkers: the order to check files in, the costliest files and the
|
|
1315
1426
|
* groups (`checkGroups`; at least `count` entries, and every file costing more than a 32nd of a
|
|
1316
1427
|
* checker's share), costliest first, from the shared queue; then the others split, in program
|
|
1317
|
-
* order, into one range of about equal cost per checker, each costliest first.
|
|
1428
|
+
* order, into one range of about equal cost per checker, each costliest first. With `inRanges`, the
|
|
1429
|
+
* statement ranges of large declaration files (`rangeUnits`) replace them in the shared queue.
|
|
1318
1430
|
*/
|
|
1319
|
-
export function planSchedule(
|
|
1431
|
+
export function planSchedule(
|
|
1432
|
+
checked: CheckedProgram,
|
|
1433
|
+
count: number,
|
|
1434
|
+
costs = costOrder(checked),
|
|
1435
|
+
inRanges = false,
|
|
1436
|
+
): CheckPlan {
|
|
1320
1437
|
const order = costs.order;
|
|
1321
1438
|
const cost = costs.cost;
|
|
1322
|
-
if (order.length <= count)
|
|
1439
|
+
if (order.length <= count) {
|
|
1440
|
+
const units = inRanges ? rangeUnits(checked, count, costs) : [];
|
|
1441
|
+
if (units.length === 0) return new CheckPlan(order, -1, [], [], [], [], 0);
|
|
1442
|
+
// The ranges take the place of their files, all in one shared queue, costliest first.
|
|
1443
|
+
const split = new Set<number>();
|
|
1444
|
+
for (let u = 0; u < units.length; u += 3) split.add(units[u]!);
|
|
1445
|
+
const entries: number[] = order.filter((i) => !split.has(i));
|
|
1446
|
+
for (let u = 0; u < units.length / 3; u++) entries.push(-1 - u);
|
|
1447
|
+
const costOf = (k: number): number => (k < 0 ? unitCost(checked, costs, units, -1 - k) : cost[k]!);
|
|
1448
|
+
entries.sort((a, b) => costOf(b) - costOf(a));
|
|
1449
|
+
return new CheckPlan(entries, -1, [], [], [], [], 0, [], units);
|
|
1450
|
+
}
|
|
1323
1451
|
let all = 0;
|
|
1324
1452
|
for (const i of order) all += cost[i]!;
|
|
1325
1453
|
// Files that cost more than a 32nd of a checker's share go first, costliest first: at the end of
|
|
@@ -1330,11 +1458,15 @@ export function planSchedule(checked: CheckedProgram, count: number, costs = cos
|
|
|
1330
1458
|
const groups = checkGroups(checked, count, groupLoad, costs);
|
|
1331
1459
|
const grouped = new Set<number>();
|
|
1332
1460
|
for (const group of groups) for (const i of group) grouped.add(i);
|
|
1461
|
+
const units = inRanges ? rangeUnits(checked, count, costs, grouped) : [];
|
|
1462
|
+
const split = new Set<number>();
|
|
1463
|
+
for (let u = 0; u < units.length; u += 3) split.add(units[u]!);
|
|
1333
1464
|
const entries: number[][] = groups.slice();
|
|
1334
|
-
for (const i of order.slice(0, heavyCount)) if (!grouped.has(i)) entries.push([i]);
|
|
1465
|
+
for (const i of order.slice(0, heavyCount)) if (!grouped.has(i) && !split.has(i)) entries.push([i]);
|
|
1466
|
+
for (let u = 0; u < units.length / 3; u++) entries.push([-1 - u]);
|
|
1335
1467
|
const entryCost = (entry: number[]): number => {
|
|
1336
1468
|
let sum = 0;
|
|
1337
|
-
for (const i of entry) sum += cost[i]!;
|
|
1469
|
+
for (const i of entry) sum += i < 0 ? unitCost(checked, costs, units, -1 - i) : cost[i]!;
|
|
1338
1470
|
return sum;
|
|
1339
1471
|
};
|
|
1340
1472
|
entries.sort((a, b) => entryCost(b) - entryCost(a) || a[0]! - b[0]!);
|
|
@@ -1347,7 +1479,7 @@ export function planSchedule(checked: CheckedProgram, count: number, costs = cos
|
|
|
1347
1479
|
}
|
|
1348
1480
|
const rest = order
|
|
1349
1481
|
.slice(heavyCount)
|
|
1350
|
-
.filter((i) => !grouped.has(i))
|
|
1482
|
+
.filter((i) => !grouped.has(i) && !split.has(i))
|
|
1351
1483
|
.sort((a, b) => a - b);
|
|
1352
1484
|
heavyCount = heavy.length;
|
|
1353
1485
|
let total = 0;
|
|
@@ -1378,9 +1510,9 @@ export function planSchedule(checked: CheckedProgram, count: number, costs = cos
|
|
|
1378
1510
|
const libraries: number[][] = [];
|
|
1379
1511
|
let references = 0;
|
|
1380
1512
|
for (const i of planned) {
|
|
1381
|
-
lengths.push(textLength[i]!);
|
|
1513
|
+
lengths.push(i < 0 ? unitLength(files[units[-3 * i - 3]!]!, units, -1 - i) : textLength[i]!);
|
|
1382
1514
|
const ids: number[] = [];
|
|
1383
|
-
for (const k of costs.libraries[i]!) {
|
|
1515
|
+
for (const k of costs.libraries[i < 0 ? units[-3 * i - 3]! : i]!) {
|
|
1384
1516
|
let id = libraryIds.get(k);
|
|
1385
1517
|
if (id === undefined) {
|
|
1386
1518
|
id = libraryCosts.length;
|
|
@@ -1398,7 +1530,7 @@ export function planSchedule(checked: CheckedProgram, count: number, costs = cos
|
|
|
1398
1530
|
process.stderr.write(
|
|
1399
1531
|
`checkers: group of ${group.length}: ${group.map((i) => files[i]!.fileName.split('/').slice(-2).join('/')).join(' ')}\n`,
|
|
1400
1532
|
);
|
|
1401
|
-
return new CheckPlan(planned, heavyCount, ranges, lengths, libraries, libraryCosts, references, groupAt);
|
|
1533
|
+
return new CheckPlan(planned, heavyCount, ranges, lengths, libraries, libraryCosts, references, groupAt, units);
|
|
1402
1534
|
}
|
|
1403
1535
|
|
|
1404
1536
|
/** With TSC_TS_CHECKERS_TRACE: the single-threaded checker's statistics, like a checker thread's. */
|
|
@@ -1422,7 +1554,8 @@ export function traceSingleChecker(checked: CheckedProgram): void {
|
|
|
1422
1554
|
* A checker thread (`onMainThread` false) also sends back its global diagnostics. At `limit` files
|
|
1423
1555
|
* it stops; `reserved` are the positions of a group its predecessor on `index` had not checked then.
|
|
1424
1556
|
* With `emit` false it doesn't emit the files it checks (`checkersEmit`). With `checking` false it
|
|
1425
|
-
* only emits them (`startParallelCheck`).
|
|
1557
|
+
* only emits them (`startParallelCheck`). A position of the order below 0 is a statement range of a
|
|
1558
|
+
* declaration file, `-1 - u` for the range at `3 * u` in `units` (`CheckPlan.units`).
|
|
1426
1559
|
*/
|
|
1427
1560
|
export function checkFromQueue(
|
|
1428
1561
|
checked: CheckedProgram,
|
|
@@ -1436,6 +1569,7 @@ export function checkFromQueue(
|
|
|
1436
1569
|
emit: boolean = true,
|
|
1437
1570
|
emitKinds: readonly number[] | undefined = undefined,
|
|
1438
1571
|
checking: boolean = true,
|
|
1572
|
+
units: readonly number[] = [],
|
|
1439
1573
|
): CheckerResult {
|
|
1440
1574
|
const start = performance.now();
|
|
1441
1575
|
const readyAt = Date.now();
|
|
@@ -1446,6 +1580,8 @@ export function checkFromQueue(
|
|
|
1446
1580
|
const diagnostics: Diagnostic[][] = [];
|
|
1447
1581
|
const declarations: Diagnostic[][] = [];
|
|
1448
1582
|
const emits: EmitResult[] = [];
|
|
1583
|
+
const unitsDone: number[] = [];
|
|
1584
|
+
const reportingUnits: number[] = [];
|
|
1449
1585
|
// Emit (or declaration emit) of a file right after checking it, with this checker.
|
|
1450
1586
|
const emitting = checkersEmit(checked, emit);
|
|
1451
1587
|
// Outputs are held for the main thread under `noEmitOnError`, where emit waits for every file's diagnostics,
|
|
@@ -1487,6 +1623,28 @@ export function checkFromQueue(
|
|
|
1487
1623
|
const k = takePosition(counter, order.length, index, plan);
|
|
1488
1624
|
if (k < 0) break;
|
|
1489
1625
|
const i = order[k]!;
|
|
1626
|
+
if (i < 0) {
|
|
1627
|
+
// A statement range of a declaration file, which has nothing to emit.
|
|
1628
|
+
const u = -1 - i;
|
|
1629
|
+
const file = files[units[3 * u]!]!;
|
|
1630
|
+
const rangeStart = verbose || timeline ? performance.now() : 0;
|
|
1631
|
+
const reports = checking && checked.checkRange(file, units[3 * u + 1]!, units[3 * u + 2]!);
|
|
1632
|
+
unitsDone.push(u);
|
|
1633
|
+
if (reports) reportingUnits.push(u);
|
|
1634
|
+
// A range doesn't block emit under `noEmitOnError`: what its checker found may be suppressed
|
|
1635
|
+
// (`// @ts-ignore`) or not the file's, which this thread doesn't know. The main thread decides
|
|
1636
|
+
// from the file's diagnostics, and the outputs are held for it.
|
|
1637
|
+
if (timeline)
|
|
1638
|
+
markAt(
|
|
1639
|
+
rangeStart,
|
|
1640
|
+
`range ${(performance.now() - rangeStart).toFixed(1)} pos ${k} statements ${units[3 * u + 1]}-${units[3 * u + 2]} ${file.fileName}`,
|
|
1641
|
+
);
|
|
1642
|
+
if (verbose)
|
|
1643
|
+
process.stderr.write(
|
|
1644
|
+
`checkers: range ${index} ${(performance.now() - rangeStart).toFixed(1)}ms statements ${units[3 * u + 1]}-${units[3 * u + 2]} ${file.fileName}\n`,
|
|
1645
|
+
);
|
|
1646
|
+
continue;
|
|
1647
|
+
}
|
|
1490
1648
|
done.push(i);
|
|
1491
1649
|
const fileStart = verbose || timeline ? performance.now() : 0;
|
|
1492
1650
|
// Without `checking` the file is only emitted: declaration emit checks what it needs.
|
|
@@ -1510,22 +1668,36 @@ export function checkFromQueue(
|
|
|
1510
1668
|
} else if (writer !== undefined) {
|
|
1511
1669
|
const emitStart = timeline ? performance.now() : 0;
|
|
1512
1670
|
const kind = (emitKinds === undefined ? EmitOnly.All : emitKinds[i]!) as EmitOnly;
|
|
1671
|
+
// Global diagnostics found while emitting are not reported: the program collects them
|
|
1672
|
+
// before it emits.
|
|
1673
|
+
const checker = checked.checker;
|
|
1513
1674
|
if (kind < 0) emits.push(new EmitResult());
|
|
1514
1675
|
else if (signatures !== undefined) {
|
|
1515
1676
|
signatures.file = files[i]!;
|
|
1516
|
-
const result = emitter!.emit([files[i]!], kind, signatures);
|
|
1677
|
+
const result = checker.withoutGlobalDiagnostics(() => emitter!.emit([files[i]!], kind, signatures));
|
|
1517
1678
|
for (const s of signatures.take()) result.declarationSignatures.push(s);
|
|
1518
1679
|
if (holding !== undefined) for (const o of holding.take()) result.heldOutputs.push(o);
|
|
1519
1680
|
emits.push(result);
|
|
1520
1681
|
} else {
|
|
1521
|
-
const result = emitter!.emit([files[i]!], kind, writer);
|
|
1682
|
+
const result = checker.withoutGlobalDiagnostics(() => emitter!.emit([files[i]!], kind, writer));
|
|
1522
1683
|
if (holding !== undefined) for (const o of holding.take()) result.heldOutputs.push(o);
|
|
1523
1684
|
emits.push(result);
|
|
1524
1685
|
}
|
|
1525
1686
|
if (timeline) markAt(emitStart, `emit ${(performance.now() - emitStart).toFixed(1)} ${files[i]!.fileName}`);
|
|
1526
|
-
} else if (emitter !== undefined)
|
|
1687
|
+
} else if (emitter !== undefined)
|
|
1688
|
+
declarations.push(
|
|
1689
|
+
checked.checker.withoutGlobalDiagnostics(() => declarationDiagnosticsOfFile(emitter, files[i]!)),
|
|
1690
|
+
);
|
|
1691
|
+
// What emitting found and forgot can stay cached in this checker (a missing global type, an
|
|
1692
|
+
// instantiation too deep), where checking a later file would report it: a new checker continues
|
|
1693
|
+
// the schedule, as at the file limit.
|
|
1694
|
+
if (checked.checker.forgottenGlobalDiagnostics() > 0) {
|
|
1695
|
+
more = true;
|
|
1696
|
+
left = reservedBy(index).splice(0);
|
|
1697
|
+
break;
|
|
1698
|
+
}
|
|
1527
1699
|
}
|
|
1528
|
-
mark(`checked ${done.length} files`);
|
|
1700
|
+
mark(`checked ${done.length} files, ${unitsDone.length} ranges`);
|
|
1529
1701
|
// The main thread reports its own global diagnostics (CheckedProgram.getGlobalDiagnostics).
|
|
1530
1702
|
const globals = onMainThread ? [] : checked.getGlobalDiagnostics().slice();
|
|
1531
1703
|
let stats: number[] = [];
|
|
@@ -1564,6 +1736,8 @@ export function checkFromQueue(
|
|
|
1564
1736
|
more,
|
|
1565
1737
|
left,
|
|
1566
1738
|
emits,
|
|
1739
|
+
unitsDone,
|
|
1740
|
+
reportingUnits,
|
|
1567
1741
|
);
|
|
1568
1742
|
}
|
|
1569
1743
|
|
|
@@ -1694,7 +1868,11 @@ export function shareWithCheckers(checked: CheckedProgram): void {
|
|
|
1694
1868
|
/**
|
|
1695
1869
|
* Checks `checked` on `checkers` threads and calls `done` once they are done. With `emits`, each thread
|
|
1696
1870
|
* emits the files it checks (`emitKinds` limits what). With `checking` false, the threads only emit:
|
|
1697
|
-
* for a program whose report has no semantic diagnostics, so that no file is checked in full.
|
|
1871
|
+
* for a program whose report has no semantic diagnostics, so that no file is checked in full. With
|
|
1872
|
+
* `emitsTo`, the emit results go only there, by file index, and nothing else the threads find reaches
|
|
1873
|
+
* the program: a declaration thread (parallel-emit.ts), while this thread's checker checks. With
|
|
1874
|
+
* `declarationsTo`, the same holds for the declaration errors of a `noEmit` program
|
|
1875
|
+
* (`checkersReportDeclarations`).
|
|
1698
1876
|
*/
|
|
1699
1877
|
export function startParallelCheck(
|
|
1700
1878
|
checked: CheckedProgram,
|
|
@@ -1703,6 +1881,8 @@ export function startParallelCheck(
|
|
|
1703
1881
|
emits: boolean = true,
|
|
1704
1882
|
emitKinds: number[] | undefined = undefined,
|
|
1705
1883
|
checking: boolean = true,
|
|
1884
|
+
emitsTo: (EmitResult | undefined)[] | undefined = undefined,
|
|
1885
|
+
declarationsTo: (Diagnostic[] | undefined)[] | undefined = undefined,
|
|
1706
1886
|
): void {
|
|
1707
1887
|
let count = checkers;
|
|
1708
1888
|
const start = performance.now();
|
|
@@ -1721,23 +1901,29 @@ export function startParallelCheck(
|
|
|
1721
1901
|
}
|
|
1722
1902
|
const orderStart = performance.now();
|
|
1723
1903
|
const costs = costOrder(checked);
|
|
1724
|
-
let plan = planSchedule(checked, count, costs);
|
|
1904
|
+
let plan = planSchedule(checked, count, costs, checking);
|
|
1725
1905
|
const fewer = libraryBoundCheckers(checked, plan, costs, count);
|
|
1726
1906
|
if (fewer < count) {
|
|
1727
1907
|
count = fewer;
|
|
1728
|
-
plan = planSchedule(checked, count, costs);
|
|
1908
|
+
plan = planSchedule(checked, count, costs, checking);
|
|
1729
1909
|
}
|
|
1730
1910
|
const order = plan.order;
|
|
1911
|
+
const units = plan.units;
|
|
1731
1912
|
const counter = scheduleOf(plan, count);
|
|
1732
1913
|
if (trace) {
|
|
1733
1914
|
let top = '';
|
|
1734
|
-
for (let k = 0; k < Math.min(5, order.length); k++)
|
|
1915
|
+
for (let k = 0; k < Math.min(5, order.length); k++)
|
|
1916
|
+
top +=
|
|
1917
|
+
' ' +
|
|
1918
|
+
(order[k]! < 0 ? `range ${-1 - order[k]!} of ` : '') +
|
|
1919
|
+
files[order[k]! < 0 ? units[-3 * order[k]! - 3]! : order[k]!]!.fileName;
|
|
1735
1920
|
process.stderr.write(
|
|
1736
|
-
`checkers: ordered ${order.length}
|
|
1921
|
+
`checkers: ordered ${order.length} positions (${units.length / 3} statement ranges) in ${(performance.now() - orderStart).toFixed(1)}ms, first:${top}\n`,
|
|
1737
1922
|
);
|
|
1738
1923
|
}
|
|
1739
1924
|
if (shared) {
|
|
1740
1925
|
publish(order);
|
|
1926
|
+
publish(units);
|
|
1741
1927
|
if (emitKinds !== undefined) publish(emitKinds);
|
|
1742
1928
|
}
|
|
1743
1929
|
mark(`planned ${order.length} files, ${plan.heavy} heavy`);
|
|
@@ -1749,15 +1935,26 @@ export function startParallelCheck(
|
|
|
1749
1935
|
perFileDeclarations.push(undefined);
|
|
1750
1936
|
perFileEmits.push(undefined);
|
|
1751
1937
|
}
|
|
1938
|
+
// For each statement range (`CheckPlan.units`): 0 until checked, 1 once checked, 2 if its checker then had
|
|
1939
|
+
// diagnostics in the file.
|
|
1940
|
+
const perUnit: number[] = [];
|
|
1941
|
+
for (let u = 0; u < units.length / 3; u++) perUnit.push(0);
|
|
1752
1942
|
const revival = shared ? undefined : new Revival(program);
|
|
1753
1943
|
const mainChecks = mainThreadChecks(shared);
|
|
1754
1944
|
const firstThread = mainChecks ? 1 : 0;
|
|
1755
1945
|
let remaining = count - firstThread;
|
|
1756
1946
|
let ownDone = false;
|
|
1757
1947
|
const finish = (): void => {
|
|
1948
|
+
if (emitsTo !== undefined || declarationsTo !== undefined) {
|
|
1949
|
+
mark('emitted on checker threads');
|
|
1950
|
+
done(performance.now() - start);
|
|
1951
|
+
return;
|
|
1952
|
+
}
|
|
1758
1953
|
if (checking) {
|
|
1954
|
+
joinRanges(checked, units, perUnit, perFile);
|
|
1759
1955
|
// A thread that failed may have taken files it never checked: check them here.
|
|
1760
|
-
for (const i of order)
|
|
1956
|
+
for (const i of order)
|
|
1957
|
+
if (i >= 0 && perFile[i] === undefined) perFile[i] = checked.unfilteredDiagnosticsOfFile(files[i]!);
|
|
1761
1958
|
checked.checkedInParallel = perFile;
|
|
1762
1959
|
}
|
|
1763
1960
|
mark('all checked');
|
|
@@ -1783,16 +1980,34 @@ export function startParallelCheck(
|
|
|
1783
1980
|
done(performance.now() - start);
|
|
1784
1981
|
};
|
|
1785
1982
|
const record = (result: CheckerResult): void => {
|
|
1983
|
+
if (declarationsTo !== undefined) {
|
|
1984
|
+
for (let k = 0; k < result.declarations.length; k++) declarationsTo[result.files[k]!] = result.declarations[k]!;
|
|
1985
|
+
if (trace)
|
|
1986
|
+
process.stderr.write(
|
|
1987
|
+
`checkers: emit-only thread ${result.index} found the declaration errors of ${result.declarations.length} files in ${result.checkTime.toFixed(1)}ms, done at ${(performance.now() - start).toFixed(1)}ms rss ${result.stats[7] ?? '?'}MB\n`,
|
|
1988
|
+
);
|
|
1989
|
+
return;
|
|
1990
|
+
}
|
|
1991
|
+
if (emitsTo !== undefined) {
|
|
1992
|
+
for (let k = 0; k < result.emits.length; k++) emitsTo[result.files[k]!] = result.emits[k]!;
|
|
1993
|
+
if (trace)
|
|
1994
|
+
process.stderr.write(
|
|
1995
|
+
`checkers: emit-only thread ${result.index} emitted ${result.emits.length} files in ${result.checkTime.toFixed(1)}ms, done at ${(performance.now() - start).toFixed(1)}ms rss ${result.stats[7] ?? '?'}MB\n`,
|
|
1996
|
+
);
|
|
1997
|
+
return;
|
|
1998
|
+
}
|
|
1786
1999
|
for (let k = 0; k < result.files.length; k++) perFile[result.files[k]!] = result.diagnostics[k]!;
|
|
1787
2000
|
for (let k = 0; k < result.declarations.length; k++)
|
|
1788
2001
|
perFileDeclarations[result.files[k]!] = result.declarations[k]!;
|
|
1789
2002
|
for (let k = 0; k < result.emits.length; k++) perFileEmits[result.files[k]!] = result.emits[k]!;
|
|
2003
|
+
for (const u of result.units) perUnit[u] = 1;
|
|
2004
|
+
for (const u of result.reportingUnits) perUnit[u] = 2;
|
|
1790
2005
|
for (const d of result.globals) checked.parallelGlobalDiagnostics.push(d);
|
|
1791
2006
|
if (trace) {
|
|
1792
2007
|
const st = result.stats;
|
|
1793
2008
|
const rel = (t: number | undefined): string => (t === undefined ? '?' : String(t - epoch));
|
|
1794
2009
|
process.stderr.write(
|
|
1795
|
-
`checkers: thread ${result.index} checked ${result.files.length} files in ${result.checkTime.toFixed(1)}ms, done at ${(performance.now() - start).toFixed(1)}ms` +
|
|
2010
|
+
`checkers: thread ${result.index} checked ${result.files.length} files and ${result.units.length} ranges in ${result.checkTime.toFixed(1)}ms, done at ${(performance.now() - start).toFixed(1)}ms` +
|
|
1796
2011
|
` [start ${rel(st[0])} ready ${rel(st[1])} end ${rel(st[2])} types ${st[3]} inst ${st[4]} user ${Math.round(st[5] ?? 0)} sys ${Math.round(st[6] ?? 0)} rss ${st[7]}MB symlinks ${st[8]} nodelinks ${st[9]} sigs ${st[10]} rel ${st[11]}]\n`,
|
|
1797
2012
|
);
|
|
1798
2013
|
}
|
|
@@ -1814,6 +2029,7 @@ export function startParallelCheck(
|
|
|
1814
2029
|
emits,
|
|
1815
2030
|
emitKinds,
|
|
1816
2031
|
checking,
|
|
2032
|
+
units,
|
|
1817
2033
|
);
|
|
1818
2034
|
worker.on('message', (message: unknown) => {
|
|
1819
2035
|
mark(`result from c${i}`);
|
|
@@ -1842,12 +2058,58 @@ export function startParallelCheck(
|
|
|
1842
2058
|
mark('reporting checker created');
|
|
1843
2059
|
const emittedHere =
|
|
1844
2060
|
!mainChecks && emitKinds === undefined ? emitUncheckedFiles(checked, order, emits) : new Map<number, EmitResult>();
|
|
1845
|
-
if (mainChecks)
|
|
1846
|
-
|
|
2061
|
+
if (mainChecks) {
|
|
2062
|
+
const own = checkFromQueue(
|
|
2063
|
+
checked,
|
|
2064
|
+
0,
|
|
2065
|
+
new Int32Array(counter),
|
|
2066
|
+
order,
|
|
2067
|
+
epoch,
|
|
2068
|
+
true,
|
|
2069
|
+
0,
|
|
2070
|
+
[],
|
|
2071
|
+
emits,
|
|
2072
|
+
emitKinds,
|
|
2073
|
+
checking,
|
|
2074
|
+
units,
|
|
2075
|
+
);
|
|
2076
|
+
record(own);
|
|
2077
|
+
// A thread continues where this checker stopped (`checkFromQueue`).
|
|
2078
|
+
if (own.more) {
|
|
2079
|
+
remaining++;
|
|
2080
|
+
spawn(0, own.reserved);
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
1847
2083
|
ownDone = true;
|
|
1848
2084
|
if (remaining === 0) finish();
|
|
1849
2085
|
}
|
|
1850
2086
|
|
|
2087
|
+
/**
|
|
2088
|
+
* Sets the diagnostics in `perFile` of each file checked in statement ranges (`units`): none from its
|
|
2089
|
+
* checkers where every range was checked and found no diagnostics in it (`perUnit`, by range:
|
|
2090
|
+
* `checkSourceFileRange`); otherwise a new checker on this thread checks it whole.
|
|
2091
|
+
*/
|
|
2092
|
+
function joinRanges(
|
|
2093
|
+
checked: CheckedProgram,
|
|
2094
|
+
units: readonly number[],
|
|
2095
|
+
perUnit: readonly number[],
|
|
2096
|
+
perFile: (Diagnostic[] | undefined)[],
|
|
2097
|
+
): void {
|
|
2098
|
+
const files = checked.program.getSourceFiles();
|
|
2099
|
+
const trace = process.env.TSC_TS_CHECKERS_TRACE !== undefined;
|
|
2100
|
+
// A file's ranges are consecutive.
|
|
2101
|
+
for (let u = 0; u < perUnit.length;) {
|
|
2102
|
+
const i = units[3 * u]!;
|
|
2103
|
+
let clean = true;
|
|
2104
|
+
for (; u < perUnit.length && units[3 * u] === i; u++) if (perUnit[u] !== 1) clean = false;
|
|
2105
|
+
if (clean) perFile[i] = checked.unfilteredDiagnosticsOfCleanRanges(files[i]!);
|
|
2106
|
+
else {
|
|
2107
|
+
if (trace) process.stderr.write(`checkers: checking ${files[i]!.fileName} whole: its ranges have diagnostics\n`);
|
|
2108
|
+
perFile[i] = checked.unfilteredDiagnosticsOfFileOnNewChecker(files[i]!);
|
|
2109
|
+
}
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
|
|
1851
2113
|
/**
|
|
1852
2114
|
* Emits, on this thread and into memory, the files that checker threads emit nothing for because
|
|
1853
2115
|
* they don't check them (`skipTypeChecking`, such as a file with `// @ts-nocheck`), while the threads
|
|
@@ -1867,7 +2129,7 @@ function emitUncheckedFiles(
|
|
|
1867
2129
|
const files = program.getSourceFiles();
|
|
1868
2130
|
const inOrder: boolean[] = [];
|
|
1869
2131
|
for (let i = 0; i < files.length; i++) inOrder.push(false);
|
|
1870
|
-
for (const i of order) inOrder[i] = true;
|
|
2132
|
+
for (const i of order) if (i >= 0) inOrder[i] = true;
|
|
1871
2133
|
let emitter: ProgramEmitter | undefined = undefined;
|
|
1872
2134
|
let holding: HoldingWriter | undefined = undefined;
|
|
1873
2135
|
for (let i = 0; i < files.length; i++) {
|
|
@@ -1909,6 +2171,8 @@ class Revival {
|
|
|
1909
2171
|
copy.more,
|
|
1910
2172
|
copy.reserved,
|
|
1911
2173
|
copy.emits.map((emit) => this.emit(emit)),
|
|
2174
|
+
copy.units,
|
|
2175
|
+
copy.reportingUnits,
|
|
1912
2176
|
);
|
|
1913
2177
|
}
|
|
1914
2178
|
|