@@ -842,6 +842,7 @@ namespace ts {
842
842
const flowLoopTypes: Type[][] = [];
843
843
const sharedFlowNodes: FlowNode[] = [];
844
844
const sharedFlowTypes: FlowType[] = [];
845
+ const flowNodeReachable: (boolean | undefined)[] = [];
845
846
const potentialThisCollisions: Node[] = [];
846
847
const potentialNewTargetCollisions: Node[] = [];
847
848
const awaitedTypeStack: number[] = [];
@@ -16991,6 +16992,40 @@ namespace ts {
16991
16992
diagnostics.add(createFileDiagnostic(sourceFile, span.start, span.length, Diagnostics.The_containing_function_or_module_body_is_too_large_for_control_flow_analysis));
16992
16993
}
16993
16994
16995
+ function isReachableFlowNode(flow: FlowNode) {
16996
+ return isReachableFlowNodeWorker(flow, /*skipCacheCheck*/ false);
16997
+ }
16998
+
16999
+ function isReachableFlowNodeWorker(flow: FlowNode, skipCacheCheck: boolean): boolean {
17000
+ while (true) {
17001
+ const flags = flow.flags;
17002
+ if (flags & FlowFlags.Shared && !skipCacheCheck) {
17003
+ const id = getFlowNodeId(flow);
17004
+ const reachable = flowNodeReachable[id];
17005
+ return reachable !== undefined ? reachable : (flowNodeReachable[id] = isReachableFlowNodeWorker(flow, /*skipCacheCheck*/ true));
17006
+ }
17007
+ if (flags & (FlowFlags.Assignment | FlowFlags.Condition | FlowFlags.SwitchClause | FlowFlags.ArrayMutation | FlowFlags.PreFinally | FlowFlags.AfterFinally)) {
17008
+ flow = (<FlowAssignment | FlowCondition | FlowSwitchClause | FlowArrayMutation | PreFinallyFlow | AfterFinallyFlow>flow).antecedent;
17009
+ }
17010
+ else if (flags & FlowFlags.Call) {
17011
+ const signature = getEffectsSignature((<FlowCall>flow).node);
17012
+ if (signature && getReturnTypeOfSignature(signature).flags & TypeFlags.Never) {
17013
+ return false;
17014
+ }
17015
+ flow = (<FlowCall>flow).antecedent;
17016
+ }
17017
+ else if (flags & FlowFlags.LoopLabel) {
17018
+ flow = (<FlowLabel>flow).antecedents![0];
17019
+ }
17020
+ else if (flags & FlowFlags.BranchLabel) {
17021
+ return every((<FlowLabel>flow).antecedents!, isReachableFlowNode);
17022
+ }
17023
+ else {
17024
+ return true;
17025
+ }
17026
+ }
17027
+ }
17028
+
16994
17029
function getFlowTypeOfReference(reference: Node, declaredType: Type, initialType = declaredType, flowContainer?: Node, couldBeUninitialized?: boolean) {
16995
17030
let key: string | undefined;
16996
17031
let keySet = false;
@@ -17146,11 +17181,11 @@ namespace ts {
17146
17181
// Assignments only narrow the computed type if the declared type is a union type. Thus, we
17147
17182
// only need to evaluate the assigned type if the declared type is a union type.
17148
17183
if (isMatchingReference(reference, node)) {
17149
- const flowType = getTypeAtFlowNode(flow.antecedent);
17150
- if (flowType === unreachableNeverType) {
17151
- return flowType;
17184
+ if (!isReachableFlowNode(flow)) {
17185
+ return unreachableNeverType;
17152
17186
}
17153
17187
if (getAssignmentTargetKind(node) === AssignmentKind.Compound) {
17188
+ const flowType = getTypeAtFlowNode(flow.antecedent);
17154
17189
return createFlowType(getBaseTypeOfLiteralType(getTypeFromFlowType(flowType)), isIncomplete(flowType));
17155
17190
}
17156
17191
if (declaredType === autoType || declaredType === autoArrayType) {
@@ -17170,16 +17205,15 @@ namespace ts {
17170
17205
// reference 'x.y.z', we may be at an assignment to 'x.y' or 'x'. In that case,
17171
17206
// return the declared type.
17172
17207
if (containsMatchingReference(reference, node)) {
17173
- const flowType = getTypeAtFlowNode(flow.antecedent);
17174
- if (flowType === unreachableNeverType) {
17175
- return flowType;
17208
+ if (!isReachableFlowNode(flow)) {
17209
+ return unreachableNeverType;
17176
17210
}
17177
17211
// A matching dotted name might also be an expando property on a function *expression*,
17178
17212
// in which case we continue control flow analysis back to the function's declaration
17179
17213
if (isVariableDeclaration(node) && (isInJSFile(node) || isVarConst(node))) {
17180
17214
const init = getDeclaredExpandoInitializer(node);
17181
17215
if (init && (init.kind === SyntaxKind.FunctionExpression || init.kind === SyntaxKind.ArrowFunction)) {
17182
- return flowType ;
17216
+ return getTypeAtFlowNode(flow.antecedent) ;
17183
17217
}
17184
17218
}
17185
17219
return declaredType;
0 commit comments