@@ -1338,7 +1338,8 @@ static SGFAccessKind getBaseAccessKind(SILGenModule &SGM,
1338
1338
AbstractStorageDecl *member,
1339
1339
SGFAccessKind accessKind,
1340
1340
AccessStrategy strategy,
1341
- CanType baseFormalType);
1341
+ CanType baseFormalType,
1342
+ bool forBorrowExpr);
1342
1343
1343
1344
namespace {
1344
1345
// / A helper class for implementing components that involve accessing
@@ -1971,7 +1972,8 @@ namespace {
1971
1972
if (!base) return LValue ();
1972
1973
auto baseAccessKind =
1973
1974
getBaseAccessKind (SGF.SGM , Storage, accessKind, strategy,
1974
- BaseFormalType);
1975
+ BaseFormalType,
1976
+ /* for borrow*/ false );
1975
1977
return LValue::forValue (baseAccessKind, base, BaseFormalType);
1976
1978
}();
1977
1979
@@ -3049,7 +3051,8 @@ class LLVM_LIBRARY_VISIBILITY SILGenBorrowedBaseVisitor
3049
3051
auto baseFormalType = getBaseFormalType (e->getBase ());
3050
3052
LValue lv = visit (
3051
3053
e->getBase (),
3052
- getBaseAccessKind (SGF.SGM , var, accessKind, strategy, baseFormalType),
3054
+ getBaseAccessKind (SGF.SGM , var, accessKind, strategy, baseFormalType,
3055
+ /* for borrow*/ true ),
3053
3056
getBaseOptions (options, strategy));
3054
3057
std::optional<ActorIsolation> actorIso;
3055
3058
if (e->isImplicitlyAsync ())
@@ -3717,14 +3720,50 @@ LValue SILGenLValue::visitDotSyntaxBaseIgnoredExpr(DotSyntaxBaseIgnoredExpr *e,
3717
3720
return visitRec (e->getRHS (), accessKind, options);
3718
3721
}
3719
3722
3723
+ // / Should the self argument of the given method always be emitted as
3724
+ // / an r-value (meaning that it can be borrowed only if that is not
3725
+ // / semantically detectable), or it acceptable to emit it as a borrowed
3726
+ // / storage reference?
3727
+ static bool shouldEmitSelfAsRValue (AccessorDecl *fn, CanType selfType,
3728
+ bool forBorrowExpr) {
3729
+ if (fn->isStatic ())
3730
+ return true ;
3731
+
3732
+ switch (fn->getSelfAccessKind ()) {
3733
+ case SelfAccessKind::Mutating:
3734
+ return false ;
3735
+ case SelfAccessKind::Borrowing:
3736
+ case SelfAccessKind::NonMutating:
3737
+ // If the accessor is a coroutine, we may want to access the projected
3738
+ // value through a borrow of the base. But if it's a regular get/set then
3739
+ // there isn't any real benefit to doing so.
3740
+ if (!fn->isCoroutine ()) {
3741
+ return true ;
3742
+ }
3743
+ // Normally we'll copy the base to minimize accesses. But if the base
3744
+ // is noncopyable, or we're accessing it in a `borrow` expression, then
3745
+ // we want to keep the access nested on the original base.
3746
+ if (forBorrowExpr || selfType->isNoncopyable ()) {
3747
+ return false ;
3748
+ }
3749
+ return true ;
3750
+
3751
+ case SelfAccessKind::LegacyConsuming:
3752
+ case SelfAccessKind::Consuming:
3753
+ return true ;
3754
+ }
3755
+ llvm_unreachable (" bad self-access kind" );
3756
+ }
3757
+
3720
3758
static SGFAccessKind getBaseAccessKindForAccessor (SILGenModule &SGM,
3721
3759
AccessorDecl *accessor,
3722
- CanType baseFormalType) {
3760
+ CanType baseFormalType,
3761
+ bool forBorrowExpr) {
3723
3762
if (accessor->isMutating ())
3724
3763
return SGFAccessKind::ReadWrite;
3725
3764
3726
3765
auto declRef = SGM.getAccessorDeclRef (accessor, ResilienceExpansion::Minimal);
3727
- if (SGM. shouldEmitSelfAsRValue (accessor, baseFormalType)) {
3766
+ if (shouldEmitSelfAsRValue (accessor, baseFormalType, forBorrowExpr )) {
3728
3767
return SGM.isNonMutatingSelfIndirect (declRef)
3729
3768
? SGFAccessKind::OwnedAddressRead
3730
3769
: SGFAccessKind::OwnedObjectRead;
@@ -3748,7 +3787,8 @@ static SGFAccessKind getBaseAccessKind(SILGenModule &SGM,
3748
3787
AbstractStorageDecl *member,
3749
3788
SGFAccessKind accessKind,
3750
3789
AccessStrategy strategy,
3751
- CanType baseFormalType) {
3790
+ CanType baseFormalType,
3791
+ bool forBorrowExpr) {
3752
3792
switch (strategy.getKind ()) {
3753
3793
case AccessStrategy::Storage:
3754
3794
return getBaseAccessKindForStorage (accessKind);
@@ -3757,7 +3797,8 @@ static SGFAccessKind getBaseAccessKind(SILGenModule &SGM,
3757
3797
assert (accessKind == SGFAccessKind::ReadWrite);
3758
3798
auto writeBaseKind = getBaseAccessKind (SGM, member, SGFAccessKind::Write,
3759
3799
strategy.getWriteStrategy (),
3760
- baseFormalType);
3800
+ baseFormalType,
3801
+ /* for borrow*/ false );
3761
3802
3762
3803
// Fast path for the common case that the write will need to mutate
3763
3804
// the base.
@@ -3767,7 +3808,8 @@ static SGFAccessKind getBaseAccessKind(SILGenModule &SGM,
3767
3808
auto readBaseKind = getBaseAccessKind (SGM, member,
3768
3809
SGFAccessKind::OwnedAddressRead,
3769
3810
strategy.getReadStrategy (),
3770
- baseFormalType);
3811
+ baseFormalType,
3812
+ /* for borrow*/ false );
3771
3813
3772
3814
// If they're the same kind, just use that.
3773
3815
if (readBaseKind == writeBaseKind)
@@ -3786,7 +3828,8 @@ static SGFAccessKind getBaseAccessKind(SILGenModule &SGM,
3786
3828
case AccessStrategy::DispatchToAccessor:
3787
3829
case AccessStrategy::DispatchToDistributedThunk: {
3788
3830
auto accessor = member->getOpaqueAccessor (strategy.getAccessor ());
3789
- return getBaseAccessKindForAccessor (SGM, accessor, baseFormalType);
3831
+ return getBaseAccessKindForAccessor (SGM, accessor, baseFormalType,
3832
+ forBorrowExpr);
3790
3833
}
3791
3834
}
3792
3835
llvm_unreachable (" bad access strategy" );
@@ -3863,7 +3906,8 @@ LValue SILGenLValue::visitMemberRefExpr(MemberRefExpr *e,
3863
3906
3864
3907
LValue lv = visitRec (e->getBase (),
3865
3908
getBaseAccessKind (SGF.SGM , var, accessKind, strategy,
3866
- getBaseFormalType (e->getBase ())),
3909
+ getBaseFormalType (e->getBase ()),
3910
+ /* for borrow */ false ),
3867
3911
getBaseOptions (options, strategy));
3868
3912
assert (lv.isValid ());
3869
3913
@@ -4069,7 +4113,8 @@ LValue SILGenLValue::visitSubscriptExpr(SubscriptExpr *e,
4069
4113
4070
4114
LValue lv = visitRec (e->getBase (),
4071
4115
getBaseAccessKind (SGF.SGM , decl, accessKind, strategy,
4072
- getBaseFormalType (e->getBase ())),
4116
+ getBaseFormalType (e->getBase ()),
4117
+ /* for borrow*/ false ),
4073
4118
getBaseOptions (options, strategy));
4074
4119
assert (lv.isValid ());
4075
4120
@@ -4426,7 +4471,8 @@ LValue SILGenFunction::emitPropertyLValue(SILLocation loc, ManagedValue base,
4426
4471
F.getResilienceExpansion ());
4427
4472
4428
4473
auto baseAccessKind =
4429
- getBaseAccessKind (SGM, ivar, accessKind, strategy, baseFormalType);
4474
+ getBaseAccessKind (SGM, ivar, accessKind, strategy, baseFormalType,
4475
+ /* for borrow*/ false );
4430
4476
4431
4477
LValueTypeData baseTypeData =
4432
4478
getValueTypeData (baseAccessKind, baseFormalType, base.getValue ());
@@ -5149,7 +5195,8 @@ RValue SILGenFunction::emitRValueForStorageLoad(
5149
5195
if (!base) return LValue ();
5150
5196
5151
5197
auto baseAccess = getBaseAccessKind (SGM, storage, accessKind,
5152
- strategy, baseFormalType);
5198
+ strategy, baseFormalType,
5199
+ /* for borrow*/ false );
5153
5200
return LValue::forValue (baseAccess, base, baseFormalType);
5154
5201
}();
5155
5202
0 commit comments