-
Notifications
You must be signed in to change notification settings - Fork 10.5k
SE-0139: Bridge all standard number types to NSNumber. #4933
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
@swift-ci Please test |
@DougGregor Mind reviewing this for inclusion in the Swift 3 branch? |
Build failed |
@implementation _SwiftTypePreservingNSNumber { | ||
/*alignas(StorageSize)*/ char storage[StorageSize]; |
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.
Seems like you want alignas(Double) alignas(int64_t) alignas(uint64_t)
to be really picky here.
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.
Unfortunately, Clang doesn't seem to let you put any alignas
decorations at all in an ObjC++ implementation without an "attributes can't be put here" error. It shouldn't really be necessary since we consistently memcpy
everything in and out of the storage.
DEFINE_ACCESSOR(int, intValue) | ||
DEFINE_ACCESSOR(unsigned int, unsignedIntValue) | ||
DEFINE_ACCESSOR(long long, longLongValue) | ||
DEFINE_ACCESSOR(unsigned long long, unsignedLongLongValue) | ||
DEFINE_ACCESSOR(float, floatValue) | ||
DEFINE_ACCESSOR(double, doubleValue) | ||
DEFINE_ACCESSOR(NSInteger, integerValue) | ||
DEFINE_ACCESSOR(NSUInteger, unsignedIntegerValue) |
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.
Huh, we just forgot these?
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.
Yep, and the default implementations in the NSNumber
root class just infinitely looped trying to redispatch themselves. Fun.
nsNumberBridging.test("${AType} to ${BType} casting fails") { | ||
let original: ${AType} = 0 | ||
let bridged = original as AnyObject as Any | ||
expectEqual(.none, bridged as? ${BType}) |
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.
expectNotNil
works for this, FWIW
} | ||
// If the NSNumber instance preserved its Swift type, we only want to allow | ||
// the cast if the type matches. | ||
if let tag = _SwiftTypePreservingNSNumberTag(rawValue: |
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 get the sneaky trick with the NonSwift
value here, but it's really subtle. Could you document _SwiftTypePreservingNSNumberTag
and it's C counterpart so nobody surprises themselves by trying to put NonSwift
in _SwiftTypePreservingNSNumberTag
?
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 elaborated the comment a bit. How's it look now?
3bf86ce
to
ede03e3
Compare
@swift-ci Please test |
Build failed |
/// enums. For an Optional<_SwiftTypePreservingNSNumberTag>, Swift uses the | ||
/// first invalid integer value to represent `.none`. This representation on | ||
/// the C side allows _SwiftTypePreservingNSNumberTag(rawValue:) on the Swift | ||
/// side to compile down to a no-op. |
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.
How about using 0 for this instead of 14?
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.
That's how it was before, but that then forces a representation change when we convert from the raw C value to the Swift enum on the Swift side, since the Swift enum always uses the compacted representation starting from zero. Definitely a microoptimization.
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.
Oh, bleah, right—the raw value isn't the representation value.
Extend NSNumber bridging to cover not only `Int`, `UInt`, `Double`, and `Bool`, but all of the standard types as well. Extend the `TypePreservingNSNumber` subclass to accommodate all of these types, so that we preserve type identity for `AnyHashable` and dynamic casting of Swift-bridged NSNumbers. If a pure Cocoa NSNumber is cast, just trust that the user knows what they're doing. This XFAILs a couple of serialization tests that attempt to build the Foundation overlay, but which don't properly handle `gyb` files.
ede03e3
to
9b1f238
Compare
@swift-ci Please test |
Extend NSNumber bridging to cover not only
Int
,UInt
,Double
, andBool
, but all of the standard types as well. Extend theTypePreservingNSNumber
subclass to accommodate all of these types, so that we preserve type identity forAnyHashable
and dynamic casting of Swift-bridged NSNumbers. If a pure Cocoa NSNumber is cast, just trust that the user knows what they're doing.