Skip to content

Commit 995cb48

Browse files
committed
add a note about using actor convenience inits
This is a follow-up to the changes that restrict uses of 'self' in certain actor initializers, to guide people to using the convenience inits for now.
1 parent 2e61dfe commit 995cb48

File tree

3 files changed

+80
-4
lines changed

3 files changed

+80
-4
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,10 @@ ERROR(self_disallowed_actor_init,none,
177177
"actor 'self' %select{can only|cannot}0 %1 from "
178178
"%select{an async|a global-actor isolated}0 initializer",
179179
(bool, StringRef))
180+
NOTE(actor_convenience_init,none,
181+
"convenience initializers allow non-isolated use of 'self' once "
182+
"initialized",
183+
())
180184

181185

182186

lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,8 @@ namespace {
496496

497497
void reportIllegalUseForActorInit(const DIMemoryUse &Use,
498498
ActorInitKind ActorKind,
499-
StringRef ProblemDesc) const;
499+
StringRef ProblemDesc,
500+
bool suggestConvenienceInit) const;
500501

501502
void handleLoadUseFailureForActorInit(const DIMemoryUse &Use,
502503
ActorInitKind ActorKind) const;
@@ -1223,7 +1224,8 @@ void LifetimeChecker::handleInOutUse(const DIMemoryUse &Use) {
12231224

12241225
// 'self' cannot be passed 'inout' from some kinds of actor initializers.
12251226
if (isRestrictedActorInitSelf(Use, &ActorKind))
1226-
reportIllegalUseForActorInit(Use, ActorKind, "be passed 'inout'");
1227+
reportIllegalUseForActorInit(Use, ActorKind, "be passed 'inout'",
1228+
/*suggestConvenienceInit=*/false);
12271229

12281230
// One additional check: 'let' properties may never be passed inout, because
12291231
// they are only allowed to have their initial value set, not a subsequent
@@ -1398,7 +1400,8 @@ void LifetimeChecker::handleEscapeUse(const DIMemoryUse &Use) {
13981400

13991401
// no escaping uses of 'self' are allowed in restricted actor inits.
14001402
if (isRestrictedActorInitSelf(Use, &ActorKind))
1401-
reportIllegalUseForActorInit(Use, ActorKind, "be captured by a closure");
1403+
reportIllegalUseForActorInit(Use, ActorKind, "be captured by a closure",
1404+
/*suggestConvenienceInit=*/true);
14021405

14031406
return;
14041407
}
@@ -1809,7 +1812,8 @@ bool LifetimeChecker::isRestrictedActorInitSelf(const DIMemoryUse& Use,
18091812
void LifetimeChecker::reportIllegalUseForActorInit(
18101813
const DIMemoryUse &Use,
18111814
ActorInitKind ActorKind,
1812-
StringRef ProblemDesc) const {
1815+
StringRef ProblemDesc,
1816+
bool suggestConvenienceInit) const {
18131817
switch(ActorKind) {
18141818
case ActorInitKind::None:
18151819
case ActorInitKind::PlainAsync:
@@ -1825,6 +1829,9 @@ void LifetimeChecker::reportIllegalUseForActorInit(
18251829
true, ProblemDesc);
18261830
break;
18271831
}
1832+
1833+
if (suggestConvenienceInit)
1834+
diagnose(Module, Use.Inst->getLoc(), diag::actor_convenience_init);
18281835
}
18291836

18301837
void LifetimeChecker::handleLoadUseFailureForActorInit(
@@ -1864,6 +1871,13 @@ void LifetimeChecker::handleLoadUseFailureForActorInit(
18641871
diagnose(Module, Use.Inst->getLoc(), diag::self_use_actor_init, true);
18651872
break;
18661873
}
1874+
1875+
// We cannot easily determine which argument in the call the use of 'self'
1876+
// appears in. If we could, then we could determine whether the callee
1877+
// is 'isolated' to that parameter, in order to avoid suggesting a convenience
1878+
// init in those cases. Thus, the phrasing of the note should be informative.
1879+
if (isa<ApplyInst>(Inst))
1880+
diagnose(Module, Use.Inst->getLoc(), diag::actor_convenience_init);
18671881
}
18681882

18691883
/// Check and diagnose various failures when a load use is not fully

test/Concurrency/actor_definite_init.swift

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,10 @@ actor Convenient {
4949
guard val > 0 else { throw BogusError.blah }
5050
self.x = 10
5151
say(msg: "hello?") // expected-error {{this use of actor 'self' can only appear in an async initializer}}
52+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
53+
5254
Task { self } // expected-error {{actor 'self' can only be captured by a closure from an async initializer}}
55+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
5356
}
5457

5558
init(asyncThrowyDesignated val: Int) async throws {
@@ -95,15 +98,26 @@ actor MyActor {
9598

9699
func helloWorld() {}
97100

101+
convenience init(ci1 c: Bool) {
102+
self.init(i1: c)
103+
Task { self }
104+
callMethod(self)
105+
}
106+
98107
init(i1 c: Bool) {
99108
self.x = 0
100109
_ = self.x
101110
self.y = self.x
102111

103112
Task { self } // expected-error{{actor 'self' can only be captured by a closure from an async initializer}}
113+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
104114

105115
self.helloWorld() // expected-error{{this use of actor 'self' can only appear in an async initializer}}
116+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
117+
106118
callMethod(self) // expected-error{{this use of actor 'self' can only appear in an async initializer}}
119+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
120+
107121
passInout(&self.x) // expected-error{{actor 'self' can only be passed 'inout' from an async initializer}}
108122

109123
self.x = self.y
@@ -115,9 +129,13 @@ actor MyActor {
115129
_ = self.hax
116130

117131
_ = computedProp // expected-error{{this use of actor 'self' can only appear in an async initializer}}
132+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
133+
118134
computedProp = 1 // expected-error{{this use of actor 'self' can only appear in an async initializer}}
135+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
119136

120137
Task { // expected-error {{actor 'self' can only be captured by a closure from an async initializer}}
138+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
121139
_ = await self.hax
122140
await self.helloWorld()
123141
}
@@ -129,9 +147,14 @@ actor MyActor {
129147
self.y = self.x
130148

131149
Task { self } // expected-error{{actor 'self' can only be captured by a closure from an async initializer}}
150+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
132151

133152
self.helloWorld() // expected-error{{this use of actor 'self' can only appear in an async initializer}}
153+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
154+
134155
callMethod(self) // expected-error{{this use of actor 'self' can only appear in an async initializer}}
156+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
157+
135158
passInout(&self.x) // expected-error{{actor 'self' can only be passed 'inout' from an async initializer}}
136159

137160
self.x = self.y
@@ -140,9 +163,13 @@ actor MyActor {
140163
_ = self.hax
141164

142165
_ = computedProp // expected-error{{this use of actor 'self' can only appear in an async initializer}}
166+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
167+
143168
computedProp = 1 // expected-error{{this use of actor 'self' can only appear in an async initializer}}
169+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
144170

145171
Task { // expected-error {{actor 'self' can only be captured by a closure from an async initializer}}
172+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
146173
_ = await self.hax
147174
await self.helloWorld()
148175
}
@@ -154,9 +181,14 @@ actor MyActor {
154181
self.y = self.x
155182

156183
Task { self } // expected-error{{actor 'self' can only be captured by a closure from an async initializer}}
184+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
157185

158186
self.helloWorld() // expected-error{{this use of actor 'self' can only appear in an async initializer}}
187+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
188+
159189
callMethod(self) // expected-error{{this use of actor 'self' can only appear in an async initializer}}
190+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
191+
160192
passInout(&self.x) // expected-error{{actor 'self' can only be passed 'inout' from an async initializer}}
161193

162194
self.x = self.y
@@ -165,9 +197,13 @@ actor MyActor {
165197
_ = self.hax
166198

167199
_ = computedProp // expected-error{{this use of actor 'self' can only appear in an async initializer}}
200+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
201+
168202
computedProp = 1 // expected-error{{this use of actor 'self' can only appear in an async initializer}}
203+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
169204

170205
Task { // expected-error {{actor 'self' can only be captured by a closure from an async initializer}}
206+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
171207
_ = await self.hax
172208
await self.helloWorld()
173209
}
@@ -179,9 +215,14 @@ actor MyActor {
179215
self.y = self.x
180216

181217
Task { self } // expected-error{{actor 'self' cannot be captured by a closure from a global-actor isolated initializer}}
218+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
182219

183220
self.helloWorld() // expected-error{{this use of actor 'self' cannot appear in a global-actor isolated initializer}}
221+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
222+
184223
callMethod(self) // expected-error{{this use of actor 'self' cannot appear in a global-actor isolated initializer}}
224+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
225+
185226
passInout(&self.x) // expected-error{{actor 'self' cannot be passed 'inout' from a global-actor isolated initializer}}
186227

187228
self.x = self.y
@@ -190,9 +231,13 @@ actor MyActor {
190231
_ = self.hax
191232

192233
_ = computedProp // expected-error{{this use of actor 'self' cannot appear in a global-actor isolated initializer}}
234+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
235+
193236
computedProp = 1 // expected-error{{this use of actor 'self' cannot appear in a global-actor isolated initializer}}
237+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
194238

195239
Task { // expected-error {{actor 'self' cannot be captured by a closure from a global-actor isolated initializer}}
240+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
196241
_ = await self.hax
197242
await self.helloWorld()
198243
}
@@ -228,9 +273,14 @@ actor MyActor {
228273
self.y = self.x
229274

230275
Task { self } // expected-error{{actor 'self' cannot be captured by a closure from a global-actor isolated initializer}}
276+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
231277

232278
self.helloWorld() // expected-error{{this use of actor 'self' cannot appear in a global-actor isolated initializer}}
279+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
280+
233281
callMethod(self) // expected-error{{this use of actor 'self' cannot appear in a global-actor isolated initializer}}
282+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
283+
234284
passInout(&self.x) // expected-error{{actor 'self' cannot be passed 'inout' from a global-actor isolated initializer}}
235285

236286
self.x = self.y
@@ -239,9 +289,13 @@ actor MyActor {
239289
_ = self.hax
240290

241291
_ = computedProp // expected-error{{this use of actor 'self' cannot appear in a global-actor isolated initializer}}
292+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
293+
242294
computedProp = 1 // expected-error{{this use of actor 'self' cannot appear in a global-actor isolated initializer}}
295+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
243296

244297
Task { // expected-error {{actor 'self' cannot be captured by a closure from a global-actor isolated initializer}}
298+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
245299
_ = await self.hax
246300
await self.helloWorld()
247301
}
@@ -257,6 +311,7 @@ actor X {
257311
init(v1 start: Int) {
258312
self.counter = start
259313
Task { await self.setCounter(start + 1) } // expected-error {{actor 'self' can only be captured by a closure from an async initializer}}
314+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
260315

261316
if self.counter != start {
262317
fatalError("where's my protection?")
@@ -319,8 +374,10 @@ actor EscapeArtist {
319374
let unchainedSelf = self
320375

321376
unchainedSelf.nonisolated() // expected-error {{this use of actor 'self' can only appear in an async initializer}}
377+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
322378

323379
let _ = { unchainedSelf.nonisolated() } // expected-error {{actor 'self' can only be captured by a closure from an async initializer}}
380+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
324381
}
325382

326383
init(attempt5: Bool) {
@@ -336,6 +393,7 @@ actor EscapeArtist {
336393
self.nonisolated()
337394
}
338395
fn() // expected-error {{this use of actor 'self' can only appear in an async initializer}}
396+
// expected-note@-1 {{convenience initializers allow non-isolated use of 'self' once initialized}}
339397
}
340398

341399
func isolatedMethod() { x += 1 }

0 commit comments

Comments
 (0)