@@ -1338,7 +1338,8 @@ static SGFAccessKind getBaseAccessKind(SILGenModule &SGM,
13381338 AbstractStorageDecl *member,
13391339 SGFAccessKind accessKind,
13401340 AccessStrategy strategy,
1341- CanType baseFormalType);
1341+ CanType baseFormalType,
1342+ bool forBorrowExpr);
13421343
13431344namespace {
13441345 // / A helper class for implementing components that involve accessing
@@ -1971,7 +1972,8 @@ namespace {
19711972 if (!base) return LValue ();
19721973 auto baseAccessKind =
19731974 getBaseAccessKind (SGF.SGM , Storage, accessKind, strategy,
1974- BaseFormalType);
1975+ BaseFormalType,
1976+ /* for borrow*/ false );
19751977 return LValue::forValue (baseAccessKind, base, BaseFormalType);
19761978 }();
19771979
@@ -3049,7 +3051,8 @@ class LLVM_LIBRARY_VISIBILITY SILGenBorrowedBaseVisitor
30493051 auto baseFormalType = getBaseFormalType (e->getBase ());
30503052 LValue lv = visit (
30513053 e->getBase (),
3052- getBaseAccessKind (SGF.SGM , var, accessKind, strategy, baseFormalType),
3054+ getBaseAccessKind (SGF.SGM , var, accessKind, strategy, baseFormalType,
3055+ /* for borrow*/ true ),
30533056 getBaseOptions (options, strategy));
30543057 std::optional<ActorIsolation> actorIso;
30553058 if (e->isImplicitlyAsync ())
@@ -3717,14 +3720,50 @@ LValue SILGenLValue::visitDotSyntaxBaseIgnoredExpr(DotSyntaxBaseIgnoredExpr *e,
37173720 return visitRec (e->getRHS (), accessKind, options);
37183721}
37193722
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+
37203758static SGFAccessKind getBaseAccessKindForAccessor (SILGenModule &SGM,
37213759 AccessorDecl *accessor,
3722- CanType baseFormalType) {
3760+ CanType baseFormalType,
3761+ bool forBorrowExpr) {
37233762 if (accessor->isMutating ())
37243763 return SGFAccessKind::ReadWrite;
37253764
37263765 auto declRef = SGM.getAccessorDeclRef (accessor, ResilienceExpansion::Minimal);
3727- if (SGM. shouldEmitSelfAsRValue (accessor, baseFormalType)) {
3766+ if (shouldEmitSelfAsRValue (accessor, baseFormalType, forBorrowExpr )) {
37283767 return SGM.isNonMutatingSelfIndirect (declRef)
37293768 ? SGFAccessKind::OwnedAddressRead
37303769 : SGFAccessKind::OwnedObjectRead;
@@ -3748,7 +3787,8 @@ static SGFAccessKind getBaseAccessKind(SILGenModule &SGM,
37483787 AbstractStorageDecl *member,
37493788 SGFAccessKind accessKind,
37503789 AccessStrategy strategy,
3751- CanType baseFormalType) {
3790+ CanType baseFormalType,
3791+ bool forBorrowExpr) {
37523792 switch (strategy.getKind ()) {
37533793 case AccessStrategy::Storage:
37543794 return getBaseAccessKindForStorage (accessKind);
@@ -3757,7 +3797,8 @@ static SGFAccessKind getBaseAccessKind(SILGenModule &SGM,
37573797 assert (accessKind == SGFAccessKind::ReadWrite);
37583798 auto writeBaseKind = getBaseAccessKind (SGM, member, SGFAccessKind::Write,
37593799 strategy.getWriteStrategy (),
3760- baseFormalType);
3800+ baseFormalType,
3801+ /* for borrow*/ false );
37613802
37623803 // Fast path for the common case that the write will need to mutate
37633804 // the base.
@@ -3767,7 +3808,8 @@ static SGFAccessKind getBaseAccessKind(SILGenModule &SGM,
37673808 auto readBaseKind = getBaseAccessKind (SGM, member,
37683809 SGFAccessKind::OwnedAddressRead,
37693810 strategy.getReadStrategy (),
3770- baseFormalType);
3811+ baseFormalType,
3812+ /* for borrow*/ false );
37713813
37723814 // If they're the same kind, just use that.
37733815 if (readBaseKind == writeBaseKind)
@@ -3786,7 +3828,8 @@ static SGFAccessKind getBaseAccessKind(SILGenModule &SGM,
37863828 case AccessStrategy::DispatchToAccessor:
37873829 case AccessStrategy::DispatchToDistributedThunk: {
37883830 auto accessor = member->getOpaqueAccessor (strategy.getAccessor ());
3789- return getBaseAccessKindForAccessor (SGM, accessor, baseFormalType);
3831+ return getBaseAccessKindForAccessor (SGM, accessor, baseFormalType,
3832+ forBorrowExpr);
37903833 }
37913834 }
37923835 llvm_unreachable (" bad access strategy" );
@@ -3863,7 +3906,8 @@ LValue SILGenLValue::visitMemberRefExpr(MemberRefExpr *e,
38633906
38643907 LValue lv = visitRec (e->getBase (),
38653908 getBaseAccessKind (SGF.SGM , var, accessKind, strategy,
3866- getBaseFormalType (e->getBase ())),
3909+ getBaseFormalType (e->getBase ()),
3910+ /* for borrow */ false ),
38673911 getBaseOptions (options, strategy));
38683912 assert (lv.isValid ());
38693913
@@ -4069,7 +4113,8 @@ LValue SILGenLValue::visitSubscriptExpr(SubscriptExpr *e,
40694113
40704114 LValue lv = visitRec (e->getBase (),
40714115 getBaseAccessKind (SGF.SGM , decl, accessKind, strategy,
4072- getBaseFormalType (e->getBase ())),
4116+ getBaseFormalType (e->getBase ()),
4117+ /* for borrow*/ false ),
40734118 getBaseOptions (options, strategy));
40744119 assert (lv.isValid ());
40754120
@@ -4426,7 +4471,8 @@ LValue SILGenFunction::emitPropertyLValue(SILLocation loc, ManagedValue base,
44264471 F.getResilienceExpansion ());
44274472
44284473 auto baseAccessKind =
4429- getBaseAccessKind (SGM, ivar, accessKind, strategy, baseFormalType);
4474+ getBaseAccessKind (SGM, ivar, accessKind, strategy, baseFormalType,
4475+ /* for borrow*/ false );
44304476
44314477 LValueTypeData baseTypeData =
44324478 getValueTypeData (baseAccessKind, baseFormalType, base.getValue ());
@@ -5149,7 +5195,8 @@ RValue SILGenFunction::emitRValueForStorageLoad(
51495195 if (!base) return LValue ();
51505196
51515197 auto baseAccess = getBaseAccessKind (SGM, storage, accessKind,
5152- strategy, baseFormalType);
5198+ strategy, baseFormalType,
5199+ /* for borrow*/ false );
51535200 return LValue::forValue (baseAccess, base, baseFormalType);
51545201 }();
51555202
0 commit comments