@@ -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 ¶m) {
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