@@ -391,16 +391,6 @@ module Flow<InputSig Input> implements OutputSig<Input> {
391
391
msg = "ClosureExpr has no body" and not ce .hasBody ( _)
392
392
}
393
393
394
- query predicate closureAliasMustBeLocal ( ClosureExpr ce , Expr access , string msg ) {
395
- exists ( BasicBlock bb1 , BasicBlock bb2 |
396
- ce .hasAliasedAccess ( access ) and
397
- ce .hasCfgNode ( bb1 , _) and
398
- access .hasCfgNode ( bb2 , _) and
399
- bb1 .getEnclosingCallable ( ) != bb2 .getEnclosingCallable ( ) and
400
- msg = "ClosureExpr has non-local alias - these are ignored"
401
- )
402
- }
403
-
404
394
private predicate astClosureParent ( Callable closure , Callable parent ) {
405
395
exists ( ClosureExpr ce , BasicBlock bb |
406
396
ce .hasBody ( closure ) and ce .hasCfgNode ( bb , _) and parent = bb .getEnclosingCallable ( )
@@ -440,7 +430,6 @@ module Flow<InputSig Input> implements OutputSig<Input> {
440
430
n = strictcount ( VariableWrite vw | localWriteStep ( vw , msg ) ) or
441
431
n = strictcount ( VariableRead vr | uniqueReadVariable ( vr , msg ) ) or
442
432
n = strictcount ( ClosureExpr ce | closureMustHaveBody ( ce , msg ) ) or
443
- n = strictcount ( ClosureExpr ce , Expr access | closureAliasMustBeLocal ( ce , access , msg ) ) or
444
433
n = strictcount ( CapturedVariable v , Callable c | variableAccessAstNesting ( v , c , msg ) ) or
445
434
n = strictcount ( Callable c | uniqueCallableLocation ( c , msg ) )
446
435
}
@@ -518,10 +507,42 @@ module Flow<InputSig Input> implements OutputSig<Input> {
518
507
}
519
508
520
509
/** Gets the enclosing callable of `ce`. */
521
- private Callable closureExprGetCallable ( ClosureExpr ce ) {
510
+ private Callable closureExprGetEnclosingCallable ( ClosureExpr ce ) {
522
511
exists ( BasicBlock bb | ce .hasCfgNode ( bb , _) and result = bb .getEnclosingCallable ( ) )
523
512
}
524
513
514
+ /** Gets the enclosing callable of `inner`. */
515
+ pragma [ nomagic]
516
+ private Callable callableGetEnclosingCallable ( Callable inner ) {
517
+ exists ( ClosureExpr closure |
518
+ closure .hasBody ( inner ) and
519
+ result = closureExprGetEnclosingCallable ( closure )
520
+ )
521
+ }
522
+
523
+ /**
524
+ * Gets a callable that contains a reference to `ce` into which `ce` could be inlined without
525
+ * bringing any variables out of scope.
526
+ *
527
+ * If `ce` was to be inlined into that reference, the resulting callable
528
+ * would become the enclosing callable, and thus capture the same variables as `ce`.
529
+ * In some sense, we model captured aliases as if this inlining has happened.
530
+ */
531
+ private Callable closureExprGetAReferencingCallable ( ClosureExpr ce ) {
532
+ exists ( Expr expr , BasicBlock bb |
533
+ ce .hasAliasedAccess ( expr ) and
534
+ expr .hasCfgNode ( bb , _) and
535
+ result = bb .getEnclosingCallable ( ) and
536
+ // The reference to `ce` is allowed to occur in a more deeply nested context
537
+ closureExprGetEnclosingCallable ( ce ) = callableGetEnclosingCallable * ( result )
538
+ )
539
+ }
540
+
541
+ /** Gets a callable containing `ce` or one of its aliases. */
542
+ private Callable closureExprGetCallable ( ClosureExpr ce ) {
543
+ result = [ closureExprGetEnclosingCallable ( ce ) , closureExprGetAReferencingCallable ( ce ) ]
544
+ }
545
+
525
546
/**
526
547
* Holds if `v` is available in `c` through capture. This can either be due to
527
548
* an explicit variable reference or through the construction of a closure
0 commit comments