tsc-ts 0.1.0 → 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.
Files changed (81) hide show
  1. package/README.md +7 -1
  2. package/dist/api/compiler/ast.d.ts +15 -3
  3. package/dist/api/compiler/ast.js +36 -15
  4. package/dist/api/compiler/checker-classes.js +2 -1
  5. package/dist/api/compiler/checker-contextual.d.ts +20 -0
  6. package/dist/api/compiler/checker-contextual.js +111 -1
  7. package/dist/api/compiler/checker-expressions.js +14 -1
  8. package/dist/api/compiler/checker-grammar.d.ts +39 -4
  9. package/dist/api/compiler/checker-grammar.js +239 -75
  10. package/dist/api/compiler/checker-heritage.js +20 -14
  11. package/dist/api/compiler/checker-jsx.js +2 -1
  12. package/dist/api/compiler/checker-modules.js +4 -2
  13. package/dist/api/compiler/checker-source-file.js +1 -1
  14. package/dist/api/compiler/checker-type-factory.js +70 -19
  15. package/dist/api/compiler/checker-type-nodes.d.ts +1 -1
  16. package/dist/api/compiler/checker-type-nodes.js +5 -5
  17. package/dist/api/compiler/checker-unused.js +15 -10
  18. package/dist/api/compiler/checker.d.ts +7 -1
  19. package/dist/api/compiler/checker.js +14 -4
  20. package/dist/api/compiler/compile-program.d.ts +5 -0
  21. package/dist/api/compiler/compile-program.js +8 -0
  22. package/dist/api/compiler/expr-record.d.ts +11 -0
  23. package/dist/api/compiler/expr-record.js +53 -0
  24. package/dist/api/compiler/file-loader.d.ts +5 -0
  25. package/dist/api/compiler/file-loader.js +7 -0
  26. package/dist/api/compiler/identifier-name.d.ts +9 -0
  27. package/dist/api/compiler/identifier-name.js +10 -0
  28. package/dist/api/compiler/jsdoc.js +4 -2
  29. package/dist/api/compiler/parser.d.ts +2 -1
  30. package/dist/api/compiler/parser.js +10 -8
  31. package/dist/api/compiler/printer/factory.js +3 -2
  32. package/dist/api/compiler/printer/printer.js +3 -2
  33. package/dist/api/compiler/program-checker.d.ts +18 -0
  34. package/dist/api/compiler/program-checker.js +27 -0
  35. package/dist/api/compiler/reparser.js +4 -3
  36. package/dist/api/compiler/scanner.d.ts +8 -0
  37. package/dist/api/compiler/scanner.js +58 -42
  38. package/dist/api/compiler/shared-results.d.ts +376 -143
  39. package/dist/api/compiler/shared-results.js +1550 -773
  40. package/dist/api/compiler/transformers/declarations.js +2 -1
  41. package/package.json +15 -10
  42. package/src/compiler/ast.ts +39 -15
  43. package/src/compiler/cgroup.ts +157 -0
  44. package/src/compiler/checker-classes.ts +2 -1
  45. package/src/compiler/checker-contextual.ts +104 -0
  46. package/src/compiler/checker-expressions.ts +16 -1
  47. package/src/compiler/checker-grammar.ts +247 -88
  48. package/src/compiler/checker-heritage.ts +31 -17
  49. package/src/compiler/checker-jsx.ts +2 -1
  50. package/src/compiler/checker-modules.ts +4 -2
  51. package/src/compiler/checker-source-file.ts +1 -1
  52. package/src/compiler/checker-type-factory.ts +67 -21
  53. package/src/compiler/checker-type-nodes.ts +5 -5
  54. package/src/compiler/checker-unused.ts +13 -8
  55. package/src/compiler/checker.ts +15 -4
  56. package/src/compiler/compile-program.ts +8 -0
  57. package/src/compiler/decoder.ts +2 -1
  58. package/src/compiler/doctor-report.ts +133 -0
  59. package/src/compiler/expr-record.ts +59 -0
  60. package/src/compiler/file-loader.ts +8 -0
  61. package/src/compiler/identifier-name.ts +13 -0
  62. package/src/compiler/jsdoc.ts +4 -2
  63. package/src/compiler/parallel-check.ts +364 -146
  64. package/src/compiler/parallel-emit.ts +3 -3
  65. package/src/compiler/parse-thread.ts +24 -2
  66. package/src/compiler/parser.ts +10 -8
  67. package/src/compiler/printer/factory.ts +3 -2
  68. package/src/compiler/printer/printer.ts +4 -2
  69. package/src/compiler/program-checker.ts +28 -0
  70. package/src/compiler/reparser.ts +7 -3
  71. package/src/compiler/run-config.ts +1383 -0
  72. package/src/compiler/run-record-read.ts +87 -0
  73. package/src/compiler/run-records.ts +575 -0
  74. package/src/compiler/scanner.ts +57 -41
  75. package/src/compiler/shared-results.ts +1626 -896
  76. package/src/compiler/thread-entry.ts +3 -1
  77. package/src/compiler/transformers/declarations.ts +2 -1
  78. package/src/compiler/tsc-build.ts +64 -6
  79. package/src/compiler/tsc-cli.ts +33 -4
  80. package/src/compiler/tsc-compile.ts +223 -9
  81. package/src/compiler/tsc-watch.ts +25 -4
