tsc-ts 0.1.1 → 0.1.2
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 +6 -0
- package/dist/api/compiler/ast.d.ts +6 -0
- package/dist/api/compiler/ast.js +19 -3
- package/dist/api/compiler/checker-grammar.d.ts +39 -4
- package/dist/api/compiler/checker-grammar.js +239 -75
- package/dist/api/compiler/checker-heritage.js +20 -14
- package/dist/api/compiler/checker-modules.js +4 -2
- package/dist/api/compiler/checker-source-file.js +1 -1
- package/dist/api/compiler/checker-type-factory.js +17 -7
- package/dist/api/compiler/checker-type-nodes.d.ts +1 -1
- package/dist/api/compiler/checker-type-nodes.js +5 -5
- package/dist/api/compiler/checker-unused.js +15 -10
- package/dist/api/compiler/checker.d.ts +2 -0
- package/dist/api/compiler/checker.js +4 -0
- package/dist/api/compiler/file-loader.d.ts +5 -0
- package/dist/api/compiler/file-loader.js +7 -0
- package/dist/api/compiler/program-checker.d.ts +18 -0
- package/dist/api/compiler/program-checker.js +27 -0
- package/package.json +14 -9
- package/src/compiler/ast.ts +20 -3
- package/src/compiler/checker-grammar.ts +247 -88
- package/src/compiler/checker-heritage.ts +31 -17
- package/src/compiler/checker-modules.ts +4 -2
- package/src/compiler/checker-source-file.ts +1 -1
- package/src/compiler/checker-type-factory.ts +14 -7
- package/src/compiler/checker-type-nodes.ts +5 -5
- package/src/compiler/checker-unused.ts +13 -8
- package/src/compiler/checker.ts +4 -0
- package/src/compiler/file-loader.ts +8 -0
- package/src/compiler/parallel-check.ts +11 -0
- package/src/compiler/parse-thread.ts +24 -2
- package/src/compiler/program-checker.ts +28 -0
- package/src/compiler/tsc-compile.ts +10 -1
|
@@ -965,16 +965,25 @@ const enum MemberKind {
|
|
|
965
965
|
* (with `checkPrivateNames`) private names shared by static and instance members.
|
|
966
966
|
*/
|
|
967
967
|
export function checkObjectTypeForDuplicateDeclarations(c: Checker, node: Node, checkPrivateNames: boolean): void {
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
968
|
+
// Only a symbol with several declarations can be a duplicate, so the maps are created for the first one.
|
|
969
|
+
let instanceNames: Map<string, MemberKind> | undefined;
|
|
970
|
+
let staticNames: Map<string, MemberKind> | undefined;
|
|
971
|
+
let privateNames: Map<string, number> | undefined;
|
|
971
972
|
const nodeInAmbientContext = (node.flags & NodeFlags.Ambient) !== 0;
|
|
972
973
|
for (const member of getMembers(node)!.nodes) {
|
|
973
974
|
if (member.kind === SyntaxKind.Constructor) {
|
|
974
975
|
for (const param of getParameters(member)!.nodes)
|
|
975
976
|
if (isParameterPropertyDeclaration(param, member) && !isBindingPattern(getName(param))) {
|
|
976
977
|
const symbol = getSymbolOfDeclaration(c, param);
|
|
977
|
-
if (symbol !== undefined
|
|
978
|
+
if (symbol !== undefined && declarationCount(symbol) > 1)
|
|
979
|
+
checkPropertyOrAccessor(
|
|
980
|
+
c,
|
|
981
|
+
node,
|
|
982
|
+
(instanceNames ??= new Map<string, MemberKind>()),
|
|
983
|
+
symbol,
|
|
984
|
+
MemberKind.Property,
|
|
985
|
+
false,
|
|
986
|
+
);
|
|
978
987
|
}
|
|
979
988
|
continue;
|
|
980
989
|
}
|
|
@@ -988,21 +997,26 @@ export function checkObjectTypeForDuplicateDeclarations(c: Checker, node: Node,
|
|
|
988
997
|
symbol.name,
|
|
989
998
|
symbolToString(c, getSymbolOfDeclaration(c, node)!),
|
|
990
999
|
);
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
member
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1000
|
+
if (declarationCount(symbol) > 1) {
|
|
1001
|
+
const names = memberIsStatic
|
|
1002
|
+
? (staticNames ??= new Map<string, MemberKind>())
|
|
1003
|
+
: (instanceNames ??= new Map<string, MemberKind>());
|
|
1004
|
+
const hasAccessorModifier = hasSyntacticModifier(member, ModifierFlags.Accessor);
|
|
1005
|
+
if (
|
|
1006
|
+
(member.kind === SyntaxKind.PropertyDeclaration && !hasAccessorModifier) ||
|
|
1007
|
+
member.kind === SyntaxKind.PropertySignature
|
|
1008
|
+
)
|
|
1009
|
+
checkPropertyOrAccessor(c, node, names, symbol, MemberKind.Property, memberIsStatic);
|
|
1010
|
+
else if (
|
|
1011
|
+
member.kind === SyntaxKind.GetAccessor ||
|
|
1012
|
+
member.kind === SyntaxKind.SetAccessor ||
|
|
1013
|
+
(member.kind === SyntaxKind.PropertyDeclaration && hasAccessorModifier)
|
|
1014
|
+
)
|
|
1015
|
+
checkPropertyOrAccessor(c, node, names, symbol, MemberKind.Accessor, memberIsStatic);
|
|
1016
|
+
}
|
|
1004
1017
|
const name = getName(member);
|
|
1005
1018
|
if (checkPrivateNames && name !== undefined && name.kind === SyntaxKind.PrivateIdentifier) {
|
|
1019
|
+
privateNames ??= new Map<string, number>();
|
|
1006
1020
|
let flags = privateNames.get(symbol.name) ?? 0;
|
|
1007
1021
|
if (flags === 3) continue;
|
|
1008
1022
|
flags |= isStatic(member) ? 2 : 1;
|
|
@@ -2167,14 +2167,16 @@ function getSymbolFlagsEx(
|
|
|
2167
2167
|
excludeTypeOnlyMeanings: boolean,
|
|
2168
2168
|
excludeLocalMeanings: boolean,
|
|
2169
2169
|
): SymbolFlags {
|
|
2170
|
-
|
|
2170
|
+
// Only a chain of aliases needs the set, so most calls never create it.
|
|
2171
|
+
let seen: Set<Symbol> | undefined;
|
|
2171
2172
|
let flags = excludeLocalMeanings ? SymbolFlags.None : symbol.flags;
|
|
2172
2173
|
while ((symbol.flags & SymbolFlags.Alias) !== 0) {
|
|
2173
2174
|
if (excludeTypeOnlyMeanings && getTypeOnlyAliasDeclaration(c, symbol) !== undefined) break;
|
|
2174
2175
|
const target = getExportSymbolOfValueSymbolIfExported(c, resolveAlias(c, symbol));
|
|
2175
2176
|
if (target === c.unknownSymbol) return SymbolFlags.All;
|
|
2176
2177
|
if ((target.flags & SymbolFlags.Alias) !== 0) {
|
|
2177
|
-
if (target === symbol || seen
|
|
2178
|
+
if (target === symbol || seen?.has(target)) break;
|
|
2179
|
+
seen ??= new Set<Symbol>();
|
|
2178
2180
|
seen.add(symbol);
|
|
2179
2181
|
seen.add(target);
|
|
2180
2182
|
}
|
|
@@ -639,7 +639,7 @@ function checkTypeMemberAccessor(c: Checker, node: Node): void {
|
|
|
639
639
|
/** Variadic tuple elements must be array-like. */
|
|
640
640
|
function checkTupleRestElements(c: Checker, node: TupleTypeNode): void {
|
|
641
641
|
for (const e of node.elements.nodes) {
|
|
642
|
-
if ((getTupleElementFlags(
|
|
642
|
+
if ((getTupleElementFlags(e) & ElementFlags.Variadic) === 0) continue;
|
|
643
643
|
if (!isArrayLikeType(c, getTypeFromTypeNode(c, getType(e)!))) {
|
|
644
644
|
c.error(e, Diagnostics.A_rest_element_type_must_be_an_array_type);
|
|
645
645
|
return;
|
|
@@ -1765,20 +1765,26 @@ export function getIntersectionType(c: Checker, types: Type[]): Type {
|
|
|
1765
1765
|
return getIntersectionTypeEx(c, types, IntersectionFlags.None, undefined);
|
|
1766
1766
|
}
|
|
1767
1767
|
|
|
1768
|
+
/**
|
|
1769
|
+
* The distinct types of an intersection, in the order they were added. Most intersections have a few
|
|
1770
|
+
* types, which a scan of `values` finds faster than a `Set` costs to build, so the set is created only
|
|
1771
|
+
* once the list grows past `INDEX_AFTER`.
|
|
1772
|
+
*/
|
|
1768
1773
|
class OrderedTypeSet {
|
|
1774
|
+
private static readonly INDEX_AFTER = 8;
|
|
1769
1775
|
readonly values: Type[] = [];
|
|
1770
|
-
private
|
|
1776
|
+
private index: Set<Type> | undefined;
|
|
1771
1777
|
includes = 0;
|
|
1772
1778
|
|
|
1773
1779
|
has(t: Type): boolean {
|
|
1774
|
-
return this.
|
|
1780
|
+
return this.index !== undefined ? this.index.has(t) : this.values.includes(t);
|
|
1775
1781
|
}
|
|
1776
1782
|
|
|
1777
1783
|
add(t: Type): void {
|
|
1778
|
-
if (
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1784
|
+
if (this.has(t)) return;
|
|
1785
|
+
this.values.push(t);
|
|
1786
|
+
if (this.index !== undefined) this.index.add(t);
|
|
1787
|
+
else if (this.values.length > OrderedTypeSet.INDEX_AFTER) this.index = new Set(this.values);
|
|
1782
1788
|
}
|
|
1783
1789
|
}
|
|
1784
1790
|
|
|
@@ -2153,7 +2159,8 @@ function addCrossProductIntersections(
|
|
|
2153
2159
|
intersections: Type[],
|
|
2154
2160
|
): void {
|
|
2155
2161
|
if (index === types.length) {
|
|
2156
|
-
|
|
2162
|
+
// getIntersectionTypeEx copies the types it keeps, so the buffer is reused for the next combination.
|
|
2163
|
+
const t = getIntersectionTypeEx(c, constituents, flags, undefined);
|
|
2157
2164
|
if ((t.flags & TypeFlags.Never) === 0) intersections.push(t);
|
|
2158
2165
|
return;
|
|
2159
2166
|
}
|
|
@@ -882,7 +882,7 @@ function getTypeFromTypeQueryNode(c: Checker, node: Node): Type {
|
|
|
882
882
|
return type;
|
|
883
883
|
}
|
|
884
884
|
|
|
885
|
-
export function getTupleElementFlags(
|
|
885
|
+
export function getTupleElementFlags(node: Node): ElementFlags {
|
|
886
886
|
switch (node.kind) {
|
|
887
887
|
case SyntaxKind.OptionalType:
|
|
888
888
|
return ElementFlags.Optional;
|
|
@@ -901,9 +901,9 @@ export function getTupleElementFlags(c: Checker, node: Node): ElementFlags {
|
|
|
901
901
|
return ElementFlags.Required;
|
|
902
902
|
}
|
|
903
903
|
|
|
904
|
-
function getTupleElementInfo(
|
|
904
|
+
function getTupleElementInfo(node: Node): TupleElementInfo {
|
|
905
905
|
return new TupleElementInfo(
|
|
906
|
-
getTupleElementFlags(
|
|
906
|
+
getTupleElementFlags(node),
|
|
907
907
|
node.kind === SyntaxKind.NamedTupleMember || node.kind === SyntaxKind.Parameter ? node : undefined,
|
|
908
908
|
);
|
|
909
909
|
}
|
|
@@ -934,7 +934,7 @@ function getArrayOrTupleTargetType(c: Checker, node: Node): Type {
|
|
|
934
934
|
parent.kind === SyntaxKind.TypeOperator && (parent as TypeOperatorNode).operator === SyntaxKind.ReadonlyKeyword;
|
|
935
935
|
if (getArrayElementTypeNode(node) !== undefined) return readonly ? c.globalReadonlyArrayType : c.globalArrayType;
|
|
936
936
|
const elementInfos: TupleElementInfo[] = [];
|
|
937
|
-
for (const e of (node as TupleTypeNode).elements.nodes) elementInfos.push(getTupleElementInfo(
|
|
937
|
+
for (const e of (node as TupleTypeNode).elements.nodes) elementInfos.push(getTupleElementInfo(e));
|
|
938
938
|
return getTupleTargetType(c, elementInfos, readonly);
|
|
939
939
|
}
|
|
940
940
|
|
|
@@ -969,7 +969,7 @@ function getTypeFromArrayOrTupleTypeNode(c: Checker, node: Node): Type {
|
|
|
969
969
|
}
|
|
970
970
|
|
|
971
971
|
function hasVariadicTupleElement(c: Checker, node: TupleTypeNode): boolean {
|
|
972
|
-
for (const e of node.elements.nodes) if ((getTupleElementFlags(
|
|
972
|
+
for (const e of node.elements.nodes) if ((getTupleElementFlags(e) & ElementFlags.Variadic) !== 0) return true;
|
|
973
973
|
return false;
|
|
974
974
|
}
|
|
975
975
|
|
|
@@ -421,8 +421,9 @@ function checkUnusedClassMembers(c: Checker, node: Node): void {
|
|
|
421
421
|
function checkUnusedLocalsAndParameters(c: Checker, node: Node): void {
|
|
422
422
|
const locals = getLocals(node);
|
|
423
423
|
if (locals === undefined) return;
|
|
424
|
-
|
|
425
|
-
|
|
424
|
+
// Created on the first unused declaration: most scopes have none.
|
|
425
|
+
let variableParents: Set<Node> | undefined;
|
|
426
|
+
let importClauses: Map<Node, Node[]> | undefined;
|
|
426
427
|
for (const local of locals.values()) {
|
|
427
428
|
const referenceKinds = c.symbolReferenceKinds.get(getSymbolId(local));
|
|
428
429
|
if ((local.flags & SymbolFlags.TypeParameter) !== 0) {
|
|
@@ -438,6 +439,7 @@ function checkUnusedLocalsAndParameters(c: Checker, node: Node): void {
|
|
|
438
439
|
case SyntaxKind.VariableDeclaration:
|
|
439
440
|
case SyntaxKind.Parameter:
|
|
440
441
|
case SyntaxKind.BindingElement:
|
|
442
|
+
variableParents ??= new Set<Node>();
|
|
441
443
|
variableParents.add(getRootDeclaration(declaration).parent!);
|
|
442
444
|
break;
|
|
443
445
|
case SyntaxKind.ImportClause:
|
|
@@ -445,6 +447,7 @@ function checkUnusedLocalsAndParameters(c: Checker, node: Node): void {
|
|
|
445
447
|
case SyntaxKind.NamespaceImport:
|
|
446
448
|
if (!isIdentifierThatStartsWithUnderscore(getName(declaration))) {
|
|
447
449
|
const importClause = importClauseFromImported(declaration);
|
|
450
|
+
importClauses ??= new Map<Node, Node[]>();
|
|
448
451
|
const unuseds = importClauses.get(importClause);
|
|
449
452
|
if (unuseds === undefined) importClauses.set(importClause, [declaration]);
|
|
450
453
|
else unuseds.push(declaration);
|
|
@@ -456,12 +459,14 @@ function checkUnusedLocalsAndParameters(c: Checker, node: Node): void {
|
|
|
456
459
|
}
|
|
457
460
|
}
|
|
458
461
|
}
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
462
|
+
if (variableParents !== undefined)
|
|
463
|
+
for (const declaration of variableParents) {
|
|
464
|
+
if (declaration.kind === SyntaxKind.VariableDeclarationList)
|
|
465
|
+
reportUnusedVariables(c, declaration, (declaration as VariableDeclarationList).declarations.nodes);
|
|
466
|
+
else reportUnusedVariableDeclarations(c, getParameters(declaration)!.nodes);
|
|
467
|
+
}
|
|
468
|
+
if (importClauses !== undefined)
|
|
469
|
+
for (const [declaration, unuseds] of importClauses) reportUnusedImports(c, declaration as ImportClause, unuseds);
|
|
465
470
|
}
|
|
466
471
|
|
|
467
472
|
function reportUnusedLocal(c: Checker, node: Node, name: string): void {
|
package/src/compiler/checker.ts
CHANGED
|
@@ -411,6 +411,8 @@ export class Checker implements TypeChecking {
|
|
|
411
411
|
// Counters for type and signature ids.
|
|
412
412
|
typeCount = 0;
|
|
413
413
|
signatureCount = 0;
|
|
414
|
+
/** Transient symbols the checker created (statistics), as tsgo's `Checker.SymbolCount`. */
|
|
415
|
+
symbolCount = 0;
|
|
414
416
|
/** Positions of members by name in the tables and lists that lazily instantiated members come from. */
|
|
415
417
|
readonly memberPositionsInLists = new Map<Symbol[], Map<string, number>>();
|
|
416
418
|
/** The property names of the last instantiation of each such list whose table is built on demand. */
|
|
@@ -1173,11 +1175,13 @@ export class Checker implements TypeChecking {
|
|
|
1173
1175
|
}
|
|
1174
1176
|
|
|
1175
1177
|
newSymbol(flags: SymbolFlags, name: string): Symbol {
|
|
1178
|
+
this.symbolCount++;
|
|
1176
1179
|
const symbol = new Symbol(flags | SymbolFlags.Transient, name);
|
|
1177
1180
|
return symbol;
|
|
1178
1181
|
}
|
|
1179
1182
|
|
|
1180
1183
|
newSymbolWithCheckFlags(flags: SymbolFlags, name: string, checkFlags: CheckFlags): Symbol {
|
|
1184
|
+
this.symbolCount++;
|
|
1181
1185
|
const symbol = new Symbol(flags | SymbolFlags.Transient, name);
|
|
1182
1186
|
symbol.checkFlags = checkFlags;
|
|
1183
1187
|
return symbol;
|
|
@@ -131,6 +131,12 @@ export class CompilerHost extends ModuleResolutionHost {
|
|
|
131
131
|
return this.fs.getAccessibleEntries(path).directories;
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
/**
|
|
135
|
+
* The metadata of the file `FileLoader` is parsing, which it computes from the file's package scope
|
|
136
|
+
* before it parses it; a host that walks the grammar of the parsed file reads it (parse-thread.ts).
|
|
137
|
+
*/
|
|
138
|
+
loadingSourceFileMetadata: SourceFileMetadata | undefined = undefined;
|
|
139
|
+
|
|
134
140
|
/** Parses a file, or returns `undefined` if it can't be read. */
|
|
135
141
|
getSourceFile(
|
|
136
142
|
fileName: string,
|
|
@@ -1222,6 +1228,8 @@ export class FileLoader {
|
|
|
1222
1228
|
? libFileMetadata
|
|
1223
1229
|
: (loaded?.metadata ?? this.loadSourceFileMetadata(task.normalizedFilePath));
|
|
1224
1230
|
const options = this.mapper.getCompilerOptionsForFile(task.path, task.normalizedFilePath);
|
|
1231
|
+
// For the host that walks the grammar of the file as it parses it (parse-thread.ts).
|
|
1232
|
+
this.host.loadingSourceFileMetadata = task.metadata;
|
|
1225
1233
|
const file = this.host.getSourceFile(
|
|
1226
1234
|
task.normalizedFilePath,
|
|
1227
1235
|
task.path,
|
|
@@ -199,6 +199,11 @@ export class CheckerResult {
|
|
|
199
199
|
readonly units: number[] = [],
|
|
200
200
|
/** Those of `units` after which its checker had diagnostics in their file (`checkSourceFileRange`). */
|
|
201
201
|
readonly reportingUnits: number[] = [],
|
|
202
|
+
/**
|
|
203
|
+
* The types, instantiations and transient symbols its checker created, which `--diagnostics` adds to
|
|
204
|
+
* the main thread's (`CheckedProgram.addCheckerCounts`); empty for a result without a checker of its own.
|
|
205
|
+
*/
|
|
206
|
+
readonly counts: number[] = [],
|
|
202
207
|
) {}
|
|
203
208
|
}
|
|
204
209
|
|
|
@@ -243,6 +248,7 @@ export type PackedResult = {
|
|
|
243
248
|
readonly reserved: number[];
|
|
244
249
|
readonly units: Int32Array;
|
|
245
250
|
readonly reportingUnits: Int32Array;
|
|
251
|
+
readonly counts: number[];
|
|
246
252
|
};
|
|
247
253
|
|
|
248
254
|
class ResultPacker {
|
|
@@ -346,6 +352,7 @@ export function packResult(result: CheckerResult, program: Program): PackedResul
|
|
|
346
352
|
reserved: result.reserved,
|
|
347
353
|
units: Int32Array.from(result.units),
|
|
348
354
|
reportingUnits: Int32Array.from(result.reportingUnits),
|
|
355
|
+
counts: result.counts,
|
|
349
356
|
};
|
|
350
357
|
}
|
|
351
358
|
|
|
@@ -475,6 +482,7 @@ export function unpackResult(
|
|
|
475
482
|
emits,
|
|
476
483
|
Array.from(packed.units),
|
|
477
484
|
Array.from(packed.reportingUnits),
|
|
485
|
+
packed.counts,
|
|
478
486
|
);
|
|
479
487
|
}
|
|
480
488
|
|
|
@@ -1928,6 +1936,7 @@ export function checkFromQueue(
|
|
|
1928
1936
|
emits,
|
|
1929
1937
|
unitsDone,
|
|
1930
1938
|
reportingUnits,
|
|
1939
|
+
onMainThread ? [] : [checked.checker.typeCount, checked.checker.totalInstantiations, checked.checker.symbolCount],
|
|
1931
1940
|
);
|
|
1932
1941
|
}
|
|
1933
1942
|
|
|
@@ -2326,6 +2335,7 @@ export function startParallelCheck(
|
|
|
2326
2335
|
done(performance.now() - start);
|
|
2327
2336
|
};
|
|
2328
2337
|
const record = (result: CheckerResult): void => {
|
|
2338
|
+
checked.addCheckerCounts(result.counts);
|
|
2329
2339
|
if (declarationsTo !== undefined) {
|
|
2330
2340
|
for (let k = 0; k < result.declarations.length; k++) declarationsTo[result.files[k]!] = result.declarations[k]!;
|
|
2331
2341
|
if (trace)
|
|
@@ -2569,6 +2579,7 @@ class Revival {
|
|
|
2569
2579
|
copy.emits.map((emit) => this.emit(emit)),
|
|
2570
2580
|
copy.units,
|
|
2571
2581
|
copy.reportingUnits,
|
|
2582
|
+
copy.counts,
|
|
2572
2583
|
);
|
|
2573
2584
|
}
|
|
2574
2585
|
|
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
import { publish } from '@scriptc/threads';
|
|
7
7
|
import { type ExternalModuleIndicatorOptions, ParseOptions, ScriptKind, type SourceFile } from './ast.js';
|
|
8
8
|
import { bindSourceFile } from './binder.js';
|
|
9
|
+
import { checkGrammarSourceFileInParseThread } from './checker-grammar.js';
|
|
9
10
|
import { useThreadTextCaches } from './diagnostics.js';
|
|
10
11
|
import { CompilerHost, FileLoader } from './file-loader.js';
|
|
11
12
|
import { computeHash } from './incremental.js';
|
|
12
|
-
import { isIncremental } from './options.js';
|
|
13
|
+
import { type CompilerOptions, isIncremental } from './options.js';
|
|
13
14
|
import type { FileSystem } from './file-system.js';
|
|
14
15
|
import {
|
|
15
16
|
fileSize,
|
|
@@ -29,6 +30,18 @@ class PreparingHost extends CompilerHost {
|
|
|
29
30
|
prepared: PreparedFile[] = [];
|
|
30
31
|
/** Whether the files' build info versions are computed (an incremental program). */
|
|
31
32
|
computesVersions = false;
|
|
33
|
+
/**
|
|
34
|
+
* Whether the files the loader parses here run their grammar checks before they are published. The
|
|
35
|
+
* walk is the checker's, run off the checking threads (checker-grammar.ts).
|
|
36
|
+
*/
|
|
37
|
+
grammarChecks = true;
|
|
38
|
+
/** The program's options, which the grammar checks of a file are given. */
|
|
39
|
+
readonly options: CompilerOptions;
|
|
40
|
+
|
|
41
|
+
constructor(fs: FileSystem, currentDirectory: string, defaultLibraryPath: string, options: CompilerOptions) {
|
|
42
|
+
super(fs, currentDirectory, defaultLibraryPath);
|
|
43
|
+
this.options = options;
|
|
44
|
+
}
|
|
32
45
|
readMs = 0;
|
|
33
46
|
parseMs = 0;
|
|
34
47
|
bindMs = 0;
|
|
@@ -49,6 +62,12 @@ class PreparingHost extends CompilerHost {
|
|
|
49
62
|
);
|
|
50
63
|
const t2 = timeline ? performance.now() : 0;
|
|
51
64
|
bindSourceFile(file);
|
|
65
|
+
// The checker does not check the declaration files `skipLibCheck` names, so it does not walk their
|
|
66
|
+
// grammar either. The walk reads the metadata the loader computed for the file, which is the one the
|
|
67
|
+
// checking thread reads it with, so it looks up no package.json the load has not looked up.
|
|
68
|
+
const metadata = this.loadingSourceFileMetadata;
|
|
69
|
+
if (this.grammarChecks && metadata !== undefined && !(this.options.skipLibCheck === true && file.isDeclarationFile))
|
|
70
|
+
checkGrammarSourceFileInParseThread(file, this.options, metadata);
|
|
52
71
|
// Published now, while its nodes are in cache: the chunk's publish (`ParseThread.load`) then skips
|
|
53
72
|
// them, where walking the whole chunk's files at once reads each node from memory again.
|
|
54
73
|
publish(file);
|
|
@@ -85,11 +104,14 @@ export class ParseThread {
|
|
|
85
104
|
private sentPackageJsons = 0;
|
|
86
105
|
|
|
87
106
|
constructor(config: ParsedCommandLine, fs: FileSystem, currentDirectory: string, defaultLibraryPath: string) {
|
|
88
|
-
this.host = new PreparingHost(fs, currentDirectory, defaultLibraryPath);
|
|
107
|
+
this.host = new PreparingHost(fs, currentDirectory, defaultLibraryPath, config.options);
|
|
89
108
|
// The versions of an incremental program's files are computed here rather than one after another
|
|
90
109
|
// on the main thread (programToSnapshot, incremental.ts).
|
|
91
110
|
this.host.computesVersions = isIncremental(config.options);
|
|
92
111
|
this.loader = new FileLoader(this.host, config);
|
|
112
|
+
// A program that does not check has no grammar diagnostics to report. An incremental program checks
|
|
113
|
+
// the files a change affects and parses all of them, so the walk stays with the checker there.
|
|
114
|
+
this.host.grammarChecks = config.options.noCheck !== true && !isIncremental(config.options);
|
|
93
115
|
// The files this thread loads are published with their chunk: text caches it computes later (of
|
|
94
116
|
// declaration files, which the parser leaves out) go to copies.
|
|
95
117
|
useThreadTextCaches();
|
|
@@ -248,6 +248,28 @@ export class CheckedProgram {
|
|
|
248
248
|
this.reportingChecker = undefined;
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
+
/** Adds the counts a checker thread sent (`CheckerResult.counts`): types, instantiations, symbols. */
|
|
252
|
+
addCheckerCounts(counts: readonly number[]): void {
|
|
253
|
+
if (counts.length < 3) return;
|
|
254
|
+
this.threadTypeCount += counts[0]!;
|
|
255
|
+
this.threadInstantiations += counts[1]!;
|
|
256
|
+
this.threadSymbolCount += counts[2]!;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* The types, instantiations and transient symbols of every checker of the program: this thread's and
|
|
261
|
+
* the checker threads', as tsgo's `Program.TypeCount`, `InstantiationCount` and `SymbolCount` add them up.
|
|
262
|
+
* Reading them doesn't create this thread's checker.
|
|
263
|
+
*/
|
|
264
|
+
checkerCounts(): { types: number; instantiations: number; symbols: number } {
|
|
265
|
+
const own = this.reportingChecker;
|
|
266
|
+
return {
|
|
267
|
+
types: (own === undefined ? 0 : own.typeCount) + this.threadTypeCount,
|
|
268
|
+
instantiations: (own === undefined ? 0 : own.totalInstantiations) + this.threadInstantiations,
|
|
269
|
+
symbols: (own === undefined ? 0 : own.symbolCount) + this.threadSymbolCount,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
|
|
251
273
|
getBindDiagnostics(file: SourceFile | undefined): Diagnostic[] {
|
|
252
274
|
return this.collect(file, (f) => f.bindDiagnostics);
|
|
253
275
|
}
|
|
@@ -272,6 +294,12 @@ export class CheckedProgram {
|
|
|
272
294
|
*/
|
|
273
295
|
referenceThreads = 1;
|
|
274
296
|
readonly parallelGlobalDiagnostics: Diagnostic[] = [];
|
|
297
|
+
/** The types checker threads created (`CheckerResult.counts`), which `--diagnostics` adds to `checker`'s. */
|
|
298
|
+
threadTypeCount = 0;
|
|
299
|
+
/** The instantiations checker threads made. */
|
|
300
|
+
threadInstantiations = 0;
|
|
301
|
+
/** The transient symbols checker threads created. */
|
|
302
|
+
threadSymbolCount = 0;
|
|
275
303
|
/**
|
|
276
304
|
* Whether the semantic diagnostics of a file include the global diagnostics its checker found while
|
|
277
305
|
* checking it, as an incremental program caches them (IncrementalProgram). Such a program doesn't report
|
|
@@ -878,6 +878,8 @@ export class Statistics {
|
|
|
878
878
|
rows.push([prefix + 'Types', String(this.types)]);
|
|
879
879
|
rows.push([prefix + 'Instantiations', String(this.instantiations)]);
|
|
880
880
|
rows.push([prefix + 'Memory used', `${Math.floor(this.memoryUsed / 1024)}K`]);
|
|
881
|
+
// The table has tsgo's rows. No runtime counter matches its allocation count (runtime.MemStats.Mallocs),
|
|
882
|
+
// so this one stays 0.
|
|
881
883
|
rows.push([prefix + 'Memory allocs', String(this.memoryAllocs)]);
|
|
882
884
|
const t = this.times;
|
|
883
885
|
if (t.configTime !== 0) rows.push([prefix + 'Config time', formatDuration(t.configTime)]);
|
|
@@ -916,7 +918,14 @@ export function statisticsOf(compilerProgram: CompilerProgram): Statistics {
|
|
|
916
918
|
statistics.identifiers += file.identifierCount;
|
|
917
919
|
statistics.symbols += file.symbolCount;
|
|
918
920
|
}
|
|
919
|
-
|
|
921
|
+
// Every checker's counts, the checker threads' included, as tsgo's statisticsFromProgram reports them.
|
|
922
|
+
const counts = compilerProgram.checked.checkerCounts();
|
|
923
|
+
statistics.symbols += counts.symbols;
|
|
924
|
+
statistics.types = counts.types;
|
|
925
|
+
statistics.instantiations = counts.instantiations;
|
|
926
|
+
// tsgo reports the Go heap in use (runtime.MemStats.Alloc); the closest this runtime has is the
|
|
927
|
+
// process's resident set, which includes the checker threads' heaps.
|
|
928
|
+
statistics.memoryUsed = process.memoryUsage.rss();
|
|
920
929
|
const t = statistics.times;
|
|
921
930
|
const source = compilerProgram.times;
|
|
922
931
|
t.configTime = source.configTime;
|