Skip to content

Commit 24fc29b

Browse files
committed
[wip] the right way to do this
1 parent 9383281 commit 24fc29b

File tree

6 files changed

+65
-59
lines changed

6 files changed

+65
-59
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3603,12 +3603,9 @@ ERROR(designated_init_in_extension,none,
36033603
ERROR(cfclass_designated_init_in_extension,none,
36043604
"designated initializer cannot be declared in an extension of %0",
36053605
(DeclName))
3606-
ERROR(enumstruct_convenience_init,none,
3606+
ERROR(no_convenience_keyword_init,none,
36073607
"initializers in %0 are not marked with 'convenience'",
36083608
(StringRef))
3609-
ERROR(actor_convenience_init,none,
3610-
"initializers in an actor are not marked with 'convenience'",
3611-
())
36123609
ERROR(nonclass_convenience_init,none,
36133610
"convenience initializer not allowed in non-class type %0",
36143611
(DeclName))

lib/Sema/TypeCheckDecl.cpp

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -379,50 +379,64 @@ CtorInitializerKind
379379
InitKindRequest::evaluate(Evaluator &evaluator, ConstructorDecl *decl) const {
380380
auto &diags = decl->getASTContext().Diags;
381381

382-
// Convenience inits are only allowed on classes and in extensions thereof.
383-
if (auto convenAttr = decl->getAttrs().getAttribute<ConvenienceAttr>()) {
384-
if (auto nominal = decl->getDeclContext()->getSelfNominalTypeDecl()) {
385-
auto classDecl = dyn_cast<ClassDecl>(nominal);
386-
387-
if (classDecl) {
388-
// Forbid convenience inits on Foreign CF types, as Swift does not yet
389-
// support user-defined factory inits.
390-
if (classDecl->getForeignClassKind() == ClassDecl::ForeignKind::CFType)
391-
diags.diagnose(decl->getLoc(), diag::cfclass_convenience_init);
392-
393-
// If it's an actor, "convenience" is not required, and it's always
394-
// a designated initializer.
382+
if (auto nominal = decl->getDeclContext()->getSelfNominalTypeDecl()) {
383+
384+
// Convenience inits are only allowed on classes and in extensions thereof.
385+
if (auto convenAttr = decl->getAttrs().getAttribute<ConvenienceAttr>()) {
386+
if (auto classDecl = dyn_cast<ClassDecl>(nominal)) {
395387
if (classDecl->isAnyActor()) {
396-
diags.diagnose(decl->getLoc(), diag::actor_convenience_init)
388+
// For an actor "convenience" is not required, but we'll honor it.
389+
diags.diagnose(decl->getLoc(),
390+
diag::no_convenience_keyword_init, "actors")
397391
.fixItRemove(convenAttr->getLocation())
398392
.warnUntilSwiftVersion(6);
399393

400-
return CtorInitializerKind::Designated;
394+
} else { // not an actor
395+
// Forbid convenience inits on Foreign CF types, as Swift does not yet
396+
// support user-defined factory inits.
397+
if (classDecl->getForeignClassKind() == ClassDecl::ForeignKind::CFType)
398+
diags.diagnose(decl->getLoc(), diag::cfclass_convenience_init);
401399
}
402400

403-
}
404-
405-
if (!classDecl) {
401+
} else { // not a ClassDecl
406402
auto ConvenienceLoc = convenAttr->getLocation();
407403

408-
// Produce a tailored diagnostic for structs and enums.
404+
// Produce a tailored diagnostic for structs and enums. They should
405+
// not have `convenience`.
409406
bool isStruct = dyn_cast<StructDecl>(nominal) != nullptr;
410407
if (isStruct || dyn_cast<EnumDecl>(nominal)) {
411-
diags.diagnose(decl->getLoc(), diag::enumstruct_convenience_init,
408+
diags.diagnose(decl->getLoc(), diag::no_convenience_keyword_init,
412409
isStruct ? "structs" : "enums")
413410
.fixItRemove(ConvenienceLoc);
414411
} else {
415-
diags.diagnose(decl->getLoc(), diag::nonclass_convenience_init,
416-
nominal->getName())
412+
diags.diagnose(decl->getLoc(), diag::no_convenience_keyword_init,
413+
nominal->getName().str())
417414
.fixItRemove(ConvenienceLoc);
418415
}
419416
return CtorInitializerKind::Designated;
420417
}
418+
419+
return CtorInitializerKind::Convenience;
421420
}
422421

423-
return CtorInitializerKind::Convenience;
422+
// if there is no `convenience` keyword...
423+
424+
// actors infer whether they are `convenience` from their body kind.
425+
if (auto classDecl = dyn_cast<ClassDecl>(nominal)) {
426+
if (classDecl->isAnyActor()) {
427+
auto kind = decl->getDelegatingOrChainedInitKind();
428+
switch (kind.initKind) {
429+
case BodyInitKind::ImplicitChained:
430+
case BodyInitKind::Chained:
431+
case BodyInitKind::None:
432+
return CtorInitializerKind::Designated;
433+
434+
case BodyInitKind::Delegating:
435+
return CtorInitializerKind::Convenience;
436+
}
437+
}
438+
}
424439

425-
} else if (auto nominal = decl->getDeclContext()->getSelfNominalTypeDecl()) {
426440
// A designated init for a class must be written within the class itself.
427441
//
428442
// This is because designated initializers of classes get a vtable entry,
@@ -447,10 +461,11 @@ InitKindRequest::evaluate(Evaluator &evaluator, ConstructorDecl *decl) const {
447461
return CtorInitializerKind::Convenience;
448462
}
449463
}
464+
} // end of Nominal context
450465

451-
if (decl->getDeclContext()->getExtendedProtocolDecl()) {
452-
return CtorInitializerKind::Convenience;
453-
}
466+
// initializers in protocol extensions must be convenience inits
467+
if (decl->getDeclContext()->getExtendedProtocolDecl()) {
468+
return CtorInitializerKind::Convenience;
454469
}
455470

456471
return CtorInitializerKind::Designated;

lib/Sema/TypeCheckStmt.cpp

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1702,7 +1702,6 @@ static void checkClassConstructorBody(ClassDecl *classDecl,
17021702
ASTContext &ctx = classDecl->getASTContext();
17031703
bool wantSuperInitCall = false;
17041704
bool isDelegating = false;
1705-
const bool isActor = classDecl->isAnyActor();
17061705

17071706
auto initKindAndExpr = ctor->getDelegatingOrChainedInitKind();
17081707
switch (initKindAndExpr.initKind) {
@@ -1733,12 +1732,7 @@ static void checkClassConstructorBody(ClassDecl *classDecl,
17331732
}
17341733

17351734
// A class designated initializer must never be delegating.
1736-
//
1737-
// An actor's designated initializers can be delegating, because there is
1738-
// no such thing as a sub-actor. But, they may require a super.init call in
1739-
// a very narrow circumstance: it's an @objc actor that needs to call
1740-
// NSObject.init()
1741-
if (ctor->isDesignatedInit() && isDelegating && !isActor) {
1735+
if (ctor->isDesignatedInit() && isDelegating) {
17421736
if (classDecl->getForeignClassKind() == ClassDecl::ForeignKind::CFType) {
17431737
ctor->diagnose(diag::delegating_designated_init_in_extension,
17441738
ctor->getDeclContext()->getDeclaredInterfaceType());

test/Concurrency/actor_isolation.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -861,14 +861,14 @@ actor SomeActorWithInits {
861861
self.nonisolated()
862862
}
863863

864-
convenience init(i3: Bool) {
864+
convenience init(i3: Bool) { // expected-warning{{initializers in actors are not marked with 'convenience'; this is an error in Swift 6}}{{3-15=}}
865865
self.init(i1: i3)
866866
_ = mutableState // expected-error{{actor-isolated property 'mutableState' can not be referenced from a non-isolated context}}
867867
self.isolated() // expected-error{{actor-isolated instance method 'isolated()' can not be referenced from a non-isolated context}}
868868
self.nonisolated()
869869
}
870870

871-
convenience init(i4: Bool) async {
871+
convenience init(i4: Bool) async { // expected-warning{{initializers in actors are not marked with 'convenience'; this is an error in Swift 6}}{{3-15=}}
872872
self.init(i1: i4)
873873
_ = mutableState
874874
self.isolated()
@@ -894,14 +894,14 @@ actor SomeActorWithInits {
894894
_ = mutableState // will be caught by flow-isolation
895895
}
896896

897-
@MainActor convenience init(i7: Bool) {
897+
@MainActor convenience init(i7: Bool) { // expected-warning{{initializers in actors are not marked with 'convenience'; this is an error in Swift 6}}{{14-26=}}
898898
self.init(i1: i7)
899899
_ = mutableState // expected-error{{actor-isolated property 'mutableState' can not be referenced from the main actor}}
900900
self.isolated() // expected-error{{actor-isolated instance method 'isolated()' can not be referenced from the main actor}}
901901
self.nonisolated()
902902
}
903903

904-
@MainActor convenience init(i8: Bool) async {
904+
@MainActor convenience init(i8: Bool) async { // expected-warning{{initializers in actors are not marked with 'convenience'; this is an error in Swift 6}}{{14-26=}}
905905
self.init(i1: i8)
906906
_ = await mutableState
907907
await self.isolated()
@@ -1243,9 +1243,9 @@ actor Counter {
12431243

12441244
}
12451245

1246-
convenience init(material: Int) async {
1246+
init(material: Int) async {
12471247
self.init()
1248-
self.counter = 10 // FIXME: this should work, and also needs to work in definite initialization by injecting hops
1248+
self.counter = 10
12491249
}
12501250
}
12511251

@@ -1272,17 +1272,17 @@ actor Butterfly {
12721272

12731273
nonisolated init(async: Void) async {}
12741274

1275-
nonisolated convenience init(icecream: Void) { // expected-warning {{'nonisolated' on an actor's synchronous initializer is invalid; this is an error in Swift 6}} {{3-15=}}
1275+
nonisolated init(icecream: Void) { // expected-warning {{'nonisolated' on an actor's synchronous initializer is invalid; this is an error in Swift 6}} {{3-15=}}
12761276
self.init()
12771277
self.flapsPerSec += 1 // expected-error {{actor-isolated property 'flapsPerSec' can not be mutated from a non-isolated context}}
12781278
}
12791279

1280-
nonisolated convenience init(cookies: Void) async {
1280+
nonisolated init(cookies: Void) async {
12811281
self.init()
12821282
self.flapsPerSec += 1 // expected-error {{actor-isolated property 'flapsPerSec' can not be mutated from a non-isolated context}}
12831283
}
12841284

1285-
convenience init(brownies: Void) {
1285+
init(brownies: Void) {
12861286
self.init()
12871287
self.flapsPerSec = 0 // expected-error {{actor-isolated property 'flapsPerSec' can not be mutated from a non-isolated context}}
12881288
}

test/Concurrency/concurrent_value_checking.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,31 +21,31 @@ actor A2 {
2121
self.localVar = value
2222
}
2323

24-
convenience init(forwardSync value: NotConcurrent) {
24+
init(forwardSync value: NotConcurrent) {
2525
self.init(value: value)
2626
}
2727

28-
convenience init(delegatingSync value: NotConcurrent) {
28+
init(delegatingSync value: NotConcurrent) {
2929
self.init(forwardSync: value)
3030
}
3131

3232
init(valueAsync value: NotConcurrent) async {
3333
self.localVar = value
3434
}
3535

36-
convenience init(forwardAsync value: NotConcurrent) async {
36+
init(forwardAsync value: NotConcurrent) async {
3737
await self.init(valueAsync: value)
3838
}
3939

40-
nonisolated convenience init(nonisoAsync value: NotConcurrent, _ c: Int) async {
40+
nonisolated init(nonisoAsync value: NotConcurrent, _ c: Int) async {
4141
if c == 0 {
4242
await self.init(valueAsync: value)
4343
} else {
4444
self.init(value: value)
4545
}
4646
}
4747

48-
convenience init(delegatingAsync value: NotConcurrent, _ c: Int) async {
48+
init(delegatingAsync value: NotConcurrent, _ c: Int) async {
4949
if c == 0 {
5050
await self.init(valueAsync: value)
5151
} else if c == 1 {

test/Concurrency/flow_isolation.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ actor Convenient {
304304
self.x = val
305305
}
306306

307-
convenience init(bigVal: Int) {
307+
init(bigVal: Int) {
308308
if bigVal < 0 {
309309
self.init(val: 0)
310310
say(msg: "hello from actor!")
@@ -315,21 +315,21 @@ actor Convenient {
315315
Task { await self.mutateIsolatedState() }
316316
}
317317

318-
convenience init!(biggerVal1 biggerVal: Int) {
318+
init!(biggerVal1 biggerVal: Int) {
319319
guard biggerVal < 1234567 else { return nil }
320320
self.init(bigVal: biggerVal)
321321
say(msg: "hello?")
322322
}
323323

324324
@MainActor
325-
convenience init?(biggerVal2 biggerVal: Int) async {
325+
init?(biggerVal2 biggerVal: Int) async {
326326
guard biggerVal < 1234567 else { return nil }
327327
self.init(bigVal: biggerVal)
328328
say(msg: "hello?")
329329
await mutateIsolatedState()
330330
}
331331

332-
convenience init() async {
332+
init() async {
333333
self.init(val: 10)
334334
self.x += 1
335335
mutateIsolatedState()
@@ -350,7 +350,7 @@ actor Convenient {
350350
Task { self }
351351
}
352352

353-
convenience init(throwyConvenient val: Int) throws {
353+
init(throwyConvenient val: Int) throws {
354354
try self.init(throwyDesignated: val)
355355
say(msg: "hello?")
356356
Task { self }
@@ -386,13 +386,13 @@ actor MyActor {
386386

387387
func helloWorld() {}
388388

389-
convenience init(ci1 c: Bool) {
389+
init(ci1 c: Bool) {
390390
self.init(i1: c)
391391
Task { self }
392392
callMethod(self)
393393
}
394394

395-
convenience init(ci2 c: Bool) async {
395+
init(ci2 c: Bool) async {
396396
self.init(i1: c)
397397
self.x = 1
398398
callMethod(self)

0 commit comments

Comments
 (0)