Skip to content

Commit 47ba176

Browse files
committed
[Typechecker] Fix _modify for properties using a property wrapper
1 parent e777840 commit 47ba176

File tree

2 files changed

+55
-5
lines changed

2 files changed

+55
-5
lines changed

lib/Sema/TypeCheckStorage.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -743,8 +743,6 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
743743
bool isMemberLValue = isLValue;
744744
auto propertyWrapperMutability =
745745
[&](Decl *decl) -> Optional<std::pair<bool, bool>> {
746-
if (accessor->isCoroutine())
747-
return None;
748746
auto var = dyn_cast<VarDecl>(decl);
749747
if (!var)
750748
return None;
@@ -1572,6 +1570,13 @@ synthesizeCoroutineAccessorBody(AccessorDecl *accessor, ASTContext &ctx) {
15721570
? TargetImpl::Ordinary
15731571
: TargetImpl::Implementation);
15741572

1573+
// If this is a variable with an attached property wrapper, then
1574+
// the accessors need to yield the wrapped value.
1575+
if (isa<VarDecl>(storage) &&
1576+
cast<VarDecl>(storage)->hasAttachedPropertyWrapper()) {
1577+
target = TargetImpl::Wrapper;
1578+
}
1579+
15751580
SourceLoc loc = storage->getLoc();
15761581
SmallVector<ASTNode, 1> body;
15771582

@@ -1602,8 +1607,11 @@ synthesizeReadCoroutineBody(AccessorDecl *read, ASTContext &ctx) {
16021607
static std::pair<BraceStmt *, bool>
16031608
synthesizeModifyCoroutineBody(AccessorDecl *modify, ASTContext &ctx) {
16041609
#ifndef NDEBUG
1605-
auto impl = modify->getStorage()->getReadWriteImpl();
1606-
assert(impl != ReadWriteImplKind::Modify &&
1610+
auto storage = modify->getStorage();
1611+
auto impl = storage->getReadWriteImpl();
1612+
auto hasWrapper = isa<VarDecl>(storage) &&
1613+
cast<VarDecl>(storage)->hasAttachedPropertyWrapper();
1614+
assert((hasWrapper || impl != ReadWriteImplKind::Modify) &&
16071615
impl != ReadWriteImplKind::Immutable);
16081616
#endif
16091617
return synthesizeCoroutineAccessorBody(modify, ctx);
@@ -2548,7 +2556,8 @@ static void finishPropertyWrapperImplInfo(VarDecl *var,
25482556
}
25492557

25502558
if (wrapperSetterIsUsable)
2551-
info = StorageImplInfo::getMutableComputed();
2559+
info = StorageImplInfo(ReadImplKind::Get, WriteImplKind::Set,
2560+
ReadWriteImplKind::Modify);
25522561
else
25532562
info = StorageImplInfo::getImmutableComputed();
25542563
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: %target-swift-emit-silgen %s | %FileCheck %s
2+
3+
@propertyWrapper
4+
struct TestWrapper<ValueType> {
5+
var wrappedValue: ValueType
6+
}
7+
8+
struct State {
9+
@TestWrapper var values: [String] = []
10+
}
11+
12+
var state = State()
13+
state.values = Array(repeating: "", count: 20000)
14+
15+
for i in 0..<20000 {
16+
// CHECK: bb3([[INDEX:%.*]] : $Int):
17+
// CHECK: [[BEGIN_ACCESS_MODIFY:%.*]] = begin_access [modify] [dynamic] {{%.*}} : $*State
18+
// CHECK: [[REF_MODIFY:%.*]] = function_ref @$s26property_wrapper_coroutine5StateV6valuesSaySSGvM : $@yield_once @convention(method) (@inout State) -> @yields @inout Array<String>
19+
// CHECK: ([[RES1:%.*]], {{%.*}}) = begin_apply [[REF_MODIFY]]([[BEGIN_ACCESS_MODIFY]]) : $@yield_once @convention(method) (@inout State) -> @yields @inout Array<String>
20+
// CHECK: [[REF_ARRAY_SUBSCRIPT:%.*]] = function_ref @$sSayxSiciM : $@yield_once @convention(method) <τ_0_0> (Int, @inout Array<τ_0_0>) -> @yields @inout τ_0_0
21+
// CHECK: ({{%.*}}, {{%.*}}) = begin_apply [[REF_ARRAY_SUBSCRIPT]]<String>([[INDEX]], [[RES1]]) : $@yield_once @convention(method) <τ_0_0> (Int, @inout Array<τ_0_0>) -> @yields @inout τ_0_0
22+
state.values[i] = String(i)
23+
}
24+
25+
// CHECK-LABEL: sil hidden [transparent] [ossa] @$s26property_wrapper_coroutine5StateV6valuesSaySSGvM : $@yield_once @convention(method) (@inout State) -> @yields @inout Array<String> {
26+
// CHECK: bb0([[STATE:%.*]] : $*State):
27+
// CHECK: debug_value_addr [[STATE]] : $*State, var, name "self", argno {{.*}}
28+
// CHECK: [[BEGIN_ACCESS:%.*]] = begin_access [modify] [unknown] [[STATE]] : $*State
29+
// CHECK: [[BACKING_ADDR:%.*]] = struct_element_addr [[BEGIN_ACCESS]] : $*State, #State._values
30+
// CHECK: [[VALUE_ADDR:%.*]] = struct_element_addr [[BACKING_ADDR]] : $*TestWrapper<Array<String>>, #TestWrapper.wrappedValue
31+
// CHECK: yield [[VALUE_ADDR]] : $*Array<String>, resume bb1, unwind bb2
32+
//
33+
// CHECK: bb1:
34+
// CHECK: end_access [[BEGIN_ACCESS]] : $*State
35+
// CHECK: [[RETURN:%.*]] = tuple ()
36+
// CHECK: return [[RETURN]] : $()
37+
//
38+
// CHECK: bb2:
39+
// CHECK: end_access [[BEGIN_ACCESS]] : $*State
40+
// CHECK: unwind
41+
// CHECK-END: }

0 commit comments

Comments
 (0)