@@ -4916,6 +4916,11 @@ class ClassifiedBlock {
4916
4916
}
4917
4917
};
4918
4918
4919
+ // / The type of block rewritten code may be placed in.
4920
+ enum class BlockKind {
4921
+ SUCCESS, ERROR, FALLBACK
4922
+ };
4923
+
4919
4924
// / A completion handler function parameter that is known to be a Bool flag
4920
4925
// / indicating success or failure.
4921
4926
struct KnownBoolFlagParam {
@@ -4937,7 +4942,7 @@ class ClosureCallbackParams final {
4937
4942
: HandlerDesc(HandlerDesc),
4938
4943
AllParams (Closure->getParameters ()->getArray()) {
4939
4944
assert (AllParams.size () == HandlerDesc.params ().size ());
4940
- assert (!( HandlerDesc.Type == HandlerType::RESULT && AllParams.size () != 1 ) );
4945
+ assert (HandlerDesc.Type != HandlerType::RESULT || AllParams.size () == 1 );
4941
4946
4942
4947
SuccessParams.insert (AllParams.begin (), AllParams.end ());
4943
4948
if (HandlerDesc.HasError && HandlerDesc.Type == HandlerType::PARAMS)
@@ -4976,29 +4981,41 @@ class ClosureCallbackParams final {
4976
4981
return HandlerDesc.shouldUnwrap (Param->getType ());
4977
4982
}
4978
4983
4984
+ // / Whether \p Param is the known Bool parameter that indicates success or
4985
+ // / failure.
4986
+ bool isKnownBoolFlagParam (const ParamDecl *Param) const {
4987
+ if (auto BoolFlag = getKnownBoolFlagParam ())
4988
+ return BoolFlag->Param == Param;
4989
+ return false ;
4990
+ }
4991
+
4979
4992
// / Whether \p Param is a closure parameter that has a binding available in
4980
- // / the async variant of the call, either as a thrown error, or a success
4981
- // / return value.
4982
- bool hasBinding (const ParamDecl *Param) const {
4983
- if (!hasParam (Param))
4984
- return false ;
4985
- if (auto BoolFlag = getKnownBoolFlagParam ()) {
4986
- if (Param == BoolFlag->Param )
4993
+ // / the async variant of the call for a particular \p Block.
4994
+ bool hasBinding (const ParamDecl *Param, BlockKind Block) const {
4995
+ switch (Block) {
4996
+ case BlockKind::SUCCESS:
4997
+ // Known bool flags get dropped from the imported async variant.
4998
+ if (isKnownBoolFlagParam (Param))
4987
4999
return false ;
5000
+
5001
+ return isSuccessParam (Param);
5002
+ case BlockKind::ERROR:
5003
+ return Param == ErrParam;
5004
+ case BlockKind::FALLBACK:
5005
+ // We generally want to bind everything in the fallback case.
5006
+ return hasParam (Param);
4988
5007
}
4989
- return true ;
5008
+ llvm_unreachable ( " Unhandled case in switch " ) ;
4990
5009
}
4991
5010
4992
- // / Retrieve the success parameters that have a binding in a call to the
4993
- // / async variant.
4994
- ArrayRef<const ParamDecl *>
4995
- getSuccessParamsToBind (SmallVectorImpl<const ParamDecl *> &Scratch) {
4996
- assert (Scratch.empty ());
4997
- for (auto *Param : SuccessParams) {
4998
- if (hasBinding (Param))
4999
- Scratch.push_back (Param);
5011
+ // / Retrieve the parameters to bind in a given \p Block.
5012
+ TinyPtrVector<const ParamDecl *> getParamsToBind (BlockKind Block) {
5013
+ TinyPtrVector<const ParamDecl *> Result;
5014
+ for (auto *Param : AllParams) {
5015
+ if (hasBinding (Param, Block))
5016
+ Result.push_back (Param);
5000
5017
}
5001
- return Scratch ;
5018
+ return Result ;
5002
5019
}
5003
5020
5004
5021
// / If there is a known Bool flag parameter indicating success or failure,
@@ -5248,7 +5265,7 @@ struct CallbackClassifier {
5248
5265
// Check to see if we have a known bool flag parameter that indicates
5249
5266
// success or failure.
5250
5267
if (auto KnownBoolFlag = Params.getKnownBoolFlagParam ()) {
5251
- if (KnownBoolFlag->Param != Cond. Subject )
5268
+ if (KnownBoolFlag->Param != SubjectParam )
5252
5269
return None;
5253
5270
5254
5271
// The path may need to be flipped depending on whether the flag indicates
@@ -6722,10 +6739,21 @@ class AsyncConverter : private SourceEntityWalker {
6722
6739
}
6723
6740
6724
6741
void addFallbackVars (ArrayRef<const ParamDecl *> FallbackParams,
6725
- ClassifiedBlocks &Blocks) {
6726
- for (auto Param : FallbackParams) {
6727
- OS << tok::kw_var << " " << newNameFor (Param) << " : " ;
6742
+ const ClosureCallbackParams &AllParams) {
6743
+ for (auto *Param : FallbackParams) {
6728
6744
auto Ty = Param->getType ();
6745
+ auto ParamName = newNameFor (Param);
6746
+
6747
+ // If this is the known bool success param, we can use 'let' and type it
6748
+ // as non-optional, as it gets bound in both blocks.
6749
+ if (AllParams.isKnownBoolFlagParam (Param)) {
6750
+ OS << tok::kw_let << " " << ParamName << " : " ;
6751
+ Ty->print (OS);
6752
+ OS << " \n " ;
6753
+ continue ;
6754
+ }
6755
+
6756
+ OS << tok::kw_var << " " << ParamName << " : " ;
6729
6757
Ty->print (OS);
6730
6758
if (!Ty->getOptionalObjectType ())
6731
6759
OS << " ?" ;
@@ -7144,6 +7172,30 @@ class AsyncConverter : private SourceEntityWalker {
7144
7172
DiagEngine.diagnose (CE->getStartLoc (), diag::missing_callback_arg);
7145
7173
}
7146
7174
7175
+ // / Add a binding to a known bool flag that indicates success or failure.
7176
+ void addBoolFlagParamBindingIfNeeded (Optional<KnownBoolFlagParam> Flag,
7177
+ BlockKind Block) {
7178
+ if (!Flag)
7179
+ return ;
7180
+ // Figure out the polarity of the binding based on the block we're in and
7181
+ // whether the flag indicates success.
7182
+ auto Polarity = true ;
7183
+ switch (Block) {
7184
+ case BlockKind::SUCCESS:
7185
+ break ;
7186
+ case BlockKind::ERROR:
7187
+ Polarity = !Polarity;
7188
+ break ;
7189
+ case BlockKind::FALLBACK:
7190
+ llvm_unreachable (" Not a valid place to bind" );
7191
+ }
7192
+ if (!Flag->IsSuccessFlag )
7193
+ Polarity = !Polarity;
7194
+
7195
+ OS << newNameFor (Flag->Param ) << " " << tok::equal << " " ;
7196
+ OS << (Polarity ? tok::kw_true : tok::kw_false) << " \n " ;
7197
+ }
7198
+
7147
7199
// / Add a call to the async alternative of \p CE and convert the \p Callback
7148
7200
// / to be executed after the async call. \p HandlerDesc describes the
7149
7201
// / completion handler in the function that's called by \p CE and \p ArgList
@@ -7165,8 +7217,7 @@ class AsyncConverter : private SourceEntityWalker {
7165
7217
DiagEngine, CallbackBody);
7166
7218
}
7167
7219
7168
- SmallVector<const ParamDecl *, 4 > Scratch;
7169
- auto SuccessBindings = CallbackParams.getSuccessParamsToBind (Scratch);
7220
+ auto SuccessBindings = CallbackParams.getParamsToBind (BlockKind::SUCCESS);
7170
7221
auto *ErrParam = CallbackParams.getErrParam ();
7171
7222
if (DiagEngine.hadAnyError ()) {
7172
7223
// For now, only fallback when the results are params with an error param,
@@ -7180,18 +7231,21 @@ class AsyncConverter : private SourceEntityWalker {
7180
7231
// assignments to the names in the outer scope.
7181
7232
InlinePatternsToPrint InlinePatterns;
7182
7233
7183
- SmallVector<const ParamDecl *, 4 > AllBindings;
7184
- AllBindings.append (SuccessBindings.begin (), SuccessBindings.end ());
7185
- AllBindings.push_back (ErrParam);
7234
+ auto AllBindings = CallbackParams.getParamsToBind (BlockKind::FALLBACK);
7186
7235
7187
7236
prepareNames (ClassifiedBlock (), AllBindings, InlinePatterns);
7188
7237
preparePlaceholdersAndUnwraps (HandlerDesc, CallbackParams,
7189
- PlaceholderMode ::FALLBACK);
7190
- addFallbackVars (AllBindings, Blocks );
7238
+ BlockKind ::FALLBACK);
7239
+ addFallbackVars (AllBindings, CallbackParams );
7191
7240
addDo ();
7192
7241
addAwaitCall (CE, Blocks.SuccessBlock , SuccessBindings, InlinePatterns,
7193
7242
HandlerDesc, /* AddDeclarations*/ false );
7194
- addFallbackCatch (ErrParam);
7243
+ OS << " \n " ;
7244
+
7245
+ // If we have a known Bool success param, we need to bind it.
7246
+ addBoolFlagParamBindingIfNeeded (CallbackParams.getKnownBoolFlagParam (),
7247
+ BlockKind::SUCCESS);
7248
+ addFallbackCatch (CallbackParams);
7195
7249
OS << " \n " ;
7196
7250
convertNodes (NodesToPrint::inBraceStmt (CallbackBody));
7197
7251
@@ -7242,7 +7296,7 @@ class AsyncConverter : private SourceEntityWalker {
7242
7296
7243
7297
prepareNames (Blocks.SuccessBlock , SuccessBindings, InlinePatterns);
7244
7298
preparePlaceholdersAndUnwraps (HandlerDesc, CallbackParams,
7245
- PlaceholderMode::SUCCESS_BLOCK );
7299
+ BlockKind::SUCCESS );
7246
7300
7247
7301
addAwaitCall (CE, Blocks.SuccessBlock , SuccessBindings, InlinePatterns,
7248
7302
HandlerDesc, /* AddDeclarations=*/ true );
@@ -7259,7 +7313,7 @@ class AsyncConverter : private SourceEntityWalker {
7259
7313
ErrInlinePatterns,
7260
7314
/* AddIfMissing=*/ HandlerDesc.Type != HandlerType::RESULT);
7261
7315
preparePlaceholdersAndUnwraps (HandlerDesc, CallbackParams,
7262
- PlaceholderMode::ERROR_BLOCK );
7316
+ BlockKind::ERROR );
7263
7317
7264
7318
addCatch (ErrOrResultParam);
7265
7319
convertNodes (Blocks.ErrorBlock .nodesToPrint ());
@@ -7529,12 +7583,17 @@ class AsyncConverter : private SourceEntityWalker {
7529
7583
OS << tok::r_paren;
7530
7584
}
7531
7585
7532
- void addFallbackCatch (const ParamDecl *ErrParam) {
7586
+ void addFallbackCatch (const ClosureCallbackParams &Params) {
7587
+ auto *ErrParam = Params.getErrParam ();
7588
+ assert (ErrParam);
7533
7589
auto ErrName = newNameFor (ErrParam);
7534
- OS << " \n "
7535
- << tok::r_brace << " " << tok::kw_catch << " " << tok::l_brace << " \n "
7536
- << ErrName << " = error\n "
7537
- << tok::r_brace;
7590
+ OS << tok::r_brace << " " << tok::kw_catch << " " << tok::l_brace << " \n "
7591
+ << ErrName << " = error\n " ;
7592
+
7593
+ // If we have a known Bool success param, we need to bind it.
7594
+ addBoolFlagParamBindingIfNeeded (Params.getKnownBoolFlagParam (),
7595
+ BlockKind::ERROR);
7596
+ OS << tok::r_brace;
7538
7597
}
7539
7598
7540
7599
void addCatch (const ParamDecl *ErrParam) {
@@ -7546,31 +7605,27 @@ class AsyncConverter : private SourceEntityWalker {
7546
7605
OS << tok::l_brace;
7547
7606
}
7548
7607
7549
- enum class PlaceholderMode {
7550
- SUCCESS_BLOCK, ERROR_BLOCK, FALLBACK
7551
- };
7552
-
7553
7608
void preparePlaceholdersAndUnwraps (AsyncHandlerDesc HandlerDesc,
7554
7609
const ClosureCallbackParams &Params,
7555
- PlaceholderMode Mode ) {
7610
+ BlockKind Block ) {
7556
7611
// Params that have been dropped always need placeholdering.
7557
7612
for (auto *Param : Params.getAllParams ()) {
7558
- if (!Params.hasBinding (Param))
7613
+ if (!Params.hasBinding (Param, Block ))
7559
7614
Placeholders.insert (Param);
7560
7615
}
7561
7616
// For the fallback case, no other params need placeholdering, as they are
7562
7617
// all freely accessible in the fallback case.
7563
- if (Mode == PlaceholderMode ::FALLBACK)
7618
+ if (Block == BlockKind ::FALLBACK)
7564
7619
return ;
7565
7620
7566
7621
switch (HandlerDesc.Type ) {
7567
7622
case HandlerType::PARAMS: {
7568
7623
auto *ErrParam = Params.getErrParam ();
7569
7624
auto SuccessParams = Params.getSuccessParams ();
7570
- switch (Mode ) {
7571
- case PlaceholderMode ::FALLBACK:
7625
+ switch (Block ) {
7626
+ case BlockKind ::FALLBACK:
7572
7627
llvm_unreachable (" Already handled" );
7573
- case PlaceholderMode::ERROR_BLOCK :
7628
+ case BlockKind::ERROR :
7574
7629
if (ErrParam) {
7575
7630
if (HandlerDesc.shouldUnwrap (ErrParam->getType ())) {
7576
7631
Placeholders.insert (ErrParam);
@@ -7580,7 +7635,7 @@ class AsyncConverter : private SourceEntityWalker {
7580
7635
Placeholders.insert (SuccessParams.begin (), SuccessParams.end ());
7581
7636
}
7582
7637
break ;
7583
- case PlaceholderMode::SUCCESS_BLOCK :
7638
+ case BlockKind::SUCCESS :
7584
7639
for (auto *SuccessParam : SuccessParams) {
7585
7640
auto Ty = SuccessParam->getType ();
7586
7641
if (HandlerDesc.shouldUnwrap (Ty)) {
0 commit comments