Skip to content

Commit 7d089a9

Browse files
committed
IRGen: Map bridged container types to their specific ObjC Clang types.
When used in @objc protocol requirements, properties, or blocks, frameworks like JSCore expect the extended type encodings to accurately reflect the class of the parameters and returns. Fixes rdar://problem/19519390. Swift SVN r28582
1 parent d1e202b commit 7d089a9

File tree

5 files changed

+93
-15
lines changed

5 files changed

+93
-15
lines changed

lib/IRGen/GenClangType.cpp

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,44 @@ clang::CanQualType GenClangType::visitBoundGenericClassType(
224224
return getClangIdType(getClangASTContext());
225225
}
226226

227+
static clang::CanQualType
228+
getClangFoundationClassType(IRGenModule &IGM, StringRef name) {
229+
auto &ctx = IGM.getClangASTContext();
230+
// Fallback to returning the "id" type if the class type cannot be found.
231+
auto id = [&]() -> clang::CanQualType {
232+
return getClangIdType(ctx);
233+
};
234+
235+
auto *Foundation = IGM.Context.getLoadedModule(IGM.Context.Id_Foundation);
236+
if (!Foundation)
237+
return id();
238+
239+
auto identifier = IGM.Context.getIdentifier(name);
240+
SmallVector<ValueDecl *, 1> results;
241+
Foundation->lookupQualified(Foundation->getType(),
242+
identifier,
243+
NL_QualifiedDefault, nullptr,
244+
results);
245+
for (auto result : results) {
246+
// If we found a type with a clang node, get its declared class type.
247+
auto clangNode = result->getClangNode();
248+
if (!clangNode)
249+
continue;
250+
251+
auto clangInterface = dyn_cast_or_null<clang::ObjCInterfaceDecl>
252+
(clangNode.getAsDecl());
253+
254+
if (!clangInterface)
255+
continue;
256+
257+
auto type = ctx.getObjCInterfaceType(clangInterface);
258+
type = ctx.getObjCObjectPointerType(type);
259+
return ctx.getCanonicalType(type);
260+
}
261+
262+
return id();
263+
}
264+
227265
clang::CanQualType
228266
GenClangType::visitBoundGenericType(CanBoundGenericType type) {
229267
// We only expect *Pointer<T>, ImplicitlyUnwrappedOptional<T>, and Optional<T>.
@@ -284,9 +322,11 @@ GenClangType::visitBoundGenericType(CanBoundGenericType type) {
284322
}
285323

286324
case StructKind::Array:
325+
return getClangFoundationClassType(IGM, "NSArray");
287326
case StructKind::Dictionary:
327+
return getClangFoundationClassType(IGM, "NSDictionary");
288328
case StructKind::Set:
289-
return getClangIdType(getClangASTContext());
329+
return getClangFoundationClassType(IGM, "NSSet");
290330

291331
case StructKind::CFunctionPointer: {
292332
auto &clangCtx = getClangASTContext();
@@ -593,8 +633,8 @@ void ClangTypeConverter::fillSpeciallyImportedTypeCache(IRGenModule &IGM) {
593633
// probably be const char* for type encoding.
594634
CACHE_STDLIB_TYPE("CString", ctx.VoidPtrTy);
595635

596-
// We import NSString* (an Obj-C object pointer) as String.
597-
CACHE_STDLIB_TYPE("String", getClangIdType(ctx));
636+
// We import NSString* as String.
637+
CACHE_STDLIB_TYPE("String", getClangFoundationClassType(IGM, "NSString"));
598638

599639
CACHE_STDLIB_TYPE("CVaListPointer", getClangDecayedVaListType(ctx));
600640

test/IRGen/Inputs/Foundation.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,30 @@
33

44
@exported import ObjectiveC
55

6+
extension NSObject: Hashable {
7+
public var hashValue: Int { return 0 }
8+
}
9+
public func ==(x: NSObject, y: NSObject) -> Bool { return x === y }
10+
611
// String/NSString bridging functions.
712
@asmname("swift_StringToNSString") internal
813
func _convertStringToNSString(string: String) -> NSString
914

1015
@asmname("swift_NSStringToString") internal
1116
func _convertNSStringToString(nsstring: NSString?) -> String
1217

18+
@asmname("swift_ArrayToNSArray") internal
19+
func _convertArrayToNSArray<T>(array: Array<T>) -> NSArray
20+
21+
@asmname("swift_NSArrayToArray") internal
22+
func _convertNSArrayToArray<T>(nsstring: NSArray?) -> Array<T>
23+
24+
@asmname("swift_DictionaryToNSDictionary") internal
25+
func _convertDictionaryToNSDictionary<K: Hashable, V>(array: Dictionary<K, V>) -> NSDictionary
26+
27+
@asmname("swift_NSDictionaryToDictionary") internal
28+
func _convertNSDictionaryToDictionary<K: Hashable, V>(nsstring: NSDictionary?) -> Dictionary<K, V>
29+
1330
// NSSet bridging entry points
1431
func _convertSetToNSSet<T: Hashable>(s: Set<T>) -> NSSet {
1532
return NSSet()

test/IRGen/objc_bridge.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ extension NSString {
142142
func nsstrArg(#s: NSString) { }
143143
}
144144

145-
class Bas : NSObject, Hashable {
145+
class Bas : NSObject {
146146
// CHECK: define internal [[OPAQUE:.*]]* @_TToFC11objc_bridge3Basg11strRealPropSS([[OPAQUE:.*]]*, i8*) unnamed_addr {{.*}} {
147147
// CHECK: define internal void @_TToFC11objc_bridge3Bass11strRealPropSS([[OPAQUE:.*]]*, i8*, [[OPAQUE:.*]]*) unnamed_addr {{.*}} {
148148
var strRealProp : String
@@ -187,7 +187,7 @@ class Bas : NSObject, Hashable {
187187

188188
deinit { var x = 10 }
189189

190-
var hashValue: Int { return 0 }
190+
override var hashValue: Int { return 0 }
191191

192192
func acceptSet(set: Set<Bas>) { }
193193
}

test/IRGen/objc_methods.swift

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
1-
// RUN: %target-swift-frontend %s -emit-ir -disable-objc-attr-requires-foundation-module | FileCheck %s
1+
// RUN: rm -rf %t && mkdir %t
2+
// RUN: %build-irgen-test-overlays
3+
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -primary-file %s -emit-ir | FileCheck %s
24

35
// REQUIRES: CPU=x86_64
46
// REQUIRES: objc_interop
57

8+
import Foundation
9+
610
// Protocol methods require extended method type encodings to capture block
7-
// signatures.
11+
// signatures and parameter object types.
812
@objc protocol Fooable {
913
func block(_: Int -> Int)
1014
func block2(_: (Int,Int) -> Int)
15+
16+
func takesString(_: String) -> String
17+
func takesArray(_: [AnyObject]) -> [AnyObject]
18+
func takesDict(_: [NSObject: AnyObject]) -> [NSObject: AnyObject]
19+
func takesSet(_: Set<NSObject>) -> Set<NSObject>
1120
}
1221

1322
class Foo: Fooable {
@@ -16,23 +25,36 @@ class Foo: Fooable {
1625
@IBAction func garply(_: AnyObject?) {}
1726
@objc func block(_: Int -> Int) {}
1827
@objc func block2(_: (Int,Int) -> Int) {}
28+
29+
@objc func takesString(x: String) -> String { return x }
30+
@objc func takesArray(x: [AnyObject]) -> [AnyObject] { return x }
31+
@objc func takesDict(x: [NSObject: AnyObject]) -> [NSObject: AnyObject] { return x }
32+
@objc func takesSet(x: Set<NSObject>) -> Set<NSObject> { return x }
1933
}
2034

2135
// CHECK: [[BLOCK_SIGNATURE_TRAD:@.*]] = private unnamed_addr constant [12 x i8] c"v24@0:8@?16\00"
2236
// CHECK: [[BLOCK_SIGNATURE_EXT_1:@.*]] = private unnamed_addr constant [18 x i8] c"v24@0:8@?<q@?q>16\00"
2337
// CHECK: [[BLOCK_SIGNATURE_EXT_2:@.*]] = private unnamed_addr constant [19 x i8] c"v24@0:8@?<q@?qq>16\00"
24-
// CHECK: @_PROTOCOL_METHOD_TYPES__TtP12objc_methods7Fooable_ = private constant { [2 x i8*] } {
25-
// CHECK: [2 x i8*] [
26-
// CHECK: i8* getelementptr inbounds ([18 x i8], [18 x i8]* [[BLOCK_SIGNATURE_EXT_1]], i64 0, i64 0),
38+
// CHECK: [[STRING_SIGNATURE_EXT:@.*]] = private unnamed_addr constant [31 x i8] c"@\22NSString\2224@0:8@\22NSString\2216\00"
39+
// CHECK: [[ARRAY_SIGNATURE_EXT:@.*]] = private unnamed_addr constant [29 x i8] c"@\22NSArray\2224@0:8@\22NSArray\2216\00"
40+
// CHECK: [[DICT_SIGNATURE_EXT:@.*]] = private unnamed_addr constant [39 x i8] c"@\22NSDictionary\2224@0:8@\22NSDictionary\2216\00"
41+
// CHECK: [[SET_SIGNATURE_EXT:@.*]] = private unnamed_addr constant [25 x i8] c"@\22NSSet\2224@0:8@\22NSSet\2216\00"
42+
// CHECK: @_PROTOCOL_METHOD_TYPES__TtP12objc_methods7Fooable_ = private constant { [6 x i8*] } {
43+
// CHECK: [6 x i8*] [
44+
// CHECK: i8* getelementptr inbounds ([18 x i8], [18 x i8]* [[BLOCK_SIGNATURE_EXT_1]], i64 0, i64 0)
2745
// CHECK: i8* getelementptr inbounds ([19 x i8], [19 x i8]* [[BLOCK_SIGNATURE_EXT_2]], i64 0, i64 0)
46+
// CHECK: i8* getelementptr inbounds ([31 x i8], [31 x i8]* [[STRING_SIGNATURE_EXT]], i64 0, i64 0)
47+
// CHECK: i8* getelementptr inbounds ([29 x i8], [29 x i8]* [[ARRAY_SIGNATURE_EXT]], i64 0, i64 0)
48+
// CHECK: i8* getelementptr inbounds ([39 x i8], [39 x i8]* [[DICT_SIGNATURE_EXT]], i64 0, i64 0)
49+
// CHECK: i8* getelementptr inbounds ([25 x i8], [25 x i8]* [[SET_SIGNATURE_EXT]], i64 0, i64 0)
2850
// CHECK: ]
2951
// CHECK: }
3052
// CHECK: [[BAZ_SIGNATURE:@.*]] = private unnamed_addr constant [8 x i8] c"v16@0:8\00"
3153
// CHECK: [[GARPLY_SIGNATURE:@.*]] = private unnamed_addr constant [11 x i8] c"v24@0:8@16\00"
3254
// CHECK: @_INSTANCE_METHODS__TtC12objc_methods3Foo = private constant { {{.*}}] } {
3355
// CHECK: i32 24,
34-
// CHECK: i32 4,
35-
// CHECK: [4 x { i8*, i8*, i8* }] [{
56+
// CHECK: i32 8,
57+
// CHECK: [8 x { i8*, i8*, i8* }] [{
3658
// CHECK: i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01L_selector_data(baz)", i64 0, i64 0),
3759
// CHECK: i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[BAZ_SIGNATURE]], i64 0, i64 0),
3860
// CHECK: i8* bitcast (void (i8*, i8*)* @_TToFC12objc_methods3Foo3bazfS0_FT_T_ to i8*)
@@ -52,7 +74,6 @@ class Foo: Fooable {
5274
// CHECK: }, section "__DATA, __objc_const", align 8
5375

5476

55-
5677
// rdar://16006333 - observing properties don't work in @objc classes
5778
@objc
5879
class ObservingAccessorTest {

test/IRGen/objc_property_attrs.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ class Foo: NSManagedObject {
4848
// -- Bridged value types
4949

5050
// nonatomic, copy, ivar k
51-
// CHECK: private unnamed_addr constant {{.*}} c"T@,N,C,Vk\00"
51+
// CHECK: private unnamed_addr constant {{.*}} c"T@\22NSString\22,N,C,Vk\00"
5252
var k: String = ""
5353
// nonatomic, readonly, ivar l
54-
// CHECK: private unnamed_addr constant {{.*}} c"T@,N,R,Vl\00"
54+
// CHECK: private unnamed_addr constant {{.*}} c"T@\22NSString\22,N,R,Vl\00"
5555
let l: String? = nil
5656
}

0 commit comments

Comments
 (0)