Fix @objcImpl subclass init visibility computation

When writing an @objc subclass of an @objcImplementation class, implicit initializers in the subclass were treated as overriding the *implementation decl*, not the *interface decl*, of the initializer in the superclass. This caused Swift to incorrectly compute the visibility of the superclass initializer and omit an `override` keyword from the module interface when one would definitely be necessary.

Correct this oversight by looking up the interface decl matching the superclass implementation in `collectNonOveriddenSuperclassInits()`.
This commit is contained in:
Becca Royal-Gordon
2023-03-23 14:17:36 -07:00
parent c0e240322e
commit e8c43bb168
2 changed files with 33 additions and 1 deletions

View File

@@ -937,6 +937,29 @@ static bool canInheritDesignatedInits(Evaluator &eval, ClassDecl *decl) {
areAllStoredPropertiesDefaultInitializable(eval, decl);
}
static ValueDecl *findImplementedObjCDecl(ValueDecl *VD) {
// If VD has an ObjC name...
if (auto vdSelector = VD->getObjCRuntimeName()) {
// and it's in an extension...
if (auto implED = dyn_cast<ExtensionDecl>(VD->getDeclContext())) {
// and that extension is the @objcImplementation of a class's main body...
if (auto interfaceCD =
dyn_cast_or_null<ClassDecl>(implED->getImplementedObjCDecl())) {
// Find the initializer in the class's main body that matches VD.
for (auto interfaceVD : interfaceCD->getAllMembers()) {
if (auto interfaceCtor = dyn_cast<ConstructorDecl>(interfaceVD)) {
if (vdSelector == interfaceCtor->getObjCRuntimeName()) {
return interfaceCtor;
}
}
}
}
}
}
return VD;
}
static void collectNonOveriddenSuperclassInits(
ClassDecl *subclass, SmallVectorImpl<ConstructorDecl *> &results) {
auto *superclassDecl = subclass->getSuperclassDecl();
@@ -968,6 +991,15 @@ static void collectNonOveriddenSuperclassInits(
subOptions, lookupResults);
for (auto decl : lookupResults) {
// HACK: If an @objcImplementation extension declares an initializer, its
// interface usually also has a declaration. We need the interface decl for
// access control computations, but the name lookup returns the
// implementation decl because it's in the Swift module. Go find the
// matching interface decl.
// (Note that this is necessary for both newly-declared inits and overrides,
// even implicit ones.)
decl = findImplementedObjCDecl(decl);
auto superclassCtor = cast<ConstructorDecl>(decl);
// Skip invalid superclass initializers.

View File

@@ -74,7 +74,7 @@ open class SwiftSubclass: ImplClass {
print("subclass mainMethod")
}
// CHECK-DAG: @objc dynamic public init()
// CHECK-DAG: @objc override dynamic public init()
// CHECK-DAG: @objc deinit
}
// CHECK: }