@@ -59,6 +59,9 @@ module CfgImpl = Make<Location, CfgInput>;
5959
6060import CfgImpl
6161
62+ /** A trivial pattern that is always guaranteed to match. */
63+ predicate trivialPat ( Pat p ) { p instanceof WildcardPat or p instanceof IdentPat }
64+
6265class AwaitExprTree extends StandardPostOrderTree instanceof AwaitExpr {
6366 override ControlFlowTree getChildNode ( int i ) { i = 0 and result = super .getExpr ( ) }
6467}
@@ -236,11 +239,43 @@ class LetExprTree extends StandardPostOrderTree instanceof LetExpr {
236239 override ControlFlowTree getChildNode ( int i ) { i = 0 and result = super .getExpr ( ) }
237240}
238241
239- class LetStmtTree extends StandardPreOrderTree instanceof LetStmt {
242+ // We handle `let` statements with trivial patterns separately as they don't
243+ // lead to non-standard control flow. For instance, in `let a = ...` it is not
244+ // interesing to create match edges as it would carry no information.
245+ class LetStmtTreeTrivialPat extends StandardPreOrderTree instanceof LetStmt {
246+ LetStmtTreeTrivialPat ( ) { trivialPat ( super .getPat ( ) ) }
247+
240248 override ControlFlowTree getChildNode ( int i ) {
241- // TODO: For now we ignore the else branch (`super.getElse`). This branch
242- // is guaranteed to be diverging so will need special treatment in the CFG.
243249 i = 0 and result = super .getInitializer ( )
250+ or
251+ i = 1 and result = super .getPat ( )
252+ }
253+ }
254+
255+ // `let` statements with interesting patterns that we want to be reflected in
256+ // the CFG.
257+ class LetStmtTree extends PreOrderTree instanceof LetStmt {
258+ LetStmtTree ( ) { not trivialPat ( super .getPat ( ) ) }
259+
260+ final override predicate propagatesAbnormal ( AstNode child ) {
261+ child = super .getInitializer ( ) or child = super .getElse ( )
262+ }
263+
264+ override predicate succ ( AstNode pred , AstNode succ , Completion c ) {
265+ // Edge to start of initializer.
266+ pred = this and first ( super .getInitializer ( ) , succ ) and completionIsSimple ( c )
267+ or
268+ // Edge from end of initializer to pattern.
269+ last ( super .getInitializer ( ) , pred , c ) and succ = super .getPat ( )
270+ or
271+ // Edge from failed pattern to `else` branch.
272+ pred = super .getPat ( ) and first ( super .getElse ( ) , succ ) and c .( MatchCompletion ) .failed ( )
273+ }
274+
275+ override predicate last ( AstNode node , Completion c ) {
276+ // Edge out of a successfully matched pattern.
277+ node = super .getPat ( ) and c .( MatchCompletion ) .succeeded ( )
278+ // NOTE: No edge out of the `else` branch as that is guaranteed to diverge.
244279 }
245280}
246281
@@ -327,6 +362,8 @@ class MethodCallExprTree extends StandardPostOrderTree instanceof MethodCallExpr
327362
328363class OffsetOfExprTree extends LeafTree instanceof OffsetOfExpr { }
329364
365+ class PatExprTree extends LeafTree instanceof Pat { }
366+
330367class PathExprTree extends LeafTree instanceof PathExpr { }
331368
332369class RecordExprTree extends StandardPostOrderTree instanceof RecordExpr {
0 commit comments