@@ -842,6 +842,7 @@ namespace ts {
842842 const flowLoopTypes: Type[][] = [];
843843 const sharedFlowNodes: FlowNode[] = [];
844844 const sharedFlowTypes: FlowType[] = [];
845+ const flowNodeReachable: (boolean | undefined)[] = [];
845846 const potentialThisCollisions: Node[] = [];
846847 const potentialNewTargetCollisions: Node[] = [];
847848 const awaitedTypeStack: number[] = [];
@@ -16991,6 +16992,40 @@ namespace ts {
1699116992 diagnostics.add(createFileDiagnostic(sourceFile, span.start, span.length, Diagnostics.The_containing_function_or_module_body_is_too_large_for_control_flow_analysis));
1699216993 }
1699316994
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+
1699417029 function getFlowTypeOfReference(reference: Node, declaredType: Type, initialType = declaredType, flowContainer?: Node, couldBeUninitialized?: boolean) {
1699517030 let key: string | undefined;
1699617031 let keySet = false;
@@ -17146,11 +17181,11 @@ namespace ts {
1714617181 // Assignments only narrow the computed type if the declared type is a union type. Thus, we
1714717182 // only need to evaluate the assigned type if the declared type is a union type.
1714817183 if (isMatchingReference(reference, node)) {
17149- const flowType = getTypeAtFlowNode(flow.antecedent);
17150- if (flowType === unreachableNeverType) {
17151- return flowType;
17184+ if (!isReachableFlowNode(flow)) {
17185+ return unreachableNeverType;
1715217186 }
1715317187 if (getAssignmentTargetKind(node) === AssignmentKind.Compound) {
17188+ const flowType = getTypeAtFlowNode(flow.antecedent);
1715417189 return createFlowType(getBaseTypeOfLiteralType(getTypeFromFlowType(flowType)), isIncomplete(flowType));
1715517190 }
1715617191 if (declaredType === autoType || declaredType === autoArrayType) {
@@ -17170,16 +17205,15 @@ namespace ts {
1717017205 // reference 'x.y.z', we may be at an assignment to 'x.y' or 'x'. In that case,
1717117206 // return the declared type.
1717217207 if (containsMatchingReference(reference, node)) {
17173- const flowType = getTypeAtFlowNode(flow.antecedent);
17174- if (flowType === unreachableNeverType) {
17175- return flowType;
17208+ if (!isReachableFlowNode(flow)) {
17209+ return unreachableNeverType;
1717617210 }
1717717211 // A matching dotted name might also be an expando property on a function *expression*,
1717817212 // in which case we continue control flow analysis back to the function's declaration
1717917213 if (isVariableDeclaration(node) && (isInJSFile(node) || isVarConst(node))) {
1718017214 const init = getDeclaredExpandoInitializer(node);
1718117215 if (init && (init.kind === SyntaxKind.FunctionExpression || init.kind === SyntaxKind.ArrowFunction)) {
17182- return flowType ;
17216+ return getTypeAtFlowNode(flow.antecedent) ;
1718317217 }
1718417218 }
1718517219 return declaredType;
0 commit comments