Skip to content

Commit 87bdddd

Browse files
committed
CSApply: Supplant 'buildCurryThunk' with a routine that builds a double curry thunk from scratch
1 parent b06b66d commit 87bdddd

File tree

1 file changed

+99
-57
lines changed

1 file changed

+99
-57
lines changed

lib/Sema/CSApply.cpp

Lines changed: 99 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)