-
Notifications
You must be signed in to change notification settings - Fork 10.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ObjC Bridging] Consistently bridge block types verbatim #77496
Conversation
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
// Dig through existential types. | ||
if (auto srcExistentialTy = dyn_cast<ExistentialTypeMetadata>(srcType)) { | ||
else if (auto srcExistentialTy = dyn_cast<ExistentialTypeMetadata>(srcType)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function has always been a long if-else chain; I've reformatted it some to make that a bit more explicit.
I've also adjusted the comment layout to hopefully make it clearer:
// Explain first if
if (...) {
...
}
// Explain second if
else if (....) {
...
}
// Explain third if
else if (...) {
...
}
// 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)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the new case: If this is a function type with a block convention, then bridge it verbatim.
CastsTests.test("block closures in array should bridge without __SwiftValue") | ||
{ | ||
let f: @convention(block) () -> Void = {} | ||
let x = ([f] as NSArray)[0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test does NSArray
bridging explicitly here, but the bug also manifests when a Swift array is implicitly bridged to NSArray when calling Obj-C code.
|
||
#import "Cast_Blocks.h" | ||
|
||
BOOL ObjCThinksObjectIsSwiftValue(id obj) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's important to verify that Objective-C really does see what we expect.
@swift-ci Please test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One possible optimization, but looks good.
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:
__SwiftValue
boxtype(of:)
does not see a__SwiftValue
boxResolves rdar://138132321