[SILGen] Implement NSString -> String bridging through _ObjectiveCBridgeable.

Introduce a new entrypoint to _ObjectiveCBridgeable,
_unconditionallyBridgeFromObjectiveC, which handles unconditional
bridging from an optional Objective-C object (e.g., an NSString) to
its bridged Swift type. Use it in SILGen to perform NSString -> String
bridging rather than the custom entry point.

Another small step toward generalized bridging.
This commit is contained in:
Doug Gregor
2016-03-14 10:35:31 -07:00
parent eb95589624
commit aa9cc23743
15 changed files with 414 additions and 62 deletions

View File

@@ -162,6 +162,15 @@ extension String : _ObjectiveCBridgeable {
self._forceBridgeFromObjectiveC(x, result: &result)
return result != nil
}
public static func _unconditionallyBridgeFromObjectiveC(
source: NSString?
) -> String {
// `nil` has historically been used as a stand-in for an empty
// string; map it to an empty string.
if _slowPath(source == nil) { return String() }
return String(source!)
}
}
//===----------------------------------------------------------------------===//
@@ -204,6 +213,12 @@ extension Int : _ObjectiveCBridgeable {
self._forceBridgeFromObjectiveC(x, result: &result)
return true
}
public static func _unconditionallyBridgeFromObjectiveC(
source: NSNumber?
) -> Int {
return source!.integerValue
}
}
extension UInt : _ObjectiveCBridgeable {
@@ -230,6 +245,7 @@ extension UInt : _ObjectiveCBridgeable {
) {
result = x.unsignedIntegerValue
}
public static func _conditionallyBridgeFromObjectiveC(
x: NSNumber,
result: inout UInt?
@@ -237,6 +253,12 @@ extension UInt : _ObjectiveCBridgeable {
self._forceBridgeFromObjectiveC(x, result: &result)
return true
}
public static func _unconditionallyBridgeFromObjectiveC(
source: NSNumber?
) -> UInt {
return source!.unsignedIntegerValue
}
}
extension Float : _ObjectiveCBridgeable {
@@ -271,6 +293,12 @@ extension Float : _ObjectiveCBridgeable {
self._forceBridgeFromObjectiveC(x, result: &result)
return true
}
public static func _unconditionallyBridgeFromObjectiveC(
source: NSNumber?
) -> Float {
return source!.floatValue
}
}
extension Double : _ObjectiveCBridgeable {
@@ -305,6 +333,12 @@ extension Double : _ObjectiveCBridgeable {
self._forceBridgeFromObjectiveC(x, result: &result)
return true
}
public static func _unconditionallyBridgeFromObjectiveC(
source: NSNumber?
) -> Double {
return source!.doubleValue
}
}
extension Bool: _ObjectiveCBridgeable {
@@ -339,6 +373,12 @@ extension Bool: _ObjectiveCBridgeable {
self._forceBridgeFromObjectiveC(x, result: &result)
return true
}
public static func _unconditionallyBridgeFromObjectiveC(
source: NSNumber?
) -> Bool {
return source!.boolValue
}
}
// CGFloat bridging.
@@ -376,6 +416,13 @@ extension CGFloat : _ObjectiveCBridgeable {
self._forceBridgeFromObjectiveC(x, result: &result)
return true
}
public static func _unconditionallyBridgeFromObjectiveC(
source: NSNumber?
) -> CGFloat {
return CGFloat(
CGFloat.NativeType._unconditionallyBridgeFromObjectiveC(source))
}
}
// Literal support for NSNumber
@@ -512,6 +559,31 @@ extension Array : _ObjectiveCBridgeable {
result = _arrayConditionalCast(anyObjectArr)
return result != nil
}
public static func _unconditionallyBridgeFromObjectiveC(
source: NSArray?
) -> Array {
_precondition(
Swift._isBridgedToObjectiveC(Element.self),
"array element type is not bridged to Objective-C")
// `nil` has historically been used as a stand-in for an empty
// array; map it to an empty array instead of failing.
if _slowPath(source == nil) { return Array() }
// If we have the appropriate native storage already, just adopt it.
if let native =
Array._bridgeFromObjectiveCAdoptingNativeStorageOf(source!) {
return native
}
if _fastPath(_isBridgedVerbatimToObjectiveC(Element.self)) {
// Forced down-cast (possible deferred type-checking)
return Array(_cocoaArray: source!)
}
return _arrayForceCast([AnyObject](_cocoaArray: source!))
}
}
//===----------------------------------------------------------------------===//
@@ -662,6 +734,37 @@ extension Dictionary : _ObjectiveCBridgeable {
return Swift._isBridgedToObjectiveC(Key.self) &&
Swift._isBridgedToObjectiveC(Value.self)
}
public static func _unconditionallyBridgeFromObjectiveC(
d: NSDictionary?
) -> Dictionary {
// `nil` has historically been used as a stand-in for an empty
// dictionary; map it to an empty dictionary.
if _slowPath(d == nil) { return Dictionary() }
if let native = [Key : Value]._bridgeFromObjectiveCAdoptingNativeStorageOf(
d! as AnyObject) {
return native
}
if _isBridgedVerbatimToObjectiveC(Key.self) &&
_isBridgedVerbatimToObjectiveC(Value.self) {
return [Key : Value](
_cocoaDictionary: unsafeBitCast(d!, to: _NSDictionary.self))
}
// `Dictionary<Key, Value>` where either `Key` or `Value` is a value type
// may not be backed by an NSDictionary.
var builder = _DictionaryBuilder<Key, Value>(count: d!.count)
d!.enumerateKeysAndObjects({
(anyObjectKey: AnyObject, anyObjectValue: AnyObject,
stop: UnsafeMutablePointer<ObjCBool>) in
builder.add(
key: Swift._forceBridgeFromObjectiveC(anyObjectKey, Key.self),
value: Swift._forceBridgeFromObjectiveC(anyObjectValue, Value.self))
})
return builder.take()
}
}
//===----------------------------------------------------------------------===//
@@ -909,6 +1012,32 @@ extension Set : _ObjectiveCBridgeable {
return result != nil
}
public static func _unconditionallyBridgeFromObjectiveC(s: NSSet?) -> Set {
// `nil` has historically been used as a stand-in for an empty
// set; map it to an empty set.
if _slowPath(s == nil) { return Set() }
if let native =
Set<Element>._bridgeFromObjectiveCAdoptingNativeStorageOf(s! as AnyObject) {
return native
}
if _isBridgedVerbatimToObjectiveC(Element.self) {
return Set<Element>(_cocoaSet: unsafeBitCast(s!, to: _NSSet.self))
}
// `Set<Element>` where `Element` is a value type may not be backed by
// an NSSet.
var builder = _SetBuilder<Element>(count: s!.count)
s!.enumerateObjects({
(anyObjectMember: AnyObject, stop: UnsafeMutablePointer<ObjCBool>) in
builder.add(member: Swift._forceBridgeFromObjectiveC(
anyObjectMember, Element.self))
})
return builder.take()
}
public static func _isBridgedToObjectiveC() -> Bool {
return Swift._isBridgedToObjectiveC(Element.self)
}