@@ -419,48 +419,60 @@ InitKindRequest::evaluate(Evaluator &evaluator, ConstructorDecl *decl) const {
419419 return CtorInitializerKind::Convenience;
420420 }
421421
422- // if there is no `convenience` keyword ...
422+ // if there's no `convenience` attribute ...
423423
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 ()) {
427428 auto kind = decl->getDelegatingOrChainedInitKind ();
428429 switch (kind.initKind ) {
429430 case BodyInitKind::ImplicitChained:
430431 case BodyInitKind::Chained:
431432 case BodyInitKind::None:
432- return CtorInitializerKind::Designated;
433+ break ; // it's designated, we need more checks.
433434
434435 case BodyInitKind::Delegating:
435436 return CtorInitializerKind::Convenience;
436437 }
437438 }
438- }
439439
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+
461473 return CtorInitializerKind::Convenience;
462474 }
463- }
475+ } // end of Class context
464476 } // end of Nominal context
465477
466478 // initializers in protocol extensions must be convenience inits
0 commit comments