Skip to content
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

[SR-8819] Darwin/Linux Behavior Mismatch: NSNumber(value: 0.25) as? Bool #3632

Closed
swift-ci opened this issue Sep 23, 2018 · 3 comments
Closed

Comments

@swift-ci
Copy link
Contributor

Previous ID SR-8819
Radar rdar://44467533
Original Reporter Kaiede (JIRA User)
Type Bug
Status Resolved
Resolution Done
Environment

Linux 4.2 (Originally Discovered on aarch64)

With 4.1 and earlier on Linux, the `as?` cast would simply always return nil.

Additional Detail from JIRA
Votes 0
Component/s Compiler, Foundation
Labels Bug, linux
Assignee None
Priority Medium

md5: 9a926a0161dab538f908996a2ab16272

Issue Description:

Darwin and Linux have different behavior with the following code: `NSNumber(value: 0.25) as? Bool`

Linux: false

Darwin: Optional(nil)

The key difference here is that I can reproduce the issue on Darwin if I build swift-corelibs-foundation directly and run the tests. As far as I can tell, this appears to be based on how the compiler is emiting the cast in IL based on the types. When running the test, this is what I get for the stack:

#0 0x0000000101ae49b5 in static Bool.conditionallyBridgeFromObjectiveC(:result🙂 at swift-corelibs-foundation/Foundation/NSNumber.swift:544#0 0x0000000101ae49b5 in static Bool.conditionallyBridgeFromObjectiveC(:result🙂 at swift-corelibs-foundation/Foundation/NSNumber.swift:544

#1 0x0000000101ae4d0f in static Bool.unconditionallyBridgeFromObjectiveC(🙂 at swift-corelibs-foundation/Foundation/NSNumber.swift:559

#2 0x00000001006d8c79 in TestNSNumberBridging.testNSNumberToBool() at swift-corelibs-foundation/TestFoundation/TestNSNumberBridging.swift:629

For this line in the test:

func testNSNumberToBool()

{ let b0 = NSNumber(value: 0) as? Bool /* ... */ }

There's a working case in `TestJSONSerialization.test_deserialize_values_withData()`:

— func deserialize_values(objectType: ObjectType)

— { /* ... / XCTAssertEqual(result?[0] as? Bool, true) / ... */ }

This has a different callstack:

#0 0x0000000101ae49b5 in static Bool.conditionallyBridgeFromObjectiveC(:result🙂 at swift-corelibs-foundation/Foundation/NSNumber.swift:544

#1 0x0000000101ae4df9 in protocol witness for static _ObjectiveCBridgeable.conditionallyBridgeFromObjectiveC(:result🙂 in conformance Bool ()

#2 0x0000000102bb2bb6 in _dynamicCastClassToValueViaObjCBridgeable(swift::OpaqueValue*, swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetMetadata<swift::InProcess> const*, (anonymous namespace)::_ObjectiveCBridgeableWitnessTable const*, swift::DynamicCastFlags) ()

#3 0x0000000102bb2d7c in _dynamicCastFromExistential(swift::OpaqueValue*, swift::OpaqueValue*, swift::TargetExistentialTypeMetadata<swift::InProcess> const*, swift::TargetMetadata<swift::InProcess> const*, swift::DynamicCastFlags) ()

#4 0x0000000100120a00 in implicit closure #&#8203;1 in TestJSONSerialization.deserialize_values(objectType🙂 ()

#5 0x0000000100143bc7 in partial apply for implicit closure #&#8203;1 in TestJSONSerialization.deserialize_values(objectType🙂 ()

#6 0x0000000100120a7a in thunk for @callee_guaranteed () -> (@unowned Bool?, @error @owned Error) ()

#7 0x0000000100143c0b in thunk for @callee_guaranteed () -> (@unowned Bool?, @error @owned Error)partial apply ()

#8 0x0000000102849093 in closure #&#8203;1 in XCTAssertEqual<A>(::_:file:line:) at swift-corelibs-xctest/Sources/XCTest/Public/XCTAssert.swift:163

#9 0x000000010284d4cd in partial apply for closure #&#8203;1 in XCTAssertEqual<A>(::_:file:line:) ()

#10 0x000000010284862b in XCTEvaluateAssertion(:message:file:line:expression:) at swift-corelibs-xctest/Sources/XCTest/Public/XCTAssert.swift:83

#11 0x0000000102848fad in XCTAssertEqual<A>(::_:file:line:) at swift-corelibs-xctest/Sources/XCTest/Public/XCTAssert.swift:162

#12 0x0000000100115f3f in TestJSONSerialization.deserialize_values(objectType🙂 at swift-corelibs-foundation/TestFoundation/TestJSONSerialization.swift:454

It looks like because it is `Any` in this case, it correctly goes down the path of emitting a dynamic cast. However, in the non-working case, I don't even get the implicit layers in the stack, suggesting that Swift is directly emitting the call to the unconditional bridge.

@belkadan
Copy link

cc @millenomi

@swift-ci
Copy link
Contributor Author

Comment by Adam Thayer (JIRA)

Some additional information here, this only reproduces on Darwin, and not Linux x86_64.

Very interesting, but probably makes this a much less interesting bug.

@spevans
Copy link
Collaborator

spevans commented Feb 23, 2020

This was fixed in #1642 for swift 4.2.4

Welcome to Swift version 4.2.4 (swift-4.2.4-RELEASE). Type :help for assistance.
  1> import Foundation
  2> print(NSNumber(value: 0.25) as? Bool)
nil

Which matches Darwin

Welcome to Apple Swift version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15).
Type :help for assistance.
  1> import Foundation
  2> print(NSNumber(value: 0.25) as? Bool)
nil

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
@shahmishal shahmishal transferred this issue from apple/swift May 5, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants