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
|
@@ -6,7 +6,7 @@ import { parentPort } from 'node:worker_threads';
|
|
|
6
6
|
import { publish, sharesPublishedGraphs } from '@scriptc/threads';
|
|
7
7
|
import { reserveNodeIds, shareNodeIds } from './ast.js';
|
|
8
8
|
import type { OutputWriter } from './compile-program.js';
|
|
9
|
-
import { useThreadTextCaches } from './diagnostics.js';
|
|
9
|
+
import { type DiagnosticFormatOptions, formattedReports, useThreadTextCaches } from './diagnostics.js';
|
|
10
10
|
import { compareReferencesOfThread, type ReferenceJob, referenceThreads } from './incremental.js';
|
|
11
11
|
import {
|
|
12
12
|
CheckerResult,
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
parallelCheck,
|
|
17
17
|
recycleFiles,
|
|
18
18
|
} from './parallel-check.js';
|
|
19
|
+
import { emitFromQueue, parallelEmit, postedEmitResult } from './parallel-emit.js';
|
|
19
20
|
import { type LoadMessage, parallelParse } from './parallel-parse.js';
|
|
20
21
|
import type { ParseThread } from './parse-thread.js';
|
|
21
22
|
import { useLazyJSDocTable } from './parser.js';
|
|
@@ -38,7 +39,7 @@ export interface ThreadDrivers {
|
|
|
38
39
|
export type ThreadSpawn = (data: ThreadData) => Worker;
|
|
39
40
|
|
|
40
41
|
/** The `workerData` of a thread of tsc-ts. */
|
|
41
|
-
export type ThreadData = CheckerThreadData | ParseThreadData | ReferenceThreadData;
|
|
42
|
+
export type ThreadData = CheckerThreadData | EmitThreadData | ParseThreadData | ReferenceThreadData;
|
|
42
43
|
|
|
43
44
|
export interface CheckerThreadData {
|
|
44
45
|
readonly kind: 'check';
|
|
@@ -54,6 +55,21 @@ export interface CheckerThreadData {
|
|
|
54
55
|
readonly emits: boolean;
|
|
55
56
|
readonly emitKinds: number[] | undefined;
|
|
56
57
|
readonly checking: boolean;
|
|
58
|
+
readonly units: number[];
|
|
59
|
+
/** The main thread's report format (`formattedReports`), which the thread formats its diagnostics in. */
|
|
60
|
+
readonly reportFormat: DiagnosticFormatOptions | undefined;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface EmitThreadData {
|
|
64
|
+
readonly kind: 'emit';
|
|
65
|
+
/** The shared, published program. */
|
|
66
|
+
readonly program: Program;
|
|
67
|
+
readonly index: number;
|
|
68
|
+
readonly counter: SharedArrayBuffer;
|
|
69
|
+
readonly files: number[];
|
|
70
|
+
readonly kinds: number[];
|
|
71
|
+
readonly nodeIds: number;
|
|
72
|
+
readonly symbolIds: number;
|
|
57
73
|
}
|
|
58
74
|
|
|
59
75
|
export interface ParseThreadData {
|
|
@@ -75,7 +91,19 @@ export interface ReferenceThreadData {
|
|
|
75
91
|
*/
|
|
76
92
|
export function startThreads(spawn: ThreadSpawn, drivers: ThreadDrivers, args: readonly string[]): void {
|
|
77
93
|
parallelCheck.writer = drivers.outputWriter();
|
|
78
|
-
parallelCheck.spawn = (
|
|
94
|
+
parallelCheck.spawn = (
|
|
95
|
+
program,
|
|
96
|
+
index,
|
|
97
|
+
counter,
|
|
98
|
+
order,
|
|
99
|
+
nodeIds,
|
|
100
|
+
symbolIds,
|
|
101
|
+
reserved,
|
|
102
|
+
emits,
|
|
103
|
+
emitKinds,
|
|
104
|
+
checking,
|
|
105
|
+
units,
|
|
106
|
+
) =>
|
|
79
107
|
spawn({
|
|
80
108
|
kind: 'check',
|
|
81
109
|
program,
|
|
@@ -89,8 +117,12 @@ export function startThreads(spawn: ThreadSpawn, drivers: ThreadDrivers, args: r
|
|
|
89
117
|
emits,
|
|
90
118
|
emitKinds,
|
|
91
119
|
checking,
|
|
120
|
+
units,
|
|
121
|
+
reportFormat: formattedReports.format,
|
|
92
122
|
});
|
|
93
123
|
if (sharesPublishedGraphs) {
|
|
124
|
+
parallelEmit.spawn = (program, index, counter, files, kinds, nodeIds, symbolIds) =>
|
|
125
|
+
spawn({ kind: 'emit', program, index, counter, files, kinds, nodeIds, symbolIds });
|
|
94
126
|
parallelParse.spawn = (configFileName, counter, index) =>
|
|
95
127
|
spawn({ kind: 'parse', configFileName, args, counter, index });
|
|
96
128
|
// The main thread compares the files a reference thread that failed did not.
|
|
@@ -109,6 +141,7 @@ export function runThread(data: unknown, drivers: ThreadDrivers): void {
|
|
|
109
141
|
const kind = (data as { kind: string }).kind;
|
|
110
142
|
if (kind === 'parse') runParseThread(data as ParseThreadData, drivers);
|
|
111
143
|
else if (kind === 'references') runReferenceThread(data as ReferenceThreadData);
|
|
144
|
+
else if (kind === 'emit') runEmitThread(data as EmitThreadData, drivers);
|
|
112
145
|
else runCheckerThread(data as CheckerThreadData, drivers);
|
|
113
146
|
}
|
|
114
147
|
|
|
@@ -127,12 +160,36 @@ function runReferenceThread(data: ReferenceThreadData): void {
|
|
|
127
160
|
mark('references compared');
|
|
128
161
|
}
|
|
129
162
|
|
|
163
|
+
/** An emit thread (parallel-emit.ts): emits JavaScript, without a checker. */
|
|
164
|
+
function runEmitThread(job: EmitThreadData, drivers: ThreadDrivers): void {
|
|
165
|
+
setTimelineThread('e' + String(job.index));
|
|
166
|
+
mark('thread start');
|
|
167
|
+
// As on a checker thread, the shared program is never written.
|
|
168
|
+
reserveNodeIds(job.nodeIds);
|
|
169
|
+
reserveSymbolIds(job.symbolIds);
|
|
170
|
+
assignSymbolIdsAtCreation();
|
|
171
|
+
useLazyJSDocTable();
|
|
172
|
+
useThreadTextCaches();
|
|
173
|
+
const program = publish(job.program);
|
|
174
|
+
const result = emitFromQueue(
|
|
175
|
+
program,
|
|
176
|
+
job.index,
|
|
177
|
+
new Int32Array(job.counter),
|
|
178
|
+
job.files,
|
|
179
|
+
job.kinds,
|
|
180
|
+
drivers.outputWriter(),
|
|
181
|
+
);
|
|
182
|
+
parentPort!.postMessage(postedEmitResult(result, program));
|
|
183
|
+
mark('result posted');
|
|
184
|
+
}
|
|
185
|
+
|
|
130
186
|
/** A checker thread (parallel-check.ts). */
|
|
131
187
|
function runCheckerThread(job: CheckerThreadData, drivers: ThreadDrivers): void {
|
|
132
188
|
const startedAt = Date.now();
|
|
133
189
|
setTimelineThread('c' + String(job.index));
|
|
134
190
|
mark('thread start');
|
|
135
191
|
parallelCheck.writer = drivers.outputWriter();
|
|
192
|
+
formattedReports.format = job.reportFormat;
|
|
136
193
|
let program: Program | undefined = undefined;
|
|
137
194
|
if (job.program !== undefined) {
|
|
138
195
|
// The shared program is never written: new ids continue above its own, and lazily parsed JSDoc
|
|
@@ -161,6 +218,7 @@ function runCheckerThread(job: CheckerThreadData, drivers: ThreadDrivers): void
|
|
|
161
218
|
job.emits,
|
|
162
219
|
job.emitKinds,
|
|
163
220
|
job.checking,
|
|
221
|
+
job.units,
|
|
164
222
|
);
|
|
165
223
|
// Packed results are copied: nothing this thread allocated stays reachable after it ends.
|
|
166
224
|
if (packsResults) parentPort!.postMessage(packResult(result, program!));
|
|
@@ -55,15 +55,20 @@ import {
|
|
|
55
55
|
SystemFileSystem,
|
|
56
56
|
} from './tsc-cli.js';
|
|
57
57
|
import {
|
|
58
|
+
checkWhileThreadsEmit,
|
|
58
59
|
emitFilesAndReportErrors,
|
|
60
|
+
emitKindsOf,
|
|
61
|
+
emitsOnThreads,
|
|
59
62
|
exitStatusOf,
|
|
60
63
|
rechecksOnThreads,
|
|
64
|
+
reportEmitAndErrors,
|
|
61
65
|
Statistics,
|
|
62
66
|
statisticsOf,
|
|
63
67
|
SystemTimeStamps,
|
|
64
68
|
} from './tsc-compile.js';
|
|
65
69
|
import { sharesPublishedGraphs } from '@scriptc/threads';
|
|
66
70
|
import { checkerThreads, parseThreads, shareWithCheckers, startParallelCheck } from './parallel-check.js';
|
|
71
|
+
import { emitThreads } from './parallel-emit.js';
|
|
67
72
|
import { LoadKind, ParseSession, clearPreparedFiles, parallelParse, reportPreparedFiles } from './parallel-parse.js';
|
|
68
73
|
import { assignSymbolIdsAtCreation } from './symbol.js';
|
|
69
74
|
|
|
@@ -792,10 +797,58 @@ export class Orchestrator {
|
|
|
792
797
|
});
|
|
793
798
|
return true;
|
|
794
799
|
}
|
|
800
|
+
if (mayUseThreads && this.emitsOnThreads(checked, oldSnapshot))
|
|
801
|
+
return this.checkWhileThreadsEmit(task, checked, times, oldSnapshot, then);
|
|
795
802
|
this.emitAndReport(task, checked, times, oldSnapshot, undefined);
|
|
796
803
|
return false;
|
|
797
804
|
}
|
|
798
805
|
|
|
806
|
+
/**
|
|
807
|
+
* Whether `checkWhileThreadsEmit` builds the project of `checked`: one whose emit threads apply
|
|
808
|
+
* (`emitsOnThreads`), that emits every file (one without old build info, or one that is not incremental)
|
|
809
|
+
* and that emits enough for the threads (`emitThreads`).
|
|
810
|
+
*/
|
|
811
|
+
private emitsOnThreads(checked: CheckedProgram, oldSnapshot: Snapshot | undefined): boolean {
|
|
812
|
+
const options = checked.program.options;
|
|
813
|
+
return (
|
|
814
|
+
emitsOnThreads(options) &&
|
|
815
|
+
(oldSnapshot === undefined || !isIncremental(options)) &&
|
|
816
|
+
emitThreads(checked.program, options.singleThreaded) > 0
|
|
817
|
+
);
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
/**
|
|
821
|
+
* The rest of `checkAndEmit` with one checker for a project that `emitsOnThreads` accepts, as `tsc -p` compiles
|
|
822
|
+
* (`compileWithEmitThreads`, tsc-compile.ts): this thread checks the program while emit threads emit its
|
|
823
|
+
* JavaScript, and the declaration thread its declarations where that pays (parallel-emit.ts). Where its pending
|
|
824
|
+
* emit leaves too little JavaScript for the threads (`emitDeclarationOnly`), this thread checks and emits it.
|
|
825
|
+
* Returns whether the threads emit, and then calls `then` once the project is emitted.
|
|
826
|
+
*/
|
|
827
|
+
private checkWhileThreadsEmit(
|
|
828
|
+
task: BuildTask,
|
|
829
|
+
checked: CheckedProgram,
|
|
830
|
+
times: CompileTimes,
|
|
831
|
+
oldSnapshot: Snapshot | undefined,
|
|
832
|
+
then: () => void,
|
|
833
|
+
): boolean {
|
|
834
|
+
const program = checked.program;
|
|
835
|
+
const options = program.options;
|
|
836
|
+
// The program is shared before its checker does more than merge the globals.
|
|
837
|
+
shareWithCheckers(checked);
|
|
838
|
+
const incrementalProgram = this.incrementalProgramOf(task, checked, times, oldSnapshot);
|
|
839
|
+
const emitKinds = emitKindsOf(incrementalProgram);
|
|
840
|
+
const threads = emitThreads(program, options.singleThreaded, emitKinds);
|
|
841
|
+
if (threads === 0) {
|
|
842
|
+
this.emitAndReport(task, checked, times, oldSnapshot, undefined, incrementalProgram);
|
|
843
|
+
return false;
|
|
844
|
+
}
|
|
845
|
+
checkWhileThreadsEmit(incrementalProgram, threads, emitKinds, (diagnostics) => {
|
|
846
|
+
this.emitAndReport(task, checked, times, oldSnapshot, undefined, incrementalProgram, diagnostics);
|
|
847
|
+
then();
|
|
848
|
+
});
|
|
849
|
+
return true;
|
|
850
|
+
}
|
|
851
|
+
|
|
799
852
|
/**
|
|
800
853
|
* The rest of `checkAndEmit` for a project with old build info on checker threads, as `tsc -p` rebuilds
|
|
801
854
|
* (`recheckInParallel`, tsc-compile.ts): the program is shared with the threads first, then the
|
|
@@ -869,22 +922,23 @@ export class Orchestrator {
|
|
|
869
922
|
oldSnapshot: Snapshot | undefined,
|
|
870
923
|
/** The wall time of checker threads that checked the program, as reported. */
|
|
871
924
|
parallelCheckTime: number | undefined,
|
|
872
|
-
/** The incremental program, where `recheckOnThreads` made it. */
|
|
925
|
+
/** The incremental program, where `recheckOnThreads` or `checkWhileThreadsEmit` made it. */
|
|
873
926
|
made?: IncrementalProgram,
|
|
927
|
+
/** The program's diagnostics, where `checkWhileThreadsEmit` collected them. */
|
|
928
|
+
diagnostics?: Diagnostic[],
|
|
874
929
|
): void {
|
|
875
930
|
const resolved = task.resolved!;
|
|
876
931
|
const sys = this.sys;
|
|
877
932
|
const program = checked.program;
|
|
878
933
|
const incrementalProgram = made ?? this.incrementalProgramOf(task, checked, times, oldSnapshot);
|
|
879
934
|
|
|
880
|
-
const
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
);
|
|
935
|
+
const reporter = new TaskDiagnosticReporter(task, this.reporter, sys, this.locale);
|
|
936
|
+
const summary = new QuietSummary(sys, {}, this.locale);
|
|
937
|
+
const writer = new TaskWriter(this, task);
|
|
938
|
+
const result =
|
|
939
|
+
diagnostics === undefined
|
|
940
|
+
? emitFilesAndReportErrors(sys, incrementalProgram, reporter, summary, writer, this.locale)
|
|
941
|
+
: reportEmitAndErrors(sys, incrementalProgram, diagnostics, reporter, summary, writer, this.locale);
|
|
888
942
|
task.exitStatus = exitStatusOf(result);
|
|
889
943
|
if (parallelCheckTime !== undefined) times.checkTime = parallelCheckTime;
|
|
890
944
|
const options = program.options;
|
package/src/compiler/tsc-cli.ts
CHANGED
|
@@ -199,6 +199,11 @@ export class DiagnosticReporter {
|
|
|
199
199
|
else this.sys.write(formatDiagnostic(diagnostic, this.format));
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
+
/** The format `reportAll` writes diagnostics in, where it writes them plainly; undefined otherwise. */
|
|
203
|
+
plainFormat(): DiagnosticFormatOptions | undefined {
|
|
204
|
+
return this.quiet || this.pretty ? undefined : this.format;
|
|
205
|
+
}
|
|
206
|
+
|
|
202
207
|
/** Writes the diagnostics at once: a write for each costs more than formatting it. */
|
|
203
208
|
reportAll(diagnostics: readonly Diagnostic[]): void {
|
|
204
209
|
if (this.quiet || diagnostics.length === 0) return;
|
|
@@ -11,9 +11,11 @@ import {
|
|
|
11
11
|
getDiagnosticsOfProgram,
|
|
12
12
|
OutputWriter,
|
|
13
13
|
PlainProgram,
|
|
14
|
+
recordMetadataKinds,
|
|
14
15
|
} from './compile-program.js';
|
|
15
|
-
import type
|
|
16
|
-
import { EmitResult } from './emitter.js';
|
|
16
|
+
import { type Diagnostic, formattedReports, type Locale } from './diagnostics.js';
|
|
17
|
+
import { EmitOnly, EmitResult } from './emitter.js';
|
|
18
|
+
import { type CompilerOptions, getEmitDeclarations } from './options.js';
|
|
17
19
|
import {
|
|
18
20
|
FileBuildInfoReader,
|
|
19
21
|
IncrementalProgram,
|
|
@@ -21,7 +23,21 @@ import {
|
|
|
21
23
|
type Snapshot,
|
|
22
24
|
TimeStampHost,
|
|
23
25
|
} from './incremental.js';
|
|
24
|
-
import {
|
|
26
|
+
import {
|
|
27
|
+
checkerThreads,
|
|
28
|
+
parallelCheck,
|
|
29
|
+
shareWithCheckers,
|
|
30
|
+
startParallelCheck,
|
|
31
|
+
traceSingleChecker,
|
|
32
|
+
} from './parallel-check.js';
|
|
33
|
+
import {
|
|
34
|
+
declarationThreadPays,
|
|
35
|
+
emitThreads,
|
|
36
|
+
startDeclarationErrorThread,
|
|
37
|
+
startDeclarationThread,
|
|
38
|
+
startMetadataEmit,
|
|
39
|
+
startParallelEmit,
|
|
40
|
+
} from './parallel-emit.js';
|
|
25
41
|
import { sharesPublishedGraphs } from '@scriptc/threads';
|
|
26
42
|
import { getNormalizedAbsolutePath } from './path.js';
|
|
27
43
|
import { sortAndDeduplicateDiagnostics } from './program.js';
|
|
@@ -122,6 +138,213 @@ export function compileThreads(_sys: System, work: CompileWork): number {
|
|
|
122
138
|
return checkerThreads(options.checkers, options.singleThreaded, work.program);
|
|
123
139
|
}
|
|
124
140
|
|
|
141
|
+
/** The number of threads to emit JavaScript on while this thread checks (`compileWithEmitThreads`), or 0. */
|
|
142
|
+
export function compileEmitThreads(work: CompileWork): number {
|
|
143
|
+
return emitThreads(work.program, work.program.options.singleThreaded);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Like `compile`, with this thread checking the program while `threads` threads emit its JavaScript
|
|
148
|
+
* (parallel-emit.ts); calls `done` with the exit status once it is emitted and reported. Returns
|
|
149
|
+
* false, and `compile` runs instead, where emit threads don't apply (`emitsOnThreads`) and for an
|
|
150
|
+
* incremental program with build info, whose rebuild emits what changed. An incremental program
|
|
151
|
+
* without build info emits every file, as its pending emit holds (`emitKindsOf`).
|
|
152
|
+
*/
|
|
153
|
+
export function compileWithEmitThreads(
|
|
154
|
+
sys: System,
|
|
155
|
+
work: CompileWork,
|
|
156
|
+
threads: number,
|
|
157
|
+
done: (status: ExitStatus) => void,
|
|
158
|
+
): boolean {
|
|
159
|
+
const program = work.program;
|
|
160
|
+
if (!emitsOnThreads(program.options)) return false;
|
|
161
|
+
if (work.incremental && !checksIncrementalOnThreads(sys, program.commandLine.buildInfoFileName())) return false;
|
|
162
|
+
const times = new CompileTimes();
|
|
163
|
+
times.configTime = work.configTime;
|
|
164
|
+
times.parseTime = work.parseTime;
|
|
165
|
+
const bindStart = performance.now();
|
|
166
|
+
const checked = new CheckedProgram(program);
|
|
167
|
+
times.bindTime = performance.now() - bindStart;
|
|
168
|
+
// The program is shared before its checker does more than merge the globals.
|
|
169
|
+
shareWithCheckers(checked);
|
|
170
|
+
let compilerProgram: CompilerProgram;
|
|
171
|
+
if (work.incremental) {
|
|
172
|
+
const old = oldSnapshotOf(sys, work, times);
|
|
173
|
+
const changesStart = performance.now();
|
|
174
|
+
compilerProgram = new IncrementalProgram(checked, times, old, new SystemTimeStamps(sys));
|
|
175
|
+
times.changesComputeTime = performance.now() - changesStart;
|
|
176
|
+
} else compilerProgram = new PlainProgram(checked, times);
|
|
177
|
+
const report = (diagnostics: Diagnostic[]): void => {
|
|
178
|
+
const result = reportEmitAndErrors(
|
|
179
|
+
sys,
|
|
180
|
+
compilerProgram,
|
|
181
|
+
diagnostics,
|
|
182
|
+
work.reporter,
|
|
183
|
+
work.errorSummary,
|
|
184
|
+
new SystemWriter(sys),
|
|
185
|
+
outputLocale(program.options),
|
|
186
|
+
);
|
|
187
|
+
traceSingleChecker(checked);
|
|
188
|
+
done(emitStatusAndReportStatistics(sys, compilerProgram, result));
|
|
189
|
+
};
|
|
190
|
+
const emitKinds = emitKindsOf(compilerProgram);
|
|
191
|
+
if (emitKinds !== undefined) threads = emitThreads(program, program.options.singleThreaded, emitKinds);
|
|
192
|
+
if (threads > 0) checkWhileThreadsEmit(compilerProgram, threads, emitKinds, report);
|
|
193
|
+
else {
|
|
194
|
+
const diagnostics = getDiagnosticsOfProgram(compilerProgram, false);
|
|
195
|
+
mark('diagnostics collected');
|
|
196
|
+
report(diagnostics);
|
|
197
|
+
}
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Whether emit threads (parallel-emit.ts) can emit a program with `options` while this thread checks it:
|
|
203
|
+
* not one that emits nothing or waits for its errors to emit (`noEmitOnError`), nor one that emits a
|
|
204
|
+
* single `outFile` from the whole program.
|
|
205
|
+
*/
|
|
206
|
+
export function emitsOnThreads(options: CompilerOptions): boolean {
|
|
207
|
+
return (
|
|
208
|
+
options.noEmit !== true &&
|
|
209
|
+
options.noEmitOnError !== true &&
|
|
210
|
+
options.listFilesOnly !== true &&
|
|
211
|
+
(options.outFile ?? '') === ''
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* What emit threads emit of each file of `program`, by file index (`emitsJavaScript`, parallel-emit.ts):
|
|
217
|
+
* for an incremental program that keeps incremental state, the emit pending before checking
|
|
218
|
+
* (`IncrementalProgram.emitKindsOnCheckers`), which checking only adds to and the program's emit
|
|
219
|
+
* completes; `undefined` where every file is emitted in full.
|
|
220
|
+
*/
|
|
221
|
+
export function emitKindsOf(program: CompilerProgram): number[] | undefined {
|
|
222
|
+
if (!(program instanceof IncrementalProgram) || !program.snapshot.canUseIncrementalState()) return undefined;
|
|
223
|
+
return program.emitKindsOnCheckers(program.program.getSourceFiles());
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Checks `compilerProgram` on this thread while `threads` emit threads emit the JavaScript of its files that
|
|
228
|
+
* `emitKinds` selects, and the declaration thread their declarations where that pays; then calls `report`
|
|
229
|
+
* with the program's diagnostics, once the outputs of every thread arrived for the program's emit to complete
|
|
230
|
+
* (`PlainProgram.emit`, `IncrementalProgram.emit`). The program must be shared (`shareWithCheckers`).
|
|
231
|
+
*/
|
|
232
|
+
export function checkWhileThreadsEmit(
|
|
233
|
+
compilerProgram: CompilerProgram,
|
|
234
|
+
threads: number,
|
|
235
|
+
emitKinds: readonly number[] | undefined,
|
|
236
|
+
report: (diagnostics: Diagnostic[]) => void,
|
|
237
|
+
): void {
|
|
238
|
+
const checked = compilerProgram.checked;
|
|
239
|
+
const program = checked.program;
|
|
240
|
+
let diagnostics: Diagnostic[] | undefined = undefined;
|
|
241
|
+
// The first wave of emit threads, and the declaration thread or the second wave.
|
|
242
|
+
let emitting = 2;
|
|
243
|
+
let declarations: (EmitResult | undefined)[] | undefined = undefined;
|
|
244
|
+
const reportOnce = (): void => {
|
|
245
|
+
if (diagnostics === undefined || emitting > 0) return;
|
|
246
|
+
if (declarations !== undefined) {
|
|
247
|
+
// The declaration thread emitted all of each decorator metadata file: its result is the file's emit.
|
|
248
|
+
for (const i of metadata) {
|
|
249
|
+
const result = declarations[i];
|
|
250
|
+
if (result === undefined) continue;
|
|
251
|
+
checked.emittedInParallel![i] = result;
|
|
252
|
+
declarations[i] = new EmitResult();
|
|
253
|
+
}
|
|
254
|
+
checked.declarationsEmittedAhead = declarations;
|
|
255
|
+
}
|
|
256
|
+
report(diagnostics);
|
|
257
|
+
};
|
|
258
|
+
const emitted = (): void => {
|
|
259
|
+
emitting--;
|
|
260
|
+
reportOnce();
|
|
261
|
+
};
|
|
262
|
+
const metadata = startParallelEmit(checked, threads, emitted, emitKinds);
|
|
263
|
+
// With declarations, the declaration thread also emits the files with decorator metadata.
|
|
264
|
+
if (getEmitDeclarations(program.options) && declarationThreadPays(1))
|
|
265
|
+
declarations = startDeclarationThread(checked, metadata, emitted, emitKinds);
|
|
266
|
+
const found = getDiagnosticsOfProgram(compilerProgram, false);
|
|
267
|
+
mark('diagnostics collected');
|
|
268
|
+
// Else they are emitted with the kinds this thread's checker gives, now that it checked.
|
|
269
|
+
if (declarations === undefined) {
|
|
270
|
+
if (metadata.length > 0) {
|
|
271
|
+
const files = program.getSourceFiles();
|
|
272
|
+
const kinds = recordMetadataKinds(
|
|
273
|
+
checked,
|
|
274
|
+
metadata.map((i) => files[i]!),
|
|
275
|
+
);
|
|
276
|
+
mark('metadata kinds recorded');
|
|
277
|
+
startMetadataEmit(checked, threads, metadata, kinds, emitted);
|
|
278
|
+
} else emitting--;
|
|
279
|
+
}
|
|
280
|
+
diagnostics = found;
|
|
281
|
+
reportOnce();
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Like `compile` for a `noEmit` program with declarations, which reports the errors of declaration emit:
|
|
286
|
+
* this thread checks the program while the declaration thread (`startDeclarationErrorThread`) finds the
|
|
287
|
+
* declaration errors of every file, then reports both; calls `done` with the exit status. Returns false
|
|
288
|
+
* where the declaration thread doesn't apply, and `compile` runs instead: an incremental program, one
|
|
289
|
+
* that waits for its errors (`noEmitOnError`), a program that isn't shared with threads, or one where a
|
|
290
|
+
* declaration thread doesn't pay (`declarationThreadPays`).
|
|
291
|
+
*/
|
|
292
|
+
export function compileWithDeclarationThread(
|
|
293
|
+
sys: System,
|
|
294
|
+
work: CompileWork,
|
|
295
|
+
done: (status: ExitStatus) => void,
|
|
296
|
+
): boolean {
|
|
297
|
+
const program = work.program;
|
|
298
|
+
const options = program.options;
|
|
299
|
+
if (
|
|
300
|
+
work.incremental ||
|
|
301
|
+
options.noEmit !== true ||
|
|
302
|
+
options.noEmitOnError === true ||
|
|
303
|
+
options.listFilesOnly === true ||
|
|
304
|
+
options.singleThreaded === true ||
|
|
305
|
+
!getEmitDeclarations(options) ||
|
|
306
|
+
parallelCheck.spawn === undefined ||
|
|
307
|
+
!sharesPublishedGraphs ||
|
|
308
|
+
!declarationThreadPays(1)
|
|
309
|
+
)
|
|
310
|
+
return false;
|
|
311
|
+
const times = new CompileTimes();
|
|
312
|
+
times.configTime = work.configTime;
|
|
313
|
+
times.parseTime = work.parseTime;
|
|
314
|
+
const bindStart = performance.now();
|
|
315
|
+
const checked = new CheckedProgram(program);
|
|
316
|
+
times.bindTime = performance.now() - bindStart;
|
|
317
|
+
shareWithCheckers(checked);
|
|
318
|
+
const compilerProgram = new PlainProgram(checked, times);
|
|
319
|
+
let diagnostics: Diagnostic[] | undefined = undefined;
|
|
320
|
+
let declaring = true;
|
|
321
|
+
const report = (): void => {
|
|
322
|
+
if (diagnostics === undefined || declaring) return;
|
|
323
|
+
const result = reportEmitAndErrors(
|
|
324
|
+
sys,
|
|
325
|
+
compilerProgram,
|
|
326
|
+
diagnostics,
|
|
327
|
+
work.reporter,
|
|
328
|
+
work.errorSummary,
|
|
329
|
+
new SystemWriter(sys),
|
|
330
|
+
outputLocale(options),
|
|
331
|
+
);
|
|
332
|
+
traceSingleChecker(checked);
|
|
333
|
+
done(emitStatusAndReportStatistics(sys, compilerProgram, result));
|
|
334
|
+
};
|
|
335
|
+
startDeclarationErrorThread(checked, (declarations) => {
|
|
336
|
+
// `PlainProgram.getDeclarationDiagnostics` reads them.
|
|
337
|
+
checked.declarationsInParallel = declarations;
|
|
338
|
+
declaring = false;
|
|
339
|
+
report();
|
|
340
|
+
});
|
|
341
|
+
// `PlainProgram.emit` reports the declaration errors once the thread has found them.
|
|
342
|
+
diagnostics = getDiagnosticsOfProgram(compilerProgram, false, true);
|
|
343
|
+
mark('diagnostics collected');
|
|
344
|
+
report();
|
|
345
|
+
return true;
|
|
346
|
+
}
|
|
347
|
+
|
|
125
348
|
/**
|
|
126
349
|
* Like `compile`, with `threads` checker threads (parallel-check.ts): calls `done` with the exit
|
|
127
350
|
* status once the threads have checked the program and it is emitted and reported.
|
|
@@ -137,6 +360,8 @@ export function compileInParallel(
|
|
|
137
360
|
times.configTime = work.configTime;
|
|
138
361
|
times.parseTime = work.parseTime;
|
|
139
362
|
const bindStart = performance.now();
|
|
363
|
+
// The checker threads format their diagnostics in the format the reporter writes them in.
|
|
364
|
+
formattedReports.format = work.reporter.plainFormat();
|
|
140
365
|
mark(`${threads} checkers`);
|
|
141
366
|
const checked = new CheckedProgram(program);
|
|
142
367
|
times.bindTime = performance.now() - bindStart;
|
|
@@ -176,6 +401,43 @@ export function compileInParallel(
|
|
|
176
401
|
};
|
|
177
402
|
const options = program.options;
|
|
178
403
|
if (!checking && (options.noEmit === true || options.noEmitOnError === true)) return finish(0);
|
|
404
|
+
if (
|
|
405
|
+
sharesPublishedGraphs &&
|
|
406
|
+
checking &&
|
|
407
|
+
!work.incremental &&
|
|
408
|
+
getEmitDeclarations(options) &&
|
|
409
|
+
options.noEmit !== true &&
|
|
410
|
+
options.noEmitOnError !== true &&
|
|
411
|
+
options.composite !== true &&
|
|
412
|
+
(options.outFile ?? '') === '' &&
|
|
413
|
+
declarationThreadPays(threads)
|
|
414
|
+
) {
|
|
415
|
+
// The checker threads emit JavaScript and the declaration thread declarations (parallel-emit.ts).
|
|
416
|
+
const kinds: number[] = [];
|
|
417
|
+
for (let i = 0; i < program.getSourceFiles().length; i++) kinds.push(EmitOnly.Js);
|
|
418
|
+
let pending = 2;
|
|
419
|
+
let checkTime = 0;
|
|
420
|
+
let declarations: (EmitResult | undefined)[] = [];
|
|
421
|
+
const joined = (): void => {
|
|
422
|
+
if (--pending > 0) return;
|
|
423
|
+
checked.javaScriptEmittedOnThreads = true;
|
|
424
|
+
checked.declarationsEmittedAhead = declarations;
|
|
425
|
+
finish(checkTime);
|
|
426
|
+
};
|
|
427
|
+
declarations = startDeclarationThread(checked, [], joined);
|
|
428
|
+
startParallelCheck(
|
|
429
|
+
checked,
|
|
430
|
+
threads,
|
|
431
|
+
(time) => {
|
|
432
|
+
checkTime = time;
|
|
433
|
+
joined();
|
|
434
|
+
},
|
|
435
|
+
true,
|
|
436
|
+
kinds,
|
|
437
|
+
checking,
|
|
438
|
+
);
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
179
441
|
startParallelCheck(checked, threads, finish, true, undefined, checking);
|
|
180
442
|
}
|
|
181
443
|
|
|
@@ -285,6 +547,19 @@ export function emitFilesAndReportErrors(
|
|
|
285
547
|
): CompileResult {
|
|
286
548
|
const diagnostics = getDiagnosticsOfProgram(program, false);
|
|
287
549
|
mark('diagnostics collected');
|
|
550
|
+
return reportEmitAndErrors(sys, program, diagnostics, reporter, errorSummary, writer, locale);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/** The rest of `emitFilesAndReportErrors`, with the program's `diagnostics` collected. */
|
|
554
|
+
export function reportEmitAndErrors(
|
|
555
|
+
sys: System,
|
|
556
|
+
program: CompilerProgram,
|
|
557
|
+
diagnostics: Diagnostic[],
|
|
558
|
+
reporter: DiagnosticReporter,
|
|
559
|
+
errorSummary: ErrorSummaryReporter,
|
|
560
|
+
writer: OutputWriter,
|
|
561
|
+
locale: Locale,
|
|
562
|
+
): CompileResult {
|
|
288
563
|
let emitResult = new EmitResult();
|
|
289
564
|
emitResult.emitSkipped = true;
|
|
290
565
|
if (program.options.listFilesOnly !== true) {
|
|
@@ -70,3 +70,26 @@ export function programDiagnostics(
|
|
|
70
70
|
return [];
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* What `semantic` answers for each of `files` and what `global` answers, after checking `files` and
|
|
76
|
+
* no other file. Checking one file can add diagnostics located in another, so every file is checked
|
|
77
|
+
* before any file's diagnostics are collected. With every file of the program listed, the answers are
|
|
78
|
+
* those of the full check.
|
|
79
|
+
*/
|
|
80
|
+
export function checkedFileDiagnostics(
|
|
81
|
+
checked: CheckedProgram,
|
|
82
|
+
files: readonly SourceFile[],
|
|
83
|
+
): { files: (readonly CompilerDiagnostic[])[]; global: readonly CompilerDiagnostic[] } {
|
|
84
|
+
for (const file of files) checked.getSemanticDiagnostics(file);
|
|
85
|
+
const program = checked.program;
|
|
86
|
+
const global = [
|
|
87
|
+
...program.getConfigFileParsingDiagnostics(),
|
|
88
|
+
...program.getProgramDiagnostics(),
|
|
89
|
+
...checked.getGlobalDiagnostics(),
|
|
90
|
+
];
|
|
91
|
+
return {
|
|
92
|
+
files: files.map((file) => checked.getSemanticDiagnostics(file)),
|
|
93
|
+
global: sortAndDeduplicateDiagnostics(global).filter((d) => d.file === undefined),
|
|
94
|
+
};
|
|
95
|
+
}
|