Skip to content

Commit e8c43bb

Browse files
committed
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()`.
1 parent c0e2403 commit e8c43bb

File tree

2 files changed

+33
-1
lines changed

2 files changed

+33
-1
lines changed

Diff for: lib/Sema/CodeSynthesis.cpp

+32
Original file line numberDiff line numberDiff line change
@@ -937,6 +937,29 @@ static bool canInheritDesignatedInits(Evaluator &eval, ClassDecl *decl) {
937937
areAllStoredPropertiesDefaultInitializable(eval, decl);
938938
}
939939

940+
static ValueDecl *findImplementedObjCDecl(ValueDecl *VD) {
941+
// If VD has an ObjC name...
942+
if (auto vdSelector = VD->getObjCRuntimeName()) {
943+
// and it's in an extension...
944+
if (auto implED = dyn_cast<ExtensionDecl>(VD->getDeclContext())) {
945+
// and that extension is the @objcImplementation of a class's main body...
946+
if (auto interfaceCD =
947+
dyn_cast_or_null<ClassDecl>(implED->getImplementedObjCDecl())) {
948+
// Find the initializer in the class's main body that matches VD.
949+
for (auto interfaceVD : interfaceCD->getAllMembers()) {
950+
if (auto interfaceCtor = dyn_cast<ConstructorDecl>(interfaceVD)) {
951+
if (vdSelector == interfaceCtor->getObjCRuntimeName()) {
952+
return interfaceCtor;
953+
}
954+
}
955+
}
956+
}
957+
}
958+
}
959+
960+
return VD;
961+
}
962+
940963
static void collectNonOveriddenSuperclassInits(
941964
ClassDecl *subclass, SmallVectorImpl<ConstructorDecl *> &results) {
942965
auto *superclassDecl = subclass->getSuperclassDecl();
@@ -968,6 +991,15 @@ static void collectNonOveriddenSuperclassInits(
968991
subOptions, lookupResults);
969992

970993
for (auto decl : lookupResults) {
994+
// HACK: If an @objcImplementation extension declares an initializer, its
995+
// interface usually also has a declaration. We need the interface decl for
996+
// access control computations, but the name lookup returns the
997+
// implementation decl because it's in the Swift module. Go find the
998+
// matching interface decl.
999+
// (Note that this is necessary for both newly-declared inits and overrides,
1000+
// even implicit ones.)
1001+
decl = findImplementedObjCDecl(decl);
1002+
9711003
auto superclassCtor = cast<ConstructorDecl>(decl);
9721004

9731005
// Skip invalid superclass initializers.

Diff for: test/ModuleInterface/objc_implementation.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ open class SwiftSubclass: ImplClass {
7474
print("subclass mainMethod")
7575
}
7676

77-
// CHECK-DAG: @objc dynamic public init()
77+
// CHECK-DAG: @objc override dynamic public init()
7878
// CHECK-DAG: @objc deinit
7979
}
8080
// CHECK: }

0 commit comments

Comments
 (0)