From 71bc3a52434fc54b39740f3aa999f1c60d81c3a5 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Thu, 23 Jun 2016 20:12:34 -0700 Subject: [PATCH] [ClangImporter] Import 'Class' as 'SomeProto.Type'. 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 --- lib/ClangImporter/ImportType.cpp | 21 ++++----- .../Inputs/custom-modules/Protocols.h | 7 +++ test/ClangModules/objc_ir.swift | 43 +++++++++++++++++++ test/PrintAsObjC/classes.swift | 2 + test/SILGen/objc_ownership_conventions.swift | 10 +++-- 5 files changed, 69 insertions(+), 14 deletions(-) diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index 14ec0d778417e..1b82159c01d2f 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -901,27 +901,28 @@ namespace { return { importedType, ImportHint::ObjCPointer }; } - // If this is id

, turn this into a protocol type. - // FIXME: What about Class

? - if (type->isObjCQualifiedIdType()) { + // If this is id

or Class

, turn this into a protocol type. + if (type->isObjCQualifiedIdType() || type->isObjCQualifiedClassType()) { SmallVector protocols; for (auto cp = type->qual_begin(), cpEnd = type->qual_end(); cp != cpEnd; ++cp) { - auto proto = cast_or_null(Impl.importDecl(*cp, - false)); + auto proto = cast_or_null(Impl.importDecl(*cp, false)); if (!proto) return Type(); protocols.push_back(proto->getDeclaredType()); } - return { ProtocolCompositionType::get(Impl.SwiftContext, protocols), - ImportHint::ObjCPointer }; + Type result = ProtocolCompositionType::get(Impl.SwiftContext, + protocols); + if (type->isObjCQualifiedClassType()) + result = ExistentialMetatypeType::get(result); + + return { result, ImportHint::ObjCPointer }; } // Beyond here, we're using AnyObject. - auto proto = Impl.SwiftContext.getProtocol( - KnownProtocolKind::AnyObject); + auto proto = Impl.SwiftContext.getProtocol(KnownProtocolKind::AnyObject); if (!proto) return Type(); @@ -931,7 +932,7 @@ namespace { } // Class maps to AnyObject.Type. - assert(type->isObjCClassType() || type->isObjCQualifiedClassType()); + assert(type->isObjCClassType()); return { ExistentialMetatypeType::get(proto->getDeclaredType()), ImportHint::ObjCPointer }; } diff --git a/test/ClangModules/Inputs/custom-modules/Protocols.h b/test/ClangModules/Inputs/custom-modules/Protocols.h index 78d97bd10cbb7..43ad828ffe70d 100644 --- a/test/ClangModules/Inputs/custom-modules/Protocols.h +++ b/test/ClangModules/Inputs/custom-modules/Protocols.h @@ -2,3 +2,10 @@ @property int bar; @end +@protocol AnotherProto +@end + +Class _Nonnull processFooType(Class _Nonnull); +Class _Nonnull processComboType(Class _Nonnull); +Class _Nonnull processComboType2(Class _Nonnull); + diff --git a/test/ClangModules/objc_ir.swift b/test/ClangModules/objc_ir.swift index 2b0e053f14f66..7fc775665cee0 100644 --- a/test/ClangModules/objc_ir.swift +++ b/test/ClangModules/objc_ir.swift @@ -110,6 +110,49 @@ func getset(p p: FooProto) { p.bar = prop } +// CHECK-LABEL: define hidden %swift.type* @_TF7objc_ir16protocolMetatypeFT1pPSo8FooProto__PMPS0__(%objc_object*) {{.*}} { +func protocolMetatype(p: FooProto) -> FooProto.Type { + // CHECK: = call %swift.type* @swift_getObjectType(%objc_object* %0) + // CHECK-NOT: {{retain|release}} + // CHECK: [[RAW_RESULT:%.+]] = call i8* @processFooType(i8* {{%.+}}) + // CHECK: [[CASTED_RESULT:%.+]] = bitcast i8* [[RAW_RESULT]] to %objc_class* + // CHECK: [[SWIFT_RESULT:%.+]] = call %swift.type* @swift_getObjCClassMetadata(%objc_class* [[CASTED_RESULT]]) + // CHECK: call void @swift_unknownRelease(%objc_object* %0) + // CHECK: ret %swift.type* [[SWIFT_RESULT]] + let type = processFooType(p.dynamicType) + return type +} // CHECK: } + +class Impl: FooProto, AnotherProto { + @objc var bar: Int32 = 0 +} + +// CHECK-LABEL: define hidden %swift.type* @_TF7objc_ir27protocolCompositionMetatypeFT1pCS_4Impl_PMPSo12AnotherProtoSo8FooProto_(%C7objc_ir4Impl*) {{.*}} { +func protocolCompositionMetatype(p: Impl) -> protocol.Type { + // CHECK: = getelementptr inbounds %C7objc_ir4Impl, %C7objc_ir4Impl* %0, i32 0, i32 0, i32 0 + // CHECK-NOT: {{retain|release}} + // CHECK: [[RAW_RESULT:%.+]] = call i8* @processComboType(i8* {{%.+}}) + // CHECK: [[CASTED_RESULT:%.+]] = bitcast i8* [[RAW_RESULT]] to %objc_class* + // CHECK: [[SWIFT_RESULT:%.+]] = call %swift.type* @swift_getObjCClassMetadata(%objc_class* [[CASTED_RESULT]]) + // CHECK: call void bitcast (void (%swift.refcounted*)* @rt_swift_release to void (%C7objc_ir4Impl*)*)(%C7objc_ir4Impl* %0) + // CHECK: ret %swift.type* [[SWIFT_RESULT]] + let type = processComboType(p.dynamicType) + return type +} // CHECK: } + +// CHECK-LABEL: define hidden %swift.type* @_TF7objc_ir28protocolCompositionMetatype2FT1pCS_4Impl_PMPSo12AnotherProtoSo8FooProto_(%C7objc_ir4Impl*) {{.*}} { +func protocolCompositionMetatype2(p: Impl) -> protocol.Type { + // CHECK: = getelementptr inbounds %C7objc_ir4Impl, %C7objc_ir4Impl* %0, i32 0, i32 0, i32 0 + // CHECK-NOT: {{retain|release}} + // CHECK: [[RAW_RESULT:%.+]] = call i8* @processComboType2(i8* {{%.+}}) + // CHECK: [[CASTED_RESULT:%.+]] = bitcast i8* [[RAW_RESULT]] to %objc_class* + // CHECK: [[SWIFT_RESULT:%.+]] = call %swift.type* @swift_getObjCClassMetadata(%objc_class* [[CASTED_RESULT]]) + // CHECK: call void bitcast (void (%swift.refcounted*)* @rt_swift_release to void (%C7objc_ir4Impl*)*)(%C7objc_ir4Impl* %0) + // CHECK: ret %swift.type* [[SWIFT_RESULT]] + let type = processComboType2(p.dynamicType) + return type +} // CHECK: } + // CHECK-LABEL: define hidden void @_TF7objc_ir17pointerPropertiesFCSo14PointerWrapperT_(%CSo14PointerWrapper*) {{.*}} { func pointerProperties(_ obj: PointerWrapper) { // CHECK: load i8*, i8** @"\01L_selector(setVoidPtr:)" diff --git a/test/PrintAsObjC/classes.swift b/test/PrintAsObjC/classes.swift index 7646ea1cc4183..0959d9c147974 100644 --- a/test/PrintAsObjC/classes.swift +++ b/test/PrintAsObjC/classes.swift @@ -233,6 +233,7 @@ typealias AliasForNSRect = NSRect // CHECK-NEXT: - (NSArray * _Nonnull)emptyArray; // CHECK-NEXT: - (NSArray * _Nullable)maybeArray; // CHECK-NEXT: - (NSRuncingMode)someEnum; +// CHECK-NEXT: - (Class _Nullable)protocolClass; // CHECK-NEXT: - (struct _NSZone * _Nullable)zone; // CHECK-NEXT: - (CFTypeRef _Nullable)cf:(CFTreeRef _Nonnull)x str:(CFStringRef _Nonnull)str str2:(CFMutableStringRef _Nonnull)str2 obj:(CFAliasForTypeRef _Nonnull)obj; // CHECK-NEXT: - (void)appKitInImplementation; @@ -248,6 +249,7 @@ typealias AliasForNSRect = NSRect func maybeArray() -> NSArray? { return nil } func someEnum() -> RuncingMode { return .mince } + func protocolClass() -> NSCoding.Type? { return nil } func zone() -> NSZone? { return nil } diff --git a/test/SILGen/objc_ownership_conventions.swift b/test/SILGen/objc_ownership_conventions.swift index 5b17779af1b7c..820d761383a01 100644 --- a/test/SILGen/objc_ownership_conventions.swift +++ b/test/SILGen/objc_ownership_conventions.swift @@ -116,16 +116,18 @@ func test11(_ g: Gizmo) -> AnyClass { // CHECK: bb0([[G:%[0-9]+]] : $Gizmo): // CHECK: strong_retain [[G]] // CHECK: [[NS_G:%[0-9]+]] = upcast [[G:%[0-9]+]] : $Gizmo to $NSObject - // 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> - // CHECK-NEXT: [[OPT_OBJC:%.*]] = apply [[GETTER]]([[NS_G]]) : $@convention(objc_method) (NSObject) -> ImplicitlyUnwrappedOptional<@objc_metatype AnyObject.Type> + // 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> + // CHECK-NEXT: [[OPT_OBJC:%.*]] = apply [[GETTER]]([[NS_G]]) : $@convention(objc_method) (NSObject) -> ImplicitlyUnwrappedOptional<@objc_metatype NSAnsing.Type> // CHECK: select_enum [[OPT_OBJC]] // CHECK: [[OBJC:%.*]] = unchecked_enum_data [[OPT_OBJC]] // CHECK-NEXT: [[THICK:%.*]] = objc_to_thick_metatype [[OBJC]] - // CHECK: [[T0:%.*]] = enum $ImplicitlyUnwrappedOptional, #ImplicitlyUnwrappedOptional.some!enumelt.1, [[THICK]] + // CHECK: [[T0:%.*]] = enum $ImplicitlyUnwrappedOptional, #ImplicitlyUnwrappedOptional.some!enumelt.1, [[THICK]] // CHECK: [[RES:%.*]] = unchecked_enum_data + // CHECK: [[OPENED:%.*]] = open_existential_metatype [[RES]] + // CHECK: [[RES_ANY:%.*]] = init_existential_metatype [[OPENED]] // CHECK: strong_release [[G]] : $Gizmo // CHECK: strong_release [[G]] : $Gizmo - // CHECK-NEXT: return [[RES]] : $@thick AnyObject.Type + // CHECK-NEXT: return [[RES_ANY]] : $@thick AnyObject.Type return g.qualifiedClassProp }