@@ -435,7 +435,7 @@ private module ControlFlowGraphImpl {
435435 }
436436
437437 /**
438- * Gets a SwitchCase 's successor SwitchCase, if any .
438+ * Holds if `succ` is `pred` 's successor ` SwitchCase` .
439439 */
440440 private predicate nextSwitchCase ( SwitchCase pred , SwitchCase succ ) {
441441 exists ( SwitchExpr se , int idx | se .getCase ( idx ) = pred and se .getCase ( idx + 1 ) = succ )
@@ -723,7 +723,7 @@ private module ControlFlowGraphImpl {
723723 */
724724 private predicate last ( ControlFlowNode n , ControlFlowNode last , Completion completion ) {
725725 // Exceptions are propagated from any sub-expression.
726- // As are any break, continue, or return completions.
726+ // As are any break, yield, continue, or return completions.
727727 exists ( Expr e | e .getParent ( ) = n |
728728 last ( e , last , completion ) and not completion instanceof NormalOrBooleanCompletion
729729 )
@@ -859,7 +859,7 @@ private module ControlFlowGraphImpl {
859859 // any other abnormal completion is propagated
860860 last ( switch .getAStmt ( ) , last , completion ) and
861861 completion != anonymousBreakCompletion ( ) and
862- completion != NormalCompletion ( )
862+ not completion instanceof NormalOrBooleanCompletion
863863 or
864864 // if the last case completes normally, then so does the switch
865865 last ( switch .getStmt ( strictcount ( switch .getAStmt ( ) ) - 1 ) , last , NormalCompletion ( ) ) and
@@ -879,32 +879,43 @@ private module ControlFlowGraphImpl {
879879 // any other abnormal completion is propagated
880880 last ( switch .getAStmt ( ) , last , completion ) and
881881 not completion instanceof YieldCompletion and
882- completion != NormalCompletion ( )
882+ not completion instanceof NormalOrBooleanCompletion
883883 )
884884 or
885- // the last node in a case rule is the last node in the right-hand side
886- // if the rhs is a statement we wrap the completion as a break
887- exists ( Completion caseCompletion |
888- last ( n .( SwitchCase ) .getRuleStatement ( ) , last , caseCompletion ) and
885+ // the last node in a case rule in statement context is the last node in the right-hand side.
886+ // If the rhs is a statement, we wrap the completion as a break.
887+ exists ( Completion caseCompletion , SwitchStmt parent , SwitchCase case |
888+ case = n and
889+ case = parent .getACase ( ) and
890+ last ( case .getRuleStatementOrExpressionStatement ( ) , last , caseCompletion ) and
889891 if caseCompletion instanceof NormalOrBooleanCompletion
890892 then completion = anonymousBreakCompletion ( )
891893 else completion = caseCompletion
892894 )
893895 or
894- // ...and if the rhs is an expression we wrap the completion as a yield
895- exists ( Completion caseCompletion |
896- last ( n .( SwitchCase ) .getRuleExpression ( ) , last , caseCompletion ) and
897- if caseCompletion instanceof NormalOrBooleanCompletion
898- then completion = YieldCompletion ( caseCompletion )
899- else completion = caseCompletion
896+ // ...and when a switch occurs in expression context, we wrap the RHS in a yield statement.
897+ // Note the wrapping can only occur in the expression case, because a statement would need
898+ // to have explicit `yield` statements.
899+ exists ( SwitchExpr parent , SwitchCase case |
900+ case = n and
901+ case = parent .getACase ( ) and
902+ (
903+ exists ( Completion caseCompletion |
904+ last ( case .getRuleExpression ( ) , last , caseCompletion ) and
905+ if caseCompletion instanceof NormalOrBooleanCompletion
906+ then completion = YieldCompletion ( caseCompletion )
907+ else completion = caseCompletion
908+ )
909+ or
910+ last ( case .getRuleStatement ( ) , last , completion )
911+ )
900912 )
901913 or
902- // The last node in a case could always be a failing pattern check.
903- last = n .( PatternCase ) and
904- completion = basicBooleanCompletion ( false )
905- or
906- // The last node in a non-rule case is its variable declaration.
914+ // The normal last node in a non-rule pattern case is its variable declaration.
915+ // Note that either rule or non-rule pattern cases can end with pattern match failure, whereupon
916+ // they branch to the next candidate pattern. This is accounted for in the `succ` relation.
907917 last = n .( PatternCase ) .getDecl ( ) and
918+ not n .( PatternCase ) .isRule ( ) and
908919 completion = NormalCompletion ( )
909920 or
910921 // the last statement of a synchronized statement is the last statement of its body
@@ -1231,6 +1242,10 @@ private module ControlFlowGraphImpl {
12311242 )
12321243 or
12331244 // Statements within a switch body execute sequentially.
1245+ // Note this includes non-rule case statements and the successful pattern match successor
1246+ // of a non-rule pattern case statement. Rule case statements do not complete normally
1247+ // (they always break or yield), and the case of pattern matching failure branching to the
1248+ // next case is specially handled in the `PatternCase` logic below.
12341249 exists ( int i |
12351250 last ( switch .getStmt ( i ) , n , completion ) and result = first ( switch .getStmt ( i + 1 ) )
12361251 )
@@ -1251,6 +1266,10 @@ private module ControlFlowGraphImpl {
12511266 )
12521267 or
12531268 // Statements within a switch body execute sequentially.
1269+ // Note this includes non-rule case statements and the successful pattern match successor
1270+ // of a non-rule pattern case statement. Rule case statements do not complete normally
1271+ // (they always break or yield), and the case of pattern matching failure branching to the
1272+ // next case is specially handled in the `PatternCase` logic below.
12541273 exists ( int i |
12551274 last ( switch .getStmt ( i ) , n , completion ) and result = first ( switch .getStmt ( i + 1 ) )
12561275 )
0 commit comments