@@ -489,14 +489,14 @@ private module ControlFlowGraphImpl {
489489 private Stmt getSwitchStatement ( SwitchBlock switch , int i ) { result .isNthChildOf ( switch , i ) }
490490
491491 /**
492- * Holds if `last` is the last node in a pattern case `pc`'s succeeding bind-and-test operation ,
492+ * Holds if `last` is the last node in any of pattern case `pc`'s succeeding bind-and-test operations ,
493493 * immediately before either falling through to execute successor statements or execute a rule body
494494 * if present. `completion` is the completion kind of the last operation.
495495 */
496496 private predicate lastPatternCaseMatchingOp (
497497 PatternCase pc , ControlFlowNode last , Completion completion
498498 ) {
499- last ( pc .getPattern ( ) , last , completion ) and
499+ last ( pc .getAPattern ( ) , last , completion ) and
500500 completion = NormalCompletion ( ) and
501501 not exists ( pc .getGuard ( ) )
502502 or
@@ -776,6 +776,18 @@ private module ControlFlowGraphImpl {
776776 last ( try .getFinally ( ) , last , NormalCompletion ( ) )
777777 }
778778
779+ private predicate isNextNormalSwitchStmt ( SwitchBlock switch , Stmt pred , Stmt succ ) {
780+ exists ( int i , Stmt immediateSucc |
781+ getSwitchStatement ( switch , i ) = pred and
782+ getSwitchStatement ( switch , i + 1 ) = immediateSucc and
783+ (
784+ if immediateSucc instanceof PatternCase
785+ then isNextNormalSwitchStmt ( switch , immediateSucc , succ )
786+ else succ = immediateSucc
787+ )
788+ )
789+ }
790+
779791 /**
780792 * Bind `last` to a cfg node nested inside `n` (or, indeed, `n` itself) such
781793 * that `last` may be the last node during an execution of `n` and finish
@@ -927,9 +939,15 @@ private module ControlFlowGraphImpl {
927939 completion != anonymousBreakCompletion ( ) and
928940 not completion instanceof NormalOrBooleanCompletion
929941 or
930- // if the last case completes normally, then so does the switch
931- last ( switch .getStmt ( strictcount ( switch .getAStmt ( ) ) - 1 ) , last , NormalCompletion ( ) ) and
932- completion = NormalCompletion ( )
942+ // if a statement without a non-pattern-case successor completes normally (or for a pattern case
943+ // the guard succeeds) then the switch completes normally.
944+ exists ( Stmt lastNormalStmt , Completion stmtCompletion |
945+ lastNormalStmt = getSwitchStatement ( switch , _) and
946+ not isNextNormalSwitchStmt ( switch , lastNormalStmt , _) and
947+ last ( lastNormalStmt , last , stmtCompletion ) and
948+ ( stmtCompletion = NormalCompletion ( ) or stmtCompletion = BooleanCompletion ( true , _) ) and
949+ completion = NormalCompletion ( )
950+ )
933951 or
934952 // if no default case exists, then normal completion of the expression may terminate the switch
935953 // Note this can't happen if there are pattern cases or a null literal, as
@@ -973,9 +991,9 @@ private module ControlFlowGraphImpl {
973991 )
974992 or
975993 // A pattern case statement can complete:
976- // * On failure of its type test (boolean false)
994+ // * On failure of its final type test (boolean false)
977995 // * On failure of its guard test if any (boolean false)
978- // * On completion of its variable declarations, if it is not a rule and has no guard (normal completion)
996+ // * On completion of one of its pattern variable declarations, if it is not a rule and has no guard (normal completion)
979997 // * On success of its guard test, if it is not a rule (boolean true)
980998 // (the latter two cases are accounted for by lastPatternCaseMatchingOp)
981999 exists ( PatternCase pc | n = pc |
@@ -1315,9 +1333,13 @@ private module ControlFlowGraphImpl {
13151333 // Note this includes non-rule case statements and the successful pattern match successor
13161334 // of a non-rule pattern case statement. Rule case statements do not complete normally
13171335 // (they always break or yield).
1318- exists ( int i |
1319- last ( getSwitchStatement ( switch , i ) , n , completion ) and
1320- result = first ( getSwitchStatement ( switch , i + 1 ) ) and
1336+ // Exception: falling through into a pattern case statement (which necessarily does not
1337+ // declare any named variables) must skip one or more such statements, otherwise we would
1338+ // incorrectly apply their type test and/or guard.
1339+ exists ( Stmt pred , Stmt succ |
1340+ isNextNormalSwitchStmt ( switch , pred , succ ) and
1341+ last ( pred , n , completion ) and
1342+ result = first ( succ ) and
13211343 ( completion = NormalCompletion ( ) or completion = BooleanCompletion ( true , _) )
13221344 )
13231345 or
@@ -1328,16 +1350,19 @@ private module ControlFlowGraphImpl {
13281350 )
13291351 or
13301352 // Pattern cases have internal edges:
1331- // * Type test success -true-> variable declarations
1353+ // * Type test success -true-> one of the possible sets of variable declarations
1354+ // n.b. for unnamed patterns (e.g. case A _, B _) this means that *one* of the
1355+ // type tests has succeeded. There aren't enough nodes in the AST to describe
1356+ // a sequential test in detail, so CFG consumers have to watch out for this case.
13321357 // * Variable declarations -normal-> guard evaluation
13331358 // * Variable declarations -normal-> rule execution (when there is no guard)
13341359 // * Guard success -true-> rule execution
13351360 exists ( PatternCase pc |
13361361 n = pc and
13371362 completion = basicBooleanCompletion ( true ) and
1338- result = first ( pc .getPattern ( ) )
1363+ result = first ( pc .getAPattern ( ) )
13391364 or
1340- last ( pc .getPattern ( ) , n , completion ) and
1365+ last ( pc .getAPattern ( ) , n , completion ) and
13411366 completion = NormalCompletion ( ) and
13421367 result = first ( pc .getGuard ( ) )
13431368 or
0 commit comments