@@ -389,6 +389,17 @@ private predicate typeEquality(AstNode n1, TypePath prefix1, AstNode n2, TypePat
389
389
prefix2 .isEmpty ( ) and
390
390
s = getRangeType ( n1 )
391
391
)
392
+ or
393
+ exists ( ClosureExpr ce , int index |
394
+ n1 = ce and
395
+ n2 = ce .getParam ( index ) .getPat ( ) and
396
+ prefix1 = closureParameterPath ( ce .getNumberOfParams ( ) , index ) and
397
+ prefix2 .isEmpty ( )
398
+ )
399
+ or
400
+ n1 .( ClosureExpr ) .getBody ( ) = n2 and
401
+ prefix1 = closureReturnPath ( ) and
402
+ prefix2 .isEmpty ( )
392
403
}
393
404
394
405
pragma [ nomagic]
@@ -1441,6 +1452,120 @@ private Type inferForLoopExprType(AstNode n, TypePath path) {
1441
1452
)
1442
1453
}
1443
1454
1455
+ /**
1456
+ * An invoked expression, the target of a call that is either a local variable
1457
+ * or a non-path expression. This means that the expression denotes a
1458
+ * first-class function.
1459
+ */
1460
+ final private class InvokedClosureExpr extends Expr {
1461
+ private CallExpr call ;
1462
+
1463
+ InvokedClosureExpr ( ) {
1464
+ call .getFunction ( ) = this and
1465
+ ( not this instanceof PathExpr or this = any ( Variable v ) .getAnAccess ( ) )
1466
+ }
1467
+
1468
+ Type getTypeAt ( TypePath path ) { result = inferType ( this , path ) }
1469
+
1470
+ CallExpr getCall ( ) { result = call }
1471
+ }
1472
+
1473
+ private module InvokedClosureSatisfiesConstraintInput implements
1474
+ SatisfiesConstraintInputSig< InvokedClosureExpr >
1475
+ {
1476
+ predicate relevantConstraint ( InvokedClosureExpr term , Type constraint ) {
1477
+ exists ( term ) and
1478
+ constraint .( TraitType ) .getTrait ( ) instanceof FnOnceTrait
1479
+ }
1480
+ }
1481
+
1482
+ /** Gets the type of `ce` when viewed as an implementation of `FnOnce`. */
1483
+ private Type invokedClosureFnTypeAt ( InvokedClosureExpr ce , TypePath path ) {
1484
+ SatisfiesConstraint< InvokedClosureExpr , InvokedClosureSatisfiesConstraintInput > :: satisfiesConstraintType ( ce ,
1485
+ _, path , result )
1486
+ }
1487
+
1488
+ /** Gets the path to a closure's return type. */
1489
+ private TypePath closureReturnPath ( ) {
1490
+ result = TypePath:: singleton ( TDynTraitTypeParameter ( any ( FnOnceTrait t ) .getOutputType ( ) ) )
1491
+ }
1492
+
1493
+ /** Gets the path to a closure with arity `arity`s `index`th parameter type. */
1494
+ private TypePath closureParameterPath ( int arity , int index ) {
1495
+ result =
1496
+ TypePath:: cons ( TDynTraitTypeParameter ( any ( FnOnceTrait t ) .getTypeParam ( ) ) ,
1497
+ TypePath:: singleton ( TTupleTypeParameter ( arity , index ) ) )
1498
+ }
1499
+
1500
+ /** Gets the path to the return type of the `FnOnce` trait. */
1501
+ private TypePath fnReturnPath ( ) {
1502
+ result = TypePath:: singleton ( TAssociatedTypeTypeParameter ( any ( FnOnceTrait t ) .getOutputType ( ) ) )
1503
+ }
1504
+
1505
+ /**
1506
+ * Gets the path to the parameter type of the `FnOnce` trait with arity `arity`
1507
+ * and index `index`.
1508
+ */
1509
+ private TypePath fnParameterPath ( int arity , int index ) {
1510
+ result =
1511
+ TypePath:: cons ( TTypeParamTypeParameter ( any ( FnOnceTrait t ) .getTypeParam ( ) ) ,
1512
+ TypePath:: singleton ( TTupleTypeParameter ( arity , index ) ) )
1513
+ }
1514
+
1515
+ pragma [ nomagic]
1516
+ private Type inferDynamicCallExprType ( Expr n , TypePath path ) {
1517
+ exists ( InvokedClosureExpr ce |
1518
+ // Propagate the function's return type to the call expression
1519
+ exists ( TypePath path0 | result = invokedClosureFnTypeAt ( ce , path0 ) |
1520
+ n = ce .getCall ( ) and
1521
+ path = path0 .stripPrefix ( fnReturnPath ( ) )
1522
+ or
1523
+ // Propagate the function's parameter type to the arguments
1524
+ exists ( int index |
1525
+ n = ce .getCall ( ) .getArgList ( ) .getArg ( index ) and
1526
+ path = path0 .stripPrefix ( fnParameterPath ( ce .getCall ( ) .getNumberOfArgs ( ) , index ) )
1527
+ )
1528
+ )
1529
+ or
1530
+ // _If_ the invoked expression has the type of a closure, then we propagate
1531
+ // the surrounding types into the closure.
1532
+ exists ( int arity , TypePath path0 |
1533
+ ce .getTypeAt ( TypePath:: nil ( ) ) .( DynTraitType ) .getTrait ( ) instanceof FnOnceTrait
1534
+ |
1535
+ // Propagate the type of arguments to the parameter types of closure
1536
+ exists ( int index |
1537
+ n = ce and
1538
+ arity = ce .getCall ( ) .getNumberOfArgs ( ) and
1539
+ result = inferType ( ce .getCall ( ) .getArg ( index ) , path0 ) and
1540
+ path = closureParameterPath ( arity , index ) .append ( path0 )
1541
+ )
1542
+ or
1543
+ // Propagate the type of the call expression to the return type of the closure
1544
+ n = ce and
1545
+ arity = ce .getCall ( ) .getNumberOfArgs ( ) and
1546
+ result = inferType ( ce .getCall ( ) , path0 ) and
1547
+ path = closureReturnPath ( ) .append ( path0 )
1548
+ )
1549
+ )
1550
+ }
1551
+
1552
+ pragma [ nomagic]
1553
+ private Type inferClosureExprType ( AstNode n , TypePath path ) {
1554
+ exists ( ClosureExpr ce |
1555
+ n = ce and
1556
+ path .isEmpty ( ) and
1557
+ result = TDynTraitType ( any ( FnOnceTrait t ) )
1558
+ or
1559
+ n = ce and
1560
+ path = TypePath:: singleton ( TDynTraitTypeParameter ( any ( FnOnceTrait t ) .getTypeParam ( ) ) ) and
1561
+ result = TTuple ( ce .getNumberOfParams ( ) )
1562
+ or
1563
+ // Propagate return type annotation to body
1564
+ n = ce .getBody ( ) and
1565
+ result = ce .getRetType ( ) .getTypeRepr ( ) .( TypeMention ) .resolveTypeAt ( path )
1566
+ )
1567
+ }
1568
+
1444
1569
pragma [ nomagic]
1445
1570
private Type inferCastExprType ( CastExpr ce , TypePath path ) {
1446
1571
result = ce .getTypeRepr ( ) .( TypeMention ) .resolveTypeAt ( path )
@@ -2068,6 +2193,10 @@ private module Cached {
2068
2193
or
2069
2194
result = inferForLoopExprType ( n , path )
2070
2195
or
2196
+ result = inferDynamicCallExprType ( n , path )
2197
+ or
2198
+ result = inferClosureExprType ( n , path )
2199
+ or
2071
2200
result = inferCastExprType ( n , path )
2072
2201
or
2073
2202
result = inferStructPatType ( n , path )
0 commit comments