@@ -955,6 +955,167 @@ namespace {
955
955
return false ;
956
956
}
957
957
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
+
958
1119
AutoClosureExpr *buildPropertyWrapperFnThunk (
959
1120
Expr *fnRef, FunctionType *fnType, AnyFunctionRef fnDecl, ConcreteDeclRef ref,
960
1121
ArrayRef<AppliedPropertyWrapper> appliedPropertyWrappers) {
0 commit comments