Skip to content

Commit 68ec6b6

Browse files
committed
Support class extensions in objcImpl
Their requirements are now included when typechecking the main body extension, and their conformances are emitted in IRGen. Fixes rdar://118535473.
1 parent 9bcd818 commit 68ec6b6

File tree

8 files changed

+68
-16
lines changed

8 files changed

+68
-16
lines changed

lib/IRGen/GenClass.cpp

+7-7
Original file line numberDiff line numberDiff line change
@@ -1242,7 +1242,7 @@ namespace {
12421242
const ClassLayout &fieldLayout)
12431243
: IGM(IGM), TheEntity(theUnion), TheExtension(nullptr),
12441244
FieldLayout(&fieldLayout) {
1245-
visitConformances(getClass());
1245+
visitConformances(getClass()->getImplementationContext());
12461246

12471247
if (getClass()->isRootDefaultActor()) {
12481248
Ivars.push_back(Field::DefaultActorStorage);
@@ -1310,12 +1310,12 @@ namespace {
13101310
/// Gather protocol records for all of the explicitly-specified Objective-C
13111311
/// protocol conformances.
13121312
void visitConformances(const IterableDeclContext *idc) {
1313-
auto dc = idc->getAsGenericContext();
1314-
if (dc->getImplementedObjCContext() != dc) {
1315-
// We want to use the conformance list imported from the ObjC header.
1316-
auto importedIDC = cast<IterableDeclContext>(
1317-
dc->getImplementedObjCContext()->getAsDecl());
1318-
visitConformances(importedIDC);
1313+
auto decl = idc->getDecl();
1314+
if (decl->getImplementedObjCDecl()) {
1315+
// We want to use the conformance lists imported from the ObjC header.
1316+
for (auto interface : decl->getAllImplementedObjCDecls()) {
1317+
visitConformances(cast<IterableDeclContext>(interface));
1318+
}
13191319
return;
13201320
}
13211321

lib/Sema/TypeCheckDeclObjC.cpp

+9-7
Original file line numberDiff line numberDiff line change
@@ -2930,16 +2930,18 @@ class ObjCImplementationChecker {
29302930

29312931
// Did we actually match this extension to an interface? (In invalid code,
29322932
// we might not have.)
2933-
auto interfaceDecl = ext->getImplementedObjCDecl();
2934-
if (!interfaceDecl)
2933+
auto interfaceDecls = ext->getAllImplementedObjCDecls();
2934+
if (interfaceDecls.empty())
29352935
return;
29362936

29372937
// Add the @_objcImplementation extension's members as candidates.
29382938
addCandidates(ext);
29392939

29402940
// Add its interface's members as requirements.
2941-
auto interface = cast<IterableDeclContext>(interfaceDecl);
2942-
addRequirements(interface);
2941+
for (auto interfaceDecl : interfaceDecls) {
2942+
auto interface = cast<IterableDeclContext>(interfaceDecl);
2943+
addRequirements(interface);
2944+
}
29432945
}
29442946

29452947
private:
@@ -3422,9 +3424,9 @@ class ObjCImplementationChecker {
34223424

34233425
// Check only applies to members of implementations, not implementations in
34243426
// their own right.
3425-
if (!cand->isObjCImplementation()
3426-
&& cand->getDeclContext()->getImplementedObjCContext()
3427-
!= req->getDeclContext())
3427+
if (!cand->isObjCImplementation() &&
3428+
getCategoryName(cand->getDeclContext()->getImplementedObjCContext())
3429+
!= getCategoryName(req->getDeclContext()))
34283430
return MatchOutcome::WrongCategory;
34293431

34303432
if (cand->getKind() != req->getKind())

test/IRGen/Inputs/objc_implementation.h

+6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@
1010

1111
@end
1212

13+
@interface ImplClass () <NSMutableCopying>
14+
15+
- (void)extensionMethod:(int)param;
16+
17+
@end
18+
1319

1420
@interface ImplClass (Category1)
1521

test/IRGen/objc_implementation.swift

+20-2
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@
1717

1818
// Metaclass
1919
// CHECK: @"OBJC_METACLASS_$_ImplClass" = global %objc_class { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, {{.*}}ptr [[_METACLASS_DATA_ImplClass:@[^, ]+]]{{.*}}, align 8
20-
// CHECK: @_PROTOCOLS_ImplClass = internal constant { i64, [1 x ptr] } { i64 1, [1 x ptr] [ptr @_PROTOCOL_NSCopying] }, section "__DATA, __objc_const", align 8
20+
// CHECK: @_PROTOCOLS_ImplClass = internal constant { i64, [2 x ptr] } { i64 2, [2 x ptr] [ptr @_PROTOCOL_NSCopying, ptr @_PROTOCOL_NSMutableCopying] }, section "__DATA, __objc_const", align 8
2121
// CHECK: [[_METACLASS_DATA_ImplClass]] = internal constant { i32, i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr } { i32 129, i32 40, i32 40, i32 0, ptr null, ptr @.str.9.ImplClass, ptr null, ptr @_PROTOCOLS_ImplClass, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
2222
// TODO: Why the extra i32 field above?
2323

2424
// Class
2525
// CHECK: [[selector_data__cxx_destruct:@[^, ]+]] = private global [14 x i8] c".cxx_destruct\00", section "__TEXT,__objc_methname,cstring_literals", align 1
26-
// CHECK: [[_INSTANCE_METHODS_ImplClass:@[^, ]+]] = internal constant { i32, i32, [7 x { ptr, ptr, ptr }] } { i32 24, i32 7, [7 x { ptr, ptr, ptr }] [{ ptr, ptr, ptr } { ptr @"\01L_selector_data(init)", ptr @".str.7.@16@0:8", ptr @"$sSo9ImplClassC19objc_implementationEABycfcTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr [[selector_data_implProperty]], ptr @".str.7.i16@0:8", ptr @"$sSo9ImplClassC19objc_implementationE12implPropertys5Int32VvgTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr [[selector_data_setImplProperty_]], ptr @".str.10.v20@0:8i16", ptr @"$sSo9ImplClassC19objc_implementationE12implPropertys5Int32VvsTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr [[selector_data_mainMethod_]], ptr @".str.10.v20@0:8i16", ptr @"$sSo9ImplClassC19objc_implementationE10mainMethodyys5Int32VFTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr @"\01L_selector_data(copyWithZone:)", ptr @".str.11.@24@0:8^v16", ptr @"$sSo9ImplClassC19objc_implementationE4copy4withypSg10ObjectiveC6NSZoneVSg_tFTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr @"\01L_selector_data(dealloc)", ptr @".str.7.v16@0:8", ptr @"$sSo9ImplClassC19objc_implementationEfDTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr [[selector_data__cxx_destruct]], ptr @".str.7.v16@0:8", ptr @"$sSo9ImplClassCfETo{{(\.ptrauth)?}}" }] }, section "__DATA, __objc_data", align 8
26+
// CHECK: [[_INSTANCE_METHODS_ImplClass:@[^, ]+]] = internal constant { i32, i32, [9 x { ptr, ptr, ptr }] } { i32 24, i32 9, [9 x { ptr, ptr, ptr }] [{ ptr, ptr, ptr } { ptr @"\01L_selector_data(init)", ptr @".str.7.@16@0:8", ptr @"$sSo9ImplClassC19objc_implementationEABycfcTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr [[selector_data_implProperty]], ptr @".str.7.i16@0:8", ptr @"$sSo9ImplClassC19objc_implementationE12implPropertys5Int32VvgTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr [[selector_data_setImplProperty_]], ptr @".str.10.v20@0:8i16", ptr @"$sSo9ImplClassC19objc_implementationE12implPropertys5Int32VvsTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr [[selector_data_mainMethod_]], ptr @".str.10.v20@0:8i16", ptr @"$sSo9ImplClassC19objc_implementationE10mainMethodyys5Int32VFTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr @"\01L_selector_data(extensionMethod:)", ptr @".str.10.v20@0:8i16", ptr @"$sSo9ImplClassC19objc_implementationE15extensionMethodyys5Int32VFTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr @"\01L_selector_data(copyWithZone:)", ptr @".str.11.@24@0:8^v16", ptr @"$sSo9ImplClassC19objc_implementationE4copy4withypSg10ObjectiveC6NSZoneVSg_tFTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr @"\01L_selector_data(mutableCopyWithZone:)", ptr @".str.11.@24@0:8^v16", ptr @"$sSo9ImplClassC19objc_implementationE11mutableCopy4withypSg10ObjectiveC6NSZoneVSg_tFTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr @"\01L_selector_data(dealloc)", ptr @".str.7.v16@0:8", ptr @"$sSo9ImplClassC19objc_implementationEfDTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr [[selector_data__cxx_destruct]], ptr @".str.7.v16@0:8", ptr @"$sSo9ImplClassCfETo{{(\.ptrauth)?}}" }] }, section "__DATA, __objc_data", align 8
2727
// CHECK: [[_IVARS_ImplClass:@[^, ]+]] = internal constant { i32, i32, [2 x { ptr, ptr, ptr, i32, i32 }] } { i32 32, i32 2, [2 x { ptr, ptr, ptr, i32, i32 }] [{ ptr, ptr, ptr, i32, i32 } { ptr @"$sSo9ImplClassC19objc_implementationE12implPropertys5Int32VvpWvd", ptr @.str.12.implProperty, ptr @.str.0., i32 2, i32 4 }, { ptr, ptr, ptr, i32, i32 } { ptr @"$sSo9ImplClassC19objc_implementationE13implProperty2So8NSObjectCSgvpWvd", ptr @.str.13.implProperty2, ptr @.str.0., i32 3, i32 8 }] }, section "__DATA, __objc_const", align 8
2828
// CHECK: [[_PROPERTIES_ImplClass:@[^, ]+]] = internal constant { i32, i32, [1 x { ptr, ptr }] } { i32 16, i32 1, [1 x { ptr, ptr }] [{ ptr, ptr } { ptr @.str.12.implProperty, ptr @".str.18.Ti,N,VimplProperty" }] }, section "__DATA, __objc_const", align 8
2929
// FIXME: Should just be @_PROTOCOLS_ImplClass, but an IRGen bug causes the protocol list to be emitted twice.
@@ -50,6 +50,7 @@
5050
final var implProperty2: NSObject?
5151

5252
@objc func mainMethod(_: Int32) { print(implProperty) }
53+
@objc func extensionMethod(_: Int32) {}
5354

5455
@objc(copyWithZone:)
5556
func copy(with zone: NSZone?) -> Any? {
@@ -59,6 +60,11 @@
5960
return copy
6061
}
6162

63+
@objc(mutableCopyWithZone:)
64+
func mutableCopy(with zone: NSZone?) -> Any? {
65+
return copy(with: zone)
66+
}
67+
6268
deinit { print(implProperty) }
6369
}
6470

@@ -199,12 +205,24 @@ public func fn(impl: ImplClass, swiftSub: SwiftSubclass) {
199205
// ObjC calling convention -[ImplClass mainMethod:]
200206
// CHECK-LABEL: define internal void @"$sSo9ImplClassC19objc_implementationE10mainMethodyys5Int32VFTo"
201207

208+
// Swift calling convention -[ImplClass extensionMethod:]
209+
// CHECK-LABEL: define hidden swiftcc void @"$sSo9ImplClassC19objc_implementationE15extensionMethodyys5Int32VF"
210+
211+
// ObjC calling convention -[ImplClass extensionMethod:]
212+
// CHECK-LABEL: define internal void @"$sSo9ImplClassC19objc_implementationE15extensionMethodyys5Int32VFTo"
213+
202214
// Swift calling convention -[ImplClass copyWithZone:]
203215
// CHECK-LABEL: define hidden swiftcc void @"$sSo9ImplClassC19objc_implementationE4copy4withypSg10ObjectiveC6NSZoneVSg_tF"
204216

205217
// ObjC calling convention -[ImplClass copyWithZone:]
206218
// CHECK-LABEL: define internal ptr @"$sSo9ImplClassC19objc_implementationE4copy4withypSg10ObjectiveC6NSZoneVSg_tFTo"
207219

220+
// Swift calling convention -[ImplClass mutableCopyWithZone:]
221+
// CHECK-LABEL: define hidden swiftcc void @"$sSo9ImplClassC19objc_implementationE11mutableCopy4withypSg10ObjectiveC6NSZoneVSg_tF"
222+
223+
// ObjC calling convention -[ImplClass mutableCopyWithZone:]
224+
// CHECK-LABEL: define internal ptr @"$sSo9ImplClassC19objc_implementationE11mutableCopy4withypSg10ObjectiveC6NSZoneVSg_tFTo"
225+
208226
// Swift calling convention -[ImplClass dealloc]
209227
// CHECK-LABEL: define linkonce_odr hidden swiftcc void @"$sSo9ImplClassC19objc_implementationEfD"
210228
// Access in this function should be DirectToStorage

test/Inputs/clang-importer-sdk/usr/include/Foundation.h

+4
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,10 @@ __attribute__((availability(ios,introduced=8.0)))
156156
- (id)copyWithZone:(nullable NSZone *)zone;
157157
@end
158158

159+
@protocol NSMutableCopying
160+
- (id)mutableCopyWithZone:(nullable NSZone *)zone;
161+
@end
162+
159163
@interface NSDictionary<KeyType, ObjectType> : NSObject /*<NSCopying, NSMutableCopying, NSSecureCoding, NSFastEnumeration>*/
160164
@property (readonly) NSUInteger count;
161165
- (nullable ObjectType)objectForKey:(nonnull KeyType)aKey;

test/decl/ext/Inputs/objc_implementation.h

+7
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@
5959

6060
@end
6161

62+
@interface ObjCClass () <NSCopying>
63+
64+
- (void)extensionMethodFromHeader1:(int)param;
65+
- (void)extensionMethodFromHeader2:(int)param;
66+
67+
@end
68+
6269
@interface ObjCClass (PresentAdditions)
6370

6471
- (void)categoryMethodFromHeader1:(int)param;

test/decl/ext/objc_implementation.swift

+10
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ protocol EmptySwiftProto {}
1212
// FIXME: give better diagnostic expected-warning@-6 {{extension for main class interface should provide implementation for instance method 'method(fromHeader3:)'}}
1313
// expected-warning@-7 {{'@_objcImplementation' extension cannot add conformance to 'EmptySwiftProto'; add this conformance with an ordinary extension}}
1414
// expected-warning@-8 {{'@_objcImplementation' extension cannot add conformance to 'EmptyObjCProto'; add this conformance in the Objective-C header}}
15+
// expected-warning@-9 {{extension for main class interface should provide implementation for instance method 'extensionMethod(fromHeader2:)'}}
1516

1617
func method(fromHeader1: CInt) {
1718
// OK, provides an implementation for the header's method.
@@ -215,6 +216,15 @@ protocol EmptySwiftProto {}
215216
@nonobjc public convenience init(notFromHeader6: CInt) {
216217
// OK
217218
}
219+
220+
@objc func extensionMethod(fromHeader1: CInt) {
221+
// OK
222+
}
223+
224+
@objc(copyWithZone:) func copy(with zone: NSZone?) -> Any {
225+
// OK
226+
return self
227+
}
218228
}
219229

220230
@_objcImplementation(PresentAdditions) extension ObjCClass {

test/decl/ext/objc_implementation_conflicts.swift

+5
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,11 @@ import objc_implementation_private
170170

171171
func instanceMethod1(_: CInt) {}
172172
func instanceMethod2(_: CInt) {}
173+
174+
@objc func extensionMethod(fromHeader1: CInt) {}
175+
@objc func extensionMethod(fromHeader2: CInt) {}
176+
177+
@objc(copyWithZone:) func copy(with zone: NSZone?) -> Any { self }
173178
}
174179

175180
@_objcImplementation(PresentAdditions) extension ObjCClass {

0 commit comments

Comments
 (0)