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