Skip to content

Commit f257252

Browse files
committed
[NFC] CSApply: Introduce a generalized routine for building single curry thunk bodies
1 parent 64ff2b2 commit f257252

File tree

3 files changed

+178
-1
lines changed

3 files changed

+178
-1
lines changed

include/swift/AST/Decl.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8058,10 +8058,14 @@ inline EnumElementDecl *EnumDecl::getUniqueElement(bool hasValue) const {
80588058
return result;
80598059
}
80608060

8061-
/// Retrieve the parameter list for a given declaration, or nullputr if there
8061+
/// Retrieve the parameter list for a given declaration, or nullptr if there
80628062
/// is none.
80638063
ParameterList *getParameterList(ValueDecl *source);
80648064

8065+
/// Retrieve the parameter list for a given declaration context, or nullptr if
8066+
/// there is none.
8067+
ParameterList *getParameterList(DeclContext *source);
8068+
80658069
/// Retrieve parameter declaration from the given source at given index, or
80668070
/// nullptr if the source does not have a parameter list.
80678071
const ParamDecl *getParameterAt(const ValueDecl *source, unsigned index);

lib/AST/Decl.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7533,6 +7533,18 @@ ParameterList *swift::getParameterList(ValueDecl *source) {
75337533
return nullptr;
75347534
}
75357535