@@ -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;
@@ -38,6 +38,7 @@ import { filterType, isTupleType } from './checker-type-factory.js';
38
38
  import { createTypeFromGenericGlobalType } from './checker-type-factory.js';
39
39
  import { isTypeAssignableTo } from './relations.js';
40
40
  import { copyDeclarations, declarationCount, getSymbolId, } from './symbol.js';
41
+ import { IdentifierName } from './identifier-name.js';
41
42
  // Names in the `JSX` namespace.
42
43
  const jsxNamespaceName = 'JSX';
43
44
  const jsxIntrinsicElementsName = 'IntrinsicElements';
@@ -824,7 +825,7 @@ export function createJsxAttributesTypeFromAttributesProperty(c, openingLikeElem
824
825
  c.symbolTypes.set(id, createArrayType(c, getUnionType(c, childTypes)));
825
826
  // A property signature in the attributes declares the synthetic `children` property, so it is
826
827
  // checked as an excess property like the attributes.
827
- const childrenDeclaration = new PropertySignatureDeclaration(undefined, new Identifier(jsxChildrenPropertyName), undefined, undefined, undefined);
828
+ const childrenDeclaration = new PropertySignatureDeclaration(undefined, new Identifier(new IdentifierName(jsxChildrenPropertyName)), undefined, undefined, undefined);
828
829
  childrenDeclaration.parent = attributeParent;
829
830
  childrenDeclaration.symbol = childrenPropSymbol;
830
831
  childrenPropSymbol.valueDeclaration = childrenDeclaration;
@@ -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
  }
