@@ -419,48 +419,60 @@ InitKindRequest::evaluate(Evaluator &evaluator, ConstructorDecl *decl) const {
419
419
return CtorInitializerKind::Convenience;
420
420
}
421
421
422
- // if there is no `convenience` keyword ...
422
+ // if there's no `convenience` attribute ...
423
423
424
- // actors infer whether they are `convenience` from their body kind.
425
- if (auto classDecl = dyn_cast<ClassDecl>(nominal)) {
426
- if (classDecl->isAnyActor ()) {
424
+ if (auto classDcl = dyn_cast<ClassDecl>(nominal)) {
425
+
426
+ // actors infer whether they are `convenience` from their body kind.
427
+ if (classDcl->isAnyActor ()) {
427
428
auto kind = decl->getDelegatingOrChainedInitKind ();
428
429
switch (kind.initKind ) {
429
430
case BodyInitKind::ImplicitChained:
430
431
case BodyInitKind::Chained:
431
432
case BodyInitKind::None:
432
- return CtorInitializerKind::Designated;
433
+ break ; // it's designated, we need more checks.
433
434
434
435
case BodyInitKind::Delegating:
435
436
return CtorInitializerKind::Convenience;
436
437
}
437
438
}
438
- }
439
439
440
- // A designated init for a class must be written within the class itself.
441
- //
442
- // This is because designated initializers of classes get a vtable entry,
443
- // and extensions cannot add vtable entries to the extended type.
444
- //
445
- // If we implement the ability for extensions defined in the same module
446
- // (or the same file) to add vtable entries, we can re-evaluate this
447
- // restriction.
448
- if (isa<ClassDecl>(nominal) && !decl->isSynthesized () &&
449
- isa<ExtensionDecl>(decl->getDeclContext ()) &&
450
- !(decl->getAttrs ().hasAttribute <DynamicReplacementAttr>())) {
451
- if (cast<ClassDecl>(nominal)->getForeignClassKind () == ClassDecl::ForeignKind::CFType) {
452
- diags.diagnose (decl->getLoc (),
453
- diag::cfclass_designated_init_in_extension,
454
- nominal->getName ());
455
- return CtorInitializerKind::Designated;
456
- } else {
457
- diags.diagnose (decl->getLoc (),
458
- diag::designated_init_in_extension,
459
- nominal->getName ())
460
- .fixItInsert (decl->getLoc (), " convenience " );
440
+ // A designated init for a class must be written within the class itself.
441
+ //
442
+ // This is because designated initializers of classes get a vtable entry,
443
+ // and extensions cannot add vtable entries to the extended type.
444
+ //
445
+ // If we implement the ability for extensions defined in the same module
446
+ // (or the same file) to add vtable entries, we can re-evaluate this
447
+ // restriction.
448
+ if (!decl->isSynthesized () &&
449
+ isa<ExtensionDecl>(decl->getDeclContext ()) &&
450
+ !(decl->getAttrs ().hasAttribute <DynamicReplacementAttr>())) {
451
+
452
+ if (classDcl->getForeignClassKind () == ClassDecl::ForeignKind::CFType) {
453
+ diags.diagnose (decl->getLoc (),
454
+ diag::designated_init_in_extension_no_convenience_tip,
455
+ nominal->getName ());
456
+
457
+ // despite having reported it as an error, say that it is designated.
458
+ return CtorInitializerKind::Designated;
459
+
460
+ } else if (classDcl->isAnyActor ()) {
461
+ // tailor the diagnostic to not mention `convenience`
462
+ diags.diagnose (decl->getLoc (),
463
+ diag::designated_init_in_extension_no_convenience_tip,
464
+ nominal->getName ());
465
+
466
+ } else {
467
+ diags.diagnose (decl->getLoc (),
468
+ diag::designated_init_in_extension,
469
+ nominal->getName ())
470
+ .fixItInsert (decl->getLoc (), " convenience " );
471
+ }
472
+
461
473
return CtorInitializerKind::Convenience;
462
474
}
463
- }
475
+ } // end of Class context
464
476
} // end of Nominal context
465
477
466
478
// initializers in protocol extensions must be convenience inits
0 commit comments