@@ -4284,6 +4284,10 @@ struct AsyncHandlerDesc {
4284
4284
return getSuccessParamAsyncReturnType (Ty)->isVoid ();
4285
4285
});
4286
4286
}
4287
+
4288
+ bool shouldUnwrap (swift::Type Ty) const {
4289
+ return HasError && Ty->isOptional ();
4290
+ }
4287
4291
};
4288
4292
4289
4293
enum class ConditionType { INVALID, NIL, NOT_NIL };
@@ -4549,18 +4553,12 @@ struct CallbackClassifier {
4549
4553
static void classifyInto (ClassifiedBlocks &Blocks,
4550
4554
llvm::DenseSet<SwitchStmt *> &HandledSwitches,
4551
4555
DiagnosticEngine &DiagEngine,
4552
- ArrayRef <const ParamDecl *> SuccessParams ,
4556
+ llvm::DenseSet <const Decl *> UnwrapParams ,
4553
4557
const ParamDecl *ErrParam, HandlerType ResultType,
4554
4558
ArrayRef<ASTNode> Body) {
4555
4559
assert (!Body.empty () && " Cannot classify empty body" );
4556
-
4557
- auto ParamsSet = llvm::DenseSet<const Decl *>(SuccessParams.begin (),
4558
- SuccessParams.end ());
4559
- if (ErrParam)
4560
- ParamsSet.insert (ErrParam);
4561
-
4562
4560
CallbackClassifier Classifier (Blocks, HandledSwitches, DiagEngine,
4563
- ParamsSet , ErrParam,
4561
+ UnwrapParams , ErrParam,
4564
4562
ResultType == HandlerType::RESULT);
4565
4563
Classifier.classifyNodes (Body);
4566
4564
}
@@ -4570,19 +4568,19 @@ struct CallbackClassifier {
4570
4568
llvm::DenseSet<SwitchStmt *> &HandledSwitches;
4571
4569
DiagnosticEngine &DiagEngine;
4572
4570
ClassifiedBlock *CurrentBlock;
4573
- llvm::DenseSet<const Decl *> ParamsSet ;
4571
+ llvm::DenseSet<const Decl *> UnwrapParams ;
4574
4572
const ParamDecl *ErrParam;
4575
4573
bool IsResultParam;
4576
4574
4577
4575
CallbackClassifier (ClassifiedBlocks &Blocks,
4578
4576
llvm::DenseSet<SwitchStmt *> &HandledSwitches,
4579
4577
DiagnosticEngine &DiagEngine,
4580
- llvm::DenseSet<const Decl *> ParamsSet ,
4578
+ llvm::DenseSet<const Decl *> UnwrapParams ,
4581
4579
const ParamDecl *ErrParam, bool IsResultParam)
4582
4580
: Blocks(Blocks), HandledSwitches(HandledSwitches),
4583
4581
DiagEngine (DiagEngine), CurrentBlock(&Blocks.SuccessBlock),
4584
- ParamsSet(ParamsSet ), ErrParam(ErrParam), IsResultParam(IsResultParam) {
4585
- }
4582
+ UnwrapParams(UnwrapParams ), ErrParam(ErrParam),
4583
+ IsResultParam(IsResultParam) { }
4586
4584
4587
4585
void classifyNodes (ArrayRef<ASTNode> Nodes) {
4588
4586
for (auto I = Nodes.begin (), E = Nodes.end (); I < E; ++I) {
@@ -4614,7 +4612,7 @@ struct CallbackClassifier {
4614
4612
ArrayRef<ASTNode> ThenNodes, Stmt *ElseStmt) {
4615
4613
llvm::DenseMap<const Decl *, CallbackCondition> CallbackConditions;
4616
4614
bool UnhandledConditions =
4617
- !CallbackCondition::all (Condition, ParamsSet , CallbackConditions);
4615
+ !CallbackCondition::all (Condition, UnwrapParams , CallbackConditions);
4618
4616
CallbackCondition ErrCondition = CallbackConditions.lookup (ErrParam);
4619
4617
4620
4618
if (UnhandledConditions) {
@@ -4942,7 +4940,7 @@ class AsyncConverter : private SourceEntityWalker {
4942
4940
getUnderlyingFunc (CE->getFn ()), StartNode.dyn_cast <Expr *>() == CE);
4943
4941
if (HandlerDesc.isValid ())
4944
4942
return addCustom (CE->getSourceRange (),
4945
- [&]() { addAsyncAlternativeCall (CE, HandlerDesc); });
4943
+ [&]() { addHoistedCallback (CE, HandlerDesc); });
4946
4944
}
4947
4945
}
4948
4946
@@ -5145,8 +5143,8 @@ class AsyncConverter : private SourceEntityWalker {
5145
5143
}
5146
5144
}
5147
5145
5148
- void addAsyncAlternativeCall (const CallExpr *CE,
5149
- const AsyncHandlerDesc &HandlerDesc) {
5146
+ void addHoistedCallback (const CallExpr *CE,
5147
+ const AsyncHandlerDesc &HandlerDesc) {
5150
5148
auto ArgList = callArgs (CE);
5151
5149
if ((size_t )HandlerDesc.Index >= ArgList.ref ().size ()) {
5152
5150
DiagEngine.diagnose (CE->getStartLoc (), diag::missing_callback_arg);
@@ -5159,53 +5157,63 @@ class AsyncConverter : private SourceEntityWalker {
5159
5157
return ;
5160
5158
}
5161
5159
5162
- ParameterList *CallbackParams = Callback->getParameters ();
5160
+ ArrayRef<const ParamDecl *> CallbackParams =
5161
+ Callback->getParameters ()->getArray ();
5163
5162
ArrayRef<ASTNode> CallbackBody = Callback->getBody ()->getElements ();
5164
- if (HandlerDesc.params ().size () != CallbackParams-> size ()) {
5163
+ if (HandlerDesc.params ().size () != CallbackParams. size ()) {
5165
5164
DiagEngine.diagnose (CE->getStartLoc (), diag::mismatched_callback_args);
5166
5165
return ;
5167
5166
}
5168
5167
5169
5168
// Note that the `ErrParam` may be a Result (in which case it's also the
5170
5169
// only element in `SuccessParams`)
5171
- ArrayRef<const ParamDecl *> SuccessParams = CallbackParams-> getArray () ;
5170
+ ArrayRef<const ParamDecl *> SuccessParams = CallbackParams;
5172
5171
const ParamDecl *ErrParam = nullptr ;
5173
- if (HandlerDesc.HasError ) {
5172
+ if (HandlerDesc.Type == HandlerType::RESULT ) {
5174
5173
ErrParam = SuccessParams.back ();
5175
- if (HandlerDesc.Type == HandlerType::PARAMS)
5176
- SuccessParams = SuccessParams.drop_back ();
5174
+ } else if (HandlerDesc.HasError ) {
5175
+ assert (HandlerDesc.Type == HandlerType::PARAMS);
5176
+ ErrParam = SuccessParams.back ();
5177
+ SuccessParams = SuccessParams.drop_back ();
5177
5178
}
5178
- ArrayRef<const ParamDecl *> ErrParams;
5179
- if (ErrParam)
5180
- ErrParams = llvm::makeArrayRef (ErrParam);
5181
5179
5182
5180
ClassifiedBlocks Blocks;
5183
5181
if (!HandlerDesc.HasError ) {
5184
5182
Blocks.SuccessBlock .addAllNodes (CallbackBody);
5185
5183
} else if (!CallbackBody.empty ()) {
5184
+ llvm::DenseSet<const Decl *> UnwrapParams;
5185
+ for (auto *Param : SuccessParams) {
5186
+ if (HandlerDesc.shouldUnwrap (Param->getType ()))
5187
+ UnwrapParams.insert (Param);
5188
+ }
5189
+ if (ErrParam)
5190
+ UnwrapParams.insert (ErrParam);
5186
5191
CallbackClassifier::classifyInto (Blocks, HandledSwitches, DiagEngine,
5187
- SuccessParams, ErrParam,
5188
- HandlerDesc.Type , CallbackBody);
5189
- if (DiagEngine.hadAnyError ()) {
5190
- // Can only fallback when the results are params, in which case only
5191
- // the names are used (defaulted to the names of the params if none)
5192
- if (HandlerDesc.Type != HandlerType::PARAMS)
5193
- return ;
5194
- DiagEngine.resetHadAnyError ();
5192
+ UnwrapParams, ErrParam, HandlerDesc.Type ,
5193
+ CallbackBody);
5194
+ }
5195
5195
5196
- setNames (ClassifiedBlock (), CallbackParams->getArray ());
5196
+ if (DiagEngine.hadAnyError ()) {
5197
+ // Can only fallback when the results are params, in which case only
5198
+ // the names are used (defaulted to the names of the params if none)
5199
+ if (HandlerDesc.Type != HandlerType::PARAMS)
5200
+ return ;
5201
+ DiagEngine.resetHadAnyError ();
5197
5202
5198
- addFallbackVars (CallbackParams->getArray (), Blocks);
5199
- addDo ();
5200
- addAwaitCall (CE, ArgList.ref (), Blocks.SuccessBlock , SuccessParams,
5201
- HandlerDesc, /* AddDeclarations=*/ !HandlerDesc.HasError );
5202
- addFallbackCatch (ErrParam);
5203
- OS << " \n " ;
5204
- convertNodes (CallbackBody);
5203
+ // Don't do any unwrapping or placeholder replacement since all params
5204
+ // are still valid in the fallback case
5205
+ prepareNames (ClassifiedBlock (), CallbackParams);
5205
5206
5206
- clearParams (CallbackParams->getArray ());
5207
- return ;
5208
- }
5207
+ addFallbackVars (CallbackParams, Blocks);
5208
+ addDo ();
5209
+ addAwaitCall (CE, ArgList.ref (), Blocks.SuccessBlock , SuccessParams,
5210
+ HandlerDesc, /* AddDeclarations=*/ !HandlerDesc.HasError );
5211
+ addFallbackCatch (ErrParam);
5212
+ OS << " \n " ;
5213
+ convertNodes (CallbackBody);
5214
+
5215
+ clearNames (CallbackParams);
5216
+ return ;
5209
5217
}
5210
5218
5211
5219
bool RequireDo = !Blocks.ErrorBlock .nodes ().empty ();
@@ -5229,25 +5237,27 @@ class AsyncConverter : private SourceEntityWalker {
5229
5237
addDo ();
5230
5238
}
5231
5239
5232
- setNames (Blocks.SuccessBlock , SuccessParams);
5240
+ prepareNames (Blocks.SuccessBlock , SuccessParams);
5241
+ preparePlaceholdersAndUnwraps (HandlerDesc, SuccessParams, ErrParam,
5242
+ /* Success=*/ true );
5243
+
5233
5244
addAwaitCall (CE, ArgList.ref (), Blocks.SuccessBlock , SuccessParams,
5234
5245
HandlerDesc, /* AddDeclarations=*/ true );
5235
-
5236
- prepareNamesForBody (HandlerDesc, SuccessParams, ErrParams);
5237
5246
convertNodes (Blocks.SuccessBlock .nodes ());
5247
+ clearNames (SuccessParams);
5238
5248
5239
5249
if (RequireDo) {
5240
- clearParams (SuccessParams);
5241
5250
// Always use the ErrParam name if none is bound
5242
- setNames (Blocks.ErrorBlock , ErrParams,
5243
- HandlerDesc.Type != HandlerType::RESULT);
5244
- addCatch (ErrParam);
5251
+ prepareNames (Blocks.ErrorBlock , llvm::makeArrayRef (ErrParam),
5252
+ HandlerDesc.Type != HandlerType::RESULT);
5253
+ preparePlaceholdersAndUnwraps (HandlerDesc, SuccessParams, ErrParam,
5254
+ /* Success=*/ false );
5245
5255
5246
- prepareNamesForBody (HandlerDesc, ErrParams, SuccessParams);
5247
- addCatchBody (ErrParam, Blocks.ErrorBlock );
5256
+ addCatch (ErrParam);
5257
+ convertNodes (Blocks.ErrorBlock .nodes ());
5258
+ OS << " \n " << tok::r_brace;
5259
+ clearNames (llvm::makeArrayRef (ErrParam));
5248
5260
}
5249
-
5250
- clearParams (CallbackParams->getArray ());
5251
5261
}
5252
5262
5253
5263
void addAwaitCall (const CallExpr *CE, ArrayRef<Expr *> Args,
@@ -5318,44 +5328,56 @@ class AsyncConverter : private SourceEntityWalker {
5318
5328
OS << tok::l_brace;
5319
5329
}
5320
5330
5321
- void addCatchBody (const ParamDecl *ErrParam,
5322
- const ClassifiedBlock &ErrorBlock) {
5323
- convertNodes (ErrorBlock.nodes ());
5324
- OS << " \n " << tok::r_brace;
5325
- }
5326
-
5327
- void prepareNamesForBody (const AsyncHandlerDesc &HandlerDesc,
5328
- ArrayRef<const ParamDecl *> CurrentParams,
5329
- ArrayRef<const ParamDecl *> OtherParams) {
5331
+ void preparePlaceholdersAndUnwraps (AsyncHandlerDesc HandlerDesc,
5332
+ ArrayRef<const ParamDecl *> SuccessParams,
5333
+ const ParamDecl *ErrParam, bool Success) {
5330
5334
switch (HandlerDesc.Type ) {
5331
5335
case HandlerType::PARAMS:
5332
- for (auto *Param : CurrentParams) {
5333
- auto Ty = Param->getType ();
5334
- if (Ty->getOptionalObjectType ()) {
5335
- Unwraps.insert (Param);
5336
- Placeholders.insert (Param);
5336
+ if (!Success) {
5337
+ if (ErrParam) {
5338
+ if (HandlerDesc.shouldUnwrap (ErrParam->getType ())) {
5339
+ Placeholders.insert (ErrParam);
5340
+ Unwraps.insert (ErrParam);
5341
+ }
5342
+ // Can't use success params in the error body
5343
+ Placeholders.insert (SuccessParams.begin (), SuccessParams.end ());
5344
+ }
5345
+ } else {
5346
+ for (auto *SuccessParam : SuccessParams) {
5347
+ auto Ty = SuccessParam->getType ();
5348
+ if (HandlerDesc.shouldUnwrap (Ty)) {
5349
+ // Either unwrap or replace with a placeholder if there's some other
5350
+ // reference
5351
+ Unwraps.insert (SuccessParam);
5352
+ Placeholders.insert (SuccessParam);
5353
+ }
5354
+
5355
+ // Void parameters get omitted where possible, so turn any reference
5356
+ // into a placeholder, as its usage is unlikely what the user wants.
5357
+ if (HandlerDesc.getSuccessParamAsyncReturnType (Ty)->isVoid ())
5358
+ Placeholders.insert (SuccessParam);
5337
5359
}
5338
- // Void parameters get omitted where possible, so turn any reference
5339
- // into a placeholder, as its usage is unlikely what the user wants.
5340
- if (HandlerDesc.getSuccessParamAsyncReturnType (Ty)->isVoid ())
5341
- Placeholders.insert (Param);
5360
+ // Can't use the error param in the success body
5361
+ if (ErrParam)
5362
+ Placeholders.insert (ErrParam);
5342
5363
}
5343
- // Use of the other params is invalid within the current body
5344
- Placeholders.insert (OtherParams.begin (), OtherParams.end ());
5345
5364
break ;
5346
5365
case HandlerType::RESULT:
5347
- // Any uses of the result parameter in the current body (that
5348
- // isn't replaced) are invalid, so replace them with a placeholder
5349
- Placeholders.insert (CurrentParams.begin (), CurrentParams.end ());
5366
+ // Any uses of the result parameter in the current body (that aren't
5367
+ // replaced) are invalid, so replace them with a placeholder.
5368
+ assert (SuccessParams.size () == 1 && SuccessParams[0 ] == ErrParam);
5369
+ Placeholders.insert (ErrParam);
5350
5370
break ;
5351
5371
default :
5352
5372
llvm_unreachable (" Unhandled handler type" );
5353
5373
}
5354
5374
}
5355
5375
5356
- // TODO: Check for clashes with existing names
5357
- void setNames (const ClassifiedBlock &Block,
5358
- ArrayRef<const ParamDecl *> Params, bool AddIfMissing = true ) {
5376
+ // TODO: Check for clashes with existing names and add all decls, not just
5377
+ // params
5378
+ void prepareNames (const ClassifiedBlock &Block,
5379
+ ArrayRef<const ParamDecl *> Params,
5380
+ bool AddIfMissing = true ) {
5359
5381
for (auto *Param : Params) {
5360
5382
StringRef Name = Block.boundName (Param);
5361
5383
if (!Name.empty ()) {
@@ -5384,7 +5406,7 @@ class AsyncConverter : private SourceEntityWalker {
5384
5406
return StringRef (Res->second );
5385
5407
}
5386
5408
5387
- void clearParams (ArrayRef<const ParamDecl *> Params) {
5409
+ void clearNames (ArrayRef<const ParamDecl *> Params) {
5388
5410
for (auto *Param : Params) {
5389
5411
Unwraps.erase (Param);
5390
5412
Placeholders.erase (Param);
0 commit comments