tsc-ts 0.1.1 → 0.1.3

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.
Files changed (41) hide show
  1. package/README.md +7 -1
  2. package/dist/api/compiler/ast.d.ts +6 -0
  3. package/dist/api/compiler/ast.js +19 -3
  4. package/dist/api/compiler/checker-functions.js +5 -1
  5. package/dist/api/compiler/checker-grammar.d.ts +39 -4
  6. package/dist/api/compiler/checker-grammar.js +239 -75
  7. package/dist/api/compiler/checker-heritage.js +20 -14
  8. package/dist/api/compiler/checker-modules.js +4 -2
  9. package/dist/api/compiler/checker-narrowing.d.ts +7 -0
  10. package/dist/api/compiler/checker-narrowing.js +31 -4
  11. package/dist/api/compiler/checker-source-file.js +16 -1
  12. package/dist/api/compiler/checker-statements.js +11 -2
  13. package/dist/api/compiler/checker-type-factory.js +17 -7
  14. package/dist/api/compiler/checker-type-nodes.d.ts +1 -1
  15. package/dist/api/compiler/checker-type-nodes.js +5 -5
  16. package/dist/api/compiler/checker-unused.js +15 -10
  17. package/dist/api/compiler/checker.d.ts +4 -0
  18. package/dist/api/compiler/checker.js +6 -0
  19. package/dist/api/compiler/file-loader.d.ts +5 -0
  20. package/dist/api/compiler/file-loader.js +7 -0
  21. package/dist/api/compiler/program-checker.d.ts +18 -0
  22. package/dist/api/compiler/program-checker.js +27 -0
  23. package/package.json +14 -9
  24. package/src/compiler/ast.ts +20 -3
  25. package/src/compiler/checker-functions.ts +5 -0
  26. package/src/compiler/checker-grammar.ts +247 -88
  27. package/src/compiler/checker-heritage.ts +31 -17
  28. package/src/compiler/checker-modules.ts +4 -2
  29. package/src/compiler/checker-narrowing.ts +30 -4
  30. package/src/compiler/checker-source-file.ts +16 -1
  31. package/src/compiler/checker-statements.ts +10 -2
  32. package/src/compiler/checker-type-factory.ts +14 -7
  33. package/src/compiler/checker-type-nodes.ts +5 -5
  34. package/src/compiler/checker-unused.ts +13 -8
  35. package/src/compiler/checker.ts +6 -0
  36. package/src/compiler/file-loader.ts +8 -0
  37. package/src/compiler/parallel-check.ts +13 -1
  38. package/src/compiler/parse-thread.ts +24 -2
  39. package/src/compiler/program-checker.ts +28 -0
  40. package/src/compiler/run-records.ts +12 -5
  41. package/src/compiler/tsc-compile.ts +10 -1
