Skip to content

Commit a3e8bb6

Browse files
committed
[DI] InitAccessors: Prevent re-initialization of init accessor property with a setter
Init accessor properties without setters behave just like `let` stored properties and can only be initialized once.
1 parent a736e18 commit a3e8bb6

File tree

2 files changed

+65
-0
lines changed

2 files changed

+65
-0
lines changed

lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1501,6 +1501,16 @@ void LifetimeChecker::handleStoreUse(unsigned UseID) {
15011501
auto allFieldsInitialized =
15021502
getAnyUninitializedMemberAtInst(Use.Inst, 0,
15031503
TheMemory.getNumElements()) == -1;
1504+
1505+
auto *AOI = cast<AssignOrInitInst>(Use.Inst);
1506+
// init accessor properties without setters behave like `let` properties
1507+
// and don't support re-initialization.
1508+
if (isa<SILUndef>(AOI->getSetter())) {
1509+
diagnose(Module, AOI->getLoc(),
1510+
diag::immutable_property_already_initialized,
1511+
AOI->getPropertyName());
1512+
}
1513+
15041514
Use.Kind = allFieldsInitialized ? DIUseKind::Set : DIUseKind::Assign;
15051515
} else if (isFullyInitialized) {
15061516
Use.Kind = DIUseKind::Assign;

test/SILOptimizer/init_accessor_definite_init_diagnostics.swift

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,3 +179,58 @@ class TestInitWithGuard {
179179
self.pair2 = (a, b)
180180
}
181181
}
182+
183+
do {
184+
class Base<T: Collection> {
185+
private var _v: T
186+
187+
var data: T {
188+
init(initialValue) initializes(_v) {
189+
_v = initialValue
190+
}
191+
192+
get { _v }
193+
}
194+
195+
init(data: T) {
196+
self.data = data
197+
}
198+
199+
init(reinit: T) {
200+
self.data = reinit
201+
self.data = reinit // expected-error {{immutable value 'data' may only be initialized once}}
202+
}
203+
}
204+
205+
class Sub<U> : Base<U> where U: Collection, U.Element == String {
206+
init(other: U) {
207+
super.init(data: other)
208+
}
209+
210+
init(error: U) {
211+
super.init(data: error)
212+
data = error // expected-error {{immutable value 'data' may only be initialized once}}
213+
}
214+
}
215+
216+
// Make sure that re-initialization is not allowed when there is no setter.
217+
struct TestPartialWithoutSetter {
218+
var _a: Int
219+
220+
var a: Int {
221+
init(initialValue) initializes(_a) {
222+
self._a = initialValue
223+
}
224+
225+
get { _a }
226+
}
227+
228+
var b: Int
229+
230+
init(v: Int) {
231+
self.a = v
232+
self.a = v // expected-error {{immutable value 'a' may only be initialized once}}
233+
self.b = v
234+
}
235+
}
236+
}

0 commit comments

Comments
 (0)