Skip to content

Commit ba384fe

Browse files
authored
[ClangImporter] Import 'Class<SomeProto>' as 'SomeProto.Type'. (#3185)
Swift has supported this for a long time using manual casts and going from Swift to Objective-C; just enable it now for the importer. rdar://problem/15101588
1 parent 5635545 commit ba384fe

File tree

5 files changed

+69
-14
lines changed

5 files changed

+69
-14
lines changed

lib/ClangImporter/ImportType.cpp

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -901,27 +901,28 @@ namespace {
901901
return { importedType, ImportHint::ObjCPointer };
902902
}
903903

904-
// If this is id<P>, turn this into a protocol type.
905-
// FIXME: What about Class<P>?
906-
if (type->isObjCQualifiedIdType()) {
904+
// If this is id<P> or Class<P>, turn this into a protocol type.
905+
if (type->isObjCQualifiedIdType() || type->isObjCQualifiedClassType()) {
907906
SmallVector<Type, 4> protocols;
908907
for (auto cp = type->qual_begin(), cpEnd = type->qual_end();
909908
cp != cpEnd; ++cp) {
910-
auto proto = cast_or_null<ProtocolDecl>(Impl.importDecl(*cp,
911-
false));
909+
auto proto = cast_or_null<ProtocolDecl>(Impl.importDecl(*cp, false));
912910
if (!proto)
913911
return Type();
914912

915913
protocols.push_back(proto->getDeclaredType());
916914
}
917915

918-
return { ProtocolCompositionType::get(Impl.SwiftContext, protocols),
919-
ImportHint::ObjCPointer };
916+
Type result = ProtocolCompositionType::get(Impl.SwiftContext,
917+
protocols);
918+
if (type->isObjCQualifiedClassType())
919+
result = ExistentialMetatypeType::get(result);
920+
921+
return { result, ImportHint::ObjCPointer };
920922
}
921923

922924
// Beyond here, we're using AnyObject.
923-
auto proto = Impl.SwiftContext.getProtocol(
924-
KnownProtocolKind::AnyObject);
925+
auto proto = Impl.SwiftContext.getProtocol(KnownProtocolKind::AnyObject);
925926
if (!proto)
926927
return Type();
927928

@@ -931,7 +932,7 @@ namespace {
931932
}
932933

933934
// Class maps to AnyObject.Type.
934-
assert(type->isObjCClassType() || type->isObjCQualifiedClassType());
935+
assert(type->isObjCClassType());
935936
return { ExistentialMetatypeType::get(proto->getDeclaredType()),
936937
ImportHint::ObjCPointer };
937938
}

test/ClangModules/Inputs/custom-modules/Protocols.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,10 @@
22
@property int bar;
33
@end
44

5+
@protocol AnotherProto
6+
@end
7+
8+
Class <FooProto> _Nonnull processFooType(Class <FooProto> _Nonnull);
9+
Class <FooProto, AnotherProto> _Nonnull processComboType(Class <FooProto, AnotherProto> _Nonnull);
10+
Class <AnotherProto, FooProto> _Nonnull processComboType2(Class <AnotherProto, FooProto> _Nonnull);
11+

test/ClangModules/objc_ir.swift

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,49 @@ func getset(p p: FooProto) {
110110
p.bar = prop
111111
}
112112

113+
// CHECK-LABEL: define hidden %swift.type* @_TF7objc_ir16protocolMetatypeFT1pPSo8FooProto__PMPS0__(%objc_object*) {{.*}} {
114+
func protocolMetatype(p: FooProto) -> FooProto.Type {
115+
// CHECK: = call %swift.type* @swift_getObjectType(%objc_object* %0)
116+
// CHECK-NOT: {{retain|release}}
117+
// CHECK: [[RAW_RESULT:%.+]] = call i8* @processFooType(i8* {{%.+}})
118+
// CHECK: [[CASTED_RESULT:%.+]] = bitcast i8* [[RAW_RESULT]] to %objc_class*
119+
// CHECK: [[SWIFT_RESULT:%.+]] = call %swift.type* @swift_getObjCClassMetadata(%objc_class* [[CASTED_RESULT]])
120+
// CHECK: call void @swift_unknownRelease(%objc_object* %0)
121+
// CHECK: ret %swift.type* [[SWIFT_RESULT]]
122+
let type = processFooType(p.dynamicType)
123+
return type
124+
} // CHECK: }
125+
126+
class Impl: FooProto, AnotherProto {
127+
@objc var bar: Int32 = 0
128+
}
129+
130+
// CHECK-LABEL: define hidden %swift.type* @_TF7objc_ir27protocolCompositionMetatypeFT1pCS_4Impl_PMPSo12AnotherProtoSo8FooProto_(%C7objc_ir4Impl*) {{.*}} {
131+
func protocolCompositionMetatype(p: Impl) -> protocol<FooProto, AnotherProto>.Type {
132+
// CHECK: = getelementptr inbounds %C7objc_ir4Impl, %C7objc_ir4Impl* %0, i32 0, i32 0, i32 0
133+
// CHECK-NOT: {{retain|release}}
134+
// CHECK: [[RAW_RESULT:%.+]] = call i8* @processComboType(i8* {{%.+}})
135+
// CHECK: [[CASTED_RESULT:%.+]] = bitcast i8* [[RAW_RESULT]] to %objc_class*
136+
// CHECK: [[SWIFT_RESULT:%.+]] = call %swift.type* @swift_getObjCClassMetadata(%objc_class* [[CASTED_RESULT]])
137+
// CHECK: call void bitcast (void (%swift.refcounted*)* @rt_swift_release to void (%C7objc_ir4Impl*)*)(%C7objc_ir4Impl* %0)
138+
// CHECK: ret %swift.type* [[SWIFT_RESULT]]
139+
let type = processComboType(p.dynamicType)
140+
return type
141+
} // CHECK: }
142+
143+
// CHECK-LABEL: define hidden %swift.type* @_TF7objc_ir28protocolCompositionMetatype2FT1pCS_4Impl_PMPSo12AnotherProtoSo8FooProto_(%C7objc_ir4Impl*) {{.*}} {
144+
func protocolCompositionMetatype2(p: Impl) -> protocol<FooProto, AnotherProto>.Type {
145+
// CHECK: = getelementptr inbounds %C7objc_ir4Impl, %C7objc_ir4Impl* %0, i32 0, i32 0, i32 0
146+
// CHECK-NOT: {{retain|release}}
147+
// CHECK: [[RAW_RESULT:%.+]] = call i8* @processComboType2(i8* {{%.+}})
148+
// CHECK: [[CASTED_RESULT:%.+]] = bitcast i8* [[RAW_RESULT]] to %objc_class*
149+
// CHECK: [[SWIFT_RESULT:%.+]] = call %swift.type* @swift_getObjCClassMetadata(%objc_class* [[CASTED_RESULT]])
150+
// CHECK: call void bitcast (void (%swift.refcounted*)* @rt_swift_release to void (%C7objc_ir4Impl*)*)(%C7objc_ir4Impl* %0)
151+
// CHECK: ret %swift.type* [[SWIFT_RESULT]]
152+
let type = processComboType2(p.dynamicType)
153+
return type
154+
} // CHECK: }
155+
113156
// CHECK-LABEL: define hidden void @_TF7objc_ir17pointerPropertiesFCSo14PointerWrapperT_(%CSo14PointerWrapper*) {{.*}} {
114157
func pointerProperties(_ obj: PointerWrapper) {
115158
// CHECK: load i8*, i8** @"\01L_selector(setVoidPtr:)"

test/PrintAsObjC/classes.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ typealias AliasForNSRect = NSRect
233233
// CHECK-NEXT: - (NSArray * _Nonnull)emptyArray;
234234
// CHECK-NEXT: - (NSArray * _Nullable)maybeArray;
235235
// CHECK-NEXT: - (NSRuncingMode)someEnum;
236+
// CHECK-NEXT: - (Class <NSCoding> _Nullable)protocolClass;
236237
// CHECK-NEXT: - (struct _NSZone * _Nullable)zone;
237238
// CHECK-NEXT: - (CFTypeRef _Nullable)cf:(CFTreeRef _Nonnull)x str:(CFStringRef _Nonnull)str str2:(CFMutableStringRef _Nonnull)str2 obj:(CFAliasForTypeRef _Nonnull)obj;
238239
// CHECK-NEXT: - (void)appKitInImplementation;
@@ -248,6 +249,7 @@ typealias AliasForNSRect = NSRect
248249
func maybeArray() -> NSArray? { return nil }
249250

250251
func someEnum() -> RuncingMode { return .mince }
252+
func protocolClass() -> NSCoding.Type? { return nil }
251253

252254
func zone() -> NSZone? { return nil }
253255

test/SILGen/objc_ownership_conventions.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,16 +116,18 @@ func test11(_ g: Gizmo) -> AnyClass {
116116
// CHECK: bb0([[G:%[0-9]+]] : $Gizmo):
117117
// CHECK: strong_retain [[G]]
118118
// CHECK: [[NS_G:%[0-9]+]] = upcast [[G:%[0-9]+]] : $Gizmo to $NSObject
119-
// CHECK: [[GETTER:%[0-9]+]] = class_method [volatile] [[NS_G]] : $NSObject, #NSObject.qualifiedClassProp!getter.1.foreign : NSObject -> () -> AnyObject.Type! , $@convention(objc_method) (NSObject) -> ImplicitlyUnwrappedOptional<@objc_metatype AnyObject.Type>
120-
// CHECK-NEXT: [[OPT_OBJC:%.*]] = apply [[GETTER]]([[NS_G]]) : $@convention(objc_method) (NSObject) -> ImplicitlyUnwrappedOptional<@objc_metatype AnyObject.Type>
119+
// CHECK: [[GETTER:%[0-9]+]] = class_method [volatile] [[NS_G]] : $NSObject, #NSObject.qualifiedClassProp!getter.1.foreign : NSObject -> () -> NSAnsing.Type! , $@convention(objc_method) (NSObject) -> ImplicitlyUnwrappedOptional<@objc_metatype NSAnsing.Type>
120+
// CHECK-NEXT: [[OPT_OBJC:%.*]] = apply [[GETTER]]([[NS_G]]) : $@convention(objc_method) (NSObject) -> ImplicitlyUnwrappedOptional<@objc_metatype NSAnsing.Type>
121121
// CHECK: select_enum [[OPT_OBJC]]
122122
// CHECK: [[OBJC:%.*]] = unchecked_enum_data [[OPT_OBJC]]
123123
// CHECK-NEXT: [[THICK:%.*]] = objc_to_thick_metatype [[OBJC]]
124-
// CHECK: [[T0:%.*]] = enum $ImplicitlyUnwrappedOptional<AnyObject.Type>, #ImplicitlyUnwrappedOptional.some!enumelt.1, [[THICK]]
124+
// CHECK: [[T0:%.*]] = enum $ImplicitlyUnwrappedOptional<NSAnsing.Type>, #ImplicitlyUnwrappedOptional.some!enumelt.1, [[THICK]]
125125
// CHECK: [[RES:%.*]] = unchecked_enum_data
126+
// CHECK: [[OPENED:%.*]] = open_existential_metatype [[RES]]
127+
// CHECK: [[RES_ANY:%.*]] = init_existential_metatype [[OPENED]]
126128
// CHECK: strong_release [[G]] : $Gizmo
127129
// CHECK: strong_release [[G]] : $Gizmo
128-
// CHECK-NEXT: return [[RES]] : $@thick AnyObject.Type
130+
// CHECK-NEXT: return [[RES_ANY]] : $@thick AnyObject.Type
129131
return g.qualifiedClassProp
130132
}
131133

0 commit comments

Comments
 (0)