7536+
ParameterList *swift::getParameterList(DeclContext *source) {
7537+
if (auto *D = source->getAsDecl()) {
7538+
if (auto *VD = dyn_cast<ValueDecl>(D)) {
7539+
return getParameterList(VD);
7540+
}
7541+
} else if (auto *CE = dyn_cast<AbstractClosureExpr>(source)) {
7542+
return CE->getParameters();
7543+
}
7544+
7545+
return nullptr;
7546+
}
7547+
75367548
const ParamDecl *swift::getParameterAt(const ValueDecl *source,
75377549
unsigned index) {
75387550
if (auto *params = getParameterList(const_cast<ValueDecl *>(source))) {

lib/Sema/CSApply.cpp

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -955,6 +955,167 @@ namespace {
955955
return false;
956956
}
957957

958+
/// If the given parameter \p param has non-trivial ownership semantics,
959+
/// adjust the type of the given expression \p expr to reflect it. The
960+
/// expression is expected to serve as either an argument or reference
961+
/// to the parameter.
962+
void adjustExprOwnershipForParam(Expr *expr,
963+
const AnyFunctionType::Param &param) {
964+
// If the 'self' parameter has non-trivial ownership, adjust the
965+
// argument accordingly.
966+
switch (param.getValueOwnership()) {
967+
case ValueOwnership::Default:
968+
case ValueOwnership::InOut:
969+
break;
970+
971+
case ValueOwnership::Owned:
972+
case ValueOwnership::Shared:
973+
assert(param.getPlainType()->isEqual(cs.getType(expr)));
974+
975+
expr->setType(ParenType::get(cs.getASTContext(), param.getPlainType(),
976+
param.getParameterFlags()));
977+
cs.cacheType(expr);
978+
break;
979+
}
980+
}
981+
982+
/// Build the call inside the body of a single curry thunk
983+
/// "{ args in base.fn(args) }".
984+
///
985+
/// \param baseExpr The captured base expression, if warranted.
986+
/// \param fnExpr The expression to be called by consecutively applying
987+
/// the optional \p baseExpr and thunk parameters.
988+
/// \param declOrClosure The underlying function-like declaration or
989+
/// closure we're going to call.
990+
/// \param thunkParamList The enclosing thunk's parameter list.
991+
/// \param locator The locator pinned on the function reference carried
992+
/// by \p fnExpr. If the function has associated applied property wrappers,
993+
/// the locator is used to pull them in.
994+
ApplyExpr *buildSingleCurryThunkBodyCall(Expr *baseExpr, Expr *fnExpr,
995+
DeclContext *declOrClosure,
996+
ParameterList *thunkParamList,
997+
ConstraintLocatorBuilder locator) {
998+
auto &ctx = cs.getASTContext();
999+
auto *const fnTy = cs.getType(fnExpr)->castTo<FunctionType>();
1000+
auto *calleeFnTy = fnTy;
1001+
1002+
if (baseExpr) {
1003+
const auto calleeSelfParam = calleeFnTy->getParams().front();
1004+
1005+
// If the 'self' parameter has non-trivial ownership, adjust the
1006+
// argument type accordingly.
1007+
adjustExprOwnershipForParam(baseExpr, calleeSelfParam);
1008+
1009+
// Uncurry the callee type in the presence of a base expression; we
1010+
// want '(args) -> result' vs. '(self) -> (args) -> result'.
1011+
calleeFnTy = calleeFnTy->getResult()->castTo<FunctionType>();
1012+
}
1013+
1014+
const auto &appliedPropertyWrappers =
1015+
solution.appliedPropertyWrappers[locator.getAnchor()];
1016+
const auto calleeDeclRef = resolveConcreteDeclRef(
1017+
dyn_cast<AbstractFunctionDecl>(declOrClosure), locator);
1018+
1019+
auto *const calleeParamList = getParameterList(declOrClosure);
1020+
const auto calleeParams = calleeFnTy->getParams();
1021+
1022+
// Rebuild the callee params: SILGen knows how to emit property-wrapped
1023+
// parameters, but the corresponding parameter types need to match the
1024+
// backing wrapper types.
1025+
SmallVector<AnyFunctionType::Param, 4> newCalleeParams;
1026+
newCalleeParams.reserve(calleeParams.size());
1027+
1028+
// Build the argument list for the call.
1029+
SmallVector<Argument, 4> args;
1030+
unsigned appliedWrapperIndex = 0;
1031+
for (const auto idx : indices(*thunkParamList)) {
1032+
auto *const thunkParamDecl = thunkParamList->get(idx);
1033+
1034+
const auto calleeParam = calleeParams[idx];
1035+
const auto calleeParamType = calleeParam.getParameterType();
1036+
const auto thunkParamType = thunkParamDecl->getType();
1037+
1038+
Expr *paramRef = new (ctx)
1039+
DeclRefExpr(thunkParamDecl, DeclNameLoc(), /*implicit*/ true);
1040+
paramRef->setType(thunkParamDecl->isInOut()
1041+
? LValueType::get(thunkParamType)
1042+
: thunkParamType);
1043+
cs.cacheType(paramRef);
1044+
1045+
paramRef = coerceToType(paramRef,
1046+
thunkParamDecl->isInOut()
1047+
? LValueType::get(calleeParamType)
1048+
: calleeParamType,
1049+
locator);
1050+
1051+
auto *const calleeParamDecl = calleeParamList->get(idx);
1052+
if (calleeParamDecl->hasAttachedPropertyWrapper()) {
1053+
// Rewrite the parameter ref to the backing wrapper initialization
1054+
// expression.
1055+
auto &appliedWrapper = appliedPropertyWrappers[appliedWrapperIndex++];
1056+
1057+
using ValueKind = AppliedPropertyWrapperExpr::ValueKind;
1058+
ValueKind valueKind = (appliedWrapper.initKind ==
1059+
PropertyWrapperInitKind::ProjectedValue
1060+
? ValueKind::ProjectedValue
1061+
: ValueKind::WrappedValue);
1062+
1063+
paramRef = AppliedPropertyWrapperExpr::create(
1064+
ctx, calleeDeclRef, calleeParamDecl, SourceLoc(),
1065+
appliedWrapper.wrapperType, paramRef, valueKind);
1066+
cs.cacheExprTypes(paramRef);
1067+
1068+
newCalleeParams.push_back(calleeParam.withType(paramRef->getType()));
1069+
1070+
// TODO: inout
1071+
// FIXME: vararg
1072+
} else {
1073+
if (thunkParamDecl->isInOut()) {
1074+
paramRef =
1075+
new (ctx) InOutExpr(SourceLoc(), paramRef, calleeParamType,
1076+
/*implicit=*/true);
1077+
} else if (thunkParamDecl->isVariadic()) {
1078+
assert(calleeParamType->isEqual(paramRef->getType()));
1079+
paramRef = VarargExpansionExpr::createParamExpansion(ctx, paramRef);
1080+
}
1081+
cs.cacheType(paramRef);
1082+
1083+
newCalleeParams.push_back(calleeParam);
1084+
}
1085+
1086+
args.emplace_back(SourceLoc(), calleeParam.getLabel(), paramRef);
1087+
}
1088+
1089+
// SILGen knows how to emit property-wrapped parameters, but the
1090+
// corresponding parameter types need to match the backing wrapper types.
1091+
// To handle this, build a new callee function type out of the adjusted
1092+
// callee params, hand it over to the conditional 'self' call, and use it
1093+
// to update the type of the called expression with respect to whether
1094+
// it's 'self'-curried.
1095+
auto *const newCalleeFnTy = FunctionType::get(
1096+
newCalleeParams, calleeFnTy->getResult(), calleeFnTy->getExtInfo());
1097+
1098+
// If given, apply the base expression to the curried 'self'
1099+
// parameter first.
1100+
if (baseExpr) {
1101+
fnExpr->setType(FunctionType::get(fnTy->getParams(), newCalleeFnTy,
1102+
fnTy->getExtInfo()));
1103+
cs.cacheType(fnExpr);
1104+
1105+
fnExpr = DotSyntaxCallExpr::create(ctx, fnExpr, SourceLoc(), baseExpr);
1106+
}
1107+
fnExpr->setType(newCalleeFnTy);
1108+
cs.cacheType(fnExpr);
1109+
1110+
// Finally, apply the argument list to the callee.
1111+
ApplyExpr *callExpr = CallExpr::createImplicit(
1112+
ctx, fnExpr, ArgumentList::createImplicit(ctx, args));
1113+
callExpr->setType(calleeFnTy->getResult());
1114+
cs.cacheType(callExpr);
1115+
1116+
return callExpr;
1117+
}
1118+
9581119
AutoClosureExpr *buildPropertyWrapperFnThunk(
9591120
Expr *fnRef, FunctionType *fnType, AnyFunctionRef fnDecl, ConcreteDeclRef ref,
9601121
ArrayRef<AppliedPropertyWrapper> appliedPropertyWrappers) {

0 commit comments

Comments
 (0)