Local caching of types of shared flow nodes

This commit is contained in:
Anders Hejlsberg
2016-05-04 13:24:05 -07:00
parent 79db146e32
commit e49773a7e9
3 changed files with 37 additions and 12 deletions

View File

@@ -653,9 +653,14 @@ namespace ts {
};
}
function setFlowNodeReferenced(flow: FlowNode) {
flow.flags |= flow.flags & FlowFlags.Referenced ? FlowFlags.Shared : FlowFlags.Referenced;
}
function addAntecedent(label: FlowLabel, antecedent: FlowNode): void {
if (!(antecedent.flags & FlowFlags.Unreachable) && !contains(label.antecedents, antecedent)) {
(label.antecedents || (label.antecedents = [])).push(antecedent);
setFlowNodeReferenced(antecedent);
}
}
@@ -673,6 +678,7 @@ namespace ts {
if (!isNarrowingExpression(expression)) {
return antecedent;
}
setFlowNodeReferenced(antecedent);
return <FlowCondition>{
flags,
antecedent,
@@ -681,6 +687,7 @@ namespace ts {
}
function createFlowAssignment(antecedent: FlowNode, node: Expression | VariableDeclaration | BindingElement): FlowNode {
setFlowNodeReferenced(antecedent);
return <FlowAssignment>{
flags: FlowFlags.Assignment,
antecedent,

View File

@@ -7378,12 +7378,17 @@ namespace ts {
return false;
}
function getFlowTypeCache(flow: FlowNode): Map<Type> {
function getFlowNodeId(flow: FlowNode): number {
if (!flow.id) {
flow.id = nextFlowId;
nextFlowId++;
}
return flowTypeCaches[flow.id] || (flowTypeCaches[flow.id] = {});
return flow.id;
}
function getFlowTypeCache(flow: FlowNode): Map<Type> {
const id = getFlowNodeId(flow);
return flowTypeCaches[id] || (flowTypeCaches[id] = {});
}
function typeMaybeAssignableTo(source: Type, target: Type) {
@@ -7578,6 +7583,7 @@ namespace ts {
function getFlowTypeOfReference(reference: Node, declaredType: Type, initialType: Type) {
let key: string;
let cachedTypes: Type[];
if (!reference.flowNode || declaredType === initialType && !(declaredType.flags & TypeFlags.Narrowable)) {
return declaredType;
}
@@ -7585,31 +7591,41 @@ namespace ts {
function getTypeAtFlowNode(flow: FlowNode): Type {
while (true) {
let type: Type;
let id = flow.flags & FlowFlags.Shared ? getFlowNodeId(flow) : 0;
if (id && cachedTypes && (type = cachedTypes[id])) {
return type;
}
if (flow.flags & FlowFlags.Assignment) {
const type = getTypeAtFlowAssignment(<FlowAssignment>flow);
type = getTypeAtFlowAssignment(<FlowAssignment>flow);
if (!type) {
flow = (<FlowAssignment>flow).antecedent;
continue;
}
return type;
}
if (flow.flags & FlowFlags.Condition) {
return getTypeAtFlowCondition(<FlowCondition>flow);
else if (flow.flags & FlowFlags.Condition) {
type = getTypeAtFlowCondition(<FlowCondition>flow);
}
if (flow.flags & FlowFlags.Label) {
else if (flow.flags & FlowFlags.Label) {
if ((<FlowLabel>flow).antecedents.length === 1) {
flow = (<FlowLabel>flow).antecedents[0];
continue;
}
return getTypeAtFlowLabel(<FlowLabel>flow);
type = getTypeAtFlowLabel(<FlowLabel>flow);
}
if (flow.flags & FlowFlags.Unreachable) {
else if (flow.flags & FlowFlags.Unreachable) {
// Unreachable code errors are reported in the binding phase. Here we
// simply return the declared type to reduce follow-on errors.
return declaredType;
type = declaredType;
}
// At the top of the flow we have the initial type
return initialType;
else {
// At the top of the flow we have the initial type
type = initialType;
}
if (id) {
(cachedTypes || (cachedTypes = []))[id] = type;
}
return type;
}
}

View File

@@ -1523,6 +1523,8 @@ namespace ts {
Assignment = 1 << 4,
TrueCondition = 1 << 5,
FalseCondition = 1 << 6,
Referenced = 1 << 7,
Shared = 1 << 8,
Label = BranchLabel | LoopLabel,
Condition = TrueCondition | FalseCondition
}