Skip to content

Commit b27b8cf

Browse files
committed
[Property Wrappers] Consider willSet mutability when deciding if a wrapped
property setter is mutating, and address other PR feedback
1 parent 0c49bb9 commit b27b8cf

File tree

3 files changed

+52
-36
lines changed

3 files changed

+52
-36
lines changed

include/swift/AST/PropertyWrappers.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,8 @@ void simple_display(llvm::raw_ostream &os, PropertyWrapperMutability m);
130130
/// Describes whether the reference to a property wrapper instance used for
131131
/// accessing a wrapped property should be an l-value or not.
132132
struct PropertyWrapperLValueness {
133-
llvm::SmallVector<bool, 1> isLValueForGetAccess;
134-
llvm::SmallVector<bool, 1> isLValueForSetAccess;
133+
llvm::SmallVector<bool, 4> isLValueForGetAccess;
134+
llvm::SmallVector<bool, 4> isLValueForSetAccess;
135135

136136
PropertyWrapperLValueness(unsigned numWrappers)
137137
: isLValueForGetAccess(numWrappers), isLValueForSetAccess(numWrappers) {}

lib/Sema/TypeCheckStorage.cpp

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -342,14 +342,16 @@ IsSetterMutatingRequest::evaluate(Evaluator &evaluator,
342342
if (auto var = dyn_cast<VarDecl>(storage)) {
343343
if (auto mut = var->getPropertyWrapperMutability()) {
344344
bool isMutating = mut->Setter == PropertyWrapperMutability::Mutating;
345-
if (auto *accessor = var->getParsedAccessor(AccessorKind::DidSet)) {
345+
if (auto *didSet = var->getParsedAccessor(AccessorKind::DidSet)) {
346346
// If there's a didSet, we call the getter for the 'oldValue', and so
347347
// should consider the getter's mutatingness as well
348-
if (!accessor->isSimpleDidSet()) {
348+
if (!didSet->isSimpleDidSet()) {
349349
isMutating |= (mut->Getter == PropertyWrapperMutability::Mutating);
350350
}
351-
isMutating |= accessor->getAttrs().hasAttribute<MutatingAttr>();
351+
isMutating |= didSet->getAttrs().hasAttribute<MutatingAttr>();
352352
}
353+
if (auto *willSet = var->getParsedAccessor(AccessorKind::WillSet))
354+
isMutating |= willSet->getAttrs().hasAttribute<MutatingAttr>();
353355
return isMutating && result;
354356
}
355357
}
@@ -738,40 +740,39 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
738740

739741
// Perform accesses to the wrappedValues along the composition chain.
740742
if (firstWrapperIdx < lastWrapperIdx) {
741-
if (auto lvalueness = getPropertyWrapperLValueness(var)) {
742-
743-
// Figure out if the outermost wrapper instance should be an l-value
744-
bool isLValueForGet = lvalueness->isLValueForGetAccess[firstWrapperIdx];
745-
bool isLValueForSet = lvalueness->isLValueForSetAccess[firstWrapperIdx];
746-
isMemberLValue = (isLValueForGet && isUsedForGetAccess) ||
747-
(isLValueForSet && isUsedForSetAccess);
748-
749-
for (unsigned i : range(firstWrapperIdx, lastWrapperIdx)) {
750-
auto wrapperInfo = var->getAttachedPropertyWrapperTypeInfo(i);
751-
auto wrappedValue = wrapperInfo.valueVar;
752-
753-
// Figure out if the wrappedValue accesses should be l-values
754-
bool isWrapperRefLValue = isLValue;
755-
if (i < lastWrapperIdx - 1) {
756-
bool isLValueForGet = lvalueness->isLValueForGetAccess[i+1];
757-
bool isLValueForSet = lvalueness->isLValueForSetAccess[i+1];
758-
isWrapperRefLValue = (isLValueForGet && isUsedForGetAccess) ||
759-
(isLValueForSet && isUsedForSetAccess);
760-
}
743+
auto lvalueness = *getPropertyWrapperLValueness(var);
744+
745+
// Figure out if the outermost wrapper instance should be an l-value
746+
bool isLValueForGet = lvalueness.isLValueForGetAccess[firstWrapperIdx];
747+
bool isLValueForSet = lvalueness.isLValueForSetAccess[firstWrapperIdx];
748+
isMemberLValue = (isLValueForGet && isUsedForGetAccess) ||
749+
(isLValueForSet && isUsedForSetAccess);
750+
751+
for (unsigned i : range(firstWrapperIdx, lastWrapperIdx)) {
752+
auto wrapperInfo = var->getAttachedPropertyWrapperTypeInfo(i);
753+
auto wrappedValue = wrapperInfo.valueVar;
754+
755+
// Figure out if the wrappedValue accesses should be l-values
756+
bool isWrapperRefLValue = isLValue;
757+
if (i < lastWrapperIdx - 1) {
758+
bool isLValueForGet = lvalueness.isLValueForGetAccess[i+1];
759+
bool isLValueForSet = lvalueness.isLValueForSetAccess[i+1];
760+
isWrapperRefLValue = (isLValueForGet && isUsedForGetAccess) ||
761+
(isLValueForSet && isUsedForSetAccess);
762+
}
761763

762-
// Check for availability of wrappedValue.
763-
if (accessor->getAccessorKind() == AccessorKind::Get ||
764-
accessor->getAccessorKind() == AccessorKind::Read) {
765-
if (wrappedValue->getAttrs().getUnavailable(ctx)) {
766-
diagnoseExplicitUnavailability(
767-
wrappedValue,
768-
var->getAttachedPropertyWrappers()[i]->getRangeWithAt(),
769-
var->getDeclContext(), nullptr);
770-
}
764+
// Check for availability of wrappedValue.
765+
if (accessor->getAccessorKind() == AccessorKind::Get ||
766+
accessor->getAccessorKind() == AccessorKind::Read) {
767+
if (wrappedValue->getAttrs().getUnavailable(ctx)) {
768+
diagnoseExplicitUnavailability(
769+
wrappedValue,
770+
var->getAttachedPropertyWrappers()[i]->getRangeWithAt(),
771+
var->getDeclContext(), nullptr);
771772
}
772-
773-
underlyingVars.push_back({ wrappedValue, isWrapperRefLValue });
774773
}
774+
775+
underlyingVars.push_back({ wrappedValue, isWrapperRefLValue });
775776
}
776777
}
777778
semantics = AccessSemantics::DirectToStorage;

test/SILGen/property_wrapper_observers.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,18 @@ struct MutatingDidSet {
9393
// CHECK-LABEL: sil private [ossa] @$s26property_wrapper_observers14MutatingDidSetV5value33_{{.*}} : $@convention(method) (Int, @inout MutatingDidSet) -> () {
9494
// CHECK: function_ref @$s26property_wrapper_observers5StateV12wrappedValueSivs : $@convention(method) (Int, State) -> ()
9595
// CHECK: function_ref @$s26property_wrapper_observers14MutatingDidSetV5value33_{{.*}} : $@convention(method) (@inout MutatingDidSet) -> ()
96+
97+
struct MutatingWillSet {
98+
@State private var value: Int {
99+
mutating willSet {}
100+
}
101+
102+
mutating func test() {
103+
value = 10
104+
}
105+
}
106+
107+
// MutatingWillSet.value.setter
108+
// CHECK-LABEL: sil private [ossa] @$s26property_wrapper_observers15MutatingWillSetV5value33_{{.*}}Sivs : $@convention(method) (Int, @inout MutatingWillSet) -> () {
109+
// CHECK: function_ref @$s26property_wrapper_observers15MutatingWillSetV5value33_{{.*}}Sivw : $@convention(method) (Int, @inout MutatingWillSet) -> ()
110+
// CHECK: function_ref @$s26property_wrapper_observers5StateV12wrappedValueSivs : $@convention(method) (Int, State) -> ()

0 commit comments

Comments
 (0)