From c01064e62890d0403423d94a439f4fe46353fc84 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 14 Apr 2019 23:24:31 -0700 Subject: [PATCH] Record flow analysis errors in NodeLinks --- src/compiler/checker.ts | 24 ++++++++++++------------ src/compiler/types.ts | 1 + 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 23c336251eba3..7a9b0501c9464 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -541,7 +541,7 @@ namespace ts { let flowLoopCount = 0; let sharedFlowCount = 0; let flowNodeCount = -1; - let flowAnalysisDisabled = false; + let flowAnalysisErrors = false; const emptyStringType = getLiteralType(""); const zeroType = getLiteralType(0); @@ -15950,17 +15950,14 @@ namespace ts { return false; } - function reportFlowControlError(node: Node) { - const block = findAncestor(node, isFunctionOrModuleBlock); - const sourceFile = getSourceFileOfNode(node); - const span = getSpanOfTokenAtPosition(sourceFile, block.statements.pos); - diagnostics.add(createFileDiagnostic(sourceFile, span.start, span.length, Diagnostics.The_containing_function_or_module_body_is_too_complex_for_control_flow_analysis)); + function getContainingBlock(node: Node) { + return findAncestor(node, isFunctionOrModuleBlock); } function getFlowTypeOfReference(reference: Node, declaredType: Type, initialType = declaredType, flowContainer?: Node, couldBeUninitialized?: boolean) { let key: string | undefined; let flowDepth = 0; - if (flowAnalysisDisabled) { + if (flowAnalysisErrors && getNodeLinks(getContainingBlock(reference)).flags & NodeCheckFlags.FlowAnalysisError) { return errorType; } if (!reference.flowNode || !couldBeUninitialized && !(declaredType.flags & TypeFlags.Narrowable)) { @@ -15984,9 +15981,14 @@ namespace ts { // We have made 2000 recursive invocations or visited 500000 control flow nodes while analyzing // the containing function or module body, the limit at which we consider the function or module // body is too complex and disable further control flow analysis. - if (!flowAnalysisDisabled) { - flowAnalysisDisabled = true; - reportFlowControlError(reference); + const block = getContainingBlock(reference); + const nodeLinks = getNodeLinks(block); + if (!(nodeLinks.flags & NodeCheckFlags.FlowAnalysisError)) { + nodeLinks.flags |= NodeCheckFlags.FlowAnalysisError; + const sourceFile = getSourceFileOfNode(block); + const span = getSpanOfTokenAtPosition(sourceFile, block.statements.pos); + diagnostics.add(createFileDiagnostic(sourceFile, span.start, span.length, Diagnostics.The_containing_function_or_module_body_is_too_complex_for_control_flow_analysis)); + flowAnalysisErrors = true; } return errorType; } @@ -26032,11 +26034,9 @@ namespace ts { } if (isFunctionOrModuleBlock(node)) { const saveFlowNodeCount = flowNodeCount; - const saveFlowAnalysisDisabled = flowAnalysisDisabled; flowNodeCount = 0; forEach(node.statements, checkSourceElement); flowNodeCount = saveFlowNodeCount; - flowAnalysisDisabled = saveFlowAnalysisDisabled; } else { forEach(node.statements, checkSourceElement); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 23d72875e4f1b..57d53ad0ed7f1 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3855,6 +3855,7 @@ namespace ts { AssignmentsMarked = 0x00800000, // Parameter assignments have been marked ClassWithConstructorReference = 0x01000000, // Class that contains a binding to its constructor inside of the class body. ConstructorReferenceInClass = 0x02000000, // Binding to a class constructor inside of the class's body. + FlowAnalysisError = 0x04000000, // Control flow analysis error in this block } /* @internal */