@@ -341,8 +341,13 @@ IsSetterMutatingRequest::evaluate(Evaluator &evaluator,
341
341
// or not based on the composition of the wrappers.
342
342
if (auto var = dyn_cast<VarDecl>(storage)) {
343
343
if (auto mut = var->getPropertyWrapperMutability ()) {
344
- return mut->Setter == PropertyWrapperMutability::Mutating
345
- && result;
344
+ bool isMutating = mut->Setter == PropertyWrapperMutability::Mutating;
345
+ if (var->getParsedAccessor (AccessorKind::DidSet)) {
346
+ // If there's a didSet, we call the getter for the 'oldValue', and so
347
+ // should consider the getter's mutatingness as well
348
+ isMutating |= (mut->Getter == PropertyWrapperMutability::Mutating);
349
+ }
350
+ return isMutating && result;
346
351
}
347
352
}
348
353
@@ -587,14 +592,17 @@ getEnclosingSelfPropertyWrapperAccess(VarDecl *property, bool forProjected) {
587
592
return result;
588
593
}
589
594
590
- // / Build an l-value for the storage of a declaration. Returns nullptr if there
595
+ // / Build a reference to the storage of a declaration. Returns nullptr if there
591
596
// / was an error. This should only occur if an invalid declaration was type
592
597
// / checked; another diagnostic should have been emitted already.
593
598
static Expr *buildStorageReference (AccessorDecl *accessor,
594
599
AbstractStorageDecl *storage,
595
600
TargetImpl target,
596
- bool isLValue,
601
+ bool isUsedForGetAccess,
602
+ bool isUsedForSetAccess,
597
603
ASTContext &ctx) {
604
+ // Whether the last component of the expression should be an l-value
605
+ bool isLValue = isUsedForSetAccess;
598
606
// Local function to "finish" the expression, creating a member reference
599
607
// to the given sequence of underlying variables.
600
608
Optional<EnclosingSelfPropertyWrapperAccess> enclosingSelfAccess;
@@ -758,46 +766,61 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
758
766
return finish (storageDRE);
759
767
}
760
768
761
- bool isMemberLValue = isLValue;
762
- auto propertyWrapperMutability =
763
- [&](Decl *decl) -> Optional<std::pair<bool , bool >> {
764
- // If we're not accessing via a property wrapper, we don't need to adjust
765
- // the mutability.
766
- if (target != TargetImpl::Wrapper && target != TargetImpl::WrapperStorage)
767
- return None;
769
+ // Build self
768
770
769
- auto var = dyn_cast<VarDecl>(decl);
770
- if (!var)
771
- return None;
772
- auto mut = var->getPropertyWrapperMutability ();
773
- if (!mut)
774
- return None;
775
- return std::make_pair (mut->Getter == PropertyWrapperMutability::Mutating,
776
- mut->Setter == PropertyWrapperMutability::Mutating);
777
- };
771
+ bool isGetterMutating = storage->isGetterMutating ();
772
+ bool isSetterMutating = storage->isSetterMutating ();
773
+ // If we're not accessing via a property wrapper, we don't need to adjust
774
+ // the mutability.
775
+ if (target == TargetImpl::Wrapper || target == TargetImpl::WrapperStorage) {
776
+ auto var = cast<VarDecl>(accessor->getStorage ());
777
+ if (auto mutability = var->getPropertyWrapperMutability ()) {
778
+ // We consider the storage's mutability too because the wrapped property
779
+ // might be part of a class, in case of which nothing is mutating.
780
+ isGetterMutating = (mutability->Getter == PropertyWrapperMutability::Mutating)
781
+ ? (storage->isGetterMutating () || storage->isSetterMutating ())
782
+ : storage->isGetterMutating ();
783
+ isSetterMutating = (mutability->Setter == PropertyWrapperMutability::Mutating)
784
+ ? (storage->isGetterMutating () || storage->isSetterMutating ())
785
+ : storage->isGetterMutating ();
786
+ }
787
+ }
778
788
779
- // If we're accessing a property wrapper, determine if the
780
- // intermediate access requires an lvalue.
781
- if (auto mut = propertyWrapperMutability (accessor->getStorage ())) {
782
- isMemberLValue = mut->first ;
783
- if (isLValue)
784
- isMemberLValue |= mut->second ;
789
+ // If the accessor is mutating, then self should be referred as an l-value
790
+ bool isSelfLValue = (isGetterMutating && isUsedForGetAccess) ||
791
+ (isSetterMutating && isUsedForSetAccess);
792
+
793
+ Expr *selfDRE = buildSelfReference (selfDecl, selfAccessKind, isSelfLValue,
794
+ /* convertTy*/ selfTypeForAccess);
795
+ if (isSelfLValue)
796
+ selfTypeForAccess = LValueType::get (selfTypeForAccess);
797
+
798
+ if (!selfDRE->getType ()->isEqual (selfTypeForAccess)) {
799
+ assert (selfAccessKind == SelfAccessorKind::Super);
800
+ selfDRE = new (ctx) DerivedToBaseExpr (selfDRE, selfTypeForAccess);
785
801
}
786
802
787
- bool isSelfLValue = storage->isGetterMutating ();
788
- if (isMemberLValue)
789
- isSelfLValue |= storage->isSetterMutating ();
803
+ // Build self.member or equivalent
790
804
791
- // If we're accessing a property wrapper, determine if
792
- // the self requires an lvalue.
793
- if (auto mut = propertyWrapperMutability (storage)) {
794
- isSelfLValue = mut->first ;
795
- if (isMemberLValue)
796
- isSelfLValue |= mut->second ;
805
+ bool isMemberLValue = isLValue;
806
+ if (target == TargetImpl::Wrapper || target == TargetImpl::WrapperStorage) {
807
+ // If the outermost property wrapper's getter / setter is mutating,
808
+ // then the reference to the backing storage should be an l-value.
809
+ auto var = cast<VarDecl>(accessor->getStorage ());
810
+ auto varMember = (target == TargetImpl::WrapperStorage)
811
+ ? &PropertyWrapperTypeInfo::projectedValueVar
812
+ : &PropertyWrapperTypeInfo::valueVar;
813
+ auto wrapper = (target == TargetImpl::WrapperStorage)
814
+ ? var->getOriginalWrappedProperty (
815
+ PropertyWrapperSynthesizedPropertyKind::StorageWrapper)
816
+ ->getAttachedPropertyWrapperTypeInfo (0 )
817
+ : var->getAttachedPropertyWrapperTypeInfo (0 );
818
+ bool isWrapperGetterMutating = (wrapper.*varMember)->isGetterMutating ();
819
+ bool isWrapperSetterMutating = (wrapper.*varMember)->isSetterMutating ();
820
+ isMemberLValue = (isWrapperGetterMutating && isUsedForGetAccess) ||
821
+ (isWrapperSetterMutating && isUsedForSetAccess);
797
822
}
798
823
799
- Expr *selfDRE = buildSelfReference (selfDecl, selfAccessKind, isSelfLValue,
800
- /* convertTy*/ selfTypeForAccess);
801
824
Expr *lookupExpr;
802
825
ConcreteDeclRef memberRef (storage, subs);
803
826
auto type = storage->getValueInterfaceType ().subst (subs);
@@ -871,6 +894,8 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
871
894
lookupExpr->setType (type);
872
895
}
873
896
897
+ // Build self.member.wrappedValue if applicable
898
+
874
899
return finish (lookupExpr);
875
900
}
876
901
@@ -881,7 +906,9 @@ createPropertyLoadOrCallSuperclassGetter(AccessorDecl *accessor,
881
906
AbstractStorageDecl *storage,
882
907
TargetImpl target,
883
908
ASTContext &ctx) {
884
- return buildStorageReference (accessor, storage, target, /* isLValue=*/ false ,
909
+ return buildStorageReference (accessor, storage, target,
910
+ /* isUsedForGetAccess=*/ true ,
911
+ /* isUsedForSetAccess=*/ false ,
885
912
ctx);
886
913
}
887
914
@@ -1033,7 +1060,9 @@ void createPropertyStoreOrCallSuperclassSetter(AccessorDecl *accessor,
1033
1060
return ;
1034
1061
1035
1062
Expr *dest = buildStorageReference (accessor, storage, target,
1036
- /* isLValue=*/ true , ctx);
1063
+ /* isUsedForGetAccess=*/ false ,
1064
+ /* isUsedForSetAccess=*/ true ,
1065
+ ctx);
1037
1066
1038
1067
// Error recovery.
1039
1068
if (dest == nullptr )
@@ -1493,7 +1522,10 @@ synthesizeObservedSetterBody(AccessorDecl *Set, TargetImpl target,
1493
1522
// parameter or it's provided explicitly in the parameter list.
1494
1523
if (!didSet->isSimpleDidSet ()) {
1495
1524
Expr *OldValueExpr =
1496
- buildStorageReference (Set, VD, target, /* isLValue=*/ true , Ctx);
1525
+ buildStorageReference (Set, VD, target,
1526
+ /* isUsedForGetAccess=*/ true ,
1527
+ /* isUsedForSetAccess=*/ true ,
1528
+ Ctx);
1497
1529
1498
1530
// Error recovery.
1499
1531
if (OldValueExpr == nullptr ) {
@@ -1609,7 +1641,10 @@ synthesizeModifyCoroutineBodyWithSimpleDidSet(AccessorDecl *accessor,
1609
1641
1610
1642
SmallVector<ASTNode, 1 > body;
1611
1643
1612
- Expr *ref = buildStorageReference (accessor, storage, target, true , ctx);
1644
+ Expr *ref = buildStorageReference (accessor, storage, target,
1645
+ /* isUsedForGetAccess=*/ true ,
1646
+ /* isUsedForSetAccess=*/ true ,
1647
+ ctx);
1613
1648
ref = maybeWrapInOutExpr (ref, ctx);
1614
1649
1615
1650
YieldStmt *yield = YieldStmt::create (ctx, loc, loc, ref, loc, true );
@@ -1686,16 +1721,19 @@ synthesizeCoroutineAccessorBody(AccessorDecl *accessor, ASTContext &ctx) {
1686
1721
SourceLoc loc = storage->getLoc ();
1687
1722
SmallVector<ASTNode, 1 > body;
1688
1723
1689
- bool isLValue = accessor->getAccessorKind () == AccessorKind::Modify;
1724
+ bool isModify = accessor->getAccessorKind () == AccessorKind::Modify;
1690
1725
1691
- if (isLValue &&
1726
+ if (isModify &&
1692
1727
(storageReadWriteImpl == ReadWriteImplKind::StoredWithSimpleDidSet ||
1693
1728
storageReadWriteImpl == ReadWriteImplKind::InheritedWithSimpleDidSet)) {
1694
1729
return synthesizeModifyCoroutineBodyWithSimpleDidSet (accessor, ctx);
1695
1730
}
1696
1731
1697
1732
// Build a reference to the storage.
1698
- Expr *ref = buildStorageReference (accessor, storage, target, isLValue, ctx);
1733
+ Expr *ref = buildStorageReference (accessor, storage, target,
1734
+ /* isUsedForGetAccess=*/ true ,
1735
+ /* isUsedForSetAccess=*/ isModify,
1736
+ ctx);
1699
1737
if (ref != nullptr ) {
1700
1738
// Wrap it with an `&` marker if this is a modify.
1701
1739
ref = maybeWrapInOutExpr (ref, ctx);
0 commit comments