Skip to content

Commit

Permalink
Ensure shared flow nodes are cached
Browse files Browse the repository at this point in the history
Flow nodes that optionally provide a flow type will delegate to their antecedent
to determine a flow type using a loop in `getFlowTypeOfReference`. If these nodes
are marked as shared then their result should be cached for future lookups, but
the registration inside `getFlowTypeOfReference` did only consider the most-recently
processed flow node. Any flow nodes up to that point that did not provide a type
but were marked as shared would therefore not be cached at all.

This commit keeps track of the first seen shared flow node and ensures that the
result type is cached for that node.
  • Loading branch information
JoostK committed Nov 4, 2020
1 parent 76cf8fd commit 57bb716
Show file tree
Hide file tree
Showing 5 changed files with 959 additions and 3 deletions.
22 changes: 19 additions & 3 deletions src/compiler/checker.ts
Expand Up @@ -21673,6 +21673,12 @@ namespace ts {
}
}

function addSharedFlowType(flow: FlowNode, type: FlowType): void {
sharedFlowNodes[sharedFlowCount] = flow;
sharedFlowTypes[sharedFlowCount] = type;
sharedFlowCount++;
}

function getFlowTypeOfReference(reference: Node, declaredType: Type, initialType = declaredType, flowContainer?: Node, couldBeUninitialized?: boolean) {
let key: string | undefined;
let isKeySet = false;
Expand Down Expand Up @@ -21715,6 +21721,7 @@ namespace ts {
return errorType;
}
flowDepth++;
let sharedFlow: FlowNode | undefined;
while (true) {
const flags = flow.flags;
if (flags & FlowFlags.Shared) {
Expand All @@ -21727,6 +21734,12 @@ namespace ts {
return sharedFlowTypes[i];
}
}

// Keep track of the shared flow that is seen first to ensure that the
// computed type is saved in the shared flow type cache.
if (!sharedFlow) {
sharedFlow = flow;
}
}
let type: FlowType | undefined;
if (flags & FlowFlags.Assignment) {
Expand Down Expand Up @@ -21792,9 +21805,12 @@ namespace ts {
}
if (flags & FlowFlags.Shared) {
// Record visited node and the associated type in the cache.
sharedFlowNodes[sharedFlowCount] = flow;
sharedFlowTypes[sharedFlowCount] = type;
sharedFlowCount++;
addSharedFlowType(flow, type);
}
if (sharedFlow && sharedFlow !== flow) {
// If a shared flow other than the currently active flow was seen, also
// record the resulting type for that shared flow.
addSharedFlowType(sharedFlow, type);
}
flowDepth--;
return type;
Expand Down
@@ -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);
}

0 comments on commit 57bb716

Please sign in to comment.