Skip to content

Commit 10947de

Browse files
committed
[SILGen] InitAccessors: Make sure that assign_or_init always directly references self
`nonmutating set` gets a copy of "self" in `GetterSetterComponent` which is expected for partial application of the setter but doesn't work for "self" reference that `assign_or_init` instruction needs to emit references to stored properties during lowering. We need to make sure that "self" is always a reference to rootself of the constructor before passing it to `assign_or_init`. Resolves: #67827 Resolves: rdar://114433261
1 parent 4ec86f2 commit 10947de

File tree

3 files changed

+120
-3
lines changed

3 files changed

+120
-3
lines changed

lib/SILGen/SILGenFunction.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1852,7 +1852,20 @@ void SILGenFunction::emitAssignOrInit(SILLocation loc, ManagedValue selfValue,
18521852
setterFRef = SILUndef::get(initFRef->getType(), F);
18531853
}
18541854

1855-
B.createAssignOrInit(loc, field, selfValue.getValue(),
1855+
auto isValueSelf = !selfValue.getType().getASTType()->mayHaveSuperclass();
1856+
// If we are emitting `assign_or_init` instruction for a value
1857+
// type, we need to make sure that "self" is always a l-value
1858+
// reference to "rootself" because `nonmutating set` loads "self"
1859+
// and referencing `selfValue` in such case is incorrect because
1860+
// it's a copy which is going to be skipped by DI.
1861+
auto selfRef = selfValue;
1862+
if (isValueSelf && !selfRef.isLValue()) {
1863+
auto *ctor = cast<ConstructorDecl>(FunctionDC->getAsDecl());
1864+
selfRef = maybeEmitValueOfLocalVarDecl(ctor->getImplicitSelfDecl(),
1865+
AccessKind::ReadWrite);
1866+
}
1867+
1868+
B.createAssignOrInit(loc, field, selfRef.getValue(),
18561869
newValue.forward(*this), initFRef, setterFRef,
18571870
AssignOrInitInst::Unknown);
18581871
}

