1212
1313import CoreFoundation
1414
15+ #if canImport(ObjectiveC)
16+ import ObjectiveC
17+ #endif
18+
1519public protocol _StructBridgeable {
1620 func _bridgeToAny( ) -> Any
1721}
1822
23+ fileprivate protocol Unwrappable {
24+ func unwrap( ) -> Any ?
25+ }
26+
27+ extension Optional : Unwrappable {
28+ func unwrap( ) -> Any ? {
29+ return self
30+ }
31+ }
32+
1933/// - Note: This does not exist currently on Darwin but it is the inverse correlation to the bridge types such that a
2034/// reference type can be converted via a callout to a conversion method.
2135public protocol _StructTypeBridgeable : _StructBridgeable {
@@ -54,18 +68,92 @@ internal protocol _NSBridgeable {
5468}
5569
5670
71+ #if !canImport(ObjectiveC)
72+ // The _NSSwiftValue protocol is in the stdlib, and only available on platforms without ObjC.
73+ extension _SwiftValue : _NSSwiftValue { }
74+ #endif
75+
5776/// - Note: This is an internal boxing value for containing abstract structures
58- internal final class _SwiftValue : NSObject , NSCopying , _NSSwiftValue {
77+ internal final class _SwiftValue : NSObject , NSCopying {
5978 public private( set) var value : Any
6079
6180 static func fetch( _ object: AnyObject ? ) -> Any ? {
6281 if let obj = object {
63- return fetch ( nonOptional: obj)
82+ let value = fetch ( nonOptional: obj)
83+ if let wrapper = value as? Unwrappable , wrapper. unwrap ( ) == nil {
84+ return nil
85+ } else {
86+ return value
87+ }
6488 }
6589 return nil
6690 }
6791
92+ #if canImport(ObjectiveC)
93+ private static var _objCNSNullClassStorage : Any . Type ?
94+ private static var objCNSNullClass : Any . Type ? {
95+ if let type = _objCNSNullClassStorage {
96+ return type
97+ }
98+
99+ let name = " NSNull "
100+ let maybeType = name. withCString { cString in
101+ return objc_getClass ( cString)
102+ }
103+
104+ if let type = maybeType as? Any . Type {
105+ _objCNSNullClassStorage = type
106+ return type
107+ } else {
108+ return nil
109+ }
110+ }
111+
112+ private static var _swiftStdlibSwiftValueClassStorage : Any . Type ?
113+ private static var swiftStdlibSwiftValueClass : Any . Type ? {
114+ if let type = _swiftStdlibSwiftValueClassStorage {
115+ return type
116+ }
117+
118+ let name = " _SwiftValue "
119+ let maybeType = name. withCString { cString in
120+ return objc_getClass ( cString)
121+ }
122+
123+ if let type = maybeType as? Any . Type {
124+ _swiftStdlibSwiftValueClassStorage = type
125+ return type
126+ } else {
127+ return nil
128+ }
129+ }
130+
131+ #endif
132+
68133 static func fetch( nonOptional object: AnyObject ) -> Any {
134+ #if canImport(ObjectiveC)
135+ // You can pass the result of a `as AnyObject` expression to this method. This can have one of three results on Darwin:
136+ // - It's a SwiftFoundation type. Bridging will take care of it below.
137+ // - It's nil. The compiler is hardcoded to return [NSNull null] for nils.
138+ // - It's some other Swift type. The compiler will box it in a native _SwiftValue.
139+ // Case 1 is handled below.
140+ // Case 2 is handled here:
141+ if type ( of: object as Any ) == objCNSNullClass {
142+ return Optional < Any > . none as Any
143+ }
144+ // Case 3 is handled here:
145+ if type ( of: object as Any ) == swiftStdlibSwiftValueClass {
146+ return object
147+ // Since this returns Any, the object is casted almost immediately — e.g.:
148+ // _SwiftValue.fetch(x) as SomeStruct
149+ // which will immediately unbox the native box. For callers, it will be exactly
150+ // as if we returned the unboxed value directly.
151+ }
152+
153+ // On Linux, case 2 is handled by the stdlib bridging machinery, and case 3 can't happen —
154+ // the compiler will produce SwiftFoundation._SwiftValue boxes rather than ObjC ones.
155+ #endif
156+
69157 if object === kCFBooleanTrue {
70158 return true
71159 } else if object === kCFBooleanFalse {
@@ -79,6 +167,13 @@ internal final class _SwiftValue : NSObject, NSCopying, _NSSwiftValue {
79167 }
80168 }
81169
170+ static func store( optional value: Any ? ) -> NSObject ? {
171+ if let val = value {
172+ return store ( val)
173+ }
174+ return nil
175+ }
176+
82177 static func store( _ value: Any ? ) -> NSObject ? {
83178 if let val = value {
84179 return store ( val)
@@ -89,8 +184,20 @@ internal final class _SwiftValue : NSObject, NSCopying, _NSSwiftValue {
89184 static func store( _ value: Any ) -> NSObject {
90185 if let val = value as? NSObject {
91186 return val
187+ } else if let opt = value as? Unwrappable , opt. unwrap ( ) == nil {
188+ return NSNull ( )
92189 } else {
93- return ( value as AnyObject ) as! NSObject
190+ #if canImport(ObjectiveC)
191+ // On Darwin, this can be a native (ObjC) _SwiftValue.
192+ let boxed = ( value as AnyObject )
193+ if !( boxed is NSObject ) {
194+ return _SwiftValue ( value) // Do not emit native boxes — wrap them in Swift Foundation boxes instead.
195+ } else {
196+ return boxed as! NSObject
197+ }
198+ #else
199+ return ( value as AnyObject ) as! NSObject
200+ #endif
94201 }
95202 }
96203
0 commit comments