Skip to content

Commit 25268ce

Browse files
committed
Separate counters for stack depth and visited flow nodes
1 parent 37d320d commit 25268ce

File tree

1 file changed

+21
-13
lines changed

1 file changed

+21
-13
lines changed

src/compiler/checker.ts

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ namespace ts {
334334
let flowLoopStart = 0;
335335
let flowLoopCount = 0;
336336
let sharedFlowCount = 0;
337-
let flowAnalysisDisabled = false;
337+
let flowNodeCount = 0;
338338

339339
const emptyStringType = getLiteralType("");
340340
const zeroType = getLiteralType(0);
@@ -11495,8 +11495,8 @@ namespace ts {
1149511495

1149611496
function getFlowTypeOfReference(reference: Node, declaredType: Type, initialType = declaredType, flowContainer?: Node, couldBeUninitialized?: boolean) {
1149711497
let key: string;
11498-
let flowLength = 0;
11499-
if (flowAnalysisDisabled) {
11498+
let flowDepth = 0;
11499+
if (flowNodeCount < 0) {
1150011500
return unknownType;
1150111501
}
1150211502
if (!reference.flowNode || !couldBeUninitialized && !(declaredType.flags & TypeFlags.Narrowable)) {
@@ -11516,14 +11516,14 @@ namespace ts {
1151611516
return resultType;
1151711517

1151811518
function getTypeAtFlowNode(flow: FlowNode): FlowType {
11519-
flowLength++;
11519+
flowDepth++;
1152011520
while (true) {
11521-
flowLength++;
11522-
if (flowLength >= 5000) {
11523-
// We have visited as many as 5000 nodes through as many as 2500 recursive invocations. Rather than
11524-
// spending an excessive amount of time and possibly overflowing the call stack, we report an error
11521+
flowNodeCount++;
11522+
if (flowDepth >= 2500 || flowNodeCount >= 100000000) {
11523+
// We have made over 2500 recursive invocations or visited over 100M flow nodes. Rather than
11524+
// overflowing the call stack or spending an excessive amount of time, we report an error
1152511525
// and disable further control flow analysis in the containing function or module body.
11526-
flowAnalysisDisabled = true;
11526+
flowNodeCount = -1;
1152711527
reportFlowControlError(reference);
1152811528
return unknownType;
1152911529
}
@@ -11534,6 +11534,7 @@ namespace ts {
1153411534
// antecedent of more than one node.
1153511535
for (let i = sharedFlowStart; i < sharedFlowCount; i++) {
1153611536
if (sharedFlowNodes[i] === flow) {
11537+
flowDepth--;
1153711538
return sharedFlowTypes[i];
1153811539
}
1153911540
}
@@ -11601,6 +11602,7 @@ namespace ts {
1160111602
sharedFlowTypes[sharedFlowCount] = type;
1160211603
sharedFlowCount++;
1160311604
}
11605+
flowDepth--;
1160411606
return type;
1160511607
}
1160611608
}
@@ -19976,9 +19978,15 @@ namespace ts {
1997619978
if (node.kind === SyntaxKind.Block) {
1997719979
checkGrammarStatementInAmbientContext(node);
1997819980
}
19979-
const saveFlowAnalysisDisabled = flowAnalysisDisabled;
19980-
forEach(node.statements, checkSourceElement);
19981-
flowAnalysisDisabled = saveFlowAnalysisDisabled;
19981+
if (isFunctionOrModuleBlock(node)) {
19982+
const saveFlowNodeCount = flowNodeCount;
19983+
flowNodeCount = 0;
19984+
forEach(node.statements, checkSourceElement);
19985+
flowNodeCount = saveFlowNodeCount;
19986+
}
19987+
else {
19988+
forEach(node.statements, checkSourceElement);
19989+
}
1998219990
if (node.locals) {
1998319991
registerForUnusedIdentifiersCheck(node);
1998419992
}
@@ -22568,7 +22576,7 @@ namespace ts {
2256822576

2256922577
deferredNodes = [];
2257022578
deferredUnusedIdentifierNodes = produceDiagnostics && noUnusedIdentifiers ? [] : undefined;
22571-
flowAnalysisDisabled = false;
22579+
flowNodeCount = 0;
2257222580

2257322581
forEach(node.statements, checkSourceElement);
2257422582

0 commit comments

Comments
 (0)