@@ -4141,6 +4141,14 @@ struct AsyncHandlerDesc {
4141
4141
return Ty->getParams ();
4142
4142
}
4143
4143
4144
+ // / Retrieve the parameters relevant to a successful return from the
4145
+ // / completion handler. This drops the Error parameter if present.
4146
+ ArrayRef<AnyFunctionType::Param> getSuccessParams () const {
4147
+ if (HasError && Type == HandlerType::PARAMS)
4148
+ return params ().drop_back ();
4149
+ return params ();
4150
+ }
4151
+
4144
4152
// / The `CallExpr` if the given node is a call to the `Handler`
4145
4153
CallExpr *getAsHandlerCall (ASTNode Node) const {
4146
4154
if (!isValid ())
@@ -4162,13 +4170,16 @@ struct AsyncHandlerDesc {
4162
4170
auto Args = ArgList.ref ();
4163
4171
4164
4172
if (Type == HandlerType::PARAMS) {
4165
- if (!HasError)
4166
- return HandlerResult (Args);
4167
-
4168
- if (!isa<NilLiteralExpr>(Args.back ()))
4173
+ // If there's an error parameter and the user isn't passing nil to it,
4174
+ // assume this is the error path.
4175
+ if (HasError && !isa<NilLiteralExpr>(Args.back ()))
4169
4176
return HandlerResult (Args.back (), true );
4170
4177
4171
- return HandlerResult (Args.drop_back ());
4178
+ // We can drop the args altogether if they're just Void.
4179
+ if (willAsyncReturnVoid ())
4180
+ return HandlerResult ();
4181
+
4182
+ return HandlerResult (HasError ? Args.drop_back () : Args);
4172
4183
} else if (Type == HandlerType::RESULT) {
4173
4184
if (Args.size () != 1 )
4174
4185
return HandlerResult (Args);
@@ -4187,12 +4198,62 @@ struct AsyncHandlerDesc {
4187
4198
return HandlerResult (Args);
4188
4199
4189
4200
auto ResultArgList = callArgs (ResultCE);
4190
- return HandlerResult (ResultArgList.ref ()[0 ],
4191
- D->getNameStr () == StringRef (" failure" ));
4201
+ auto isFailure = D->getNameStr () == StringRef (" failure" );
4202
+
4203
+ // We can drop the arg altogether if it's just Void.
4204
+ if (!isFailure && willAsyncReturnVoid ())
4205
+ return HandlerResult ();
4206
+
4207
+ // Otherwise the arg gets the .success() or .failure() call dropped.
4208
+ return HandlerResult (ResultArgList.ref ()[0 ], isFailure);
4192
4209
}
4193
4210
4194
4211
llvm_unreachable (" Unhandled result type" );
4195
4212
}
4213
+
4214
+ // Convert the type of a success parameter in the completion handler function
4215
+ // to a return type suitable for an async function. If there is an error
4216
+ // parameter present e.g (T?, Error?) -> Void, this unwraps a level of
4217
+ // optionality from T?. If this is a Result<T, U> type, returns the success
4218
+ // type T.
4219
+ swift::Type getSuccessParamAsyncReturnType (swift::Type Ty) const {
4220
+ switch (Type) {
4221
+ case HandlerType::PARAMS: {
4222
+ // If there's an Error parameter in the handler, the success branch can
4223
+ // be unwrapped.
4224
+ if (HasError)
4225
+ Ty = Ty->lookThroughSingleOptionalType ();
4226
+
4227
+ return Ty;
4228
+ }
4229
+ case HandlerType::RESULT: {
4230
+ // Result<T, U> maps to T.
4231
+ return Ty->castTo <BoundGenericType>()->getGenericArgs ()[0 ];
4232
+ }
4233
+ case HandlerType::INVALID:
4234
+ llvm_unreachable (" Invalid handler type" );
4235
+ }
4236
+ }
4237
+
4238
+ // / Gets the return value types for the async equivalent of this handler.
4239
+ ArrayRef<swift::Type>
4240
+ getAsyncReturnTypes (SmallVectorImpl<swift::Type> &Scratch) const {
4241
+ for (auto &Param : getSuccessParams ()) {
4242
+ auto Ty = Param.getParameterType ();
4243
+ Scratch.push_back (getSuccessParamAsyncReturnType (Ty));
4244
+ }
4245
+ return Scratch;
4246
+ }
4247
+
4248
+ // / Whether the async equivalent of this handler returns Void.
4249
+ bool willAsyncReturnVoid () const {
4250
+ // If all of the success params will be converted to Void return types,
4251
+ // this will be a Void async function.
4252
+ return llvm::all_of (getSuccessParams (), [&](auto ¶m) {
4253
+ auto Ty = param.getParameterType ();
4254
+ return getSuccessParamAsyncReturnType (Ty)->isVoid ();
4255
+ });
4256
+ }
4196
4257
};
4197
4258
4198
4259
enum class ConditionType { INVALID, NIL, NOT_NIL };
@@ -4911,42 +4972,24 @@ class AsyncConverter : private SourceEntityWalker {
4911
4972
return ;
4912
4973
}
4913
4974
4914
- auto HandlerParams = TopHandler.params ();
4915
- if (TopHandler.Type == HandlerType::PARAMS && TopHandler.HasError ) {
4916
- HandlerParams = HandlerParams.drop_back ();
4917
- }
4918
-
4919
- if (HandlerParams.empty ()) {
4975
+ SmallVector<Type, 2 > Scratch;
4976
+ auto ReturnTypes = TopHandler.getAsyncReturnTypes (Scratch);
4977
+ if (ReturnTypes.empty ()) {
4920
4978
OS << " " ;
4921
4979
return ;
4922
4980
}
4923
4981
4924
- OS << " -> " ;
4982
+ // Print the function result type, making sure to omit a '-> Void' return.
4983
+ if (!TopHandler.willAsyncReturnVoid ()) {
4984
+ OS << " -> " ;
4985
+ if (ReturnTypes.size () > 1 )
4986
+ OS << " (" ;
4925
4987
4926
- if (HandlerParams.size () > 1 ) {
4927
- OS << " (" ;
4928
- }
4929
- for (size_t I = 0 , E = HandlerParams.size (); I < E; ++I) {
4930
- if (I > 0 ) {
4931
- OS << " , " ;
4932
- }
4988
+ llvm::interleave (
4989
+ ReturnTypes, [&](Type Ty) { Ty->print (OS); }, [&]() { OS << " , " ; });
4933
4990
4934
- auto &Param = HandlerParams[I];
4935
- if (TopHandler.Type == HandlerType::PARAMS) {
4936
- Type ToPrint = Param.getPlainType ();
4937
- if (TopHandler.HasError )
4938
- ToPrint = ToPrint->lookThroughSingleOptionalType ();
4939
- ToPrint->print (OS);
4940
- } else if (TopHandler.Type == HandlerType::RESULT) {
4941
- auto ResultTy = Param.getPlainType ()->getAs <BoundGenericType>();
4942
- assert (ResultTy && " Result must have generic type" );
4943
- ResultTy->getGenericArgs ()[0 ]->print (OS);
4944
- } else {
4945
- llvm_unreachable (" Unhandled handler type" );
4946
- }
4947
- }
4948
- if (HandlerParams.size () > 1 ) {
4949
- OS << " )" ;
4991
+ if (ReturnTypes.size () > 1 )
4992
+ OS << " )" ;
4950
4993
}
4951
4994
4952
4995
if (FD->hasBody ())
@@ -5073,8 +5116,7 @@ class AsyncConverter : private SourceEntityWalker {
5073
5116
addFallbackVars (CallbackParams->getArray (), Blocks);
5074
5117
addDo ();
5075
5118
addAwaitCall (CE, ArgList.ref (), Blocks.SuccessBlock , SuccessParams,
5076
- /* HasError=*/ HandlerDesc.HasError ,
5077
- /* AddDeclarations=*/ !HandlerDesc.HasError );
5119
+ HandlerDesc, /* AddDeclarations=*/ !HandlerDesc.HasError );
5078
5120
addFallbackCatch (ErrParam);
5079
5121
OS << " \n " ;
5080
5122
convertNodes (CallbackBody);
@@ -5107,10 +5149,9 @@ class AsyncConverter : private SourceEntityWalker {
5107
5149
5108
5150
setNames (Blocks.SuccessBlock , SuccessParams);
5109
5151
addAwaitCall (CE, ArgList.ref (), Blocks.SuccessBlock , SuccessParams,
5110
- /* HasError=*/ HandlerDesc.HasError ,
5111
- /* AddDeclarations=*/ true );
5152
+ HandlerDesc, /* AddDeclarations=*/ true );
5112
5153
5113
- prepareNamesForBody (HandlerDesc. Type , SuccessParams, ErrParams);
5154
+ prepareNamesForBody (HandlerDesc, SuccessParams, ErrParams);
5114
5155
convertNodes (Blocks.SuccessBlock .nodes ());
5115
5156
5116
5157
if (RequireDo) {
@@ -5120,7 +5161,7 @@ class AsyncConverter : private SourceEntityWalker {
5120
5161
HandlerDesc.Type != HandlerType::RESULT);
5121
5162
addCatch (ErrParam);
5122
5163
5123
- prepareNamesForBody (HandlerDesc. Type , ErrParams, SuccessParams);
5164
+ prepareNamesForBody (HandlerDesc, ErrParams, SuccessParams);
5124
5165
addCatchBody (ErrParam, Blocks.ErrorBlock );
5125
5166
}
5126
5167
@@ -5129,9 +5170,11 @@ class AsyncConverter : private SourceEntityWalker {
5129
5170
5130
5171
void addAwaitCall (const CallExpr *CE, ArrayRef<Expr *> Args,
5131
5172
const ClassifiedBlock &SuccessBlock,
5132
- ArrayRef<const ParamDecl *> SuccessParams, bool HasError,
5133
- bool AddDeclarations) {
5134
- if (!SuccessParams.empty ()) {
5173
+ ArrayRef<const ParamDecl *> SuccessParams,
5174
+ const AsyncHandlerDesc &HandlerDesc, bool AddDeclarations) {
5175
+ // Print the bindings to match the completion handler success parameters,
5176
+ // making sure to omit in the case of a Void return.
5177
+ if (!SuccessParams.empty () && !HandlerDesc.willAsyncReturnVoid ()) {
5135
5178
if (AddDeclarations) {
5136
5179
if (SuccessBlock.allLet ()) {
5137
5180
OS << tok::kw_let;
@@ -5153,7 +5196,7 @@ class AsyncConverter : private SourceEntityWalker {
5153
5196
OS << " " << tok::equal << " " ;
5154
5197
}
5155
5198
5156
- if (HasError) {
5199
+ if (HandlerDesc. HasError ) {
5157
5200
OS << tok::kw_try << " " ;
5158
5201
}
5159
5202
OS << " await " ;
@@ -5199,16 +5242,21 @@ class AsyncConverter : private SourceEntityWalker {
5199
5242
OS << " \n " << tok::r_brace;
5200
5243
}
5201
5244
5202
- void prepareNamesForBody (HandlerType ResultType ,
5245
+ void prepareNamesForBody (const AsyncHandlerDesc &HandlerDesc ,
5203
5246
ArrayRef<const ParamDecl *> CurrentParams,
5204
5247
ArrayRef<const ParamDecl *> OtherParams) {
5205
- switch (ResultType ) {
5248
+ switch (HandlerDesc. Type ) {
5206
5249
case HandlerType::PARAMS:
5207
5250
for (auto *Param : CurrentParams) {
5208
- if (Param->getType ()->getOptionalObjectType ()) {
5251
+ auto Ty = Param->getType ();
5252
+ if (Ty->getOptionalObjectType ()) {
5209
5253
Unwraps.insert (Param);
5210
5254
Placeholders.insert (Param);
5211
5255
}
5256
+ // Void parameters get omitted where possible, so turn any reference
5257
+ // into a placeholder, as its usage is unlikely what the user wants.
5258
+ if (HandlerDesc.getSuccessParamAsyncReturnType (Ty)->isVoid ())
5259
+ Placeholders.insert (Param);
5212
5260
}
5213
5261
// Use of the other params is invalid within the current body
5214
5262
Placeholders.insert (OtherParams.begin (), OtherParams.end ());
0 commit comments