@@ -561,6 +561,7 @@ namespace ts {
561
561
const symbolLinks: SymbolLinks[] = [];
562
562
const nodeLinks: NodeLinks[] = [];
563
563
const flowLoopCaches: Map<Type>[] = [];
564
+ const flowAssignmentCaches: Map<Type>[] = [];
564
565
const flowLoopNodes: FlowNode[] = [];
565
566
const flowLoopKeys: string[] = [];
566
567
const flowLoopTypes: Type[][] = [];
@@ -16093,6 +16094,7 @@ namespace ts {
16093
16094
16094
16095
function getFlowTypeOfReference(reference: Node, declaredType: Type, initialType = declaredType, flowContainer?: Node, couldBeUninitialized?: boolean) {
16095
16096
let key: string | undefined;
16097
+ let keySet = false;
16096
16098
let flowDepth = 0;
16097
16099
if (flowAnalysisDisabled) {
16098
16100
return errorType;
@@ -16113,6 +16115,14 @@ namespace ts {
16113
16115
}
16114
16116
return resultType;
16115
16117
16118
+ function getOrSetCacheKey() {
16119
+ if (keySet) {
16120
+ return key;
16121
+ }
16122
+ keySet = true;
16123
+ return key = getFlowCacheKey(reference, declaredType, initialType, flowContainer);
16124
+ }
16125
+
16116
16126
function getTypeAtFlowNode(flow: FlowNode): FlowType {
16117
16127
if (flowDepth === 2000) {
16118
16128
// We have made 2000 recursive invocations. To avoid overflowing the call stack we report an error
@@ -16124,6 +16134,17 @@ namespace ts {
16124
16134
flowDepth++;
16125
16135
while (true) {
16126
16136
const flags = flow.flags;
16137
+ if (flags & FlowFlags.Cached) {
16138
+ const key = getOrSetCacheKey();
16139
+ if (key) {
16140
+ const id = getFlowNodeId(flow);
16141
+ const cache = flowAssignmentCaches[id] || (flowAssignmentCaches[id] = createMap<Type>());
16142
+ const cached = cache.get(key);
16143
+ if (cached) {
16144
+ return cached;
16145
+ }
16146
+ }
16147
+ }
16127
16148
if (flags & FlowFlags.Shared) {
16128
16149
// We cache results of flow type resolution for shared nodes that were previously visited in
16129
16150
// the same getFlowTypeOfReference invocation. A node is considered shared when it is the
@@ -16154,6 +16175,15 @@ namespace ts {
16154
16175
flow = (<FlowAssignment>flow).antecedent;
16155
16176
continue;
16156
16177
}
16178
+ else if (flowLoopCount === flowLoopStart) { // Only cache assignments when not within loop analysis
16179
+ const key = getOrSetCacheKey();
16180
+ if (key && !isIncomplete(type)) {
16181
+ flow.flags |= FlowFlags.Cached;
16182
+ const id = getFlowNodeId(flow);
16183
+ const cache = flowAssignmentCaches[id] || (flowAssignmentCaches[id] = createMap<Type>());
16184
+ cache.set(key, type as Type);
16185
+ }
16186
+ }
16157
16187
}
16158
16188
else if (flags & FlowFlags.Condition) {
16159
16189
type = getTypeAtFlowCondition(<FlowCondition>flow);
@@ -16366,12 +16396,10 @@ namespace ts {
16366
16396
// this flow loop junction, return the cached type.
16367
16397
const id = getFlowNodeId(flow);
16368
16398
const cache = flowLoopCaches[id] || (flowLoopCaches[id] = createMap<Type>());
16399
+ const key = getOrSetCacheKey();
16369
16400
if (!key) {
16370
- key = getFlowCacheKey(reference, declaredType, initialType, flowContainer);
16371
16401
// No cache key is generated when binding patterns are in unnarrowable situations
16372
- if (!key) {
16373
- return declaredType;
16374
- }
16402
+ return declaredType;
16375
16403
}
16376
16404
const cached = cache.get(key);
16377
16405
if (cached) {
0 commit comments