Cache control flow types only at loop-back junctions

This commit is contained in:
Anders Hejlsberg
2016-04-25 11:23:56 -07:00
parent 4039146163
commit b88269bace
3 changed files with 21 additions and 9 deletions
+12 -5
View File
@@ -645,6 +645,13 @@ namespace ts {
};
}
function createFlowLoopLabel(): FlowLabel {
return {
kind: FlowKind.LoopLabel,
antecedents: undefined
};
}
function addAntecedent(label: FlowLabel, antecedent: FlowNode): void {
if (antecedent.kind !== FlowKind.Unreachable && !contains(label.antecedents, antecedent)) {
(label.antecedents || (label.antecedents = [])).push(antecedent);
@@ -755,7 +762,7 @@ namespace ts {
}
function bindWhileStatement(node: WhileStatement): void {
const preWhileLabel = createFlowLabel();
const preWhileLabel = createFlowLoopLabel();
const preBodyLabel = createFlowLabel();
const postWhileLabel = createFlowLabel();
addAntecedent(preWhileLabel, currentFlow);
@@ -768,7 +775,7 @@ namespace ts {
}
function bindDoStatement(node: DoStatement): void {
const preDoLabel = createFlowLabel();
const preDoLabel = createFlowLoopLabel();
const preConditionLabel = createFlowLabel();
const postDoLabel = createFlowLabel();
addAntecedent(preDoLabel, currentFlow);
@@ -781,7 +788,7 @@ namespace ts {
}
function bindForStatement(node: ForStatement): void {
const preLoopLabel = createFlowLabel();
const preLoopLabel = createFlowLoopLabel();
const preBodyLabel = createFlowLabel();
const postLoopLabel = createFlowLabel();
bind(node.initializer);
@@ -796,7 +803,7 @@ namespace ts {
}
function bindForInOrForOfStatement(node: ForInStatement | ForOfStatement): void {
const preLoopLabel = createFlowLabel();
const preLoopLabel = createFlowLoopLabel();
const postLoopLabel = createFlowLabel();
addAntecedent(preLoopLabel, currentFlow);
currentFlow = preLoopLabel;
@@ -943,7 +950,7 @@ namespace ts {
}
function bindLabeledStatement(node: LabeledStatement): void {
const preStatementLabel = createFlowLabel();
const preStatementLabel = createFlowLoopLabel();
const postStatementLabel = createFlowLabel();
bind(node.label);
addAntecedent(preStatementLabel, currentFlow);
+8 -4
View File
@@ -7592,6 +7592,7 @@ namespace ts {
case FlowKind.Condition:
return getTypeAtFlowCondition(<FlowCondition>flow);
case FlowKind.Label:
case FlowKind.LoopLabel:
if ((<FlowLabel>flow).antecedents.length === 1) {
flow = (<FlowLabel>flow).antecedents[0];
continue;
@@ -7639,7 +7640,8 @@ namespace ts {
}
function getTypeAtFlowCondition(flow: FlowCondition) {
return narrowType(getTypeAtFlowNode(flow.antecedent), flow.expression, flow.assumeTrue);
const type = getTypeAtFlowNode(flow.antecedent);
return type && narrowType(type, flow.expression, flow.assumeTrue);
}
function getTypeAtFlowNodeCached(flow: FlowNode) {
@@ -7665,13 +7667,15 @@ namespace ts {
flowStackCount--;
// Record the result only if the cache is still empty. If checkExpressionCached was called
// during processing it is possible we've already recorded a result.
return cache[key] || (cache[key] = type);
return cache[key] || type && (cache[key] = type);
}
function getTypeAtFlowLabel(flow: FlowLabel) {
const antecedentTypes: Type[] = [];
for (const antecedent of flow.antecedents) {
const type = getTypeAtFlowNodeCached(antecedent);
const type = flow.kind === FlowKind.LoopLabel ?
getTypeAtFlowNodeCached(antecedent) :
getTypeAtFlowNode(antecedent);
if (type) {
// If the type at a particular antecedent path is the declared type and the
// reference is known to always be assigned (i.e. when declared and initial types
@@ -7685,7 +7689,7 @@ namespace ts {
}
}
}
return antecedentTypes.length === 0 ? declaredType :
return antecedentTypes.length === 0 ? undefined :
antecedentTypes.length === 1 ? antecedentTypes[0] :
getUnionType(antecedentTypes);
}
+1
View File
@@ -1519,6 +1519,7 @@ namespace ts {
Unreachable,
Start,
Label,
LoopLabel,
Assignment,
Condition
}