@@ -1259,6 +1259,103 @@ namespace {
12591259 return thunk;
12601260 }
12611261
1262+ // / Build a "{ self in { args in self.fn(args) } }" nested curry thunk.
1263+ // /
1264+ // / \param memberRef The expression to be called in the inner thunk by
1265+ // / consecutively applying the captured outer thunk's 'self' parameter and
1266+ // / the parameters of the inner thunk.
1267+ // / \param member The underlying function declaration to be called.
1268+ // / \param outerThunkTy The type of the outer thunk.
1269+ // / \param memberLocator The locator pinned on the member reference. If the
1270+ // / function has associated applied property wrappers, the locator is used
1271+ // / to pull them in.
1272+ AutoClosureExpr *
1273+ buildDoubleCurryThunk (DeclRefExpr *memberRef, ValueDecl *member,
1274+ FunctionType *outerThunkTy,
1275+ ConstraintLocatorBuilder memberLocator) {
1276+ auto &ctx = cs.getASTContext ();
1277+
1278+ const auto selfThunkParam = outerThunkTy->getParams ().front ();
1279+ const auto selfThunkParamTy = selfThunkParam.getPlainType ();
1280+
1281+ // Build the 'self' param for the outer thunk, "{ self in ... }".
1282+ auto *const selfParamDecl =
1283+ new (ctx) ParamDecl (SourceLoc (),
1284+ /* argument label*/ SourceLoc (), Identifier (),
1285+ /* parameter name*/ SourceLoc (), ctx.Id_self , dc);
1286+ selfParamDecl->setInterfaceType (selfThunkParamTy->mapTypeOutOfContext ());
1287+ selfParamDecl->setSpecifier (
1288+ ParamDecl::getParameterSpecifierForValueOwnership (
1289+ selfThunkParam.getValueOwnership ()));
1290+ selfParamDecl->setImplicit ();
1291+
1292+ // Build a reference to the 'self' parameter.
1293+ Expr *selfParamRef = new (ctx) DeclRefExpr (selfParamDecl, DeclNameLoc (),
1294+ /* implicit=*/ true );
1295+ selfParamRef->setType (selfThunkParam.isInOut ()
1296+ ? LValueType::get (selfThunkParamTy)
1297+ : selfThunkParamTy);
1298+ cs.cacheType (selfParamRef);
1299+
1300+ if (selfThunkParam.isInOut ()) {
1301+ selfParamRef =
1302+ new (ctx) InOutExpr (SourceLoc (), selfParamRef, selfThunkParamTy,
1303+ /* implicit=*/ true );
1304+ cs.cacheType (selfParamRef);
1305+ }
1306+
1307+ const auto selfCalleeParam =
1308+ cs.getType (memberRef)->castTo <FunctionType>()->getParams ().front ();
1309+ const auto selfCalleeParamTy = selfCalleeParam.getPlainType ();
1310+
1311+ // Open the 'self' parameter reference if warranted.
1312+ Expr *selfOpenedRef = selfParamRef;
1313+ if (selfCalleeParamTy->hasOpenedExistential ()) {
1314+ // If we're opening an existential:
1315+ // - The type of 'ref' inside the thunk is written in terms of the
1316+ // open existental archetype.
1317+ // - The type of the thunk is written in terms of the
1318+ // erased existential bounds.
1319+ auto opaqueValueTy = selfCalleeParamTy;
1320+ if (selfCalleeParam.isInOut ())
1321+ opaqueValueTy = LValueType::get (opaqueValueTy);
1322+
1323+ selfOpenedRef = new (ctx) OpaqueValueExpr (SourceLoc (), opaqueValueTy);
1324+ cs.cacheType (selfOpenedRef);
1325+
1326+ // If we're opening an existential and the thunk's 'self' parameter has
1327+ // non-trivial ownership, we must adjust the parameter reference type
1328+ // here, because the body will use the opaque value instead.
1329+ adjustExprOwnershipForParam (selfParamRef, selfThunkParam);
1330+ }
1331+
1332+ // The inner thunk, "{ args... in self.member(args...) }".
1333+ auto *const innerThunk = buildSingleCurryThunk (
1334+ selfOpenedRef, memberRef, cast<DeclContext>(member),
1335+ outerThunkTy->getResult ()->castTo <FunctionType>(), memberLocator);
1336+
1337+ // Rewrite the body to close the existential if warranted.
1338+ if (selfCalleeParamTy->hasOpenedExistential ()) {
1339+ auto *body = innerThunk->getSingleExpressionBody ();
1340+ body = new (ctx) OpenExistentialExpr (
1341+ selfParamRef, cast<OpaqueValueExpr>(selfOpenedRef), body,
1342+ body->getType ());
1343+ cs.cacheType (body);
1344+
1345+ innerThunk->setBody (body);
1346+ }
1347+
1348+ // Finally, construct the outer thunk.
1349+ auto outerThunk = new (ctx) AutoClosureExpr (
1350+ innerThunk, outerThunkTy, AutoClosureExpr::InvalidDiscriminator, dc);
1351+ outerThunk->setThunkKind (AutoClosureExpr::Kind::DoubleCurryThunk);
1352+ outerThunk->setParameterList (
1353+ ParameterList::create (ctx, SourceLoc (), selfParamDecl, SourceLoc ()));
1354+ cs.cacheType (outerThunk);
1355+
1356+ return outerThunk;
1357+ }
1358+
12621359 // / Build a new member reference with the given base and member.
12631360 Expr *buildMemberRef (Expr *base, SourceLoc dotLoc,
12641361 SelectedOverload overload, DeclNameLoc memberLoc,
@@ -1597,65 +1694,10 @@ namespace {
15971694 ->castTo <FunctionType>();
15981695 }
15991696
1600- auto discriminator = AutoClosureExpr::InvalidDiscriminator;
1601-
1602- // The outer closure.
1603- //
1604- // let outerClosure = "{ self in \(closure) }"
1605- auto selfParam = curryThunkTy->getParams ()[0 ];
1606- auto selfParamDecl = new (context) ParamDecl (
1607- SourceLoc (),
1608- /* argument label*/ SourceLoc (), Identifier (),
1609- /* parameter name*/ SourceLoc (), context.Id_self ,
1610- dc);
1611-
1612- auto selfParamTy = selfParam.getPlainType ();
1613- bool isLValue = selfParam.isInOut ();
1614-
1615- selfParamDecl->setInterfaceType (selfParamTy->mapTypeOutOfContext ());
1616- selfParamDecl->setSpecifier (
1617- ParamDecl::getParameterSpecifierForValueOwnership (
1618- selfParam.getValueOwnership ()));
1619- selfParamDecl->setImplicit ();
1620-
1621- auto *outerParams =
1622- ParameterList::create (context, SourceLoc (), selfParamDecl,
1623- SourceLoc ());
1624-
1625- // The inner closure.
1626- //
1627- // let closure = "{ args... in self.member(args...) }"
1628- auto selfFnTy = curryThunkTy->getResult ()->castTo <FunctionType>();
1629-
1630- Expr *selfParamRef =
1631- new (context) DeclRefExpr (selfParamDecl, DeclNameLoc (),
1632- /* implicit=*/ true );
1633-
1634- selfParamRef->setType (
1635- isLValue ? LValueType::get (selfParamTy) : selfParamTy);
1636- cs.cacheType (selfParamRef);
1637-
1638- if (isLValue) {
1639- selfParamRef =
1640- new (context) InOutExpr (SourceLoc (), selfParamRef, selfParamTy,
1641- /* implicit=*/ true );
1642- cs.cacheType (selfParamRef);
1643- }
1644-
1645- auto closure = buildCurryThunk (member, selfFnTy, selfParamRef, ref,
1646- memberLocator);
1647-
1648- auto outerClosure =
1649- new (context) AutoClosureExpr (closure, selfFnTy, discriminator, dc);
1650- outerClosure->setThunkKind (AutoClosureExpr::Kind::DoubleCurryThunk);
1651-
1652- outerClosure->setParameterList (outerParams);
1653- outerClosure->setType (curryThunkTy);
1654- cs.cacheType (outerClosure);
1655-
16561697 // Replace the DeclRefExpr with a closure expression which SILGen
16571698 // knows how to emit.
1658- ref = outerClosure;
1699+ ref = buildDoubleCurryThunk (declRefExpr, member, curryThunkTy,
1700+ memberLocator);
16591701 }
16601702
16611703 // If the member is a method with a dynamic 'Self' result type, wrap an
0 commit comments