test/Interpreter/init_accessors.swift

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -847,3 +847,77 @@ do {
847847
// CHECK-NEXT: TestMixedDefaultInitalizable(a: nil, b: Optional(""))
848848
// CHECK-NEXT: TestMixedDefaultInitalizable(a: nil, b: Optional("Hello"))
849849
// CHECK-NEXT: TestMixedDefaultInitalizable(a: nil, b: Optional(""))
850+
851+
do {
852+
struct TestNonMutatingSetDefault {
853+
var _count: Int
854+
855+
var count: Int = 42 {
856+
@storageRestrictions(initializes: _count)
857+
init {
858+
_count = newValue
859+
}
860+
861+
get { _count }
862+
nonmutating set {}
863+
}
864+
}
865+
866+
struct TestNonMutatingSetNoDefault {
867+
var _count: Int
868+
869+
var count: Int {
870+
@storageRestrictions(initializes: _count)
871+
init {
872+
print("init accessor is called: \(newValue)")
873+
_count = newValue
874+
}
875+
876+
get { _count }
877+
878+
nonmutating set {
879+
print("nonmutating set called: \(newValue)")
880+
}
881+
}
882+
883+
init(value: Int) {
884+
self.count = value
885+
self.count = value + 1
886+
}
887+
}
888+
889+
struct TestNonMutatingSetCustom {
890+
var _count: Int
891+
892+
var count: Int = 42 {
893+
@storageRestrictions(initializes: _count)
894+
init {
895+
print("init accessor is called: \(newValue)")
896+
_count = newValue
897+
}
898+
899+
get { _count }
900+
901+
nonmutating set {
902+
print("nonmutating set called: \(newValue)")
903+
}
904+
}
905+
906+
init(custom: Int) {
907+
count = custom
908+
}
909+
}
910+
911+
print("test-nonmutating-set-1: \(TestNonMutatingSetDefault())")
912+
print("test-nonmutating-set-2: \(TestNonMutatingSetDefault(count: 0))")
913+
print("test-nonmutating-set-3: \(TestNonMutatingSetNoDefault(value: -1))")
914+
print("test-nonmutating-set-4: \(TestNonMutatingSetCustom(custom: 0))")
915+
}
916+
// CHECK: test-nonmutating-set-1: TestNonMutatingSetDefault(_count: 42)
917+
// CHECK-NEXT: test-nonmutating-set-2: TestNonMutatingSetDefault(_count: 0)
918+
// CHECK-NEXT: init accessor is called: -1
919+
// CHECK-NEXT: nonmutating set called: 0
920+
// CHECK-NEXT: test-nonmutating-set-3: TestNonMutatingSetNoDefault(_count: -1)
921+
// CHECK-NEXT: init accessor is called: 42
922+
// CHECK-NEXT: nonmutating set called: 0
923+
// CHECK-NEXT: test-nonmutating-set-4: TestNonMutatingSetCustom(_count: 42)

test/SILOptimizer/init_accessor_raw_sil_lowering.swift

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ func test_default_inits() {
225225
// CHECK: [[INIT_ACCESSOR:%.*]] = function_ref @$s23assign_or_init_lowering18test_default_initsyyF5Test1L_V1xSivi : $@convention(thin) (Int) -> @out Int
226226
// CHECK: [[SETTER_REF:%.*]] = function_ref @$s23assign_or_init_lowering18test_default_initsyyF5Test1L_V1xSivs : $@convention(method) (Int, @inout Test1) -> ()
227227
// CHECK-NEXT: [[SETTER:%.*]] = partial_apply [callee_guaranteed] [[SETTER_REF]]([[SELF_REF]]) : $@convention(method) (Int, @inout Test1) -> ()
228-
// CHECK-NEXT: assign_or_init [init] #<abstract function>Test1.x, self [[SELF_REF]] : $*Test1, value [[INIT_VAL]] : $Int, init [[INIT_ACCESSOR]] : $@convention(thin) (Int) -> @out Int, set [[SETTER]] : $@callee_guaranteed (Int) -> ()
228+
// CHECK-NEXT: assign_or_init [init] #<abstract function>Test1.x, self %1 : $*Test1, value [[INIT_VAL]] : $Int, init [[INIT_ACCESSOR]] : $@convention(thin) (Int) -> @out Int, set [[SETTER]] : $@callee_guaranteed (Int) -> ()
229229
// CHECK-NEXT: end_access [[SELF_REF]] : $*Test1
230230
// CHECK-NEXT: destroy_value [[SETTER]] : $@callee_guaranteed (Int) -> ()
231231
init() {
@@ -238,7 +238,7 @@ func test_default_inits() {
238238
// CHECK: [[INIT_ACCESSOR:%.*]] = function_ref @$s23assign_or_init_lowering18test_default_initsyyF5Test1L_V1xSivi : $@convention(thin) (Int) -> @out Int
239239
// CHECK: [[SETTER_REF:%.*]] = function_ref @$s23assign_or_init_lowering18test_default_initsyyF5Test1L_V1xSivs : $@convention(method) (Int, @inout Test1) -> ()
240240
// CHECK-NEXT: [[SETTER:%.*]] = partial_apply [callee_guaranteed] [[SETTER_REF]]([[SELF_REF]]) : $@convention(method) (Int, @inout Test1) -> ()
241-
// CHECK-NEXT: assign_or_init [init] #<abstract function>Test1.x, self [[SELF_REF]] : $*Test1, value [[INIT_VAL]] : $Int, init [[INIT_ACCESSOR]] : $@convention(thin) (Int) -> @out Int, set [[SETTER]] : $@callee_guaranteed (Int) -> ()
241+
// CHECK-NEXT: assign_or_init [init] #<abstract function>Test1.x, self %2 : $*Test1, value [[INIT_VAL]] : $Int, init [[INIT_ACCESSOR]] : $@convention(thin) (Int) -> @out Int, set [[SETTER]] : $@callee_guaranteed (Int) -> ()
242242
// CHECK-NEXT: end_access [[SELF_REF]] : $*Test1
243243
// CHECK-NEXT: destroy_value [[SETTER]] : $@callee_guaranteed (Int) -> ()
244244
//
@@ -396,3 +396,33 @@ func test_handling_of_superclass_properties() {
396396
}
397397
}
398398
}
399+
400+
func test_handling_of_nonmutating_set() {
401+
struct Test {
402+
private var _count: Int
403+
404+
var count: Int = 42 {
405+
@storageRestrictions(initializes: _count)
406+
init {
407+
_count = newValue
408+
}
409+
get {
410+
_count
411+
}
412+
nonmutating set {
413+
// Update store
414+
}
415+
}
416+
417+
// CHECK-LABEL: sil private [ossa] @$s23assign_or_init_lowering32test_handling_of_nonmutating_setyyF4TestL_V5countADSi_tcfC : $@convention(method) (Int, @thin Test.Type) -> Test
418+
// CHECK: [[INIT_VALUE:%.*]] = function_ref @$s23assign_or_init_lowering32test_handling_of_nonmutating_setyyF4TestL_V5countSivpfi : $@convention(thin) () -> Int
419+
// CHECK-NEXT: [[VALUE:%.*]] = apply [[INIT_VALUE]]() : $@convention(thin) () -> Int
420+
// CHECK: assign_or_init [init] #<abstract function>Test.count, self %2 : $*Test, value [[VALUE]] : $Int, init {{.*}} : $@convention(thin) (Int) -> @out Int, set {{.*}} : $@callee_guaranteed (Int) -> ()
421+
// CHECK: assign_or_init [set] #<abstract function>Test.count, self %2 : $*Test, value %0 : $Int, init {{.*}} : $@convention(thin) (Int) -> @out Int, set {{.*}} : $@callee_guaranteed (Int) -> ()
422+
// CHECK: assign_or_init [set] #<abstract function>Test.count, self %2 : $*Test, value [[ZERO:%.*]] : $Int, init {{.*}} : $@convention(thin) (Int) -> @out Int, set {{.*}} : $@callee_guaranteed (Int) -> ()
423+
init(count: Int) {
424+
self.count = count
425+
self.count = 0
426+
}
427+
}
428+
}

0 commit comments

Comments
 (0)