Runtime: Handle bridging from ObjC objects to Any or boxed types.

This commit is contained in:
Joe Groff
2016-07-24 09:01:14 -07:00
parent 32b50c624d
commit b1fb1fa3ea
2 changed files with 101 additions and 23 deletions

View File

@@ -246,6 +246,27 @@ func _bridgeNonVerbatimFromObjectiveC<T>(
_ result: inout T?
)
/// Helper stub to upcast to Any and store the result to an inout Any?
/// on the C++ runtime's behalf.
// COMPILER_INTRINSIC
@_silgen_name("_swift_bridgeNonVerbatimFromObjectiveCToAny")
public func _bridgeNonVerbatimFromObjectiveCToAny(
_ x: AnyObject,
_ result: inout Any?
) {
result = x as Any
}
/// Helper stub to upcast to Optional on the C++ runtime's behalf.
// COMPILER_INTRINSIC
@_silgen_name("_swift_bridgeNonVerbatimBoxedValue")
public func _bridgeNonVerbatimBoxedValue<NativeType>(
_ x: UnsafePointer<NativeType>,
_ result: inout NativeType?
) {
result = x.pointee
}
/// Runtime optional to conditionally perform a bridge from an object to a value
/// type.
///

View File

@@ -2837,6 +2837,60 @@ extern "C" const Metadata *_swift_getBridgedNonVerbatimObjectiveCType(
return nullptr;
}
// @_silgen_name("_swift_bridgeNonVerbatimFromObjectiveCToAny")
// func _bridgeNonVerbatimFromObjectiveCToAny(
// x: AnyObject,
// inout result: Any?
// )
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
extern "C" void
_swift_bridgeNonVerbatimFromObjectiveCToAny(HeapObject *sourceValue,
OpaqueValue *destValue);
// @_silgen_name("_swift_bridgeNonVerbatimBoxedValue")
// func _bridgeNonVerbatimBoxedValue<NativeType>(
// x: UnsafePointer<NativeType>,
// inout result: NativeType?
// )
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
extern "C" void
_swift_bridgeNonVerbatimBoxedValue(const OpaqueValue *sourceValue,
OpaqueValue *destValue,
const Metadata *nativeType);
// Try bridging by conversion to Any or boxing if applicable.
static bool tryBridgeNonVerbatimFromObjectiveCUniversal(
HeapObject *sourceValue,
const Metadata *nativeType,
OpaqueValue *destValue
) {
// If the type is the Any type, we can bridge by "upcasting" the object
// to Any.
if (auto nativeExistential = dyn_cast<ExistentialTypeMetadata>(nativeType)) {
if (nativeExistential->Protocols.NumProtocols == 0) {
_swift_bridgeNonVerbatimFromObjectiveCToAny(sourceValue,
destValue);
return true;
}
}
// Check if the value is a box containing a value of the desired type.
if (auto srcBox = getAsSwiftValue((id)sourceValue)) {
const Metadata *sourceType;
const OpaqueValue *sourceBoxedValue;
std::tie(sourceType, sourceBoxedValue) = getValueFromSwiftValue(srcBox);
if (sourceType == nativeType) {
_swift_bridgeNonVerbatimBoxedValue(sourceBoxedValue,
destValue,
nativeType);
return true;
}
}
return false;
}
// @_silgen_name("_swift_bridgeNonVerbatimFromObjectiveC")
// func _bridgeNonVerbatimFromObjectiveC<NativeType>(
// x: AnyObject,
@@ -2851,12 +2905,12 @@ _swift_bridgeNonVerbatimFromObjectiveC(
OpaqueValue *destValue,
const Metadata *nativeType_
) {
if (tryBridgeNonVerbatimFromObjectiveCUniversal(sourceValue, nativeType,
destValue))
return;
// Check if the type conforms to _BridgedToObjectiveC.
if (const auto *bridgeWitness = findBridgeWitness(nativeType)) {
// if the type also conforms to _ConditionallyBridgedToObjectiveC,
// make sure it bridges at runtime
if (bridgeWitness->isBridgedToObjectiveC(nativeType, nativeType,
bridgeWitness)) {
// Check if sourceValue has the _ObjectiveCType type required by the
// protocol.
const Metadata *objectiveCType =
@@ -2875,7 +2929,6 @@ _swift_bridgeNonVerbatimFromObjectiveC(
return;
}
}
}
// Fail.
swift::crash("value type is not bridged to Objective-C");
@@ -2895,6 +2948,10 @@ _swift_bridgeNonVerbatimFromObjectiveCConditional(
OpaqueValue *destValue,
const Metadata *nativeType_
) {
if (tryBridgeNonVerbatimFromObjectiveCUniversal(sourceValue, nativeType,
destValue))
return true;
// Local function that releases the source and returns false.
auto fail = [&] () -> bool {
swift_unknownRelease(sourceValue);