@@ -389,6 +389,17 @@ private predicate typeEquality(AstNode n1, TypePath prefix1, AstNode n2, TypePat
389389 prefix2 .isEmpty ( ) and
390390 s = getRangeType ( n1 )
391391 )
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 ( )
392403}
393404
394405pragma [ nomagic]
@@ -1441,6 +1452,120 @@ private Type inferForLoopExprType(AstNode n, TypePath path) {
14411452 )
14421453}
14431454
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+
14441569pragma [ nomagic]
14451570private Type inferCastExprType ( CastExpr ce , TypePath path ) {
14461571 result = ce .getTypeRepr ( ) .( TypeMention ) .resolveTypeAt ( path )
@@ -2068,6 +2193,10 @@ private module Cached {
20682193 or
20692194 result = inferForLoopExprType ( n , path )
20702195 or
2196+ result = inferDynamicCallExprType ( n , path )
2197+ or
2198+ result = inferClosureExprType ( n , path )
2199+ or
20712200 result = inferCastExprType ( n , path )
20722201 or
20732202 result = inferStructPatType ( n , path )
0 commit comments