Introduce _ConditionallyBridgedToObjectiveC.bridgeFromObjectiveCConditional.

This entry point is used in conditional downcasts (as?) to attempt to
bridge from an Objective-C class down to a specific native type (e.g.,
array, dictionary), bridging all elements eagerly so that it can
produce nil if the bridging would fail.

This is the scaffolding for <rdar://problem/17319154>, and makes the
example there work, but there is much more cleanup and optimization to
do.



Swift SVN r18999
This commit is contained in:
Doug Gregor
2014-06-19 14:48:00 +00:00
parent 62cad3dce8
commit 2e3863b211
11 changed files with 223 additions and 7 deletions

View File

@@ -1448,7 +1448,7 @@ struct _BridgedToObjectiveCWitnessTable {
// func bridgeToObjectiveC() -> ObjectiveCType
HeapObject *(*bridgeToObjectiveC)(OpaqueValue *self, const Metadata *Self);
// func bridgeFromObjectiveC(x: ObjectiveCType) -> Self?
// class func bridgeFromObjectiveC(x: ObjectiveCType) -> Self?
OpaqueExistentialContainer (*bridgeFromObjectiveC)(HeapObject *sourceValue,
const Metadata *self,
const Metadata *selfType);
@@ -1466,6 +1466,12 @@ struct _ConditionallyBridgedToObjectiveCWitnessTable {
// class func isBridgedToObjectiveC() -> bool
bool (*isBridgedToObjectiveC)(const Metadata *value, const Metadata *T);
// class func bridgeFromObjectiveCConditional(x: ObjectiveCType) -> Self?
OpaqueExistentialContainer (*bridgeFromObjectiveCConditional)(
HeapObject *sourceValue,
const Metadata *self,
const Metadata *selfType);
};
// }
@@ -1583,6 +1589,56 @@ swift_bridgeNonVerbatimFromObjectiveC(
return _TFSs26_injectNothingIntoOptionalU__FT_GSqQ__(nativeType);
}
// @asmname("swift_bridgeNonVerbatimFromObjectiveCConditional")
// func _bridgeNonVerbatimFromObjectiveCConditional<NativeType>(
// x: AnyObject, nativeType: NativeType.Type
// ) -> NativeType?
extern "C" OpaqueExistentialContainer
swift_bridgeNonVerbatimFromObjectiveCConditional(
HeapObject *sourceValue,
const Metadata *nativeType,
const Metadata *nativeType_
) {
// Local function that releases the source and produces a nil.
auto produceNil = [&] () -> OpaqueExistentialContainer {
swift_unknownRelease(sourceValue);
return _TFSs26_injectNothingIntoOptionalU__FT_GSqQ__(nativeType);
};
// Check if the type conforms to _BridgedToObjectiveC.
const auto *bridgeWitness = findBridgeWitness(nativeType);
if (!bridgeWitness)
return produceNil();
// Dig out the Objective-C class type through which the native type
// is bridged.
const Metadata *objectiveCType =
bridgeWitness->getObjectiveCType(nativeType, nativeType);
// Check whether we can downcast the source value to the Objective-C
// type.
auto sourceValueAsObjectiveCType =
const_cast<void*>(swift_dynamicCastUnknownClass(sourceValue,
objectiveCType));
if (!sourceValueAsObjectiveCType)
return produceNil();
// If the type also conforms to _ConditionallyBridgedToObjectiveC,
// use conditional bridging.
if (auto conditionalWitness = findConditionalBridgeWitness(nativeType)) {
return conditionalWitness->bridgeFromObjectiveCConditional(
static_cast<HeapObject*>(sourceValueAsObjectiveCType),
nativeType, nativeType);
}
// Perform direct bridging. bridgeFromObjectiveC returns `Self?`;
// this function returns `NativeType`, so we don't need to re-wrap
// the optional.
return bridgeWitness->bridgeFromObjectiveC(
static_cast<HeapObject*>(sourceValueAsObjectiveCType),
nativeType, nativeType);
}
// func isBridgedNonVerbatimToObjectiveC<T>(x: T.Type) -> Bool
extern "C" bool swift_isBridgedNonVerbatimToObjectiveC(
const Metadata *value, const Metadata *T