@@ -940,7 +940,7 @@ namespace ts {
940940 const mergedSymbols: Symbol[] = [];
941941 const symbolLinks: SymbolLinks[] = [];
942942 const nodeLinks: NodeLinks[] = [];
943- const flowLoopCaches : ESMap<string, Type>[] = [];
943+ const flowLabelCaches : ESMap<string, Type>[] = [];
944944 const flowLoopNodes: FlowNode[] = [];
945945 const flowLoopKeys: string[] = [];
946946 const flowLoopTypes: Type[][] = [];
@@ -21656,6 +21656,7 @@ namespace ts {
2165621656 let key: string | undefined;
2165721657 let isKeySet = false;
2165821658 let flowDepth = 0;
21659+ let cacheableBranches = true;
2165921660 if (flowAnalysisDisabled) {
2166021661 return errorType;
2166121662 }
@@ -21747,9 +21748,14 @@ namespace ts {
2174721748 else if (flags & FlowFlags.ReduceLabel) {
2174821749 const target = (<FlowReduceLabel>flow).target;
2174921750 const saveAntecedents = target.antecedents;
21751+ // Modifying the antecedents of a node means we lose our ability to use the cross-invocation branch cache
21752+ // (since that may have follow-on effects on analysis returned by other nodes if the results get cached)
21753+ const oldCacheableBranches = cacheableBranches;
21754+ cacheableBranches = false;
2175021755 target.antecedents = (<FlowReduceLabel>flow).antecedents;
2175121756 type = getTypeAtFlowNode((<FlowReduceLabel>flow).antecedent);
2175221757 target.antecedents = saveAntecedents;
21758+ cacheableBranches = oldCacheableBranches;
2175321759 }
2175421760 else if (flags & FlowFlags.Start) {
2175521761 // Check if we should continue with the control flow of the containing function.
@@ -21955,6 +21961,17 @@ namespace ts {
2195521961 }
2195621962
2195721963 function getTypeAtFlowBranchLabel(flow: FlowLabel): FlowType {
21964+ const id = getFlowNodeId(flow);
21965+ const cache = flowLabelCaches[id] || (flowLabelCaches[id] = new Map<string, Type>());
21966+ const key = getOrSetCacheKey();
21967+ if (!key) {
21968+ // No cache key is generated when binding patterns are in unnarrowable situations
21969+ return declaredType;
21970+ }
21971+ const cached = cacheableBranches && cache.get(key);
21972+ if (cached) {
21973+ return cached;
21974+ }
2195821975 const antecedentTypes: Type[] = [];
2195921976 let subtypeReduction = false;
2196021977 let seenIncomplete = false;
@@ -22004,14 +22021,18 @@ namespace ts {
2200422021 }
2200522022 }
2200622023 }
22007- return createFlowType(getUnionOrEvolvingArrayType(antecedentTypes, subtypeReduction ? UnionReduction.Subtype : UnionReduction.Literal), seenIncomplete);
22024+ const result = createFlowType(getUnionOrEvolvingArrayType(antecedentTypes, subtypeReduction ? UnionReduction.Subtype : UnionReduction.Literal), seenIncomplete);
22025+ if (!seenIncomplete && cacheableBranches) {
22026+ cache.set(key, result as Type);
22027+ }
22028+ return result;
2200822029 }
2200922030
2201022031 function getTypeAtFlowLoopLabel(flow: FlowLabel): FlowType {
2201122032 // If we have previously computed the control flow type for the reference at
2201222033 // this flow loop junction, return the cached type.
2201322034 const id = getFlowNodeId(flow);
22014- const cache = flowLoopCaches [id] || (flowLoopCaches [id] = new Map<string, Type>());
22035+ const cache = flowLabelCaches [id] || (flowLabelCaches [id] = new Map<string, Type>());
2201522036 const key = getOrSetCacheKey();
2201622037 if (!key) {
2201722038 // No cache key is generated when binding patterns are in unnarrowable situations
0 commit comments