@@ -668,17 +668,18 @@ function areTypeParametersIdentical(c, lists, targetParameters) {
668
668
  * (with `checkPrivateNames`) private names shared by static and instance members.
669
669
  */
670
670
  export function checkObjectTypeForDuplicateDeclarations(c, node, checkPrivateNames) {
671
- const instanceNames = new Map();
672
- const staticNames = new Map();
673
- const privateNames = new Map();
671
+ // Only a symbol with several declarations can be a duplicate, so the maps are created for the first one.
672
+ let instanceNames;
673
+ let staticNames;
674
+ let privateNames;
674
675
  const nodeInAmbientContext = (node.flags & 8388608 /* NodeFlags.Ambient */) !== 0;
675
676
  for (const member of getMembers(node).nodes) {
676
677
  if (member.kind === 178 /* SyntaxKind.Constructor */) {
677
678
  for (const param of getParameters(member).nodes)
678
679
  if (isParameterPropertyDeclaration(param, member) && !isBindingPattern(getName(param))) {
679
680
  const symbol = getSymbolOfDeclaration(c, param);
680
- if (symbol !== undefined)
681
- checkPropertyOrAccessor(c, node, instanceNames, symbol, 1 /* MemberKind.Property */, false);
681
+ if (symbol !== undefined && declarationCount(symbol) > 1)
682
+ checkPropertyOrAccessor(c, node, (instanceNames ??= new Map()), symbol, 1 /* MemberKind.Property */, false);
682
683
  }
683
684
  continue;
684
685
  }
@@ -688,17 +689,22 @@ export function checkObjectTypeForDuplicateDeclarations(c, node, checkPrivateNam
688
689
  const memberIsStatic = hasStaticModifier(member);
689
690
  if (!nodeInAmbientContext && memberIsStatic && symbol.name === 'prototype')
690
691
  c.error(getName(member), 838 /* Diagnostics.Static_property_0_conflicts_with_built_in_property_Function_0_of_constructor_function_1 */, symbol.name, symbolToString(c, getSymbolOfDeclaration(c, node)));
691
- const names = memberIsStatic ? staticNames : instanceNames;
692
- const hasAccessorModifier = hasSyntacticModifier(member, 512 /* ModifierFlags.Accessor */);
693
- if ((member.kind === 174 /* SyntaxKind.PropertyDeclaration */ && !hasAccessorModifier) ||
694
- member.kind === 173 /* SyntaxKind.PropertySignature */)
695
- checkPropertyOrAccessor(c, node, names, symbol, 1 /* MemberKind.Property */, memberIsStatic);
696
- else if (member.kind === 179 /* SyntaxKind.GetAccessor */ ||
697
- member.kind === 180 /* SyntaxKind.SetAccessor */ ||
698
- (member.kind === 174 /* SyntaxKind.PropertyDeclaration */ && hasAccessorModifier))
699
- checkPropertyOrAccessor(c, node, names, symbol, 2 /* MemberKind.Accessor */, memberIsStatic);
692
+ if (declarationCount(symbol) > 1) {
693
+ const names = memberIsStatic
694
+ ? (staticNames ??= new Map())
695
+ : (instanceNames ??= new Map());
696
+ const hasAccessorModifier = hasSyntacticModifier(member, 512 /* ModifierFlags.Accessor */);
697
+ if ((member.kind === 174 /* SyntaxKind.PropertyDeclaration */ && !hasAccessorModifier) ||
698
+ member.kind === 173 /* SyntaxKind.PropertySignature */)
699
+ checkPropertyOrAccessor(c, node, names, symbol, 1 /* MemberKind.Property */, memberIsStatic);
700
+ else if (member.kind === 179 /* SyntaxKind.GetAccessor */ ||
701
+ member.kind === 180 /* SyntaxKind.SetAccessor */ ||
702
+ (member.kind === 174 /* SyntaxKind.PropertyDeclaration */ && hasAccessorModifier))
703
+ checkPropertyOrAccessor(c, node, names, symbol, 2 /* MemberKind.Accessor */, memberIsStatic);
704
+ }
700
705
  const name = getName(member);
701
706
  if (checkPrivateNames && name !== undefined && name.kind === 80 /* SyntaxKind.PrivateIdentifier */) {
707
+ privateNames ??= new Map();
702
708
  let flags = privateNames.get(symbol.name) ?? 0;
703
709
  if (flags === 3)
704
710
  continue;
@@ -1525,7 +1525,8 @@ function getSymbolFlagsExcludingTypeOnly(c, symbol) {
1525
1525
  }
1526
1526
  /** `getSymbolFlags`, optionally stopping at type-only aliases or leaving out the symbol's own flags. */
1527
1527
  function getSymbolFlagsEx(c, symbol, excludeTypeOnlyMeanings, excludeLocalMeanings) {
1528
- const seen = new Set();
1528
+ // Only a chain of aliases needs the set, so most calls never create it.
1529
+ let seen;
1529
1530
  let flags = excludeLocalMeanings ? 0 /* SymbolFlags.None */ : symbol.flags;
1530
1531
  while ((symbol.flags & 2097152 /* SymbolFlags.Alias */) !== 0) {
1531
1532
  if (excludeTypeOnlyMeanings && getTypeOnlyAliasDeclaration(c, symbol) !== undefined)
@@ -1534,8 +1535,9 @@ function getSymbolFlagsEx(c, symbol, excludeTypeOnlyMeanings, excludeLocalMeanin
1534
1535
  if (target === c.unknownSymbol)
1535
1536
  return 1073741823 /* SymbolFlags.All */;
1536
1537
  if ((target.flags & 2097152 /* SymbolFlags.Alias */) !== 0) {
1537
- if (target === symbol || seen.has(target))
1538
+ if (target === symbol || seen?.has(target))
1538
1539
  break;
1540
+ seen ??= new Set();
1539
1541
  seen.add(symbol);
1540
1542
  seen.add(target);
1541
1543
  }
@@ -112,6 +112,13 @@ export declare function getEvolvingArrayType(c: Checker, elementType: Type): Typ
112
112
  export declare function isEvolvingArrayOperationTarget(c: Checker, node: Node): boolean;
113
113
  /** The array type an evolving array settles on; `any[]` while it has no elements. */
114
114
  export declare function finalizeEvolvingArrayType(c: Checker, t: Type): Type;
115
+ /**
116
+ * Ends the narrowing stopped in `body`, whose checks have finished: what follows the body starts over.
117
+ * A walk that stopped in another body keeps its body's narrowing stopped.
118
+ */
119
+ export declare function endFlowAnalysisStop(c: Checker, body: Node): void;
120
+ /** Whether `node` is the body of a function or a module, where flow analysis starts over (flowAnalysisDisabled). */
121
+ export declare function isFunctionOrModuleBlock(node: Node): boolean;
115
122
  /**
116
123
  * The type of `symbol` at `location`. A destructured variable of a const declaration or unassigned
117
124
  * parameter is narrowed by checks of its siblings: in `const { kind, payload } = action`, testing
@@ -182,7 +182,7 @@ export function getFlowTypeOfReference(c, reference, declaredType, initialType,
182
182
  }
183
183
  /** `getFlowTypeOfReference` at `flowNode`, for pseudo-references such as binding patterns. */
184
184
  export function getFlowTypeOfReferenceAt(c, reference, declaredType, initialType, flowContainer, flowNode) {
185
- if (c.flowAnalysisDisabled)
185
+ if (c.flowAnalysisDisabled && isInFlowAnalysisStop(c, reference))
186
186
  return c.errorType;
187
187
  if (flowNode === undefined)
188
188
  return declaredType;
@@ -211,7 +211,7 @@ export function getFlowTypeOfReferenceAt(c, reference, declaredType, initialType
211
211
  f.steps >= minFlowWalkSteps &&
212
212
  !f.incomplete &&
213
213
  !f.positional &&
214
- !c.flowAnalysisDisabled &&
214
+ !(c.flowAnalysisDisabled && isInFlowAnalysisStop(c, reference)) &&
215
215
  c.resolutionCycleCount === cycles) {
216
216
  const walk = f.walk;
217
217
  if (walk !== undefined) {
@@ -248,6 +248,7 @@ function complete(f, t) {
248
248
  export function getTypeAtFlowNode(c, f, start) {
249
249
  if (f.depth === 2000) {
250
250
  c.flowAnalysisDisabled = true;
251
+ c.flowAnalysisDisabledBody = getContainingFlowBody(f.reference);
251
252
  reportFlowControlError(c, f.reference);
252
253
  return complete(f, c.errorType);
253
254
  }
@@ -2759,17 +2760,43 @@ function getContextFreeTypeOfExpression(c, node) {
2759
2760
  links.contextFreeType = t;
2760
2761
  return t;
2761
2762
  }
2762
- function reportFlowControlError(c, node) {
2763
+ /** The body whose walk reached the flow limit, or undefined when no body is stopped. */
2764
+ function getContainingFlowBody(node) {
2763
2765
  let block = node;
2764
2766
  while (block !== undefined && !isFunctionOrModuleBlock(block))
2765
2767
  block = block.parent;
2768
+ return block;
2769
+ }
2770
+ /** Whether `node` is in the body whose walk reached the flow limit, or in a body it contains. */
2771
+ function isInFlowAnalysisStop(c, node) {
2772
+ const stop = c.flowAnalysisDisabledBody;
2773
+ if (stop === undefined)
2774
+ return false;
2775
+ for (let n = node; n !== undefined; n = n.parent)
2776
+ if (n === stop)
2777
+ return true;
2778
+ return false;
2779
+ }
2780
+ /**
2781
+ * Ends the narrowing stopped in `body`, whose checks have finished: what follows the body starts over.
2782
+ * A walk that stopped in another body keeps its body's narrowing stopped.
2783
+ */
2784
+ export function endFlowAnalysisStop(c, body) {
2785
+ if (c.flowAnalysisDisabledBody !== body)
2786
+ return;
2787
+ c.flowAnalysisDisabled = false;
2788
+ c.flowAnalysisDisabledBody = undefined;
2789
+ }
2790
+ function reportFlowControlError(c, node) {
2791
+ const block = getContainingFlowBody(node);
2766
2792
  if (block === undefined)
2767
2793
  return;
2768
2794
  const file = getSourceFileOfNode(node);
2769
2795
  const span = getRangeOfTokenAtPosition(file, getStatements(block).pos);
2770
2796
  c.addDiagnostic(new Diagnostic(file.diagnosticFile(), span.pos, span.end, 724 /* Diagnostics.The_containing_function_or_module_body_is_too_large_for_control_flow_analysis */, []));
2771
2797
  }
2772
- function isFunctionOrModuleBlock(node) {
2798
+ /** Whether `node` is the body of a function or a module, where flow analysis starts over (flowAnalysisDisabled). */
2799
+ export function isFunctionOrModuleBlock(node) {
2773
2800
  return (node.kind === 308 /* SyntaxKind.SourceFile */ ||
2774
2801
  node.kind === 270 /* SyntaxKind.ModuleBlock */ ||
2775
2802
  (node.kind === 243 /* SyntaxKind.Block */ && node.parent !== undefined && isFunctionLike(node.parent)));
@@ -43,6 +43,11 @@ import { checkContextualDeprecations, checkDeprecatedTypeReference } from './che
43
43
  * identifiers, which need the whole file checked first.
44
44
  */
45
45
  export function checkSourceFile(c, file, checkUnused = false) {
46
+ // A source file is a module body: narrowing stopped by a body too large for control flow analysis
47
+ // (flowAnalysisDisabled, checker-narrowing.ts) starts over in the next check. A checker checks many files
48
+ // (parallel-check.ts), so its diagnostics of a file must not depend on the files it checked before it.
49
+ c.flowAnalysisDisabled = false;
50
+ c.flowAnalysisDisabledBody = undefined;
46
51
  const links = c.nodeLinks(file);
47
52
  if ((links.flags & 1 /* NodeCheckFlags.TypeChecked */) === 0) {
48
53
  links.flags |= 1 /* NodeCheckFlags.TypeChecked */;
@@ -52,6 +57,9 @@ export function checkSourceFile(c, file, checkUnused = false) {
52
57
  links.flags |= 2 /* NodeCheckFlags.UnusedChecked */;
53
58
  checkUnusedIdentifiers(c, file);
54
59
  }
60
+ // Every body of the file has finished its checks; a stop recorded for one of them ends with the file.
61
+ c.flowAnalysisDisabled = false;
62
+ c.flowAnalysisDisabledBody = undefined;
55
63
  }
56
64
  function checkSourceFileWorker(c, file) {
57
65
  c.fileBeingChecked = file;
@@ -89,6 +97,10 @@ function checkSourceFileWorker(c, file) {
89
97
  */
90
98
  export function checkSourceFileRange(c, file, start, end) {
91
99
  const statements = getStatements(file).nodes;
100
+ // A range of a file's statements is part of its module body: narrowing stopped by a body too large for
101
+ // control flow analysis (flowAnalysisDisabled, checker-narrowing.ts) starts over in the next range.
102
+ c.flowAnalysisDisabled = false;
103
+ c.flowAnalysisDisabledBody = undefined;
92
104
  c.fileBeingChecked = file;
93
105
  for (let i = start; i < end; i++)
94
106
  checkSourceElement(c, statements[i]);
@@ -106,6 +118,9 @@ export function checkSourceFileRange(c, file, start, end) {
106
118
  produceDeferredDiagnostics(c);
107
119
  // Deferred nodes of a later range are queued again (checkNodeDeferred).
108
120
  c.nodeLinks(file).deferredNodes = undefined;
121
+ // The range's bodies have finished their checks; a stop recorded for one of them ends with the range.
122
+ c.flowAnalysisDisabled = false;
123
+ c.flowAnalysisDisabledBody = undefined;
109
124
  return c.diagnostics.forFile(file.fileName).length > 0;
110
125
  }
111
126
  /**
@@ -520,7 +535,7 @@ function checkTypeMemberAccessor(c, node) {
520
535
  /** Variadic tuple elements must be array-like. */
521
536
  function checkTupleRestElements(c, node) {
522
537
  for (const e of node.elements.nodes) {
523
- if ((getTupleElementFlags(c, e) & 8 /* ElementFlags.Variadic */) === 0)
538
+ if ((getTupleElementFlags(e) & 8 /* ElementFlags.Variadic */) === 0)
524
539
  continue;
525
540
  if (!isArrayLikeType(c, getTypeFromTypeNode(c, getType(e)))) {
526
541
  c.error(e, 732 /* Diagnostics.A_rest_element_type_must_be_an_array_type */);
@@ -7,7 +7,7 @@ import { checkIteratedTypeOrElementType } from './checker-iteration.js';
7
7
  import { checkDestructuringAssignment } from './checker-destructuring.js';
8
8
  import { checkReferenceExpression, checkTestingKnownTruthyType, checkTruthinessExpression, isTypeEqualityComparableTo, } from './checker-operators.js';
9
9
  import { checkTypeComparableTo, isTypeAssignableTo } from './relations.js';
10
- import { isReachableFlowNode } from './checker-narrowing.js';
10
+ import { endFlowAnalysisStop, isFunctionOrModuleBlock, isReachableFlowNode } from './checker-narrowing.js';
11
11
  import { getIndexType, isTypeAssignableToKindEx as isTypeAssignableToKind } from './checker-type-operators.js';
12
12
  import { getExtractStringType } from './checker-symbol-types.js';
13
13
  import { checkSourceElement } from './checker-source-file.js';
@@ -21,8 +21,17 @@ import { checkExternalEmitHelpers } from './checker-emit-helpers.js';
21
21
  import { typeToString } from './type-printer.js';
22
22
  import { getNonNullableType, hasTypeFacts } from './checker-flow.js';
23
23
  export function checkBlock(c, node) {
24
- for (const s of getStatements(node).nodes)
24
+ const statements = getStatements(node).nodes;
25
+ if (!isFunctionOrModuleBlock(node)) {
26
+ for (const s of statements)
27
+ checkSourceElement(c, s);
28
+ return;
29
+ }
30
+ // A body too large for control flow analysis stops narrowing in the rest of that body only
31
+ // (flowAnalysisDisabled, checker-narrowing.ts); what follows the body starts over.
32
+ for (const s of statements)
25
33
  checkSourceElement(c, s);
34
+ endFlowAnalysisStop(c, node);
26
35
  }
27
36
  export function checkExpressionStatement(c, node) {
28
37
  checkExpression(c, getExpression(node));
@@ -1749,18 +1749,27 @@ export function intersectTypes(c, type1, type2) {
1749
1749
  export function getIntersectionType(c, types) {
1750
1750
  return getIntersectionTypeEx(c, types, 0 /* IntersectionFlags.None */, undefined);
1751
1751
  }
1752
+ /**
1753
+ * The distinct types of an intersection, in the order they were added. Most intersections have a few
1754
+ * types, which a scan of `values` finds faster than a `Set` costs to build, so the set is created only
1755
+ * once the list grows past `INDEX_AFTER`.
1756
+ */
1752
1757
  class OrderedTypeSet {
1758
+ static INDEX_AFTER = 8;
1753
1759
  values = [];
1754
- seen = new Set();
1760
+ index;
1755
1761
  includes = 0;
1756
1762
  has(t) {
1757
- return this.seen.has(t);
1763
+ return this.index !== undefined ? this.index.has(t) : this.values.includes(t);
1758
1764
  }
1759
1765
  add(t) {
1760
- if (!this.seen.has(t)) {
1761
- this.seen.add(t);
1762
- this.values.push(t);
1763
- }
1766
+ if (this.has(t))
1767
+ return;
1768
+ this.values.push(t);
1769
+ if (this.index !== undefined)
1770
+ this.index.add(t);
1771
+ else if (this.values.length > OrderedTypeSet.INDEX_AFTER)
1772
+ this.index = new Set(this.values);
1764
1773
  }
1765
1774
  }
1766
1775
  function addTypesToIntersection(c, set, types) {
@@ -2126,7 +2135,8 @@ function getCrossProductIntersections(c, types, flags) {
2126
2135
  */
2127
2136
  function addCrossProductIntersections(c, types, flags, constituents, index, unit, intersections) {
2128
2137
  if (index === types.length) {
2129
- const t = getIntersectionTypeEx(c, constituents.slice(), flags, undefined);
2138
+ // getIntersectionTypeEx copies the types it keeps, so the buffer is reused for the next combination.
2139
+ const t = getIntersectionTypeEx(c, constituents, flags, undefined);
2130
2140
  if ((t.flags & 262144 /* TypeFlags.Never */) === 0)
2131
2141
  intersections.push(t);
2132
2142
  return;
@@ -20,7 +20,7 @@ export declare function isTypeAlias(node: Node): boolean;
20
20
  export declare function getAliasForTypeNode(c: Checker, node: Node): TypeAlias | undefined;
21
21
  export declare function getAliasSymbolForTypeNode(c: Checker, node: Node): Symbol | undefined;
22
22
  export declare function getTypeAliasInstantiation(c: Checker, symbol: Symbol, typeArguments: Type[], alias: TypeAlias | undefined): Type;
23
- export declare function getTupleElementFlags(c: Checker, node: Node): ElementFlags;
23
+ export declare function getTupleElementFlags(node: Node): ElementFlags;
24
24
  /** Type arguments of a deferred reference from its node. */
25
25
  export declare function getTypeArgumentsOfDeferredReference(c: Checker, node: Node, target: InterfaceType): Type[];
26
26
  /** The symbol an identifier resolves to, cached on the identifier. */
@@ -711,7 +711,7 @@ function getTypeFromTypeQueryNode(c, node) {
711
711
  }
712
712
  return type;
713
713
  }
714
- export function getTupleElementFlags(c, node) {
714
+ export function getTupleElementFlags(node) {
715
715
  switch (node.kind) {
716
716
  case 192 /* SyntaxKind.OptionalType */:
717
717
  return 2 /* ElementFlags.Optional */;
@@ -730,8 +730,8 @@ export function getTupleElementFlags(c, node) {
730
730
  }
731
731
  return 1 /* ElementFlags.Required */;
732
732
  }
733
- function getTupleElementInfo(c, node) {
734
- return new TupleElementInfo(getTupleElementFlags(c, node), node.kind === 204 /* SyntaxKind.NamedTupleMember */ || node.kind === 171 /* SyntaxKind.Parameter */ ? node : undefined);
733
+ function getTupleElementInfo(node) {
734
+ return new TupleElementInfo(getTupleElementFlags(node), node.kind === 204 /* SyntaxKind.NamedTupleMember */ || node.kind === 171 /* SyntaxKind.Parameter */ ? node : undefined);
735
735
  }
736
736
  function getArrayElementTypeNode(node) {
737
737
  switch (node.kind) {
@@ -760,7 +760,7 @@ function getArrayOrTupleTargetType(c, node) {
760
760
  return readonly ? c.globalReadonlyArrayType : c.globalArrayType;
761
761
  const elementInfos = [];
762
762
  for (const e of node.elements.nodes)
763
- elementInfos.push(getTupleElementInfo(c, e));
763
+ elementInfos.push(getTupleElementInfo(e));
764
764
  return getTupleTargetType(c, elementInfos, readonly);
765
765
  }
766
766
  function getTypeFromArrayOrTupleTypeNode(c, node) {
@@ -787,7 +787,7 @@ function getTypeFromArrayOrTupleTypeNode(c, node) {
787
787
  }
788
788
  function hasVariadicTupleElement(c, node) {
789
789
  for (const e of node.elements.nodes)
790
- if ((getTupleElementFlags(c, e) & 8 /* ElementFlags.Variadic */) !== 0)
790
+ if ((getTupleElementFlags(e) & 8 /* ElementFlags.Variadic */) !== 0)
791
791
  return true;
792
792
  return false;
793
793
  }
@@ -326,8 +326,9 @@ function checkUnusedLocalsAndParameters(c, node) {
326
326
  const locals = getLocals(node);
327
327
  if (locals === undefined)
328
328
  return;
329
- const variableParents = new Set();
330
- const importClauses = new Map();
329
+ // Created on the first unused declaration: most scopes have none.
330
+ let variableParents;
331
+ let importClauses;
331
332
  for (const local of locals.values()) {
332
333
  const referenceKinds = c.symbolReferenceKinds.get(getSymbolId(local));
333
334
  if ((local.flags & 262144 /* SymbolFlags.TypeParameter */) !== 0) {
@@ -343,6 +344,7 @@ function checkUnusedLocalsAndParameters(c, node) {
343
344
  case 262 /* SyntaxKind.VariableDeclaration */:
344
345
  case 171 /* SyntaxKind.Parameter */:
345
346
  case 210 /* SyntaxKind.BindingElement */:
347
+ variableParents ??= new Set();
346
348
  variableParents.add(getRootDeclaration(declaration).parent);
347
349
  break;
348
350
  case 275 /* SyntaxKind.ImportClause */:
@@ -350,6 +352,7 @@ function checkUnusedLocalsAndParameters(c, node) {
350
352
  case 276 /* SyntaxKind.NamespaceImport */:
351
353
  if (!isIdentifierThatStartsWithUnderscore(getName(declaration))) {
352
354
  const importClause = importClauseFromImported(declaration);
355
+ importClauses ??= new Map();
353
356
  const unuseds = importClauses.get(importClause);
354
357
  if (unuseds === undefined)
355
358
  importClauses.set(importClause, [declaration]);
@@ -363,14 +366,16 @@ function checkUnusedLocalsAndParameters(c, node) {
363
366
  }
364
367
  }
365
368
  }
366
- for (const declaration of variableParents) {
367
- if (declaration.kind === 263 /* SyntaxKind.VariableDeclarationList */)
368
- reportUnusedVariables(c, declaration, declaration.declarations.nodes);
369
- else
370
- reportUnusedVariableDeclarations(c, getParameters(declaration).nodes);
371
- }
372
- for (const [declaration, unuseds] of importClauses)
373
- reportUnusedImports(c, declaration, unuseds);
369
+ if (variableParents !== undefined)
370
+ for (const declaration of variableParents) {
371
+ if (declaration.kind === 263 /* SyntaxKind.VariableDeclarationList */)
372
+ reportUnusedVariables(c, declaration, declaration.declarations.nodes);
373
+ else
374
+ reportUnusedVariableDeclarations(c, getParameters(declaration).nodes);
375
+ }
376
+ if (importClauses !== undefined)
377
+ for (const [declaration, unuseds] of importClauses)
378
+ reportUnusedImports(c, declaration, unuseds);
374
379
  }
375
380
  function reportUnusedLocal(c, node, name) {
376
381
  const message = isTypeDeclaration(node)
@@ -155,6 +155,8 @@ export declare class Checker implements TypeChecking {
155
155
  readonly noUncheckedIndexedAccess: boolean;
156
156
  typeCount: number;
157
157
  signatureCount: number;
158
+ /** Transient symbols the checker created (statistics), as tsgo's `Checker.SymbolCount`. */
159
+ symbolCount: number;
158
160
  /** Positions of members by name in the tables and lists that lazily instantiated members come from. */
159
161
  readonly memberPositionsInLists: Map<Symbol[], Map<string, number>>;
160
162
  /** The property names of the last instantiation of each such list whose table is built on demand. */
@@ -464,6 +466,8 @@ export declare class Checker implements TypeChecking {
464
466
  /** `{ meta: ImportMeta }`, the type of `import.meta` for symbol queries. */
465
467
  importMetaExpressionType: Type | undefined;
466
468
  flowAnalysisDisabled: boolean;
469
+ /** The body whose walk reached the flow limit (flowAnalysisDisabled), until its checks finish. */
470
+ flowAnalysisDisabledBody: Node | undefined;
467
471
  inlineLevel: number;
468
472
  /**
469
473
  * Shared flow nodes cached by the walks in progress, with their types: the first
@@ -282,6 +282,8 @@ export class Checker {
282
282
  // Counters for type and signature ids.
283
283
  typeCount = 0;
284
284
  signatureCount = 0;
285
+ /** Transient symbols the checker created (statistics), as tsgo's `Checker.SymbolCount`. */
286
+ symbolCount = 0;
285
287
  /** Positions of members by name in the tables and lists that lazily instantiated members come from. */
286
288
  memberPositionsInLists = new Map();
287
289
  /** The property names of the last instantiation of each such list whose table is built on demand. */
@@ -610,6 +612,8 @@ export class Checker {
610
612
  importMetaExpressionType = undefined;
611
613
  // Control flow analysis
612
614
  flowAnalysisDisabled = false;
615
+ /** The body whose walk reached the flow limit (flowAnalysisDisabled), until its checks finish. */
616
+ flowAnalysisDisabledBody = undefined;
613
617
  inlineLevel = 0;
614
618
  /**
615
619
  * Shared flow nodes cached by the walks in progress, with their types: the first
@@ -982,10 +986,12 @@ export class Checker {
982
986
  return new TypeParameter(this.nextTypeId(), symbol);
983
987
  }
984
988
  newSymbol(flags, name) {
989
+ this.symbolCount++;
985
990
  const symbol = new Symbol(flags | 33554432 /* SymbolFlags.Transient */, name);
986
991
  return symbol;
987
992
  }
988
993
  newSymbolWithCheckFlags(flags, name, checkFlags) {
994
+ this.symbolCount++;
989
995
  const symbol = new Symbol(flags | 33554432 /* SymbolFlags.Transient */, name);
990
996
  symbol.checkFlags = checkFlags;
991
997
  return symbol;
@@ -29,6 +29,11 @@ export declare class CompilerHost extends ModuleResolutionHost {
29
29
  readFile(path: string): string | undefined;
30
30
  realpath(path: string): string;
31
31
  getDirectories(path: string): readonly string[];
32
+ /**
33
+ * The metadata of the file `FileLoader` is parsing, which it computes from the file's package scope
34
+ * before it parses it; a host that walks the grammar of the parsed file reads it (parse-thread.ts).
35
+ */
36
+ loadingSourceFileMetadata: SourceFileMetadata | undefined;
32
37
  /** Parses a file, or returns `undefined` if it can't be read. */
33
38
  getSourceFile(fileName: string, path: string, externalModuleIndicatorOptions: ExternalModuleIndicatorOptions): SourceFile | undefined;
34
39
  /** The config of a referenced project, or `undefined` if it can't be read. */
@@ -51,6 +51,11 @@ export class CompilerHost extends ModuleResolutionHost {
51
51
  getDirectories(path) {
52
52
  return this.fs.getAccessibleEntries(path).directories;
53
53
  }
54
+ /**
55
+ * The metadata of the file `FileLoader` is parsing, which it computes from the file's package scope
56
+ * before it parses it; a host that walks the grammar of the parsed file reads it (parse-thread.ts).
57
+ */
58
+ loadingSourceFileMetadata = undefined;
54
59
  /** Parses a file, or returns `undefined` if it can't be read. */
55
60
  getSourceFile(fileName, path, externalModuleIndicatorOptions) {
56
61
  // A file that parse threads prepared (parallel-parse.ts).
@@ -1054,6 +1059,8 @@ export class FileLoader {
1054
1059
  ? libFileMetadata
1055
1060
  : (loaded?.metadata ?? this.loadSourceFileMetadata(task.normalizedFilePath));
1056
1061
  const options = this.mapper.getCompilerOptionsForFile(task.path, task.normalizedFilePath);
1062
+ // For the host that walks the grammar of the file as it parses it (parse-thread.ts).
1063
+ this.host.loadingSourceFileMetadata = task.metadata;
1057
1064
  const file = this.host.getSourceFile(task.normalizedFilePath, task.path, getExternalModuleIndicatorOptions(task.normalizedFilePath, options, task.metadata));
1058
1065
  if (file === undefined)
1059
1066
  return;
@@ -88,6 +88,18 @@ export declare class CheckedProgram {
88
88
  createChecker(): Checker;
89
89
  /** Frees the checker that reports the program's diagnostics (`disposeChecker`). */
90
90
  disposeCheckers(): void;
91
+ /** Adds the counts a checker thread sent (`CheckerResult.counts`): types, instantiations, symbols. */
92
+ addCheckerCounts(counts: readonly number[]): void;
93
+ /**
94
+ * The types, instantiations and transient symbols of every checker of the program: this thread's and
95
+ * the checker threads', as tsgo's `Program.TypeCount`, `InstantiationCount` and `SymbolCount` add them up.
96
+ * Reading them doesn't create this thread's checker.
97
+ */
98
+ checkerCounts(): {
99
+ types: number;
100
+ instantiations: number;
101
+ symbols: number;
102
+ };
91
103
  getBindDiagnostics(file: SourceFile | undefined): Diagnostic[];
92
104
  /**
93
105
  * Diagnostics of checker threads (parallel-check.ts): the semantic diagnostics of each file by file
@@ -109,6 +121,12 @@ export declare class CheckedProgram {
109
121
  */
110
122
  referenceThreads: number;
111
123
  readonly parallelGlobalDiagnostics: Diagnostic[];
124
+ /** The types checker threads created (`CheckerResult.counts`), which `--diagnostics` adds to `checker`'s. */
125
+ threadTypeCount: number;
126
+ /** The instantiations checker threads made. */
127
+ threadInstantiations: number;
128
+ /** The transient symbols checker threads created. */
129
+ threadSymbolCount: number;
112
130
  /**
113
131
  * Whether the semantic diagnostics of a file include the global diagnostics its checker found while
114
132
  * checking it, as an incremental program caches them (IncrementalProgram). Such a program doesn't report
@@ -176,6 +176,27 @@ export class CheckedProgram {
176
176
  disposeChecker(this.reportingChecker);
177
177
  this.reportingChecker = undefined;
178
178
  }
179
+ /** Adds the counts a checker thread sent (`CheckerResult.counts`): types, instantiations, symbols. */
180
+ addCheckerCounts(counts) {
181
+ if (counts.length < 3)
182
+ return;
183
+ this.threadTypeCount += counts[0];
184
+ this.threadInstantiations += counts[1];
185
+ this.threadSymbolCount += counts[2];
186
+ }
187
+ /**
188
+ * The types, instantiations and transient symbols of every checker of the program: this thread's and
189
+ * the checker threads', as tsgo's `Program.TypeCount`, `InstantiationCount` and `SymbolCount` add them up.
190
+ * Reading them doesn't create this thread's checker.
191
+ */
192
+ checkerCounts() {
193
+ const own = this.reportingChecker;
194
+ return {
195
+ types: (own === undefined ? 0 : own.typeCount) + this.threadTypeCount,
196
+ instantiations: (own === undefined ? 0 : own.totalInstantiations) + this.threadInstantiations,
197
+ symbols: (own === undefined ? 0 : own.symbolCount) + this.threadSymbolCount,
198
+ };
199
+ }
179
200
  getBindDiagnostics(file) {
180
201
  return this.collect(file, (f) => f.bindDiagnostics);
181
202
  }
@@ -199,6 +220,12 @@ export class CheckedProgram {
199
220
  */
200
221
  referenceThreads = 1;
201
222
  parallelGlobalDiagnostics = [];
223
+ /** The types checker threads created (`CheckerResult.counts`), which `--diagnostics` adds to `checker`'s. */
224
+ threadTypeCount = 0;
225
+ /** The instantiations checker threads made. */
226
+ threadInstantiations = 0;
227
+ /** The transient symbols checker threads created. */
228
+ threadSymbolCount = 0;
202
229
  /**
203
230
  * Whether the semantic diagnostics of a file include the global diagnostics its checker found while
204
231
  * checking it, as an incremental program caches them (IncrementalProgram). Such a program doesn't report
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsc-ts",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "The TypeScript 7 compiler, ported to TypeScript and compiled to a native executable.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -28,19 +28,24 @@
28
28
  },
29
29
  "./package.json": "./package.json"
30
30
  },
31
- "dependencies": {
31
+ "peerDependencies": {
32
32
  "@scriptc/threads": "0.4.8"
33
33
  },
34
+ "peerDependenciesMeta": {
35
+ "@scriptc/threads": {
36
+ "optional": true
37
+ }
38
+ },
34
39
  "engines": {
35
40
  "node": ">=20"
36
41
  },
37
42
  "optionalDependencies": {
38
- "@tsc-ts/darwin-arm64": "0.1.1",
39
- "@tsc-ts/darwin-x64": "0.1.1",
40
- "@tsc-ts/linux-arm64-gnu": "0.1.1",
41
- "@tsc-ts/linux-arm64-musl": "0.1.1",
42
- "@tsc-ts/linux-x64-gnu": "0.1.1",
43
- "@tsc-ts/linux-x64-musl": "0.1.1",
44
- "@tsc-ts/win32-x64-msvc": "0.1.1"
43
+ "@tsc-ts/darwin-arm64": "0.1.3",
44
+ "@tsc-ts/darwin-x64": "0.1.3",
45
+ "@tsc-ts/linux-arm64-gnu": "0.1.3",
46
+ "@tsc-ts/linux-arm64-musl": "0.1.3",
47
+ "@tsc-ts/linux-x64-gnu": "0.1.3",
48
+ "@tsc-ts/linux-x64-musl": "0.1.3",
49
+ "@tsc-ts/win32-x64-msvc": "0.1.3"
45
50
  }
46
51
  }
@@ -209,9 +209,14 @@ export abstract class NodeVisitor {
209
209
  }
210
210
  }
211
211
 
212
- // Native builds store `pos`, `end` and `id` as 32-bit integers when every write provably stores an
213
- // int32, so writes of values the compiler can't bound (parameters, the id counter) are coerced
214
- // with `| 0`; the values are always int32.
212
+ // Native builds store `pos`, `end` and `id` as 32-bit integers when every write provably stores
213
+ // an int32, so writes of values the compiler can't bound (parameters, the id counter) are
214
+ // coerced with `| 0`; the values are always int32.
215
+ //
216
+ // The fields of a node that the public API's node types declare are stored fields, not values
217
+ // computed from or packed into another field: a native build copies the stored fields of a node
218
+ // into a record when API code narrows one (`node as StringLiteralLike`), and a field behind an
219
+ // accessor is not copied.
215
220
  export abstract class Node implements ProgramLifetime {
216
221
  readonly kind: SyntaxKind;
217
222
  flags: NodeFlags;
@@ -8244,6 +8249,7 @@ export const emptyCommentDirectives: readonly CommentDirective[] = [];
8244
8249
  export const emptyPragmas: readonly Pragma[] = [];
8245
8250
  export const emptyFileReferences: readonly FileReference[] = [];
8246
8251
  export const emptyPatternAmbientModules: readonly PatternAmbientModule[] = [];
8252
+ const emptyNumbers: readonly number[] = [];
8247
8253
 
8248
8254
  /** `list` with `item` appended: a new array when `list` is empty (it may be shared), else `list` itself. */
8249
8255
  export function appendToList<T>(list: readonly T[], item: T): readonly T[] {
@@ -8320,6 +8326,14 @@ export class SourceFile extends Node {
8320
8326
  /** UMD exports from `export as namespace N`. */
8321
8327
  globalExports: SymbolTable | undefined;
8322
8328
 
8329
+ // Set by the grammar checks of a parse thread (checker-grammar.ts).
8330
+ /** The diagnostics the parse thread's grammar walk reported for this file. */
8331
+ grammarDiagnostics: Diagnostic[] | undefined;
8332
+ /** The nodes of this file whose grammar check needs the checker, in tree order. */
8333
+ grammarResidualNodes: Node[] | undefined;
8334
+ /** The blocks and statements that reported a statement in an ambient context. */
8335
+ grammarAmbientReports: readonly number[];
8336
+
8323
8337
  constructor(
8324
8338
  fileName: string,
8325
8339
  path: string,
@@ -8373,6 +8387,9 @@ export class SourceFile extends Node {
8373
8387
  this.symbolCount = 0;
8374
8388
  this.patternAmbientModules = emptyPatternAmbientModules;
8375
8389
  this.globalExports = undefined;
8390
+ this.grammarDiagnostics = undefined;
8391
+ this.grammarResidualNodes = undefined;
8392
+ this.grammarAmbientReports = emptyNumbers;
8376
8393
  }
8377
8394
 
8378
8395
  forEachChild(v: NodeVisitor): boolean {