Skip to content

Commit f657e3c

Browse files
committed
Merge branch 'master' into stringLiteralCompletions
2 parents b9ab4d3 + 72c19ec commit f657e3c

File tree

185 files changed

+5244
-1073
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

185 files changed

+5244
-1073
lines changed

src/compiler/binder.ts

Lines changed: 72 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -129,15 +129,16 @@ namespace ts {
129129
let Symbol: { new (flags: SymbolFlags, name: string): Symbol };
130130
let classifiableNames: Map<string>;
131131

132-
const unreachableFlow: FlowNode = { kind: FlowKind.Unreachable };
133-
const reportedUnreachableFlow: FlowNode = { kind: FlowKind.Unreachable };
132+
const unreachableFlow: FlowNode = { flags: FlowFlags.Unreachable };
133+
const reportedUnreachableFlow: FlowNode = { flags: FlowFlags.Unreachable };
134134

135135
function bindSourceFile(f: SourceFile, opts: CompilerOptions) {
136136
file = f;
137137
options = opts;
138138
languageVersion = getEmitScriptTarget(options);
139139
inStrictMode = !!file.externalModuleIndicator;
140140
classifiableNames = {};
141+
symbolCount = 0;
141142

142143
Symbol = objectAllocator.getSymbolConstructor();
143144

@@ -470,7 +471,7 @@ namespace ts {
470471
savedActiveLabels = activeLabels;
471472

472473
hasExplicitReturn = false;
473-
currentFlow = { kind: FlowKind.Start };
474+
currentFlow = { flags: FlowFlags.Start };
474475
currentBreakTarget = undefined;
475476
currentContinueTarget = undefined;
476477
activeLabels = undefined;
@@ -482,7 +483,7 @@ namespace ts {
482483

483484
bindReachableStatement(node);
484485

485-
if (currentFlow.kind !== FlowKind.Unreachable && isFunctionLikeKind(kind) && nodeIsPresent((<FunctionLikeDeclaration>node).body)) {
486+
if (!(currentFlow.flags & FlowFlags.Unreachable) && isFunctionLikeKind(kind) && nodeIsPresent((<FunctionLikeDeclaration>node).body)) {
486487
flags |= NodeFlags.HasImplicitReturn;
487488
if (hasExplicitReturn) {
488489
flags |= NodeFlags.HasExplicitReturn;
@@ -638,55 +639,80 @@ namespace ts {
638639
return false;
639640
}
640641

641-
function createFlowLabel(): FlowLabel {
642+
function createBranchLabel(): FlowLabel {
642643
return {
643-
kind: FlowKind.Label,
644+
flags: FlowFlags.BranchLabel,
644645
antecedents: undefined
645646
};
646647
}
647648

648-
function createFlowLoopLabel(): FlowLabel {
649+
function createLoopLabel(): FlowLabel {
649650
return {
650-
kind: FlowKind.LoopLabel,
651+
flags: FlowFlags.LoopLabel,
651652
antecedents: undefined
652653
};
653654
}
654655

656+
function setFlowNodeReferenced(flow: FlowNode) {
657+
// On first reference we set the Referenced flag, thereafter we set the Shared flag
658+
flow.flags |= flow.flags & FlowFlags.Referenced ? FlowFlags.Shared : FlowFlags.Referenced;
659+
}
660+
655661
function addAntecedent(label: FlowLabel, antecedent: FlowNode): void {
656-
if (antecedent.kind !== FlowKind.Unreachable && !contains(label.antecedents, antecedent)) {
662+
if (!(antecedent.flags & FlowFlags.Unreachable) && !contains(label.antecedents, antecedent)) {
657663
(label.antecedents || (label.antecedents = [])).push(antecedent);
664+
setFlowNodeReferenced(antecedent);
658665
}
659666
}
660667

661-
function createFlowCondition(antecedent: FlowNode, expression: Expression, assumeTrue: boolean): FlowNode {
662-
if (antecedent.kind === FlowKind.Unreachable) {
668+
function createFlowCondition(flags: FlowFlags, antecedent: FlowNode, expression: Expression): FlowNode {
669+
if (antecedent.flags & FlowFlags.Unreachable) {
663670
return antecedent;
664671
}
665672
if (!expression) {
666-
return assumeTrue ? antecedent : unreachableFlow;
673+
return flags & FlowFlags.TrueCondition ? antecedent : unreachableFlow;
667674
}
668-
if (expression.kind === SyntaxKind.TrueKeyword && !assumeTrue || expression.kind === SyntaxKind.FalseKeyword && assumeTrue) {
675+
if (expression.kind === SyntaxKind.TrueKeyword && flags & FlowFlags.FalseCondition ||
676+
expression.kind === SyntaxKind.FalseKeyword && flags & FlowFlags.TrueCondition) {
669677
return unreachableFlow;
670678
}
671679
if (!isNarrowingExpression(expression)) {
672680
return antecedent;
673681
}
682+
setFlowNodeReferenced(antecedent);
674683
return <FlowCondition>{
675-
kind: FlowKind.Condition,
684+
flags,
676685
antecedent,
677686
expression,
678-
assumeTrue
679687
};
680688
}
681689

682690
function createFlowAssignment(antecedent: FlowNode, node: Expression | VariableDeclaration | BindingElement): FlowNode {
691+
setFlowNodeReferenced(antecedent);
683692
return <FlowAssignment>{
684-
kind: FlowKind.Assignment,
693+
flags: FlowFlags.Assignment,
685694
antecedent,
686695
node
687696
};
688697
}
689698

699+
function skipSimpleConditionalFlow(flow: FlowNode) {
700+
// We skip over simple conditional flows of the form 'x ? aaa : bbb', where 'aaa' and 'bbb' contain
701+
// no constructs that affect control flow type analysis. Such simple flows have no effect on the
702+
// code paths that follow and ignoring them means we'll do less work.
703+
if (flow.flags & FlowFlags.BranchLabel && (<FlowLabel>flow).antecedents.length === 2) {
704+
const a = (<FlowLabel>flow).antecedents[0];
705+
const b = (<FlowLabel>flow).antecedents[1];
706+
if ((a.flags & FlowFlags.TrueCondition && b.flags & FlowFlags.FalseCondition ||
707+
a.flags & FlowFlags.FalseCondition && b.flags & FlowFlags.TrueCondition) &&
708+
(<FlowCondition>a).antecedent === (<FlowCondition>b).antecedent &&
709+
(<FlowCondition>a).expression === (<FlowCondition>b).expression) {
710+
return (<FlowCondition>a).antecedent;
711+
}
712+
}
713+
return flow;
714+
}
715+
690716
function finishFlowLabel(flow: FlowLabel): FlowNode {
691717
const antecedents = flow.antecedents;
692718
if (!antecedents) {
@@ -695,7 +721,7 @@ namespace ts {
695721
if (antecedents.length === 1) {
696722
return antecedents[0];
697723
}
698-
return flow;
724+
return skipSimpleConditionalFlow(flow);
699725
}
700726

701727
function isStatementCondition(node: Node) {
@@ -746,8 +772,8 @@ namespace ts {
746772
currentTrueTarget = saveTrueTarget;
747773
currentFalseTarget = saveFalseTarget;
748774
if (!node || !isLogicalExpression(node)) {
749-
addAntecedent(trueTarget, createFlowCondition(currentFlow, node, /*assumeTrue*/ true));
750-
addAntecedent(falseTarget, createFlowCondition(currentFlow, node, /*assumeTrue*/ false));
775+
addAntecedent(trueTarget, createFlowCondition(FlowFlags.TrueCondition, currentFlow, node));
776+
addAntecedent(falseTarget, createFlowCondition(FlowFlags.FalseCondition, currentFlow, node));
751777
}
752778
}
753779

@@ -762,9 +788,9 @@ namespace ts {
762788
}
763789

764790
function bindWhileStatement(node: WhileStatement): void {
765-
const preWhileLabel = createFlowLoopLabel();
766-
const preBodyLabel = createFlowLabel();
767-
const postWhileLabel = createFlowLabel();
791+
const preWhileLabel = createLoopLabel();
792+
const preBodyLabel = createBranchLabel();
793+
const postWhileLabel = createBranchLabel();
768794
addAntecedent(preWhileLabel, currentFlow);
769795
currentFlow = preWhileLabel;
770796
bindCondition(node.expression, preBodyLabel, postWhileLabel);
@@ -775,9 +801,9 @@ namespace ts {
775801
}
776802

777803
function bindDoStatement(node: DoStatement): void {
778-
const preDoLabel = createFlowLoopLabel();
779-
const preConditionLabel = createFlowLabel();
780-
const postDoLabel = createFlowLabel();
804+
const preDoLabel = createLoopLabel();
805+
const preConditionLabel = createBranchLabel();
806+
const postDoLabel = createBranchLabel();
781807
addAntecedent(preDoLabel, currentFlow);
782808
currentFlow = preDoLabel;
783809
bindIterativeStatement(node.statement, postDoLabel, preConditionLabel);
@@ -788,9 +814,9 @@ namespace ts {
788814
}
789815

790816
function bindForStatement(node: ForStatement): void {
791-
const preLoopLabel = createFlowLoopLabel();
792-
const preBodyLabel = createFlowLabel();
793-
const postLoopLabel = createFlowLabel();
817+
const preLoopLabel = createLoopLabel();
818+
const preBodyLabel = createBranchLabel();
819+
const postLoopLabel = createBranchLabel();
794820
bind(node.initializer);
795821
addAntecedent(preLoopLabel, currentFlow);
796822
currentFlow = preLoopLabel;
@@ -803,8 +829,8 @@ namespace ts {
803829
}
804830

805831
function bindForInOrForOfStatement(node: ForInStatement | ForOfStatement): void {
806-
const preLoopLabel = createFlowLoopLabel();
807-
const postLoopLabel = createFlowLabel();
832+
const preLoopLabel = createLoopLabel();
833+
const postLoopLabel = createBranchLabel();
808834
addAntecedent(preLoopLabel, currentFlow);
809835
currentFlow = preLoopLabel;
810836
bind(node.expression);
@@ -819,9 +845,9 @@ namespace ts {
819845
}
820846

821847
function bindIfStatement(node: IfStatement): void {
822-
const thenLabel = createFlowLabel();
823-
const elseLabel = createFlowLabel();
824-
const postIfLabel = createFlowLabel();
848+
const thenLabel = createBranchLabel();
849+
const elseLabel = createBranchLabel();
850+
const postIfLabel = createBranchLabel();
825851
bindCondition(node.expression, thenLabel, elseLabel);
826852
currentFlow = finishFlowLabel(thenLabel);
827853
bind(node.thenStatement);
@@ -874,7 +900,7 @@ namespace ts {
874900
}
875901

876902
function bindTryStatement(node: TryStatement): void {
877-
const postFinallyLabel = createFlowLabel();
903+
const postFinallyLabel = createBranchLabel();
878904
const preTryFlow = currentFlow;
879905
// TODO: Every statement in try block is potentially an exit point!
880906
bind(node.tryBlock);
@@ -892,7 +918,7 @@ namespace ts {
892918
}
893919

894920
function bindSwitchStatement(node: SwitchStatement): void {
895-
const postSwitchLabel = createFlowLabel();
921+
const postSwitchLabel = createBranchLabel();
896922
bind(node.expression);
897923
const saveBreakTarget = currentBreakTarget;
898924
const savePreSwitchCaseFlow = preSwitchCaseFlow;
@@ -914,17 +940,17 @@ namespace ts {
914940
for (let i = 0; i < clauses.length; i++) {
915941
const clause = clauses[i];
916942
if (clause.statements.length) {
917-
if (currentFlow.kind === FlowKind.Unreachable) {
943+
if (currentFlow.flags & FlowFlags.Unreachable) {
918944
currentFlow = preSwitchCaseFlow;
919945
}
920946
else {
921-
const preCaseLabel = createFlowLabel();
947+
const preCaseLabel = createBranchLabel();
922948
addAntecedent(preCaseLabel, preSwitchCaseFlow);
923949
addAntecedent(preCaseLabel, currentFlow);
924950
currentFlow = finishFlowLabel(preCaseLabel);
925951
}
926952
bind(clause);
927-
if (currentFlow.kind !== FlowKind.Unreachable && i !== clauses.length - 1 && options.noFallthroughCasesInSwitch) {
953+
if (!(currentFlow.flags & FlowFlags.Unreachable) && i !== clauses.length - 1 && options.noFallthroughCasesInSwitch) {
928954
errorOnFirstToken(clause, Diagnostics.Fallthrough_case_in_switch);
929955
}
930956
}
@@ -950,8 +976,8 @@ namespace ts {
950976
}
951977

952978
function bindLabeledStatement(node: LabeledStatement): void {
953-
const preStatementLabel = createFlowLoopLabel();
954-
const postStatementLabel = createFlowLabel();
979+
const preStatementLabel = createLoopLabel();
980+
const postStatementLabel = createBranchLabel();
955981
bind(node.label);
956982
addAntecedent(preStatementLabel, currentFlow);
957983
const activeLabel = pushActiveLabel(node.label.text, postStatementLabel, preStatementLabel);
@@ -1000,7 +1026,7 @@ namespace ts {
10001026
}
10011027

10021028
function bindLogicalExpression(node: BinaryExpression, trueTarget: FlowLabel, falseTarget: FlowLabel) {
1003-
const preRightLabel = createFlowLabel();
1029+
const preRightLabel = createBranchLabel();
10041030
if (node.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) {
10051031
bindCondition(node.left, preRightLabel, falseTarget);
10061032
}
@@ -1030,7 +1056,7 @@ namespace ts {
10301056
const operator = node.operatorToken.kind;
10311057
if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken) {
10321058
if (isTopLevelLogicalExpression(node)) {
1033-
const postExpressionLabel = createFlowLabel();
1059+
const postExpressionLabel = createBranchLabel();
10341060
bindLogicalExpression(node, postExpressionLabel, postExpressionLabel);
10351061
currentFlow = finishFlowLabel(postExpressionLabel);
10361062
}
@@ -1047,9 +1073,9 @@ namespace ts {
10471073
}
10481074

10491075
function bindConditionalExpressionFlow(node: ConditionalExpression) {
1050-
const trueLabel = createFlowLabel();
1051-
const falseLabel = createFlowLabel();
1052-
const postExpressionLabel = createFlowLabel();
1076+
const trueLabel = createBranchLabel();
1077+
const falseLabel = createBranchLabel();
1078+
const postExpressionLabel = createBranchLabel();
10531079
bindCondition(node.condition, trueLabel, falseLabel);
10541080
currentFlow = finishFlowLabel(trueLabel);
10551081
bind(node.whenTrue);
@@ -2064,7 +2090,7 @@ namespace ts {
20642090
}
20652091

20662092
function checkUnreachable(node: Node): boolean {
2067-
if (currentFlow.kind !== FlowKind.Unreachable) {
2093+
if (!(currentFlow.flags & FlowFlags.Unreachable)) {
20682094
return false;
20692095
}
20702096
if (currentFlow === unreachableFlow) {

0 commit comments

Comments
 (0)