[ObjC Bridging] Consistently bridge block types verbatim

A `@convention(block)` closure in Swift is completely compatible with Objective-C
and does not need to be wrapped in a `__SwiftValue` box for use.

Previously, it was bridged verbatim when appearing by itself, but
could end up boxed when it went through array bridging.

The test verifies that:
* Objective-C does not see a `__SwiftValue` box
* Swift `type(of:)` does not see a `__SwiftValue` box
* Objective-C can actually call the closure

Resolves rdar://138132321
This commit is contained in:
Tim Kientzle
2024-11-08 13:49:21 -08:00
parent bf30a19106
commit c262248a27
5 changed files with 126 additions and 8 deletions

View File

@@ -1289,9 +1289,8 @@ static id bridgeAnythingNonVerbatimToObjectiveC(OpaqueValue *src,
swift_unknownObjectRetain(result);
return result;
}
// Dig through existential types.
if (auto srcExistentialTy = dyn_cast<ExistentialTypeMetadata>(srcType)) {
else if (auto srcExistentialTy = dyn_cast<ExistentialTypeMetadata>(srcType)) {
OpaqueValue *srcInnerValue;
const Metadata *srcInnerType;
bool isOutOfLine;
@@ -1320,10 +1319,9 @@ static id bridgeAnythingNonVerbatimToObjectiveC(OpaqueValue *src,
}
return result;
}
// Handle metatypes.
if (isa<ExistentialMetatypeMetadata>(srcType)
|| isa<MetatypeMetadata>(srcType)) {
// Handle metatypes and existential metatypes
else if (isa<ExistentialMetatypeMetadata>(srcType)
|| isa<MetatypeMetadata>(srcType)) {
const Metadata *srcMetatypeValue;
memcpy(&srcMetatypeValue, src, sizeof(srcMetatypeValue));
@@ -1342,8 +1340,9 @@ static id bridgeAnythingNonVerbatimToObjectiveC(OpaqueValue *src,
return objc_retain(protocolObj);
}
}
}
// Handle bridgeable types.
} else if (auto srcBridgeWitness = findBridgeWitness(srcType)) {
else if (auto srcBridgeWitness = findBridgeWitness(srcType)) {
// Bridge the source value to an object.
auto srcBridgedObject =
srcBridgeWitness->bridgeToObjectiveC(src, srcType, srcBridgeWitness);
@@ -1353,13 +1352,24 @@ static id bridgeAnythingNonVerbatimToObjectiveC(OpaqueValue *src,
srcType->vw_destroy(src);
return (id)srcBridgedObject;
}
// Handle Errors.
} else if (auto srcErrorWitness = findErrorWitness(srcType)) {
else if (auto srcErrorWitness = findErrorWitness(srcType)) {
// Bridge the source value to an NSError.
auto flags = consume ? DynamicCastFlags::TakeOnSuccess
: DynamicCastFlags::Default;
return dynamicCastValueToNSError(src, srcType, srcErrorWitness, flags);
}
// Handle functions: "Block" types can be bridged literally
else if (auto fn = dyn_cast<FunctionTypeMetadata>(srcType)) {
if (fn->getConvention() == FunctionMetadataConvention::Block) {
id result;
memcpy(&result, src, sizeof(id));
if (!consume)
swift_unknownObjectRetain(result);
return result;
}
}
// Fall back to boxing.
return (id)bridgeAnythingToSwiftValueObject(src, srcType, consume);