(flow)
| 70648 | return createFlowType(getUnionOrEvolvingArrayType(antecedentTypes, subtypeReduction ? 2 /* UnionReduction.Subtype */ : 1 /* UnionReduction.Literal */), seenIncomplete); |
| 70649 | } |
| 70650 | function getTypeAtFlowLoopLabel(flow) { |
| 70651 | // If we have previously computed the control flow type for the reference at |
| 70652 | // this flow loop junction, return the cached type. |
| 70653 | var id = getFlowNodeId(flow); |
| 70654 | var cache = flowLoopCaches[id] || (flowLoopCaches[id] = new ts.Map()); |
| 70655 | var key = getOrSetCacheKey(); |
| 70656 | if (!key) { |
| 70657 | // No cache key is generated when binding patterns are in unnarrowable situations |
| 70658 | return declaredType; |
| 70659 | } |
| 70660 | var cached = cache.get(key); |
| 70661 | if (cached) { |
| 70662 | return cached; |
| 70663 | } |
| 70664 | // If this flow loop junction and reference are already being processed, return |
| 70665 | // the union of the types computed for each branch so far, marked as incomplete. |
| 70666 | // It is possible to see an empty array in cases where loops are nested and the |
| 70667 | // back edge of the outer loop reaches an inner loop that is already being analyzed. |
| 70668 | // In such cases we restart the analysis of the inner loop, which will then see |
| 70669 | // a non-empty in-process array for the outer loop and eventually terminate because |
| 70670 | // the first antecedent of a loop junction is always the non-looping control flow |
| 70671 | // path that leads to the top. |
| 70672 | for (var i = flowLoopStart; i < flowLoopCount; i++) { |
| 70673 | if (flowLoopNodes[i] === flow && flowLoopKeys[i] === key && flowLoopTypes[i].length) { |
| 70674 | return createFlowType(getUnionOrEvolvingArrayType(flowLoopTypes[i], 1 /* UnionReduction.Literal */), /*incomplete*/ true); |
| 70675 | } |
| 70676 | } |
| 70677 | // Add the flow loop junction and reference to the in-process stack and analyze |
| 70678 | // each antecedent code path. |
| 70679 | var antecedentTypes = []; |
| 70680 | var subtypeReduction = false; |
| 70681 | var firstAntecedentType; |
| 70682 | for (var _i = 0, _a = flow.antecedents; _i < _a.length; _i++) { |
| 70683 | var antecedent = _a[_i]; |
| 70684 | var flowType = void 0; |
| 70685 | if (!firstAntecedentType) { |
| 70686 | // The first antecedent of a loop junction is always the non-looping control |
| 70687 | // flow path that leads to the top. |
| 70688 | flowType = firstAntecedentType = getTypeAtFlowNode(antecedent); |
| 70689 | } |
| 70690 | else { |
| 70691 | // All but the first antecedent are the looping control flow paths that lead |
| 70692 | // back to the loop junction. We track these on the flow loop stack. |
| 70693 | flowLoopNodes[flowLoopCount] = flow; |
| 70694 | flowLoopKeys[flowLoopCount] = key; |
| 70695 | flowLoopTypes[flowLoopCount] = antecedentTypes; |
| 70696 | flowLoopCount++; |
| 70697 | var saveFlowTypeCache = flowTypeCache; |
| 70698 | flowTypeCache = undefined; |
| 70699 | flowType = getTypeAtFlowNode(antecedent); |
| 70700 | flowTypeCache = saveFlowTypeCache; |
| 70701 | flowLoopCount--; |
| 70702 | // If we see a value appear in the cache it is a sign that control flow analysis |
| 70703 | // was restarted and completed by checkExpressionCached. We can simply pick up |
| 70704 | // the resulting type and bail out. |
| 70705 | var cached_1 = cache.get(key); |
| 70706 | if (cached_1) { |
| 70707 | return cached_1; |
no test coverage detected
searching dependent graphs…