@@ -355,8 +355,13 @@ IsSetterMutatingRequest::evaluate(Evaluator &evaluator,
355
355
// or not based on the composition of the wrappers.
356
356
if (auto var = dyn_cast<VarDecl>(storage)) {
357
357
if (auto mut = var->getPropertyWrapperMutability ()) {
358
- return mut->Setter == PropertyWrapperMutability::Mutating
359
- && result;
358
+ bool isMutating = mut->Setter == PropertyWrapperMutability::Mutating;
359
+ if (var->getParsedAccessor (AccessorKind::DidSet)) {
360
+ // If there's a didSet, we call the getter for the 'oldValue', and so
361
+ // should consider the getter's mutatingness as well
362
+ isMutating |= (mut->Getter == PropertyWrapperMutability::Mutating);
363
+ }
364
+ return isMutating && result;
360
365
}
361
366
}
362
367
@@ -601,14 +606,18 @@ getEnclosingSelfPropertyWrapperAccess(VarDecl *property, bool forProjected) {
601
606
return result;
602
607
}
603
608
604
- // / Build an l-value for the storage of a declaration. Returns nullptr if there
609
+ // / Build a reference to the storage of a declaration. Returns nullptr if there
605
610
// / was an error. This should only occur if an invalid declaration was type
606
611
// / checked; another diagnostic should have been emitted already.
612
+
607
613
static Expr *buildStorageReference (AccessorDecl *accessor,
608
614
AbstractStorageDecl *storage,
609
615
TargetImpl target,
610
- bool isLValue,
616
+ bool isUsedForGetAccess,
617
+ bool isUsedForSetAccess,
611
618
ASTContext &ctx) {
619
+ // Whether the last component of the expression should be an l-value
620
+ bool isLValue = isUsedForSetAccess;
612
621
// Local function to "finish" the expression, creating a member reference
613
622
// to the given sequence of underlying variables.
614
623
Optional<EnclosingSelfPropertyWrapperAccess> enclosingSelfAccess;
@@ -762,38 +771,27 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
762
771
return finish (storageDRE);
763
772
}
764
773
765
- bool isMemberLValue = isLValue;
766
- auto propertyWrapperMutability =
767
- [&](Decl *decl) -> Optional<std::pair<bool , bool >> {
768
- auto var = dyn_cast<VarDecl>(decl);
769
- if (!var)
770
- return None;
771
- auto mut = var->getPropertyWrapperMutability ();
772
- if (!mut)
773
- return None;
774
- return std::make_pair (mut->Getter == PropertyWrapperMutability::Mutating,
775
- mut->Setter == PropertyWrapperMutability::Mutating);
776
- };
774
+ // Build self
777
775
778
- // If we're accessing a property wrapper, determine if the
779
- // intermediate access requires an lvalue.
780
- if (auto mut = propertyWrapperMutability (accessor->getStorage ())) {
781
- isMemberLValue = mut->first ;
782
- if (isLValue)
783
- isMemberLValue |= mut->second ;
776
+ bool isGetterMutating = storage->isGetterMutating ();
777
+ bool isSetterMutating = storage->isSetterMutating ();
778
+ if (target == TargetImpl::Wrapper || target == TargetImpl::WrapperStorage) {
779
+ auto var = cast<VarDecl>(accessor->getStorage ());
780
+ if (auto mutability = var->getPropertyWrapperMutability ()) {
781
+ // We consider the storage's mutability too because the wrapped property
782
+ // might be part of a class, in case of which nothing is mutating.
783
+ isGetterMutating = (mutability->Getter == PropertyWrapperMutability::Mutating)
784
+ ? (storage->isGetterMutating () || storage->isSetterMutating ())
785
+ : storage->isGetterMutating ();
786
+ isSetterMutating = (mutability->Setter == PropertyWrapperMutability::Mutating)
787
+ ? (storage->isGetterMutating () || storage->isSetterMutating ())
788
+ : storage->isGetterMutating ();
789
+ }
784
790
}
785
791
786
- bool isSelfLValue = storage->isGetterMutating ();
787
- if (isMemberLValue)
788
- isSelfLValue |= storage->isSetterMutating ();
789
-
790
- // If we're accessing a property wrapper, determine if
791
- // the self requires an lvalue.
792
- if (auto mut = propertyWrapperMutability (storage)) {
793
- isSelfLValue = mut->first ;
794
- if (isMemberLValue)
795
- isSelfLValue |= mut->second ;
796
- }
792
+ // If the accessor is mutating, then self should be referred as an l-value
793
+ bool isSelfLValue = (isGetterMutating && isUsedForGetAccess) ||
794
+ (isSetterMutating && isUsedForSetAccess);
797
795
798
796
Expr *selfDRE =
799
797
buildSelfReference (selfDecl, selfAccessKind, isSelfLValue,
@@ -806,6 +804,27 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
806
804
selfDRE = new (ctx) DerivedToBaseExpr (selfDRE, selfTypeForAccess);
807
805
}
808
806
807
+ // Build self.member or equivalent
808
+
809
+ bool isMemberLValue = isLValue;
810
+ if (target == TargetImpl::Wrapper || target == TargetImpl::WrapperStorage) {
811
+ // If the outermost property wrapper's getter / setter is mutating,
812
+ // then the reference to the backing storage should be an l-value.
813
+ auto var = cast<VarDecl>(accessor->getStorage ());
814
+ auto varMember = (target == TargetImpl::WrapperStorage)
815
+ ? &PropertyWrapperTypeInfo::projectedValueVar
816
+ : &PropertyWrapperTypeInfo::valueVar;
817
+ auto wrapper = (target == TargetImpl::WrapperStorage)
818
+ ? var->getOriginalWrappedProperty (
819
+ PropertyWrapperSynthesizedPropertyKind::StorageWrapper)
820
+ ->getAttachedPropertyWrapperTypeInfo (0 )
821
+ : var->getAttachedPropertyWrapperTypeInfo (0 );
822
+ bool isWrapperGetterMutating = (wrapper.*varMember)->isGetterMutating ();
823
+ bool isWrapperSetterMutating = (wrapper.*varMember)->isSetterMutating ();
824
+ isMemberLValue = (isWrapperGetterMutating && isUsedForGetAccess) ||
825
+ (isWrapperSetterMutating && isUsedForSetAccess);
826
+ }
827
+
809
828
Expr *lookupExpr;
810
829
ConcreteDeclRef memberRef (storage, subs);
811
830
auto type = storage->getValueInterfaceType ().subst (subs);
@@ -883,6 +902,8 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
883
902
lookupExpr->setType (type);
884
903
}
885
904
905
+ // Build self.member.wrappedValue if applicable
906
+
886
907
return finish (lookupExpr);
887
908
}
888
909
@@ -893,7 +914,9 @@ createPropertyLoadOrCallSuperclassGetter(AccessorDecl *accessor,
893
914
AbstractStorageDecl *storage,
894
915
TargetImpl target,
895
916
ASTContext &ctx) {
896
- return buildStorageReference (accessor, storage, target, /* isLValue=*/ false ,
917
+ return buildStorageReference (accessor, storage, target,
918
+ /* isUsedForGetAccess=*/ true ,
919
+ /* isUsedForSetAccess=*/ false ,
897
920
ctx);
898
921
}
899
922
@@ -1045,7 +1068,9 @@ void createPropertyStoreOrCallSuperclassSetter(AccessorDecl *accessor,
1045
1068
return ;
1046
1069
1047
1070
Expr *dest = buildStorageReference (accessor, storage, target,
1048
- /* isLValue=*/ true , ctx);
1071
+ /* isUsedForGetAccess=*/ false ,
1072
+ /* isUsedForSetAccess=*/ true ,
1073
+ ctx);
1049
1074
1050
1075
// Error recovery.
1051
1076
if (dest == nullptr )
@@ -1495,7 +1520,10 @@ synthesizeObservedSetterBody(AccessorDecl *Set, TargetImpl target,
1495
1520
VarDecl *OldValue = nullptr ;
1496
1521
if (VD->getParsedAccessor (AccessorKind::DidSet)) {
1497
1522
Expr *OldValueExpr
1498
- = buildStorageReference (Set, VD, target, /* isLValue=*/ true , Ctx);
1523
+ = buildStorageReference (Set, VD, target,
1524
+ /* isUsedForGetAccess=*/ true ,
1525
+ /* isUsedForSetAccess=*/ true ,
1526
+ Ctx);
1499
1527
1500
1528
// Error recovery.
1501
1529
if (OldValueExpr == nullptr ) {
@@ -1626,10 +1654,13 @@ synthesizeCoroutineAccessorBody(AccessorDecl *accessor, ASTContext &ctx) {
1626
1654
SourceLoc loc = storage->getLoc ();
1627
1655
SmallVector<ASTNode, 1 > body;
1628
1656
1629
- bool isLValue = accessor->getAccessorKind () == AccessorKind::Modify;
1657
+ bool isModify = accessor->getAccessorKind () == AccessorKind::Modify;
1630
1658
1631
1659
// Build a reference to the storage.
1632
- Expr *ref = buildStorageReference (accessor, storage, target, isLValue, ctx);
1660
+ Expr *ref = buildStorageReference (accessor, storage, target,
1661
+ /* isUsedForGetAccess=*/ true ,
1662
+ /* isUsedForSetAccess=*/ isModify,
1663
+ ctx);
1633
1664
if (ref != nullptr ) {
1634
1665
// Wrap it with an `&` marker if this is a modify.
1635
1666
ref = maybeWrapInOutExpr (ref, ctx);
0 commit comments