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.
- package/README.md +7 -1
- package/dist/api/compiler/ast.d.ts +15 -3
- package/dist/api/compiler/ast.js +36 -15
- package/dist/api/compiler/checker-classes.js +2 -1
- package/dist/api/compiler/checker-contextual.d.ts +20 -0
- package/dist/api/compiler/checker-contextual.js +111 -1
- package/dist/api/compiler/checker-expressions.js +14 -1
- 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-jsx.js +2 -1
- 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 +70 -19
- 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 +7 -1
- package/dist/api/compiler/checker.js +14 -4
- package/dist/api/compiler/compile-program.d.ts +5 -0
- package/dist/api/compiler/compile-program.js +8 -0
- package/dist/api/compiler/expr-record.d.ts +11 -0
- package/dist/api/compiler/expr-record.js +53 -0
- package/dist/api/compiler/file-loader.d.ts +5 -0
- package/dist/api/compiler/file-loader.js +7 -0
- package/dist/api/compiler/identifier-name.d.ts +9 -0
- package/dist/api/compiler/identifier-name.js +10 -0
- package/dist/api/compiler/jsdoc.js +4 -2
- package/dist/api/compiler/parser.d.ts +2 -1
- package/dist/api/compiler/parser.js +10 -8
- package/dist/api/compiler/printer/factory.js +3 -2
- package/dist/api/compiler/printer/printer.js +3 -2
- package/dist/api/compiler/program-checker.d.ts +18 -0
- package/dist/api/compiler/program-checker.js +27 -0
- package/dist/api/compiler/reparser.js +4 -3
- package/dist/api/compiler/scanner.d.ts +8 -0
- package/dist/api/compiler/scanner.js +58 -42
- package/dist/api/compiler/shared-results.d.ts +376 -143
- package/dist/api/compiler/shared-results.js +1550 -773
- package/dist/api/compiler/transformers/declarations.js +2 -1
- package/package.json +15 -10
- package/src/compiler/ast.ts +39 -15
- package/src/compiler/cgroup.ts +157 -0
- package/src/compiler/checker-classes.ts +2 -1
- package/src/compiler/checker-contextual.ts +104 -0
- package/src/compiler/checker-expressions.ts +16 -1
- package/src/compiler/checker-grammar.ts +247 -88
- package/src/compiler/checker-heritage.ts +31 -17
- package/src/compiler/checker-jsx.ts +2 -1
- package/src/compiler/checker-modules.ts +4 -2
- package/src/compiler/checker-source-file.ts +1 -1
- package/src/compiler/checker-type-factory.ts +67 -21
- package/src/compiler/checker-type-nodes.ts +5 -5
- package/src/compiler/checker-unused.ts +13 -8
- package/src/compiler/checker.ts +15 -4
- package/src/compiler/compile-program.ts +8 -0
- package/src/compiler/decoder.ts +2 -1
- package/src/compiler/doctor-report.ts +133 -0
- package/src/compiler/expr-record.ts +59 -0
- package/src/compiler/file-loader.ts +8 -0
- package/src/compiler/identifier-name.ts +13 -0
- package/src/compiler/jsdoc.ts +4 -2
- package/src/compiler/parallel-check.ts +364 -146
- package/src/compiler/parallel-emit.ts +3 -3
- package/src/compiler/parse-thread.ts +24 -2
- package/src/compiler/parser.ts +10 -8
- package/src/compiler/printer/factory.ts +3 -2
- package/src/compiler/printer/printer.ts +4 -2
- package/src/compiler/program-checker.ts +28 -0
- package/src/compiler/reparser.ts +7 -3
- package/src/compiler/run-config.ts +1383 -0
- package/src/compiler/run-record-read.ts +87 -0
- package/src/compiler/run-records.ts +575 -0
- package/src/compiler/scanner.ts +57 -41
- package/src/compiler/shared-results.ts +1626 -896
- package/src/compiler/thread-entry.ts +3 -1
- package/src/compiler/transformers/declarations.ts +2 -1
- package/src/compiler/tsc-build.ts +64 -6
- package/src/compiler/tsc-cli.ts +33 -4
- package/src/compiler/tsc-compile.ts +223 -9
- 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
|
-
|
|
672
|
-
|
|
673
|
-
|
|
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
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
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
|
-
|
|
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
|
|
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(
|
|
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
|
-
//
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
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
|
|
1202
|
-
|
|
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.
|
|
1217
|
+
if (result !== c.errorType)
|
|
1218
|
+
c.unionOfUnionTypesById.set(id, result);
|
|
1208
1219
|
}
|
|
1209
1220
|
return result;
|
|
1210
1221
|
}
|
|
1211
|
-
|
|
1212
|
-
|
|
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.
|
|
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
|
-
|
|
1760
|
+
index;
|
|
1714
1761
|
includes = 0;
|
|
1715
1762
|
has(t) {
|
|
1716
|
-
return this.
|
|
1763
|
+
return this.index !== undefined ? this.index.has(t) : this.values.includes(t);
|
|
1717
1764
|
}
|
|
1718
1765
|
add(t) {
|
|
1719
|
-
if (
|
|
1720
|
-
|
|
1721
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
734
|
-
return new TupleElementInfo(getTupleElementFlags(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
330
|
-
|
|
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
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
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:
|
|
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 {
|
|
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)
|
|
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
|
-
|
|
890
|
-
|
|
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
|
+
}
|