@@ -2926,7 +2926,8 @@ static Expr *findStorageReferenceExprForBorrow(Expr *e) {
2926
2926
return nullptr ;
2927
2927
}
2928
2928
2929
- Expr *ArgumentSource::findStorageReferenceExprForMoveOnlyBorrow () && {
2929
+ Expr *ArgumentSource::findStorageReferenceExprForMoveOnlyBorrow (
2930
+ SILGenFunction &SGF) && {
2930
2931
if (!isExpr ())
2931
2932
return nullptr ;
2932
2933
@@ -2935,10 +2936,32 @@ Expr *ArgumentSource::findStorageReferenceExprForMoveOnlyBorrow() && {
2935
2936
if (!li)
2936
2937
return nullptr ;
2937
2938
2938
- auto lvExpr = ::findStorageReferenceExprForBorrow (li->getSubExpr ());
2939
+ auto * lvExpr = ::findStorageReferenceExprForBorrow (li->getSubExpr ());
2939
2940
2940
- // Claim the value of this argument if we found a storage reference.
2941
+ // Claim the value of this argument if we found a storage reference that has a
2942
+ // move only base.
2941
2943
if (lvExpr) {
2944
+ // We want to perform a borrow if our initial type is a pure move only /or/
2945
+ // if after looking through multiple copyable member ref expr, we get to a
2946
+ // move only member ref expr or a move only decl ref expr.
2947
+ //
2948
+ // NOTE: We purposely do not look through load implying that if we have
2949
+ // copyable types extracted from a move only class, we will not borrow.
2950
+ auto *iterExpr = lvExpr;
2951
+ while (true ) {
2952
+ SILType ty = SGF.getLoweredType (
2953
+ iterExpr->getType ()->getWithoutSpecifierType ()->getCanonicalType ());
2954
+ if (ty.isPureMoveOnly ())
2955
+ break ;
2956
+
2957
+ if (auto *mre = dyn_cast<MemberRefExpr>(iterExpr)) {
2958
+ iterExpr = mre->getBase ();
2959
+ continue ;
2960
+ }
2961
+
2962
+ return nullptr ;
2963
+ }
2964
+
2942
2965
(void )std::move (*this ).asKnownExpr ();
2943
2966
}
2944
2967
@@ -3081,7 +3104,11 @@ class ArgEmitter {
3081
3104
return ;
3082
3105
}
3083
3106
3084
- if (loweredSubstArgType.isPureMoveOnly () && param.isGuaranteed ()) {
3107
+ // If we have a guaranteed paramter, see if we have a move only type and can
3108
+ // emit it borrow.
3109
+ //
3110
+ // We check for move only in tryEmitBorrowedMoveOnly.
3111
+ if (param.isGuaranteed ()) {
3085
3112
if (tryEmitBorrowedMoveOnly (std::move (arg), loweredSubstArgType,
3086
3113
loweredSubstParamType, origParamType,
3087
3114
paramSlice))
@@ -3264,13 +3291,14 @@ class ArgEmitter {
3264
3291
ClaimedParamsRef paramsSlice) {
3265
3292
assert (paramsSlice.size () == 1 );
3266
3293
3267
- // Try to find an expression we can emit as an l-value.
3268
- auto lvExpr = std::move (arg).findStorageReferenceExprForMoveOnlyBorrow ();
3294
+ // Try to find an expression we can emit as a borrowed l-value.
3295
+ auto lvExpr = std::move (arg).findStorageReferenceExprForMoveOnlyBorrow (SGF );
3269
3296
if (!lvExpr)
3270
3297
return false ;
3271
3298
3272
3299
emitBorrowed (lvExpr, loweredSubstArgType, loweredSubstParamType,
3273
3300
origParamType, paramsSlice);
3301
+
3274
3302
return true ;
3275
3303
}
3276
3304
0 commit comments