-
Notifications
You must be signed in to change notification settings - Fork 10.5k
SE-0139: NSValue bridging #4865
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
Conversation
We need the encode string to be able to construct NSValues using the core valueWithBytes:objCType: API. This builtin only works with concrete, @objc-representable types for now, which should be sufficient for a stdlib-internal API.
@swift-ci Please test |
Build failed |
Build failed |
@@ -3951,8 +3951,17 @@ bool ASTContext::isStandardLibraryTypeBridgedInFoundation( | |||
nominal == getStringDecl() || | |||
nominal == getErrorDecl() || | |||
nominal == getAnyHashableDecl() || | |||
// Weird one-off case where CGFloat is bridged to NSNumber. | |||
nominal->getName() == Id_CGFloat); | |||
// Foundation is a dependency of CoreGraphics, but |
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.
Foundation isn't actually a dependency of CoreGraphics; IIRC the two frameworks are unrelated in iOS, and related the other way on macOS.
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.
Interesting. The Swift overlays are set up in CMake such that Foundation's overlay depends on the CoreGraphics one on all platforms. Would it make sense to change it the other way, if that's purely a Swift-build-system layering and not a system one?
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.
"Foundation is a dependency of CoreGraphics" means "CoreGraphics depends on Foundation", no?
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 check also strikes me as incredibly general. Should we just give up and say all imported types might be bridged at some point?
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.
Sorry, I meant "Foundation depends on CoreGraphics". Treating all imported types as possibly bridged might be prudent for ABI compatibility, if we want to reserve the right to continue adding new bridging relationships after ABI stability is declared.
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.
I'm less concerned about ABI stability than about us either being too general or not general enough. Either we think it's worth maintaining this list, or we don't.
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.
(You're right that it won't be possible to add cross-module bridging relationships post-stability, but that seems reasonable.)
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.
@atrick or @aschwaighofer, how big of a perf impact do you think it'd be if we assumed all imported C value types might have an _ObjectiveCBridgeable
conformance?
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.
What kind of an impact do you have in mind? Generating a bunch of conformances bloats the binary and metadata. I guess that could be measured. I don't think the optimizer makes use of knowledge of the absence of a conformance. I don't think we could make that assumption for a public type.
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.
@atrick It looks like we do try to make optimization assumptions for the lack of _ObjectiveCBridgeable
conformances by disallowing conformances to that protocol outside of the type's defining module, except for this hardcoded list of exceptions. I'm not sure how valuable that is anymore in the world of id
-as-Any
, since there's at least one way to bridge everything to and from a class type now.
|
||
|
||
func getObjCTypeEncoding<T>(_: T) { | ||
// CHECK: call void @use({{.* i8]\*}} [[INT32:@[0-9]+]], |
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.
You should be able to check the actual encode strings too, right?
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.
I could, but I wasn't sure that the churn of tracking down and conditionalizing the exact encode strings for each type on each supported platform really gave meaningful coverage over just verifying that the builtin works at all. Clang ought to exercise the underlying type encoding code fairly well already.
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.
Sure, but nothing is checking that the builtin works at all.
SWIFT_MODULE_DEPENDS_WATCHOS Foundation | ||
SWIFT_MODULE_DEPENDS simd | ||
SWIFT_MODULE_DEPENDS_WATCHOS | ||
SWIFT_MODULE_DEPENDS Foundation simd |
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.
You can probably just remove the previous line, but it wasn't incorrect the old way—the non-watchOS platforms already indirectly depend on Foundation.
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.
Good catch.
3cd9b9b
to
853afe5
Compare
@swift-ci Please test |
Build failed |
853afe5
to
edf0aec
Compare
@swift-ci Please test |
@jrose-apple You've already glanced over this, but do you mind reviewing for inclusion in 3.0.1 as well? |
I'll do another pass tonight; the first pass wasn't too thorough. |
Build failed |
Seems good for now. Still a few open questions but nothing that would affect the 3.0 branch. |
edf0aec
to
c58492c
Compare
@swift-ci Please test |
@jrose-apple I updated the comment in ASTContext.cpp and added some tests for specific type encodings that ought to be stable across platforms. How's this look for 3.0 now? |
Ship it! |
Build failed |
c58492c
to
c69d35d
Compare
@swift-ci Please test |
Build failed |
@phausler Is this Foundation test failure expected, or transient?
|
@swift-ci Please test |
yea that failure is transient, we have seen it flutter a bit and it really needs to be replaced with loopback testing |
Build failed |
Build failed |
For every struct type for which the frameworks provides an NSValue category for boxing and unboxing values of that type, provide an _ObjectiveCBridgeable conformance in the Swift overlay that bridges that struct to NSValue, allowing the structs to be used naturally with id-as-Any APIs and Cocoa container classes. This is mostly a matter of gyb-ing out boilerplate using `NSValue.init(bytes:objCType:)` to construct the instance, `NSValue.objCType` to check its type when casting, and `NSValue.getValue(_:)` to extract the unboxed value, though there are a number of special snowflake cases that need special accommodation: - To maintain proper layering, CoreGraphics structs need to be bridged in the Foundation overlay. - AVFoundation provides the NSValue boxing categories for structs owned by CoreMedia, but it does so using its own internal subclasses of NSValue, and these subclasses do not interop properly with the standard `NSValue` subclasses instantiated by Foundation. To do the right thing, we therefore have to let AVFoundation provide the bridging implementation for the CoreMedia types, and we have to use its category methods to do so. - SceneKit provides NSValue categories to box and unbox SCNVector3, SCNVector4, and SCNMatrix4; however, the methods it provides do so in an unusual way. SCNVector3 and SCNVector4 are packaged into `CGRect`s and then the CGRect is boxed using `valueWithCGRect:`. SCNMatrix4 is copied into a CATransform3D, which is then boxed using `valueWithCATransform3D:` from CoreAnimation. To be consistent with what SceneKit does, use its category methods for these types as well, and when casting, check the type against the type encoding SceneKit uses rather than the type encoding of the expected type.
c69d35d
to
86fbeee
Compare
@swift-ci Please test |
For every struct type for which the frameworks provides an NSValue category for boxing and unboxing values of that type, provide an
_ObjectiveCBridgeable
conformance in the Swift overlay that bridges that struct to NSValue, allowing the structs to be used naturally with id-as-Any APIs and Cocoa container classes. This is mostly a matter of gyb-ing out boilerplate usingNSValue.init(bytes:objCType:)
to construct the instance,NSValue.objCType
to check its type when casting, andNSValue.getValue(_:)
to extract the unboxed value, though there are a number of special snowflake cases that need special accommodation:NSValue
subclasses instantiated by Foundation. To do the right thing, we therefore have to let AVFoundation provide the bridging implementation for the CoreMedia types, and we have to use its category methods to do so.CGRect
s and then the CGRect is boxed usingvalueWithCGRect:
. SCNMatrix4 is copied into a CATransform3D, which is then boxed usingvalueWithCATransform3D:
from CoreAnimation. To be consistent with what SceneKit does, use its category methods for these types as well, and when casting, check the type against the type encoding SceneKit uses rather than the type encoding of the expected type.