Skip to content

Commit 9b1b2b3

Browse files
committed
Sema: Fix crash with stored property that has on-demand 'modify' accessor
If a stored property has observers, the 'modify' coroutine body takes a special form which directly yields the underlying storage and calls the 'didSet' and/or 'willSet' accessors. However, if a property is 'dynamic', the 'modify' coroutine is synthesized on-demand and it's SIL is serialized. It cannot reference the 'didSet' or 'willSet' accessors, since they are private. Furthermore, an on-demand accessor must also work if the property is overridden in a subclass. So in this case, fall back to the more general 'modify' synthesis code, which just calls the getter followed by the setter. Fixes <rdar://problem/62339808>.
1 parent 31d5385 commit 9b1b2b3

File tree

2 files changed

+25
-1
lines changed

2 files changed

+25
-1
lines changed

lib/Sema/TypeCheckStorage.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1760,9 +1760,16 @@ synthesizeCoroutineAccessorBody(AccessorDecl *accessor, ASTContext &ctx) {
17601760

17611761
bool isModify = accessor->getAccessorKind() == AccessorKind::Modify;
17621762

1763+
// Special-case for a modify coroutine of a simple stored property with
1764+
// observers. We can yield a borrowed copy of the underlying storage
1765+
// in this case. However, if the accessor was synthesized on-demand,
1766+
// we do the more general thing, because on-demand accessors might be
1767+
// serialized, which prevents them from being able to directly reference
1768+
// didSet/willSet accessors, which are private.
17631769
if (isModify &&
17641770
(storageReadWriteImpl == ReadWriteImplKind::StoredWithSimpleDidSet ||
1765-
storageReadWriteImpl == ReadWriteImplKind::InheritedWithSimpleDidSet)) {
1771+
storageReadWriteImpl == ReadWriteImplKind::InheritedWithSimpleDidSet) &&
1772+
!accessor->hasForcedStaticDispatch()) {
17661773
return synthesizeModifyCoroutineBodyWithSimpleDidSet(accessor, ctx);
17671774
}
17681775

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %target-swift-emit-silgen %s -disable-objc-attr-requires-foundation-module | %FileCheck %s
2+
// REQUIRES: objc_interop
3+
4+
public protocol Proto {
5+
var property: Int { get set }
6+
}
7+
8+
public class ClassWithDynamicObservedProperty : Proto {
9+
@objc public dynamic var property: Int = 0 {
10+
didSet {}
11+
}
12+
}
13+
14+
// CHECK-LABEL: sil shared [serialized] [ossa] @$s40observers_with_on_demand_modify_accessor32ClassWithDynamicObservedPropertyC8propertySivM : $@yield_once @convention(method) (@guaranteed ClassWithDynamicObservedProperty) -> @yields @inout Int {
15+
// CHECK: objc_method %0 : $ClassWithDynamicObservedProperty, #ClassWithDynamicObservedProperty.property!getter.foreign
16+
// CHECK: objc_method %0 : $ClassWithDynamicObservedProperty, #ClassWithDynamicObservedProperty.property!setter.foreign
17+
// CHECK: return

0 commit comments

Comments
 (0)