Refactor from FlowKind to FlowFlags

This commit is contained in:
Anders Hejlsberg
2016-05-04 12:44:27 -07:00
parent e9122a9f34
commit 79db146e32
3 changed files with 80 additions and 77 deletions

View File

@@ -129,8 +129,8 @@ namespace ts {
let Symbol: { new (flags: SymbolFlags, name: string): Symbol };
let classifiableNames: Map<string>;
const unreachableFlow: FlowNode = { kind: FlowKind.Unreachable };
const reportedUnreachableFlow: FlowNode = { kind: FlowKind.Unreachable };
const unreachableFlow: FlowNode = { flags: FlowFlags.Unreachable };
const reportedUnreachableFlow: FlowNode = { flags: FlowFlags.Unreachable };
function bindSourceFile(f: SourceFile, opts: CompilerOptions) {
file = f;
@@ -471,7 +471,7 @@ namespace ts {
savedActiveLabels = activeLabels;
hasExplicitReturn = false;
currentFlow = { kind: FlowKind.Start };
currentFlow = { flags: FlowFlags.Start };
currentBreakTarget = undefined;
currentContinueTarget = undefined;
activeLabels = undefined;
@@ -483,7 +483,7 @@ namespace ts {
bindReachableStatement(node);
if (currentFlow.kind !== FlowKind.Unreachable && isFunctionLikeKind(kind) && nodeIsPresent((<FunctionLikeDeclaration>node).body)) {
if (!(currentFlow.flags & FlowFlags.Unreachable) && isFunctionLikeKind(kind) && nodeIsPresent((<FunctionLikeDeclaration>node).body)) {
flags |= NodeFlags.HasImplicitReturn;
if (hasExplicitReturn) {
flags |= NodeFlags.HasExplicitReturn;
@@ -639,50 +639,50 @@ namespace ts {
return false;
}
function createFlowLabel(): FlowLabel {
function createBranchLabel(): FlowLabel {
return {
kind: FlowKind.Label,
flags: FlowFlags.BranchLabel,
antecedents: undefined
};
}
function createFlowLoopLabel(): FlowLabel {
function createLoopLabel(): FlowLabel {
return {
kind: FlowKind.LoopLabel,
flags: FlowFlags.LoopLabel,
antecedents: undefined
};
}
function addAntecedent(label: FlowLabel, antecedent: FlowNode): void {
if (antecedent.kind !== FlowKind.Unreachable && !contains(label.antecedents, antecedent)) {
if (!(antecedent.flags & FlowFlags.Unreachable) && !contains(label.antecedents, antecedent)) {
(label.antecedents || (label.antecedents = [])).push(antecedent);
}
}
function createFlowCondition(antecedent: FlowNode, expression: Expression, assumeTrue: boolean): FlowNode {
if (antecedent.kind === FlowKind.Unreachable) {
function createFlowCondition(flags: FlowFlags, antecedent: FlowNode, expression: Expression): FlowNode {
if (antecedent.flags & FlowFlags.Unreachable) {
return antecedent;
}
if (!expression) {
return assumeTrue ? antecedent : unreachableFlow;
return flags & FlowFlags.TrueCondition ? antecedent : unreachableFlow;
}
if (expression.kind === SyntaxKind.TrueKeyword && !assumeTrue || expression.kind === SyntaxKind.FalseKeyword && assumeTrue) {
if (expression.kind === SyntaxKind.TrueKeyword && flags & FlowFlags.FalseCondition ||
expression.kind === SyntaxKind.FalseKeyword && flags & FlowFlags.TrueCondition) {
return unreachableFlow;
}
if (!isNarrowingExpression(expression)) {
return antecedent;
}
return <FlowCondition>{
kind: FlowKind.Condition,
flags,
antecedent,
expression,
assumeTrue
};
}
function createFlowAssignment(antecedent: FlowNode, node: Expression | VariableDeclaration | BindingElement): FlowNode {
return <FlowAssignment>{
kind: FlowKind.Assignment,
flags: FlowFlags.Assignment,
antecedent,
node
};
@@ -747,8 +747,8 @@ namespace ts {
currentTrueTarget = saveTrueTarget;
currentFalseTarget = saveFalseTarget;
if (!node || !isLogicalExpression(node)) {
addAntecedent(trueTarget, createFlowCondition(currentFlow, node, /*assumeTrue*/ true));
addAntecedent(falseTarget, createFlowCondition(currentFlow, node, /*assumeTrue*/ false));
addAntecedent(trueTarget, createFlowCondition(FlowFlags.TrueCondition, currentFlow, node));
addAntecedent(falseTarget, createFlowCondition(FlowFlags.FalseCondition, currentFlow, node));
}
}
@@ -763,9 +763,9 @@ namespace ts {
}
function bindWhileStatement(node: WhileStatement): void {
const preWhileLabel = createFlowLoopLabel();
const preBodyLabel = createFlowLabel();
const postWhileLabel = createFlowLabel();
const preWhileLabel = createLoopLabel();
const preBodyLabel = createBranchLabel();
const postWhileLabel = createBranchLabel();
addAntecedent(preWhileLabel, currentFlow);
currentFlow = preWhileLabel;
bindCondition(node.expression, preBodyLabel, postWhileLabel);
@@ -776,9 +776,9 @@ namespace ts {
}
function bindDoStatement(node: DoStatement): void {
const preDoLabel = createFlowLoopLabel();
const preConditionLabel = createFlowLabel();
const postDoLabel = createFlowLabel();
const preDoLabel = createLoopLabel();
const preConditionLabel = createBranchLabel();
const postDoLabel = createBranchLabel();
addAntecedent(preDoLabel, currentFlow);
currentFlow = preDoLabel;
bindIterativeStatement(node.statement, postDoLabel, preConditionLabel);
@@ -789,9 +789,9 @@ namespace ts {
}
function bindForStatement(node: ForStatement): void {
const preLoopLabel = createFlowLoopLabel();
const preBodyLabel = createFlowLabel();
const postLoopLabel = createFlowLabel();
const preLoopLabel = createLoopLabel();
const preBodyLabel = createBranchLabel();
const postLoopLabel = createBranchLabel();
bind(node.initializer);
addAntecedent(preLoopLabel, currentFlow);
currentFlow = preLoopLabel;
@@ -804,8 +804,8 @@ namespace ts {
}
function bindForInOrForOfStatement(node: ForInStatement | ForOfStatement): void {
const preLoopLabel = createFlowLoopLabel();
const postLoopLabel = createFlowLabel();
const preLoopLabel = createLoopLabel();
const postLoopLabel = createBranchLabel();
addAntecedent(preLoopLabel, currentFlow);
currentFlow = preLoopLabel;
bind(node.expression);
@@ -820,9 +820,9 @@ namespace ts {
}
function bindIfStatement(node: IfStatement): void {
const thenLabel = createFlowLabel();
const elseLabel = createFlowLabel();
const postIfLabel = createFlowLabel();
const thenLabel = createBranchLabel();
const elseLabel = createBranchLabel();
const postIfLabel = createBranchLabel();
bindCondition(node.expression, thenLabel, elseLabel);
currentFlow = finishFlowLabel(thenLabel);
bind(node.thenStatement);
@@ -875,7 +875,7 @@ namespace ts {
}
function bindTryStatement(node: TryStatement): void {
const postFinallyLabel = createFlowLabel();
const postFinallyLabel = createBranchLabel();
const preTryFlow = currentFlow;
// TODO: Every statement in try block is potentially an exit point!
bind(node.tryBlock);
@@ -893,7 +893,7 @@ namespace ts {
}
function bindSwitchStatement(node: SwitchStatement): void {
const postSwitchLabel = createFlowLabel();
const postSwitchLabel = createBranchLabel();
bind(node.expression);
const saveBreakTarget = currentBreakTarget;
const savePreSwitchCaseFlow = preSwitchCaseFlow;
@@ -915,17 +915,17 @@ namespace ts {
for (let i = 0; i < clauses.length; i++) {
const clause = clauses[i];
if (clause.statements.length) {
if (currentFlow.kind === FlowKind.Unreachable) {
if (currentFlow.flags & FlowFlags.Unreachable) {
currentFlow = preSwitchCaseFlow;
}
else {
const preCaseLabel = createFlowLabel();
const preCaseLabel = createBranchLabel();
addAntecedent(preCaseLabel, preSwitchCaseFlow);
addAntecedent(preCaseLabel, currentFlow);
currentFlow = finishFlowLabel(preCaseLabel);
}
bind(clause);
if (currentFlow.kind !== FlowKind.Unreachable && i !== clauses.length - 1 && options.noFallthroughCasesInSwitch) {
if (!(currentFlow.flags & FlowFlags.Unreachable) && i !== clauses.length - 1 && options.noFallthroughCasesInSwitch) {
errorOnFirstToken(clause, Diagnostics.Fallthrough_case_in_switch);
}
}
@@ -951,8 +951,8 @@ namespace ts {
}
function bindLabeledStatement(node: LabeledStatement): void {
const preStatementLabel = createFlowLoopLabel();
const postStatementLabel = createFlowLabel();
const preStatementLabel = createLoopLabel();
const postStatementLabel = createBranchLabel();
bind(node.label);
addAntecedent(preStatementLabel, currentFlow);
const activeLabel = pushActiveLabel(node.label.text, postStatementLabel, preStatementLabel);
@@ -1001,7 +1001,7 @@ namespace ts {
}
function bindLogicalExpression(node: BinaryExpression, trueTarget: FlowLabel, falseTarget: FlowLabel) {
const preRightLabel = createFlowLabel();
const preRightLabel = createBranchLabel();
if (node.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) {
bindCondition(node.left, preRightLabel, falseTarget);
}
@@ -1031,7 +1031,7 @@ namespace ts {
const operator = node.operatorToken.kind;
if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken) {
if (isTopLevelLogicalExpression(node)) {
const postExpressionLabel = createFlowLabel();
const postExpressionLabel = createBranchLabel();
bindLogicalExpression(node, postExpressionLabel, postExpressionLabel);
currentFlow = finishFlowLabel(postExpressionLabel);
}
@@ -1048,9 +1048,9 @@ namespace ts {
}
function bindConditionalExpressionFlow(node: ConditionalExpression) {
const trueLabel = createFlowLabel();
const falseLabel = createFlowLabel();
const postExpressionLabel = createFlowLabel();
const trueLabel = createBranchLabel();
const falseLabel = createBranchLabel();
const postExpressionLabel = createBranchLabel();
bindCondition(node.condition, trueLabel, falseLabel);
currentFlow = finishFlowLabel(trueLabel);
bind(node.whenTrue);
@@ -2065,7 +2065,7 @@ namespace ts {
}
function checkUnreachable(node: Node): boolean {
if (currentFlow.kind !== FlowKind.Unreachable) {
if (!(currentFlow.flags & FlowFlags.Unreachable)) {
return false;
}
if (currentFlow === unreachableFlow) {

View File

@@ -7585,27 +7585,28 @@ namespace ts {
function getTypeAtFlowNode(flow: FlowNode): Type {
while (true) {
switch (flow.kind) {
case FlowKind.Assignment:
const type = getTypeAtFlowAssignment(<FlowAssignment>flow);
if (!type) {
flow = (<FlowAssignment>flow).antecedent;
continue;
}
return type;
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;
}
return getTypeAtFlowLabel(<FlowLabel>flow);
case FlowKind.Unreachable:
// Unreachable code errors are reported in the binding phase. Here we
// simply return the declared type to reduce follow-on errors.
return declaredType;
if (flow.flags & FlowFlags.Assignment) {
const type = getTypeAtFlowAssignment(<FlowAssignment>flow);
if (!type) {
flow = (<FlowAssignment>flow).antecedent;
continue;
}
return type;
}
if (flow.flags & FlowFlags.Condition) {
return getTypeAtFlowCondition(<FlowCondition>flow);
}
if (flow.flags & FlowFlags.Label) {
if ((<FlowLabel>flow).antecedents.length === 1) {
flow = (<FlowLabel>flow).antecedents[0];
continue;
}
return getTypeAtFlowLabel(<FlowLabel>flow);
}
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;
}
// At the top of the flow we have the initial type
return initialType;
@@ -7644,7 +7645,7 @@ namespace ts {
function getTypeAtFlowCondition(flow: FlowCondition) {
const type = getTypeAtFlowNode(flow.antecedent);
return type && narrowType(type, flow.expression, flow.assumeTrue);
return type && narrowType(type, flow.expression, (flow.flags & FlowFlags.TrueCondition) !== 0);
}
function getTypeAtFlowNodeCached(flow: FlowNode) {
@@ -7676,7 +7677,7 @@ namespace ts {
function getTypeAtFlowLabel(flow: FlowLabel) {
const antecedentTypes: Type[] = [];
for (const antecedent of flow.antecedents) {
const type = flow.kind === FlowKind.LoopLabel ?
const type = flow.flags & FlowFlags.LoopLabel ?
getTypeAtFlowNodeCached(antecedent) :
getTypeAtFlowNode(antecedent);
if (!type) {

View File

@@ -1515,17 +1515,20 @@ namespace ts {
isBracketed: boolean;
}
export const enum FlowKind {
Unreachable,
Start,
Label,
LoopLabel,
Assignment,
Condition
export const enum FlowFlags {
Unreachable = 1 << 0,
Start = 1 << 1,
BranchLabel = 1 << 2,
LoopLabel = 1 << 3,
Assignment = 1 << 4,
TrueCondition = 1 << 5,
FalseCondition = 1 << 6,
Label = BranchLabel | LoopLabel,
Condition = TrueCondition | FalseCondition
}
export interface FlowNode {
kind: FlowKind; // Node kind
flags: FlowFlags;
id?: number; // Node id used by flow type cache in checker
}
@@ -1545,7 +1548,6 @@ namespace ts {
// node's location in the control flow.
export interface FlowCondition extends FlowNode {
expression: Expression;
assumeTrue: boolean;
antecedent: FlowNode;
}