@@ -520,7 +520,7 @@ function checkTypeMemberAccessor(c, node) {
520
520
  /** Variadic tuple elements must be array-like. */
521
521
  function checkTupleRestElements(c, node) {
522
522
  for (const e of node.elements.nodes) {
523
- if ((getTupleElementFlags(c, e) & 8 /* ElementFlags.Variadic */) === 0)
523
+ if ((getTupleElementFlags(e) & 8 /* ElementFlags.Variadic */) === 0)
524
524
  continue;
525
525
  if (!isArrayLikeType(c, getTypeFromTypeNode(c, getType(e)))) {
526
526
  c.error(e, 732 /* Diagnostics.A_rest_element_type_must_be_an_array_type */);
@@ -1187,37 +1187,78 @@ export function getUnionTypeEx(c, types, unionReduction, alias, origin) {
1187
1187
  return c.neverType;
1188
1188
  if (types.length === 1)
1189
1189
  return types[0];
1190
- // Optimize the common case of unioning a union with some other type, like `undefined`.
1191
- if (types.length === 2 &&
1192
- origin === undefined &&
1193
- ((types[0].flags & 134217728 /* TypeFlags.Union */) !== 0 || (types[1].flags & 134217728 /* TypeFlags.Union */) !== 0)) {
1194
- let id1 = types[0].id;
1195
- let id2 = types[1].id;
1190
+ // Unioning two types is the common case, both a union with some other type, like `undefined`, and
1191
+ // two constituents of a list, and the same pairs recur. The union is a function of the two types,
1192
+ // the reduction and the alias, so the result is cached by the pair. A union that exceeded the
1193
+ // complexity limit was reported at the expression that needed it and comes back as the error
1194
+ // type: caching that would silence the report at the next expression with the same input list, so
1195
+ // an error result is not cached.
1196
+ if (types.length === 2 && origin === undefined) {
1197
+ const t0 = types[0];
1198
+ const t1 = types[1];
1199
+ let id1 = t0.id;
1200
+ let id2 = t1.id;
1196
1201
  if (id1 > id2) {
1197
1202
  const t = id1;
1198
1203
  id1 = id2;
1199
1204
  id2 = t;
1200
1205
  }
1201
- // Without an alias, both ids and the reduction pack into one exact number.
1202
- if (alias === undefined && id2 < UnionPairIdLimit) {
1206
+ // Without an alias or a constrained intersection, both ids and the reduction pack into one
1207
+ // exact number. A constrained intersection's reduction resolves a type variable's constraint
1208
+ // (`addTypeToUnion`), so those pairs take the general path.
1209
+ if (alias === undefined &&
1210
+ id2 < UnionPairIdLimit &&
1211
+ !isConstrainedIntersection(t0) &&
1212
+ !isConstrainedIntersection(t1)) {
1203
1213
  const id = (id1 * UnionPairIdLimit + id2) * 4 + unionReduction;
1204
1214
  let result = c.unionOfUnionTypesById.get(id);
1205
1215
  if (result === undefined) {
1206
1216
  result = getUnionTypeWorker(c, types, unionReduction, alias, undefined);
1207
- c.unionOfUnionTypesById.set(id, result);
1217
+ if (result !== c.errorType)
1218
+ c.unionOfUnionTypesById.set(id, result);
1208
1219
  }
1209
1220
  return result;
1210
1221
  }
1211
- const key = id1 + ',' + id2 + ',' + unionReduction + aliasKey(alias);
1212
- let result = c.unionOfUnionTypes.get(key);
1222
+ if ((t0.flags & 134217728 /* TypeFlags.Union */) !== 0 || (t1.flags & 134217728 /* TypeFlags.Union */) !== 0) {
1223
+ const key = id1 + ',' + id2 + ',' + unionReduction + aliasKey(alias);
1224
+ let result = c.unionOfUnionTypes.get(key);
1225
+ if (result === undefined) {
1226
+ result = getUnionTypeWorker(c, types, unionReduction, alias, undefined);
1227
+ if (result !== c.errorType)
1228
+ c.unionOfUnionTypes.set(key, result);
1229
+ }
1230
+ return result;
1231
+ }
1232
+ }
1233
+ // Longer lists recur too, from nested unions and from constituents mapped in the same order.
1234
+ // Normalizing a list costs a sort of its constituents and the reductions, and the union is a
1235
+ // function of the list as given, the reduction and the alias, so the result is cached by the list.
1236
+ if (origin === undefined) {
1237
+ const hash = typeListHash(types, alias, unionReduction);
1238
+ let result = c.unionTypesByInputList.get(hash, types, alias, unionReduction);
1213
1239
  if (result === undefined) {
1214
1240
  result = getUnionTypeWorker(c, types, unionReduction, alias, undefined);
1215
- c.unionOfUnionTypes.set(key, result);
1241
+ if (result !== c.errorType && !hasConstrainedIntersection(types))
1242
+ c.unionTypesByInputList.set(hash, types.slice(), alias, unionReduction, result);
1216
1243
  }
1217
1244
  return result;
1218
1245
  }
1219
1246
  return getUnionTypeWorker(c, types, unionReduction, alias, origin);
1220
1247
  }
1248
+ /** An intersection that `addTypeToUnion` reduces by resolving a type variable's constraint. */
1249
+ function isConstrainedIntersection(t) {
1250
+ return (t.flags & 268435456 /* TypeFlags.Intersection */) !== 0 && (t.objectFlags & 134217728 /* ObjectFlags.IsConstrainedTypeVariable */) !== 0;
1251
+ }
1252
+ /** Whether `addTypesToUnion` would set `IncludesConstrainedTypeVariable` for `types`. */
1253
+ function hasConstrainedIntersection(types) {
1254
+ for (const t of types) {
1255
+ if (isConstrainedIntersection(t))
1256
+ return true;
1257
+ if ((t.flags & 134217728 /* TypeFlags.Union */) !== 0 && hasConstrainedIntersection(t.types))
1258
+ return true;
1259
+ }
1260
+ return false;
1261
+ }
1221
1262
  class TypeSet {
1222
1263
  types = [];
1223
1264
  includes = 0;
@@ -1708,18 +1749,27 @@ export function intersectTypes(c, type1, type2) {
1708
1749
  export function getIntersectionType(c, types) {
1709
1750
  return getIntersectionTypeEx(c, types, 0 /* IntersectionFlags.None */, undefined);
1710
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
+ */
1711
1757
  class OrderedTypeSet {
1758
+ static INDEX_AFTER = 8;
1712
1759
  values = [];
1713
- seen = new Set();
1760
+ index;
1714
1761
  includes = 0;
1715
1762
  has(t) {
1716
- return this.seen.has(t);
1763
+ return this.index !== undefined ? this.index.has(t) : this.values.includes(t);
1717
1764
  }
1718
1765
  add(t) {
1719
- if (!this.seen.has(t)) {
1720
- this.seen.add(t);
1721
- this.values.push(t);
1722
- }
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);
1723
1773
  }
1724
1774
  }
1725
1775
  function addTypesToIntersection(c, set, types) {
@@ -2085,7 +2135,8 @@ function getCrossProductIntersections(c, types, flags) {
2085
2135
  */
2086
2136
  function addCrossProductIntersections(c, types, flags, constituents, index, unit, intersections) {
2087
2137
  if (index === types.length) {
2088
- 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);
2089
2140
  if ((t.flags & 262144 /* TypeFlags.Never */) === 0)
2090
2141
  intersections.push(t);
2091
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)
@@ -2,6 +2,7 @@ import type { ModuleSpecifierResult } from './node-builder-names.js';
2
2
  import type { EmitHelperFileLinks } from './checker-emit-helpers.js';
3
3
  import type { Node, PatternAmbientModule, SourceFile } from './ast.js';
4
4
  import { CompactIntLinkTable, CompactLinkTable, IntLinkTable, LinkTable, PagedIdSet, SparseLinkTable } from './link-tables.js';
5
+ import { ExprCheckRecord } from './expr-record.js';
5
6
  import { Diagnostic, type DiagnosticMessage, Diagnostics } from './diagnostics.js';
6
7
  import { type CompilerOptions, ModuleKind, ScriptTarget } from './options.js';
7
8
  import { CheckFlags, Symbol, SymbolFlags, type SymbolTable } from './symbol.js';
@@ -154,6 +155,8 @@ export declare class Checker implements TypeChecking {
154
155
  readonly noUncheckedIndexedAccess: boolean;
155
156
  typeCount: number;
156
157
  signatureCount: number;
158
+ /** Transient symbols the checker created (statistics), as tsgo's `Checker.SymbolCount`. */
159
+ symbolCount: number;
157
160
  /** Positions of members by name in the tables and lists that lazily instantiated members come from. */
158
161
  readonly memberPositionsInLists: Map<Symbol[], Map<string, number>>;
159
162
  /** The property names of the last instantiation of each such list whose table is built on demand. */
@@ -225,6 +228,8 @@ export declare class Checker implements TypeChecking {
225
228
  readonly resolvedSymbols: CompactLinkTable<Symbol>;
226
229
  /** The resolved type of a type node or expression. */
227
230
  readonly resolvedTypes: CompactLinkTable<Type>;
231
+ /** The type the last completed check of each expression key produced (expr-record.ts). */
232
+ readonly exprCheckRecord: ExprCheckRecord;
228
233
  /** The resolved signature of a call-like node or a signature declaration. */
229
234
  readonly resolvedSignatures: CompactLinkTable<Signature>;
230
235
  /** Merged symbols, indexed by the id of the symbol merged into them. */
@@ -274,6 +279,7 @@ export declare class Checker implements TypeChecking {
274
279
  readonly unionOfUnionTypes: Map<string, Type>;
275
280
  /** `unionOfUnionTypes` without an alias, by both ids and the reduction packed into one number. */
276
281
  readonly unionOfUnionTypesById: Map<number, Type>;
282
+ readonly unionTypesByInputList: TypeListCache<Type>;
277
283
  readonly intersectionTypes: TypeListCache<Type>;
278
284
  readonly tupleTypes: Map<string, Type>;
279
285
  readonly indexedAccessTypes: Map<string, Type>;
@@ -548,7 +554,7 @@ export declare class Checker implements TypeChecking {
548
554
  /** The access flags of the key `getIndexedAccessTypeEx` keeps each indexed access type by. */
549
555
  indexedAccessKeyFlags: Map<Type, number> | undefined;
550
556
  /** Where results are shared between checker threads (shared-results.ts): the file of each diagnostic deferred. */
551
- deferredDiagnosticFiles: string[] | undefined;
557
+ deferredDiagnosticFiles: number[] | undefined;
552
558
  constructor(host: CheckerHost);
553
559
  /** Checks `file` if needed and returns its semantic diagnostics, sorted. */
554
560
  getDiagnostics(file: SourceFile): Diagnostic[];
@@ -1,5 +1,6 @@
1
1
  import { sideOf } from './side-state.js';
2
2
  import { CompactIntLinkTable, CompactLinkTable, IntLinkTable, LinkTable, PagedIdSet, SparseLinkTable, } from './link-tables.js';
3
+ import { ExprCheckRecord } from './expr-record.js';
3
4
  import { getErrorRangeForNode, getSourceFileOfNode } from './binder-utilities.js';
4
5
  import { Diagnostic, compareDiagnostics, equalDiagnostics, } from './diagnostics.js';
5
6
  import { ModuleKind, ScriptTarget, getEmitScriptTarget, getIsolatedModules, getStrictOptionValue, shouldPreserveConstEnums, } from './options.js';
@@ -17,7 +18,7 @@ import { InferenceCaches } from './checker-inference.js';
17
18
  import { AssignmentMarker } from './checker-narrowing.js';
18
19
  import { JsxState } from './checker-jsx.js';
19
20
  import { SourceFileMetadata, getEmitModuleFormatOfFile } from './program-utilities.js';
20
- import { shareThreads, startThreadSharing } from './shared-results.js';
21
+ import { startThreadSharing } from './shared-results.js';
21
22
  /** What the checker needs from a program. */
22
23
  export class CheckerHost {
23
24
  /** How a module name in `file` resolved in `mode`, if the program resolved it. */
@@ -281,6 +282,8 @@ export class Checker {
281
282
  // Counters for type and signature ids.
282
283
  typeCount = 0;
283
284
  signatureCount = 0;
285
+ /** Transient symbols the checker created (statistics), as tsgo's `Checker.SymbolCount`. */
286
+ symbolCount = 0;
284
287
  /** Positions of members by name in the tables and lists that lazily instantiated members come from. */
285
288
  memberPositionsInLists = new Map();
286
289
  /** The property names of the last instantiation of each such list whose table is built on demand. */
@@ -358,6 +361,8 @@ export class Checker {
358
361
  resolvedSymbols = new CompactLinkTable();
359
362
  /** The resolved type of a type node or expression. */
360
363
  resolvedTypes = new CompactLinkTable();
364
+ /** The type the last completed check of each expression key produced (expr-record.ts). */
365
+ exprCheckRecord = new ExprCheckRecord();
361
366
  /** The resolved signature of a call-like node or a signature declaration. */
362
367
  resolvedSignatures = new CompactLinkTable();
363
368
  /** Merged symbols, indexed by the id of the symbol merged into them. */
@@ -409,6 +414,7 @@ export class Checker {
409
414
  unionOfUnionTypes = new Map();
410
415
  /** `unionOfUnionTypes` without an alias, by both ids and the reduction packed into one number. */
411
416
  unionOfUnionTypesById = new Map();
417
+ unionTypesByInputList = new TypeListCache();
412
418
  intersectionTypes = new TypeListCache();
413
419
  tupleTypes = new Map();
414
420
  indexedAccessTypes = new Map();
@@ -576,7 +582,7 @@ export class Checker {
576
582
  deferDiagnostic(node, report) {
577
583
  this.deferredDiagnostics.push(report);
578
584
  if (this.deferredDiagnosticFiles !== undefined)
579
- this.deferredDiagnosticFiles.push(getSourceFileOfNode(node).fileName);
585
+ this.deferredDiagnosticFiles.push(this.fileIndex.get(getSourceFileOfNode(node)) ?? -1);
580
586
  }
581
587
  /**
582
588
  * The checked object literals of each file whose members may set deprecated properties of their contextual
@@ -886,8 +892,9 @@ export class Checker {
886
892
  mergeAmbientModulesAndAugmentations(this);
887
893
  this.modulesMerged = true;
888
894
  this.mergeDiagnostics.push(this.diagnostics.takeLog(), this.suggestionDiagnostics.takeLog());
889
- if (shareThreads)
890
- startThreadSharing(this);
895
+ // Returns unless this thread was given sharing data (`ThreadSharingData` in its worker data): the
896
+ // main thread, and every thread of a run that didn't share.
897
+ startThreadSharing(this);
891
898
  if (this.threadSharing !== undefined) {
892
899
  this.distributedConditionals = new Map();
893
900
  this.distributedByKey = new Map();
@@ -977,10 +984,12 @@ export class Checker {
977
984
  return new TypeParameter(this.nextTypeId(), symbol);
978
985
  }
979
986
  newSymbol(flags, name) {
987
+ this.symbolCount++;
980
988
  const symbol = new Symbol(flags | 33554432 /* SymbolFlags.Transient */, name);
981
989
  return symbol;
982
990
  }
983
991
  newSymbolWithCheckFlags(flags, name, checkFlags) {
992
+ this.symbolCount++;
984
993
  const symbol = new Symbol(flags | 33554432 /* SymbolFlags.Transient */, name);
985
994
  symbol.checkFlags = checkFlags;
986
995
  return symbol;
@@ -1059,6 +1068,7 @@ export function disposeChecker(c) {
1059
1068
  c.unionTypes.clear();
1060
1069
  c.unionOfUnionTypes.clear();
1061
1070
  c.unionOfUnionTypesById.clear();
1071
+ c.unionTypesByInputList.clear();
1062
1072
  c.intersectionTypes.clear();
1063
1073
  c.tupleTypes.clear();
1064
1074
  c.indexedAccessTypes.clear();
@@ -105,6 +105,11 @@ export declare abstract class CompilerProgram {
105
105
  readonly times: CompileTimes;
106
106
  readonly emitter: ProgramEmitter;
107
107
  constructor(checked: CheckedProgram, times: CompileTimes);
108
+ /**
109
+ * Whether this run checked the program, which `getDiagnosticsOfProgram` sets when it checks it. A run
110
+ * stopped before checking, by syntax errors or `--noCheck`, keeps no record (`run-records.ts`).
111
+ */
112
+ checkedTheProgram: boolean;
108
113
  /**
109
114
  * The time spent in declaration emit while checking, to count as emit time rather than check time, since
110
115
  * the last call. Only an incremental program emits while checking, to compute signatures.
@@ -311,6 +311,11 @@ export class CompilerProgram {
311
311
  this.times = times;
312
312
  this.emitter = new ProgramEmitter(checked);
313
313
  }
314
+ /**
315
+ * Whether this run checked the program, which `getDiagnosticsOfProgram` sets when it checks it. A run
316
+ * stopped before checking, by syntax errors or `--noCheck`, keeps no record (`run-records.ts`).
317
+ */
318
+ checkedTheProgram = false;
314
319
  /**
315
320
  * The time spent in declaration emit while checking, to count as emit time rather than check time, since
316
321
  * the last call. Only an incremental program emits while checking, to compute signatures.
@@ -447,6 +452,9 @@ export function getDiagnosticsOfProgram(program, withDeclarationDiagnostics, dec
447
452
  for (const d of program.getGlobalDiagnostics(false))
448
453
  result.push(d);
449
454
  if (result.length === configCount) {
455
+ // With `--noCheck` the checker skips every file: the run checked nothing to sample (`run-records.ts`).
456
+ if (options.noCheck !== true)
457
+ program.checkedTheProgram = true;
450
458
  const checkStart = performance.now();
451
459
  const semantic = program.getSemanticDiagnostics();
452
460
  // Declaration emit that computed signatures while checking counts as emit time, as in TypeScript 7.1.
@@ -0,0 +1,11 @@
1
+ import type { Type } from './checker-types.js';
2
+ export declare class ExprCheckRecord {
3
+ /** The node id of the check at each entry, plus one; zero where no check is recorded. */
4
+ private readonly nodeIds;
5
+ private readonly modes;
6
+ private readonly types;
7
+ /** The type the last completed check of the node under `mode` produced, if the entry holds it. */
8
+ get(nodeId: number, mode: number): Type | undefined;
9
+ /** Records that a check of the node under `mode` produced `type`. */
10
+ set(nodeId: number, mode: number, type: Type): void;
11
+ }
@@ -0,0 +1,53 @@
1
+ // The type the last completed check of an expression produced, by node and check mode, for the
2
+ // expressions that are checked with no contextual type.
3
+ //
4
+ // The checker checks some expressions more than once with the same inputs: a body that the eager
5
+ // pass reached and the deferred pass reaches again, a node re-checked after a loop body, an
6
+ // argument of a second inference round. A check is a function of the node, the check mode and the
7
+ // checker's state, and the state only grows while the checker runs, so a check that completed
8
+ // earlier answers the next check of the same node: the later check would produce the type the
9
+ // earlier one produced, report the diagnostics it reported and defer the nodes it deferred.
10
+ //
11
+ // A contextual type is part of the inputs, so the record can only serve an expression whose check
12
+ // has none: the checker-contextual predicate says so before the record is consulted, and a check
13
+ // under a contextual type never reads or writes the record. For the same reason the record is not
14
+ // consulted while an inference context is in force: what the check infers into depends on it.
15
+ //
16
+ // The record is a direct-mapped table that stores the key beside the value, so a lookup that lands
17
+ // on another node reads the entry as a miss. Its size bounds the memory and the cache the lookups
18
+ // use: an entry is a node id, a mode and a type slot, the whole table takes about 200 KB, and 2^14
19
+ // entries serve nearly all repeats (2^14 against 2^20 loses 0.1% of the check on the largest
20
+ // program measured).
21
+ /** Entries in the record; a power of two. */
22
+ const EntryCount = 1 << 14;
23
+ const EntryMask = EntryCount - 1;
24
+ /** The types by entry; a slot holds the type of the check recorded at that entry. */
25
+ function newTypeSlots() {
26
+ const slots = [];
27
+ for (let i = 0; i < EntryCount; i++)
28
+ slots.push(undefined);
29
+ return slots;
30
+ }
31
+ function entryOf(nodeId, mode) {
32
+ return (Math.imul(nodeId, 0x9e3779b1) ^ mode) & EntryMask;
33
+ }
34
+ export class ExprCheckRecord {
35
+ /** The node id of the check at each entry, plus one; zero where no check is recorded. */
36
+ nodeIds = new Int32Array(EntryCount);
37
+ modes = new Uint8Array(EntryCount);
38
+ types = newTypeSlots();
39
+ /** The type the last completed check of the node under `mode` produced, if the entry holds it. */
40
+ get(nodeId, mode) {
41
+ const entry = entryOf(nodeId, mode);
42
+ if (this.nodeIds[entry] !== nodeId + 1 || this.modes[entry] !== mode)
43
+ return undefined;
44
+ return this.types[entry];
45
+ }
46
+ /** Records that a check of the node under `mode` produced `type`. */
47
+ set(nodeId, mode, type) {
48
+ const entry = entryOf(nodeId, mode);
49
+ this.nodeIds[entry] = nodeId + 1;
50
+ this.modes[entry] = mode;
51
+ this.types[entry] = type;
52
+ }
53
+ }
@@ -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;
@@ -0,0 +1,9 @@
1
+ import type { ProgramLifetime } from '@scriptc/types';
2
+ /**
3
+ * The text of an identifier. The identifiers a parser's scanner interns with the same text share one
4
+ * (scanner.ts `IdentifierTable`), and natively an identifier refers to it in 4 bytes.
5
+ */
6
+ export declare class IdentifierName implements ProgramLifetime {
7
+ readonly text: string;
8
+ constructor(text: string);
9
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The text of an identifier. The identifiers a parser's scanner interns with the same text share one
3
+ * (scanner.ts `IdentifierTable`), and natively an identifier refers to it in 4 bytes.
4
+ */
5
+ export class IdentifierName {
6
+ text;
7
+ constructor(text) {
8
+ this.text = text;
9
+ }
10
+ }