@@ -1714,6 +1714,26 @@ static ManagedValue convertFunctionRepresentation(SILGenFunction &SGF,
17141714 llvm_unreachable (" bad representation" );
17151715}
17161716
1717+ // Ideally our prolog/epilog emission would be able to handle all possible
1718+ // reabstractions and conversions. Until then, this returns true if a closure
1719+ // literal of type `literalType` can be directly emitted by SILGen as
1720+ // `convertedType`.
1721+ static bool canPeepholeLiteralClosureConversion (Type literalType,
1722+ Type convertedType) {
1723+ auto literalFnType = literalType->getAs <FunctionType>();
1724+ auto convertedFnType = convertedType->getAs <FunctionType>();
1725+
1726+ if (!literalFnType || !convertedFnType)
1727+ return false ;
1728+
1729+ // Does the conversion only add `throws`?
1730+ if (literalFnType->isEqual (convertedFnType->getWithoutThrowing ())) {
1731+ return true ;
1732+ }
1733+
1734+ return false ;
1735+ }
1736+
17171737RValue RValueEmitter::visitFunctionConversionExpr (FunctionConversionExpr *e,
17181738 SGFContext C)
17191739{
@@ -1748,6 +1768,38 @@ RValue RValueEmitter::visitFunctionConversionExpr(FunctionConversionExpr *e,
17481768 return RValue (SGF, e, result);
17491769 }
17501770
1771+ // If the function being converted is a closure literal, then the only use
1772+ // of the closure should be as the destination type of the conversion. Rather
1773+ // than emit the closure as is and convert it, see if we can emit the closure
1774+ // directly as the desired type.
1775+ //
1776+ // TODO: Move this up when we can emit closures directly with C calling
1777+ // convention.
1778+ auto subExpr = e->getSubExpr ()->getSemanticsProvidingExpr ();
1779+ if (isa<AbstractClosureExpr>(subExpr)
1780+ && canPeepholeLiteralClosureConversion (subExpr->getType (),
1781+ e->getType ())) {
1782+ // If we're emitting into a context with a preferred abstraction pattern
1783+ // already, carry that along.
1784+ auto origType = C.getAbstractionPattern ();
1785+ // If not, use the conversion type as the desired abstraction pattern.
1786+ if (!origType) {
1787+ origType = AbstractionPattern (e->getType ()->getCanonicalType ());
1788+ }
1789+
1790+ auto substType = subExpr->getType ()->getCanonicalType ();
1791+
1792+ auto conversion = Conversion::getSubstToOrig (*origType, substType,
1793+ SGF.getLoweredType (*origType, substType));
1794+ ConvertingInitialization convertingInit (conversion, SGFContext ());
1795+ auto closure = SGF.emitRValue (subExpr,
1796+ SGFContext (&convertingInit))
1797+ .getAsSingleValue (SGF, e);
1798+ closure = SGF.emitSubstToOrigValue (e, closure, *origType, substType);
1799+
1800+ return RValue (SGF, e, closure);
1801+ }
1802+
17511803 // Handle a reference to a "thin" native Swift function that only changes
17521804 // representation and refers to an inherently thin function reference.
17531805 if (destRepTy->getRepresentation () == FunctionTypeRepresentation::Thin) {
0 commit comments