Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -940,7 +940,7 @@ namespace ts {
const mergedSymbols: Symbol[] = [];
const symbolLinks: SymbolLinks[] = [];
const nodeLinks: NodeLinks[] = [];
const flowLoopCaches: ESMap<string, Type>[] = [];
const flowLabelCaches: ESMap<string, Type>[] = [];
const flowLoopNodes: FlowNode[] = [];
const flowLoopKeys: string[] = [];
const flowLoopTypes: Type[][] = [];
Expand Down Expand Up @@ -21656,6 +21656,7 @@ namespace ts {
let key: string | undefined;
let isKeySet = false;
let flowDepth = 0;
let cacheableBranches = true;
if (flowAnalysisDisabled) {
return errorType;
}
Expand Down Expand Up @@ -21747,9 +21748,14 @@ namespace ts {
else if (flags & FlowFlags.ReduceLabel) {
const target = (<FlowReduceLabel>flow).target;
const saveAntecedents = target.antecedents;
// Modifying the antecedents of a node means we lose our ability to use the cross-invocation branch cache
// (since that may have follow-on effects on analysis returned by other nodes if the results get cached)
const oldCacheableBranches = cacheableBranches;
cacheableBranches = false;
target.antecedents = (<FlowReduceLabel>flow).antecedents;
type = getTypeAtFlowNode((<FlowReduceLabel>flow).antecedent);
target.antecedents = saveAntecedents;
cacheableBranches = oldCacheableBranches;
}
else if (flags & FlowFlags.Start) {
// Check if we should continue with the control flow of the containing function.
Expand Down Expand Up @@ -21955,6 +21961,17 @@ namespace ts {
}

function getTypeAtFlowBranchLabel(flow: FlowLabel): FlowType {
const id = getFlowNodeId(flow);
const cache = flowLabelCaches[id] || (flowLabelCaches[id] = new Map<string, Type>());
const key = getOrSetCacheKey();
if (!key) {
// No cache key is generated when binding patterns are in unnarrowable situations
return declaredType;
}
const cached = cacheableBranches && cache.get(key);
if (cached) {
return cached;
}
const antecedentTypes: Type[] = [];
let subtypeReduction = false;
let seenIncomplete = false;
Expand Down Expand Up @@ -22004,14 +22021,18 @@ namespace ts {
}
}
}
return createFlowType(getUnionOrEvolvingArrayType(antecedentTypes, subtypeReduction ? UnionReduction.Subtype : UnionReduction.Literal), seenIncomplete);
const result = createFlowType(getUnionOrEvolvingArrayType(antecedentTypes, subtypeReduction ? UnionReduction.Subtype : UnionReduction.Literal), seenIncomplete);
if (!seenIncomplete && cacheableBranches) {
cache.set(key, result as Type);
}
return result;
}

function getTypeAtFlowLoopLabel(flow: FlowLabel): FlowType {
// If we have previously computed the control flow type for the reference at
// this flow loop junction, return the cached type.
const id = getFlowNodeId(flow);
const cache = flowLoopCaches[id] || (flowLoopCaches[id] = new Map<string, Type>());
const cache = flowLabelCaches[id] || (flowLabelCaches[id] = new Map<string, Type>());
const key = getOrSetCacheKey();
if (!key) {
// No cache key is generated when binding patterns are in unnarrowable situations
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
//// [controlFlowManyCallExpressionStatementsPerf.ts]
function test(x: boolean): boolean { return x; }

let state = true;

if (state) {
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
test(state as any && state);
}

//// [controlFlowManyCallExpressionStatementsPerf.js]
function test(x) { return x; }
var state = true;
if (state) {
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
test(state && state);
}
Loading