mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-06-10 02:18:37 -05:00
Refactor from FlowKind to FlowFlags
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user