@@ -129,8 +129,8 @@ 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 ;
@@ -471,7 +471,7 @@ namespace ts {
471471 savedActiveLabels = activeLabels ;
472472
473473 hasExplicitReturn = false ;
474- currentFlow = { kind : FlowKind . Start } ;
474+ currentFlow = { flags : FlowFlags . Start } ;
475475 currentBreakTarget = undefined ;
476476 currentContinueTarget = undefined ;
477477 activeLabels = undefined ;
@@ -483,7 +483,7 @@ namespace ts {
483483
484484 bindReachableStatement ( node ) ;
485485
486- if ( currentFlow . kind !== FlowKind . Unreachable && isFunctionLikeKind ( kind ) && nodeIsPresent ( ( < FunctionLikeDeclaration > node ) . body ) ) {
486+ if ( ! ( currentFlow . flags & FlowFlags . Unreachable ) && isFunctionLikeKind ( kind ) && nodeIsPresent ( ( < FunctionLikeDeclaration > node ) . body ) ) {
487487 flags |= NodeFlags . HasImplicitReturn ;
488488 if ( hasExplicitReturn ) {
489489 flags |= NodeFlags . HasExplicitReturn ;
@@ -639,55 +639,80 @@ namespace ts {
639639 return false ;
640640 }
641641
642- function createFlowLabel ( ) : FlowLabel {
642+ function createBranchLabel ( ) : FlowLabel {
643643 return {
644- kind : FlowKind . Label ,
644+ flags : FlowFlags . BranchLabel ,
645645 antecedents : undefined
646646 } ;
647647 }
648648
649- function createFlowLoopLabel ( ) : FlowLabel {
649+ function createLoopLabel ( ) : FlowLabel {
650650 return {
651- kind : FlowKind . LoopLabel ,
651+ flags : FlowFlags . LoopLabel ,
652652 antecedents : undefined
653653 } ;
654654 }
655655
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+
656661 function addAntecedent ( label : FlowLabel , antecedent : FlowNode ) : void {
657- if ( antecedent . kind !== FlowKind . Unreachable && ! contains ( label . antecedents , antecedent ) ) {
662+ if ( ! ( antecedent . flags & FlowFlags . Unreachable ) && ! contains ( label . antecedents , antecedent ) ) {
658663 ( label . antecedents || ( label . antecedents = [ ] ) ) . push ( antecedent ) ;
664+ setFlowNodeReferenced ( antecedent ) ;
659665 }
660666 }
661667
662- function createFlowCondition ( antecedent : FlowNode , expression : Expression , assumeTrue : boolean ) : FlowNode {
663- if ( antecedent . kind === FlowKind . Unreachable ) {
668+ function createFlowCondition ( flags : FlowFlags , antecedent : FlowNode , expression : Expression ) : FlowNode {
669+ if ( antecedent . flags & FlowFlags . Unreachable ) {
664670 return antecedent ;
665671 }
666672 if ( ! expression ) {
667- return assumeTrue ? antecedent : unreachableFlow ;
673+ return flags & FlowFlags . TrueCondition ? antecedent : unreachableFlow ;
668674 }
669- 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 ) {
670677 return unreachableFlow ;
671678 }
672679 if ( ! isNarrowingExpression ( expression ) ) {
673680 return antecedent ;
674681 }
682+ setFlowNodeReferenced ( antecedent ) ;
675683 return < FlowCondition > {
676- kind : FlowKind . Condition ,
684+ flags ,
677685 antecedent,
678686 expression,
679- assumeTrue
680687 } ;
681688 }
682689
683690 function createFlowAssignment ( antecedent : FlowNode , node : Expression | VariableDeclaration | BindingElement ) : FlowNode {
691+ setFlowNodeReferenced ( antecedent ) ;
684692 return < FlowAssignment > {
685- kind : FlowKind . Assignment ,
693+ flags : FlowFlags . Assignment ,
686694 antecedent,
687695 node
688696 } ;
689697 }
690698
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+
691716 function finishFlowLabel ( flow : FlowLabel ) : FlowNode {
692717 const antecedents = flow . antecedents ;
693718 if ( ! antecedents ) {
@@ -696,7 +721,7 @@ namespace ts {
696721 if ( antecedents . length === 1 ) {
697722 return antecedents [ 0 ] ;
698723 }
699- return flow ;
724+ return skipSimpleConditionalFlow ( flow ) ;
700725 }
701726
702727 function isStatementCondition ( node : Node ) {
@@ -747,8 +772,8 @@ namespace ts {
747772 currentTrueTarget = saveTrueTarget ;
748773 currentFalseTarget = saveFalseTarget ;
749774 if ( ! node || ! isLogicalExpression ( node ) ) {
750- addAntecedent ( trueTarget , createFlowCondition ( currentFlow , node , /*assumeTrue*/ true ) ) ;
751- addAntecedent ( falseTarget , createFlowCondition ( currentFlow , node , /*assumeTrue*/ false ) ) ;
775+ addAntecedent ( trueTarget , createFlowCondition ( FlowFlags . TrueCondition , currentFlow , node ) ) ;
776+ addAntecedent ( falseTarget , createFlowCondition ( FlowFlags . FalseCondition , currentFlow , node ) ) ;
752777 }
753778 }
754779
@@ -763,9 +788,9 @@ namespace ts {
763788 }
764789
765790 function bindWhileStatement ( node : WhileStatement ) : void {
766- const preWhileLabel = createFlowLoopLabel ( ) ;
767- const preBodyLabel = createFlowLabel ( ) ;
768- const postWhileLabel = createFlowLabel ( ) ;
791+ const preWhileLabel = createLoopLabel ( ) ;
792+ const preBodyLabel = createBranchLabel ( ) ;
793+ const postWhileLabel = createBranchLabel ( ) ;
769794 addAntecedent ( preWhileLabel , currentFlow ) ;
770795 currentFlow = preWhileLabel ;
771796 bindCondition ( node . expression , preBodyLabel , postWhileLabel ) ;
@@ -776,9 +801,9 @@ namespace ts {
776801 }
777802
778803 function bindDoStatement ( node : DoStatement ) : void {
779- const preDoLabel = createFlowLoopLabel ( ) ;
780- const preConditionLabel = createFlowLabel ( ) ;
781- const postDoLabel = createFlowLabel ( ) ;
804+ const preDoLabel = createLoopLabel ( ) ;
805+ const preConditionLabel = createBranchLabel ( ) ;
806+ const postDoLabel = createBranchLabel ( ) ;
782807 addAntecedent ( preDoLabel , currentFlow ) ;
783808 currentFlow = preDoLabel ;
784809 bindIterativeStatement ( node . statement , postDoLabel , preConditionLabel ) ;
@@ -789,9 +814,9 @@ namespace ts {
789814 }
790815
791816 function bindForStatement ( node : ForStatement ) : void {
792- const preLoopLabel = createFlowLoopLabel ( ) ;
793- const preBodyLabel = createFlowLabel ( ) ;
794- const postLoopLabel = createFlowLabel ( ) ;
817+ const preLoopLabel = createLoopLabel ( ) ;
818+ const preBodyLabel = createBranchLabel ( ) ;
819+ const postLoopLabel = createBranchLabel ( ) ;
795820 bind ( node . initializer ) ;
796821 addAntecedent ( preLoopLabel , currentFlow ) ;
797822 currentFlow = preLoopLabel ;
@@ -804,8 +829,8 @@ namespace ts {
804829 }
805830
806831 function bindForInOrForOfStatement ( node : ForInStatement | ForOfStatement ) : void {
807- const preLoopLabel = createFlowLoopLabel ( ) ;
808- const postLoopLabel = createFlowLabel ( ) ;
832+ const preLoopLabel = createLoopLabel ( ) ;
833+ const postLoopLabel = createBranchLabel ( ) ;
809834 addAntecedent ( preLoopLabel , currentFlow ) ;
810835 currentFlow = preLoopLabel ;
811836 bind ( node . expression ) ;
@@ -820,9 +845,9 @@ namespace ts {
820845 }
821846
822847 function bindIfStatement ( node : IfStatement ) : void {
823- const thenLabel = createFlowLabel ( ) ;
824- const elseLabel = createFlowLabel ( ) ;
825- const postIfLabel = createFlowLabel ( ) ;
848+ const thenLabel = createBranchLabel ( ) ;
849+ const elseLabel = createBranchLabel ( ) ;
850+ const postIfLabel = createBranchLabel ( ) ;
826851 bindCondition ( node . expression , thenLabel , elseLabel ) ;
827852 currentFlow = finishFlowLabel ( thenLabel ) ;
828853 bind ( node . thenStatement ) ;
@@ -875,7 +900,7 @@ namespace ts {
875900 }
876901
877902 function bindTryStatement ( node : TryStatement ) : void {
878- const postFinallyLabel = createFlowLabel ( ) ;
903+ const postFinallyLabel = createBranchLabel ( ) ;
879904 const preTryFlow = currentFlow ;
880905 // TODO: Every statement in try block is potentially an exit point!
881906 bind ( node . tryBlock ) ;
@@ -893,7 +918,7 @@ namespace ts {
893918 }
894919
895920 function bindSwitchStatement ( node : SwitchStatement ) : void {
896- const postSwitchLabel = createFlowLabel ( ) ;
921+ const postSwitchLabel = createBranchLabel ( ) ;
897922 bind ( node . expression ) ;
898923 const saveBreakTarget = currentBreakTarget ;
899924 const savePreSwitchCaseFlow = preSwitchCaseFlow ;
@@ -915,17 +940,17 @@ namespace ts {
915940 for ( let i = 0 ; i < clauses . length ; i ++ ) {
916941 const clause = clauses [ i ] ;
917942 if ( clause . statements . length ) {
918- if ( currentFlow . kind === FlowKind . Unreachable ) {
943+ if ( currentFlow . flags & FlowFlags . Unreachable ) {
919944 currentFlow = preSwitchCaseFlow ;
920945 }
921946 else {
922- const preCaseLabel = createFlowLabel ( ) ;
947+ const preCaseLabel = createBranchLabel ( ) ;
923948 addAntecedent ( preCaseLabel , preSwitchCaseFlow ) ;
924949 addAntecedent ( preCaseLabel , currentFlow ) ;
925950 currentFlow = finishFlowLabel ( preCaseLabel ) ;
926951 }
927952 bind ( clause ) ;
928- if ( currentFlow . kind !== FlowKind . Unreachable && i !== clauses . length - 1 && options . noFallthroughCasesInSwitch ) {
953+ if ( ! ( currentFlow . flags & FlowFlags . Unreachable ) && i !== clauses . length - 1 && options . noFallthroughCasesInSwitch ) {
929954 errorOnFirstToken ( clause , Diagnostics . Fallthrough_case_in_switch ) ;
930955 }
931956 }
@@ -951,8 +976,8 @@ namespace ts {
951976 }
952977
953978 function bindLabeledStatement ( node : LabeledStatement ) : void {
954- const preStatementLabel = createFlowLoopLabel ( ) ;
955- const postStatementLabel = createFlowLabel ( ) ;
979+ const preStatementLabel = createLoopLabel ( ) ;
980+ const postStatementLabel = createBranchLabel ( ) ;
956981 bind ( node . label ) ;
957982 addAntecedent ( preStatementLabel , currentFlow ) ;
958983 const activeLabel = pushActiveLabel ( node . label . text , postStatementLabel , preStatementLabel ) ;
@@ -1001,7 +1026,7 @@ namespace ts {
10011026 }
10021027
10031028 function bindLogicalExpression ( node : BinaryExpression , trueTarget : FlowLabel , falseTarget : FlowLabel ) {
1004- const preRightLabel = createFlowLabel ( ) ;
1029+ const preRightLabel = createBranchLabel ( ) ;
10051030 if ( node . operatorToken . kind === SyntaxKind . AmpersandAmpersandToken ) {
10061031 bindCondition ( node . left , preRightLabel , falseTarget ) ;
10071032 }
@@ -1031,7 +1056,7 @@ namespace ts {
10311056 const operator = node . operatorToken . kind ;
10321057 if ( operator === SyntaxKind . AmpersandAmpersandToken || operator === SyntaxKind . BarBarToken ) {
10331058 if ( isTopLevelLogicalExpression ( node ) ) {
1034- const postExpressionLabel = createFlowLabel ( ) ;
1059+ const postExpressionLabel = createBranchLabel ( ) ;
10351060 bindLogicalExpression ( node , postExpressionLabel , postExpressionLabel ) ;
10361061 currentFlow = finishFlowLabel ( postExpressionLabel ) ;
10371062 }
@@ -1048,9 +1073,9 @@ namespace ts {
10481073 }
10491074
10501075 function bindConditionalExpressionFlow ( node : ConditionalExpression ) {
1051- const trueLabel = createFlowLabel ( ) ;
1052- const falseLabel = createFlowLabel ( ) ;
1053- const postExpressionLabel = createFlowLabel ( ) ;
1076+ const trueLabel = createBranchLabel ( ) ;
1077+ const falseLabel = createBranchLabel ( ) ;
1078+ const postExpressionLabel = createBranchLabel ( ) ;
10541079 bindCondition ( node . condition , trueLabel , falseLabel ) ;
10551080 currentFlow = finishFlowLabel ( trueLabel ) ;
10561081 bind ( node . whenTrue ) ;
@@ -2065,7 +2090,7 @@ namespace ts {
20652090 }
20662091
20672092 function checkUnreachable ( node : Node ) : boolean {
2068- if ( currentFlow . kind !== FlowKind . Unreachable ) {
2093+ if ( ! ( currentFlow . flags & FlowFlags . Unreachable ) ) {
20692094 return false ;
20702095 }
20712096 if ( currentFlow === unreachableFlow ) {
0 commit comments