Add instantaneous events when depth limits are hit

This commit is contained in:
Andrew Casey
2020-08-28 15:51:52 -07:00
parent 7b40895b29
commit 36489ff5c6
2 changed files with 22 additions and 1 deletions

View File

@@ -10804,6 +10804,7 @@ namespace ts {
// very high likelihood we're dealing with an infinite generic type that perpetually generates
// new type identities as we descend into it. We stop the recursion here and mark this type
// and the outer types as having circular constraints.
tracing.instant(tracing.Phase.Check, "getImmediateBaseConstraint_DepthLimit", { typeId: t.id, originalTypeId: type.id, depth: constraintDepth });
error(currentNode, Diagnostics.Type_instantiation_is_excessively_deep_and_possibly_infinite);
nonTerminating = true;
return t.immediateBaseConstraint = noConstraintType;
@@ -12878,6 +12879,7 @@ namespace ts {
// caps union types at 5000 unique literal types and 1000 unique object types.
const estimatedCount = (count / (len - i)) * len;
if (estimatedCount > (primitivesOnly ? 25000000 : 1000000)) {
tracing.instant(tracing.Phase.Check, "removeSubtypes_DepthLimit", { typeIds: types.map(t => t.id) });
error(currentNode, Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent);
return false;
}
@@ -14940,6 +14942,7 @@ namespace ts {
// We have reached 50 recursive type instantiations and there is a very high likelyhood we're dealing
// with a combination of infinite generic types that perpetually generate new type identities. We stop
// the recursion here by yielding the error type.
tracing.instant(tracing.Phase.Check, "instantiateType_DepthLimit", { typeId: type.id, instantiationDepth, instantiationCount });
error(currentNode, Diagnostics.Type_instantiation_is_excessively_deep_and_possibly_infinite);
return errorType;
}
@@ -16058,6 +16061,7 @@ namespace ts {
reportIncompatibleStack();
}
if (overflow) {
tracing.instant(tracing.Phase.Check, "checkTypeRelatedTo_DepthLimit", { sourceId: source.id, targetId: target.id, depth });
const diag = error(errorNode || currentNode, Diagnostics.Excessive_stack_depth_comparing_types_0_and_1, typeToString(source), typeToString(target));
if (errorOutputContainer) {
(errorOutputContainer.errors || (errorOutputContainer.errors = [])).push(diag);
@@ -17358,6 +17362,7 @@ namespace ts {
numCombinations *= countTypes(getTypeOfSymbol(sourceProperty));
if (numCombinations > 25) {
// We've reached the complexity limit.
tracing.instant(tracing.Phase.Check, "typeRelatedToDiscriminatedType_DepthLimit", { sourceId: source.id, targetId: target.id, numCombinations });
return Ternary.False;
}
}
@@ -18281,7 +18286,10 @@ namespace ts {
for (let i = 0; i < depth; i++) {
if (getRecursionIdentity(stack[i]) === identity) {
count++;
if (count >= 5) return true;
if (count >= 5) {
tracing.instant(tracing.Phase.Check, "isDeeplyNestedType_DepthLimit", { typeId: type.id, typeIdStack: stack.map(t => t.id), depth, count });
return true;
}
}
}
}
@@ -21089,6 +21097,7 @@ namespace ts {
if (flowDepth === 2000) {
// We have made 2000 recursive invocations. To avoid overflowing the call stack we report an error
// and disable further control flow analysis in the containing function or module body.
tracing.instant(tracing.Phase.Check, "getTypeAtFlowNode_DepthLimit", { flowId: flow.id });
flowAnalysisDisabled = true;
reportFlowControlError(reference);
return errorType;

View File

@@ -112,6 +112,18 @@ namespace ts.tracing {
performance.measure("Tracing", "beginTracing", "endTracing");
}
export function instant(phase: Phase, name: string, args: object) {
if (!traceFd) {
return;
}
Debug.assert(fs);
performance.mark("beginTracing");
fs.writeSync(traceFd, `{"pid":1,"tid":1,"ph":"i","cat":"${phase}","ts":${1000 * timestamp()},"name":"${name}","s":"g","args":{ "ts": ${JSON.stringify(args)} }},\n`);
performance.mark("endTracing");
performance.measure("Tracing", "beginTracing", "endTracing");
}
function indexFromOne(lc: LineAndCharacter): LineAndCharacter {
return {
line: lc.line + 1,