Skip to content

Commit c3070e0

Browse files
committed
[SILGen] InitAccessors: Don't use init accessor to initialize superclass properties
`super.init()` should fully initialize "super" which means that such properties are mutated via a setter. (cherry picked from commit c87daab)
1 parent 9fc690f commit c3070e0

File tree

3 files changed

+56
-0
lines changed

3 files changed

+56
-0
lines changed

lib/SILGen/SILGenLValue.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1642,6 +1642,14 @@ namespace {
16421642
if (!isAssignmentToSelfParamInInit)
16431643
return false;
16441644

1645+
// Properties declared in a superclass cannot be initialized via
1646+
// init accessor because `super.init()` should always precede
1647+
// any such property reference which means that it can only be
1648+
// mutated by a setter call.
1649+
if (varDecl->getDeclContext()->getSelfNominalTypeDecl() !=
1650+
fnDecl->getDeclContext()->getSelfNominalTypeDecl())
1651+
return false;
1652+
16451653
auto *initAccessor = varDecl->getAccessor(AccessorKind::Init);
16461654
if (!initAccessor)
16471655
return false;

test/SILOptimizer/init_accessor_definite_init_diagnostics.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,3 +247,26 @@ do {
247247
}
248248
}
249249
}
250+
251+
do {
252+
class Entity {
253+
var _age: Int
254+
var age: Int = 0 {
255+
@storageRestrictions(initializes: _age)
256+
init { _age = newValue }
257+
get { _age }
258+
set { _age = newValue }
259+
}
260+
}
261+
262+
class Person : Entity {
263+
init(age: Int) {
264+
self.age = age // expected-error {{'self' used in property access 'age' before 'super.init' call}}
265+
}
266+
267+
init(otherAge: Int) {
268+
super.init()
269+
self.age = otherAge // Ok
270+
}
271+
}
272+
}

test/SILOptimizer/init_accessor_raw_sil_lowering.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
// REQUIRES: asserts
44

5+
56
struct Test1 {
67
var _a: Int
78
var _b: String
@@ -264,3 +265,27 @@ func test_default_inits() {
264265
// CHECK: assign_or_init [init] self %0 : $Test4, value [[Y_VALUE]] : $String, init {{.*}} : $@convention(thin) (@owned String) -> @out String, set undef : $@convention(thin) (@owned String) -> @out String
265266
}
266267
}
268+
269+
func test_handling_of_superclass_properties() {
270+
class Entity {
271+
var _age: Int
272+
var age: Int = 0 {
273+
@storageRestrictions(initializes: _age)
274+
init { _age = newValue }
275+
get { _age }
276+
set { _age = newValue }
277+
}
278+
}
279+
280+
class Person : Entity {
281+
// CHECK-LABEL: sil private [ossa] @$s23assign_or_init_lowering38test_handling_of_superclass_propertiesyyF6PersonL_C3ageADSi_tcfc : $@convention(method) (Int, @owned Person) -> @owned Person
282+
// CHECK: [[SELF:%.*]] = load [copy] %2 : $*Person
283+
// CHECK-NEXT: [[SELF_AS_ENTITY:%.*]] = upcast [[SELF]] : $Person to $Entity
284+
// CHECK-NEXT: [[AGE_SETTER:%.*]] = class_method [[SELF_AS_ENTITY]] : $Entity, #<abstract function>Entity.age!setter : (Entity) -> (Int) -> (), $@convention(method) (Int, @guaranteed Entity) -> ()
285+
// CHECK-NEXT: {{.*}} = apply [[AGE_SETTER]](%0, [[SELF_AS_ENTITY]]) : $@convention(method) (Int, @guaranteed Entity) -> ()
286+
init(age: Int) {
287+
super.init()
288+
self.age = age
289+
}
290+
}
291+
}

0 commit comments

Comments
 (0)