@@ -4971,6 +4971,11 @@ class ClassifiedBlock {
4971
4971
}
4972
4972
};
4973
4973
4974
+ // / The type of block rewritten code may be placed in.
4975
+ enum class BlockKind {
4976
+ SUCCESS, ERROR, FALLBACK
4977
+ };
4978
+
4974
4979
// / A completion handler function parameter that is known to be a Bool flag
4975
4980
// / indicating success or failure.
4976
4981
struct KnownBoolFlagParam {
@@ -4992,7 +4997,7 @@ class ClosureCallbackParams final {
4992
4997
: HandlerDesc(HandlerDesc),
4993
4998
AllParams (Closure->getParameters ()->getArray()) {
4994
4999
assert (AllParams.size () == HandlerDesc.params ().size ());
4995
- assert (!( HandlerDesc.Type == HandlerType::RESULT && AllParams.size () != 1 ) );
5000
+ assert (HandlerDesc.Type != HandlerType::RESULT || AllParams.size () == 1 );
4996
5001
4997
5002
SuccessParams.insert (AllParams.begin (), AllParams.end ());
4998
5003
if (HandlerDesc.HasError && HandlerDesc.Type == HandlerType::PARAMS)
@@ -5031,29 +5036,41 @@ class ClosureCallbackParams final {
5031
5036
return HandlerDesc.shouldUnwrap (Param->getType ());
5032
5037
}
5033
5038
5039
+ // / Whether \p Param is the known Bool parameter that indicates success or
5040
+ // / failure.
5041
+ bool isKnownBoolFlagParam (const ParamDecl *Param) const {
5042
+ if (auto BoolFlag = getKnownBoolFlagParam ())
5043
+ return BoolFlag->Param == Param;
5044
+ return false ;
5045
+ }
5046
+
5034
5047
// / Whether \p Param is a closure parameter that has a binding available in
5035
- // / the async variant of the call, either as a thrown error, or a success
5036
- // / return value.
5037
- bool hasBinding (const ParamDecl *Param) const {
5038
- if (!hasParam (Param))
5039
- return false ;
5040
- if (auto BoolFlag = getKnownBoolFlagParam ()) {
5041
- if (Param == BoolFlag->Param )
5048
+ // / the async variant of the call for a particular \p Block.
5049
+ bool hasBinding (const ParamDecl *Param, BlockKind Block) const {
5050
+ switch (Block) {
5051
+ case BlockKind::SUCCESS:
5052
+ // Known bool flags get dropped from the imported async variant.
5053
+ if (isKnownBoolFlagParam (Param))
5042
5054
return false ;
5055
+
5056
+ return isSuccessParam (Param);
5057
+ case BlockKind::ERROR:
5058
+ return Param == ErrParam;
5059
+ case BlockKind::FALLBACK:
5060
+ // We generally want to bind everything in the fallback case.
5061
+ return hasParam (Param);
5043
5062
}
5044
- return true ;
5063
+ llvm_unreachable ( " Unhandled case in switch " ) ;
5045
5064
}
5046
5065
5047
- // / Retrieve the success parameters that have a binding in a call to the
5048
- // / async variant.
5049
- ArrayRef<const ParamDecl *>
5050
- getSuccessParamsToBind (SmallVectorImpl<const ParamDecl *> &Scratch) {
5051
- assert (Scratch.empty ());
5052
- for (auto *Param : SuccessParams) {
5053
- if (hasBinding (Param))
5054
- Scratch.push_back (Param);
5066
+ // / Retrieve the parameters to bind in a given \p Block.
5067
+ TinyPtrVector<const ParamDecl *> getParamsToBind (BlockKind Block) {
5068
+ TinyPtrVector<const ParamDecl *> Result;
5069
+ for (auto *Param : AllParams) {
5070
+ if (hasBinding (Param, Block))
5071
+ Result.push_back (Param);
5055
5072
}
5056
- return Scratch ;
5073
+ return Result ;
5057
5074
}
5058
5075
5059
5076
// / If there is a known Bool flag parameter indicating success or failure,
@@ -5303,7 +5320,7 @@ struct CallbackClassifier {
5303
5320
// Check to see if we have a known bool flag parameter that indicates
5304
5321
// success or failure.
5305
5322
if (auto KnownBoolFlag = Params.getKnownBoolFlagParam ()) {
5306
- if (KnownBoolFlag->Param != Cond. Subject )
5323
+ if (KnownBoolFlag->Param != SubjectParam )
5307
5324
return None;
5308
5325
5309
5326
// The path may need to be flipped depending on whether the flag indicates
@@ -6785,10 +6802,21 @@ class AsyncConverter : private SourceEntityWalker {
6785
6802
}
6786
6803
6787
6804
void addFallbackVars (ArrayRef<const ParamDecl *> FallbackParams,
6788
- ClassifiedBlocks &Blocks) {
6789
- for (auto Param : FallbackParams) {
6790
- OS << tok::kw_var << " " << newNameFor (Param) << " : " ;
6805
+ const ClosureCallbackParams &AllParams) {
6806
+ for (auto *Param : FallbackParams) {
6791
6807
auto Ty = Param->getType ();
6808
+ auto ParamName = newNameFor (Param);
6809
+
6810
+ // If this is the known bool success param, we can use 'let' and type it
6811
+ // as non-optional, as it gets bound in both blocks.
6812
+ if (AllParams.isKnownBoolFlagParam (Param)) {
6813
+ OS << tok::kw_let << " " << ParamName << " : " ;
6814
+ Ty->print (OS);
6815
+ OS << " \n " ;
6816
+ continue ;
6817
+ }
6818
+
6819
+ OS << tok::kw_var << " " << ParamName << " : " ;
6792
6820
Ty->print (OS);
6793
6821
if (!Ty->getOptionalObjectType ())
6794
6822
OS << " ?" ;
@@ -7207,6 +7235,30 @@ class AsyncConverter : private SourceEntityWalker {
7207
7235
DiagEngine.diagnose (CE->getStartLoc (), diag::missing_callback_arg);
7208
7236
}
7209
7237
7238
+ // / Add a binding to a known bool flag that indicates success or failure.
7239
+ void addBoolFlagParamBindingIfNeeded (Optional<KnownBoolFlagParam> Flag,
7240
+ BlockKind Block) {
7241
+ if (!Flag)
7242
+ return ;
7243
+ // Figure out the polarity of the binding based on the block we're in and
7244
+ // whether the flag indicates success.
7245
+ auto Polarity = true ;
7246
+ switch (Block) {
7247
+ case BlockKind::SUCCESS:
7248
+ break ;
7249
+ case BlockKind::ERROR:
7250
+ Polarity = !Polarity;
7251
+ break ;
7252
+ case BlockKind::FALLBACK:
7253
+ llvm_unreachable (" Not a valid place to bind" );
7254
+ }
7255
+ if (!Flag->IsSuccessFlag )
7256
+ Polarity = !Polarity;
7257
+
7258
+ OS << newNameFor (Flag->Param ) << " " << tok::equal << " " ;
7259
+ OS << (Polarity ? tok::kw_true : tok::kw_false) << " \n " ;
7260
+ }
7261
+
7210
7262
// / Add a call to the async alternative of \p CE and convert the \p Callback
7211
7263
// / to be executed after the async call. \p HandlerDesc describes the
7212
7264
// / completion handler in the function that's called by \p CE and \p ArgList
@@ -7229,8 +7281,7 @@ class AsyncConverter : private SourceEntityWalker {
7229
7281
DiagEngine, CallbackBody);
7230
7282
}
7231
7283
7232
- SmallVector<const ParamDecl *, 4 > Scratch;
7233
- auto SuccessBindings = CallbackParams.getSuccessParamsToBind (Scratch);
7284
+ auto SuccessBindings = CallbackParams.getParamsToBind (BlockKind::SUCCESS);
7234
7285
auto *ErrParam = CallbackParams.getErrParam ();
7235
7286
if (DiagEngine.hadAnyError ()) {
7236
7287
// For now, only fallback when the results are params with an error param,
@@ -7244,18 +7295,21 @@ class AsyncConverter : private SourceEntityWalker {
7244
7295
// assignments to the names in the outer scope.
7245
7296
InlinePatternsToPrint InlinePatterns;
7246
7297
7247
- SmallVector<const ParamDecl *, 4 > AllBindings;
7248
- AllBindings.append (SuccessBindings.begin (), SuccessBindings.end ());
7249
- AllBindings.push_back (ErrParam);
7298
+ auto AllBindings = CallbackParams.getParamsToBind (BlockKind::FALLBACK);
7250
7299
7251
7300
prepareNames (ClassifiedBlock (), AllBindings, InlinePatterns);
7252
7301
preparePlaceholdersAndUnwraps (HandlerDesc, CallbackParams,
7253
- PlaceholderMode ::FALLBACK);
7254
- addFallbackVars (AllBindings, Blocks );
7302
+ BlockKind ::FALLBACK);
7303
+ addFallbackVars (AllBindings, CallbackParams );
7255
7304
addDo ();
7256
7305
addAwaitCall (CE, ArgList.ref (), Blocks.SuccessBlock , SuccessBindings,
7257
7306
InlinePatterns, HandlerDesc, /* AddDeclarations*/ false );
7258
- addFallbackCatch (ErrParam);
7307
+ OS << " \n " ;
7308
+
7309
+ // If we have a known Bool success param, we need to bind it.
7310
+ addBoolFlagParamBindingIfNeeded (CallbackParams.getKnownBoolFlagParam (),
7311
+ BlockKind::SUCCESS);
7312
+ addFallbackCatch (CallbackParams);
7259
7313
OS << " \n " ;
7260
7314
convertNodes (NodesToPrint::inBraceStmt (CallbackBody));
7261
7315
@@ -7305,7 +7359,7 @@ class AsyncConverter : private SourceEntityWalker {
7305
7359
7306
7360
prepareNames (Blocks.SuccessBlock , SuccessBindings, InlinePatterns);
7307
7361
preparePlaceholdersAndUnwraps (HandlerDesc, CallbackParams,
7308
- PlaceholderMode::SUCCESS_BLOCK );
7362
+ BlockKind::SUCCESS );
7309
7363
7310
7364
addAwaitCall (CE, ArgList.ref (), Blocks.SuccessBlock , SuccessBindings,
7311
7365
InlinePatterns, HandlerDesc, /* AddDeclarations=*/ true );
@@ -7322,7 +7376,7 @@ class AsyncConverter : private SourceEntityWalker {
7322
7376
ErrInlinePatterns,
7323
7377
/* AddIfMissing=*/ HandlerDesc.Type != HandlerType::RESULT);
7324
7378
preparePlaceholdersAndUnwraps (HandlerDesc, CallbackParams,
7325
- PlaceholderMode::ERROR_BLOCK );
7379
+ BlockKind::ERROR );
7326
7380
7327
7381
addCatch (ErrOrResultParam);
7328
7382
convertNodes (Blocks.ErrorBlock .nodesToPrint ());
@@ -7590,12 +7644,17 @@ class AsyncConverter : private SourceEntityWalker {
7590
7644
OS << tok::r_paren;
7591
7645
}
7592
7646
7593
- void addFallbackCatch (const ParamDecl *ErrParam) {
7647
+ void addFallbackCatch (const ClosureCallbackParams &Params) {
7648
+ auto *ErrParam = Params.getErrParam ();
7649
+ assert (ErrParam);
7594
7650
auto ErrName = newNameFor (ErrParam);
7595
- OS << " \n "
7596
- << tok::r_brace << " " << tok::kw_catch << " " << tok::l_brace << " \n "
7597
- << ErrName << " = error\n "
7598
- << tok::r_brace;
7651
+ OS << tok::r_brace << " " << tok::kw_catch << " " << tok::l_brace << " \n "
7652
+ << ErrName << " = error\n " ;
7653
+
7654
+ // If we have a known Bool success param, we need to bind it.
7655
+ addBoolFlagParamBindingIfNeeded (Params.getKnownBoolFlagParam (),
7656
+ BlockKind::ERROR);
7657
+ OS << tok::r_brace;
7599
7658
}
7600
7659
7601
7660
void addCatch (const ParamDecl *ErrParam) {
@@ -7607,31 +7666,27 @@ class AsyncConverter : private SourceEntityWalker {
7607
7666
OS << tok::l_brace;
7608
7667
}
7609
7668
7610
- enum class PlaceholderMode {
7611
- SUCCESS_BLOCK, ERROR_BLOCK, FALLBACK
7612
- };
7613
-
7614
7669
void preparePlaceholdersAndUnwraps (AsyncHandlerDesc HandlerDesc,
7615
7670
const ClosureCallbackParams &Params,
7616
- PlaceholderMode Mode ) {
7671
+ BlockKind Block ) {
7617
7672
// Params that have been dropped always need placeholdering.
7618
7673
for (auto *Param : Params.getAllParams ()) {
7619
- if (!Params.hasBinding (Param))
7674
+ if (!Params.hasBinding (Param, Block ))
7620
7675
Placeholders.insert (Param);
7621
7676
}
7622
7677
// For the fallback case, no other params need placeholdering, as they are
7623
7678
// all freely accessible in the fallback case.
7624
- if (Mode == PlaceholderMode ::FALLBACK)
7679
+ if (Block == BlockKind ::FALLBACK)
7625
7680
return ;
7626
7681
7627
7682
switch (HandlerDesc.Type ) {
7628
7683
case HandlerType::PARAMS: {
7629
7684
auto *ErrParam = Params.getErrParam ();
7630
7685
auto SuccessParams = Params.getSuccessParams ();
7631
- switch (Mode ) {
7632
- case PlaceholderMode ::FALLBACK:
7686
+ switch (Block ) {
7687
+ case BlockKind ::FALLBACK:
7633
7688
llvm_unreachable (" Already handled" );
7634
- case PlaceholderMode::ERROR_BLOCK :
7689
+ case BlockKind::ERROR :
7635
7690
if (ErrParam) {
7636
7691
if (HandlerDesc.shouldUnwrap (ErrParam->getType ())) {
7637
7692
Placeholders.insert (ErrParam);
@@ -7641,7 +7696,7 @@ class AsyncConverter : private SourceEntityWalker {
7641
7696
Placeholders.insert (SuccessParams.begin (), SuccessParams.end ());
7642
7697
}
7643
7698
break ;
7644
- case PlaceholderMode::SUCCESS_BLOCK :
7699
+ case BlockKind::SUCCESS :
7645
7700
for (auto *SuccessParam : SuccessParams) {
7646
7701
auto Ty = SuccessParam->getType ();
7647
7702
if (HandlerDesc.shouldUnwrap (Ty)) {
0 commit comments