@@ -323,6 +323,8 @@ namespace ts {
323
323
let constraintDepth = 0;
324
324
let currentNode: Node | undefined;
325
325
326
+ const typeCatalog: Type[] = []; // NB: id is index + 1
327
+
326
328
const emptySymbols = createSymbolTable();
327
329
const arrayVariances = [VarianceFlags.Covariant];
328
330
@@ -366,6 +368,7 @@ namespace ts {
366
368
getNodeCount: () => sum(host.getSourceFiles(), "nodeCount"),
367
369
getIdentifierCount: () => sum(host.getSourceFiles(), "identifierCount"),
368
370
getSymbolCount: () => sum(host.getSourceFiles(), "symbolCount") + symbolCount,
371
+ getTypeCatalog: () => typeCatalog,
369
372
getTypeCount: () => typeCount,
370
373
getInstantiationCount: () => totalInstantiationCount,
371
374
getRelationCacheSizes: () => ({
@@ -380,6 +383,7 @@ namespace ts {
380
383
getMergedSymbol,
381
384
getDiagnostics,
382
385
getGlobalDiagnostics,
386
+ getRecursionIdentity,
383
387
getTypeOfSymbolAtLocation: (symbol, locationIn) => {
384
388
const location = getParseTreeNode(locationIn);
385
389
return location ? getTypeOfSymbolAtLocation(symbol, location) : errorType;
@@ -3674,6 +3678,7 @@ namespace ts {
3674
3678
const result = new Type(checker, flags);
3675
3679
typeCount++;
3676
3680
result.id = typeCount;
3681
+ typeCatalog.push(result);
3677
3682
return result;
3678
3683
}
3679
3684
@@ -10847,6 +10852,7 @@ namespace ts {
10847
10852
// very high likelihood we're dealing with an infinite generic type that perpetually generates
10848
10853
// new type identities as we descend into it. We stop the recursion here and mark this type
10849
10854
// and the outer types as having circular constraints.
10855
+ tracing.instant(tracing.Phase.Check, "getImmediateBaseConstraint_DepthLimit", { typeId: t.id, originalTypeId: type.id, depth: constraintDepth });
10850
10856
error(currentNode, Diagnostics.Type_instantiation_is_excessively_deep_and_possibly_infinite);
10851
10857
nonTerminating = true;
10852
10858
return t.immediateBaseConstraint = noConstraintType;
@@ -12936,6 +12942,7 @@ namespace ts {
12936
12942
// caps union types at 5000 unique literal types and 1000 unique object types.
12937
12943
const estimatedCount = (count / (len - i)) * len;
12938
12944
if (estimatedCount > (primitivesOnly ? 25000000 : 1000000)) {
12945
+ tracing.instant(tracing.Phase.Check, "removeSubtypes_DepthLimit", { typeIds: types.map(t => t.id) });
12939
12946
error(currentNode, Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent);
12940
12947
return false;
12941
12948
}
@@ -15096,6 +15103,7 @@ namespace ts {
15096
15103
// We have reached 50 recursive type instantiations and there is a very high likelyhood we're dealing
15097
15104
// with a combination of infinite generic types that perpetually generate new type identities. We stop
15098
15105
// the recursion here by yielding the error type.
15106
+ tracing.instant(tracing.Phase.Check, "instantiateType_DepthLimit", { typeId: type.id, instantiationDepth, instantiationCount });
15099
15107
error(currentNode, Diagnostics.Type_instantiation_is_excessively_deep_and_possibly_infinite);
15100
15108
return errorType;
15101
15109
}
@@ -16195,6 +16203,7 @@ namespace ts {
16195
16203
containingMessageChain?: () => DiagnosticMessageChain | undefined,
16196
16204
errorOutputContainer?: { errors?: Diagnostic[], skipLogging?: boolean },
16197
16205
): boolean {
16206
+
16198
16207
let errorInfo: DiagnosticMessageChain | undefined;
16199
16208
let relatedInfo: [DiagnosticRelatedInformation, ...DiagnosticRelatedInformation[]] | undefined;
16200
16209
let maybeKeys: string[];
@@ -16216,6 +16225,7 @@ namespace ts {
16216
16225
reportIncompatibleStack();
16217
16226
}
16218
16227
if (overflow) {
16228
+ tracing.instant(tracing.Phase.Check, "checkTypeRelatedTo_DepthLimit", { sourceId: source.id, targetId: target.id, depth });
16219
16229
const diag = error(errorNode || currentNode, Diagnostics.Excessive_stack_depth_comparing_types_0_and_1, typeToString(source), typeToString(target));
16220
16230
if (errorOutputContainer) {
16221
16231
(errorOutputContainer.errors || (errorOutputContainer.errors = [])).push(diag);
@@ -16257,6 +16267,8 @@ namespace ts {
16257
16267
if (errorNode && errorOutputContainer && errorOutputContainer.skipLogging && result === Ternary.False) {
16258
16268
Debug.assert(!!errorOutputContainer.errors, "missed opportunity to interact with error.");
16259
16269
}
16270
+
16271
+
16260
16272
return result !== Ternary.False;
16261
16273
16262
16274
function resetErrorInfo(saved: ReturnType<typeof captureErrorCalculationState>) {
@@ -17034,6 +17046,17 @@ namespace ts {
17034
17046
return originalHandler!(onlyUnreliable);
17035
17047
};
17036
17048
}
17049
+
17050
+ if (expandingFlags === ExpandingFlags.Both) {
17051
+ tracing.instant(tracing.Phase.Check, "recursiveTypeRelatedTo_DepthLimit", {
17052
+ sourceId: source.id,
17053
+ sourceIdStack: sourceStack.map(t => t.id),
17054
+ targetId: target.id,
17055
+ targetIdStack: targetStack.map(t => t.id),
17056
+ depth,
17057
+ });
17058
+ }
17059
+
17037
17060
const result = expandingFlags !== ExpandingFlags.Both ? structuredTypeRelatedTo(source, target, reportErrors, intersectionState) : Ternary.Maybe;
17038
17061
if (outofbandVarianceMarkerHandler) {
17039
17062
outofbandVarianceMarkerHandler = originalHandler;
@@ -17059,6 +17082,13 @@ namespace ts {
17059
17082
}
17060
17083
17061
17084
function structuredTypeRelatedTo(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary {
17085
+ tracing.begin(tracing.Phase.Check, "structuredTypeRelatedTo", { sourceId: source.id, targetId: target.id });
17086
+ const result = structuredTypeRelatedToWorker(source, target, reportErrors, intersectionState);
17087
+ tracing.end();
17088
+ return result;
17089
+ }
17090
+
17091
+ function structuredTypeRelatedToWorker(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary {
17062
17092
if (intersectionState & IntersectionState.PropertyCheck) {
17063
17093
return propertiesRelatedTo(source, target, reportErrors, /*excludedProperties*/ undefined, IntersectionState.None);
17064
17094
}
@@ -17517,6 +17547,7 @@ namespace ts {
17517
17547
numCombinations *= countTypes(getTypeOfSymbol(sourceProperty));
17518
17548
if (numCombinations > 25) {
17519
17549
// We've reached the complexity limit.
17550
+ tracing.instant(tracing.Phase.Check, "typeRelatedToDiscriminatedType_DepthLimit", { sourceId: source.id, targetId: target.id, numCombinations });
17520
17551
return Ternary.False;
17521
17552
}
17522
17553
}
@@ -18267,6 +18298,7 @@ namespace ts {
18267
18298
function getVariancesWorker<TCache extends { variances?: VarianceFlags[] }>(typeParameters: readonly TypeParameter[] = emptyArray, cache: TCache, createMarkerType: (input: TCache, param: TypeParameter, marker: Type) => Type): VarianceFlags[] {
18268
18299
let variances = cache.variances;
18269
18300
if (!variances) {
18301
+ tracing.begin(tracing.Phase.Check, "getVariancesWorker", { arity: typeParameters.length, id: (cache as any).id ?? (cache as any).declaredType?.id ?? -1 });
18270
18302
// The emptyArray singleton is used to signal a recursive invocation.
18271
18303
cache.variances = emptyArray;
18272
18304
variances = [];
@@ -18301,6 +18333,7 @@ namespace ts {
18301
18333
variances.push(variance);
18302
18334
}
18303
18335
cache.variances = variances;
18336
+ tracing.end();
18304
18337
}
18305
18338
return variances;
18306
18339
}
@@ -18449,7 +18482,9 @@ namespace ts {
18449
18482
for (let i = 0; i < depth; i++) {
18450
18483
if (getRecursionIdentity(stack[i]) === identity) {
18451
18484
count++;
18452
- if (count >= 5) return true;
18485
+ if (count >= 5) {
18486
+ return true;
18487
+ }
18453
18488
}
18454
18489
}
18455
18490
}
@@ -19554,6 +19589,7 @@ namespace ts {
19554
19589
inferFromTypes(originalSource, originalTarget);
19555
19590
19556
19591
function inferFromTypes(source: Type, target: Type): void {
19592
+
19557
19593
if (!couldContainTypeVariables(target)) {
19558
19594
return;
19559
19595
}
@@ -21296,6 +21332,7 @@ namespace ts {
21296
21332
if (flowDepth === 2000) {
21297
21333
// We have made 2000 recursive invocations. To avoid overflowing the call stack we report an error
21298
21334
// and disable further control flow analysis in the containing function or module body.
21335
+ tracing.instant(tracing.Phase.Check, "getTypeAtFlowNode_DepthLimit", { flowId: flow.id });
21299
21336
flowAnalysisDisabled = true;
21300
21337
reportFlowControlError(reference);
21301
21338
return errorType;
@@ -30504,6 +30541,7 @@ namespace ts {
30504
30541
}
30505
30542
30506
30543
function checkExpression(node: Expression | QualifiedName, checkMode?: CheckMode, forceTuple?: boolean): Type {
30544
+ tracing.begin(tracing.Phase.Check, "checkExpression", { kind: node.kind, pos: node.pos, end: node.end });
30507
30545
const saveCurrentNode = currentNode;
30508
30546
currentNode = node;
30509
30547
instantiationCount = 0;
@@ -30513,6 +30551,7 @@ namespace ts {
30513
30551
checkConstEnumAccess(node, type);
30514
30552
}
30515
30553
currentNode = saveCurrentNode;
30554
+ tracing.end();
30516
30555
return type;
30517
30556
}
30518
30557
@@ -33306,8 +33345,10 @@ namespace ts {
33306
33345
}
33307
33346
33308
33347
function checkVariableDeclaration(node: VariableDeclaration) {
33348
+ tracing.begin(tracing.Phase.Check, "checkVariableDeclaration", { kind: node.kind, pos: node.pos, end: node.end });
33309
33349
checkGrammarVariableDeclaration(node);
33310
- return checkVariableLikeDeclaration(node);
33350
+ checkVariableLikeDeclaration(node);
33351
+ tracing.end();
33311
33352
}
33312
33353
33313
33354
function checkBindingElement(node: BindingElement) {
@@ -36348,10 +36389,12 @@ namespace ts {
36348
36389
}
36349
36390
36350
36391
function checkSourceFile(node: SourceFile) {
36392
+ tracing.begin(tracing.Phase.Check, "checkSourceFile", { path: node.path });
36351
36393
performance.mark("beforeCheck");
36352
36394
checkSourceFileWorker(node);
36353
36395
performance.mark("afterCheck");
36354
36396
performance.measure("Check", "beforeCheck", "afterCheck");
36397
+ tracing.end();
36355
36398
}
36356
36399
36357
36400
function unusedIsError(kind: UnusedKind, isAmbient: boolean): boolean {
0 commit comments