Skip to content

Commit e1d7410

Browse files
author
Itai Ferber
committed
Fix NSNumber's custom AnyHashable representation
When we give NSNumber a custom AnyHashable representation, we want to give it as large a box as possible. When we want to compare it against other AnyHashable boxes such as Int or UInt, it's always possible to upcast the Int/UInt to a larger integer size like Int64 or UInt64 for the comparison. By eliminating the smaller boxes we create, we can maintain the existing behavior that _SwiftTypePreservingNSNumber gave us.
1 parent 7b33533 commit e1d7410

File tree

1 file changed

+21
-15
lines changed

1 file changed

+21
-15
lines changed

stdlib/public/SDK/Foundation/NSNumber.swift

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -647,33 +647,39 @@ extension NSNumber : _HasCustomAnyHashableRepresentation {
647647
// AnyHashable to NSObject.
648648
@nonobjc
649649
public func _toCustomAnyHashable() -> AnyHashable? {
650+
// The custom AnyHashable representation here is used when checking for
651+
// equality during bridging NSDictionary to Dictionary (or looking up
652+
// values in a Dictionary bridged to NSDictionary).
653+
//
654+
// When we've got NSNumber values as keys that we want to compare
655+
// through an AnyHashable box, we want to compare values through the
656+
// largest box size we've got available to us (i.e. upcast numbers).
657+
// This happens to resemble the representation that NSNumber uses
658+
// internally: (long long | unsigned long long | double).
659+
//
660+
// This allows us to compare things like
661+
//
662+
// ([Int : Any] as [AnyHashable : Any]) vs. [NSNumber : Any]
663+
//
664+
// because Int can be upcast to Int64 and compared with the number's
665+
// Int64 value.
666+
//
667+
// If NSNumber adds 128-bit representations, this will need to be
668+
// updated to use those.
650669
if let nsDecimalNumber: NSDecimalNumber = self as? NSDecimalNumber {
651670
return AnyHashable(nsDecimalNumber.decimalValue)
652671
} else if self === kCFBooleanTrue as NSNumber {
653672
return AnyHashable(true)
654673
} else if self === kCFBooleanFalse as NSNumber {
655674
return AnyHashable(false)
656-
} else if NSNumber(value: int8Value) == self {
657-
return AnyHashable(int8Value)
658-
} else if NSNumber(value: uint8Value) == self {
659-
return AnyHashable(uint8Value)
660-
} else if NSNumber(value: int16Value) == self {
661-
return AnyHashable(int16Value)
662-
} else if NSNumber(value: uint16Value) == self {
663-
return AnyHashable(uint16Value)
664-
} else if NSNumber(value: int32Value) == self {
665-
return AnyHashable(int32Value)
666-
} else if NSNumber(value: uint32Value) == self {
667-
return AnyHashable(uint32Value)
668675
} else if NSNumber(value: int64Value) == self {
669676
return AnyHashable(int64Value)
670-
} else if NSNumber(value: floatValue) == self {
671-
return AnyHashable(floatValue)
677+
} else if NSNumber(value: uint64Value) == self {
678+
return AnyHashable(uint64Value)
672679
} else if NSNumber(value: doubleValue) == self {
673680
return AnyHashable(doubleValue)
674681
} else {
675682
return nil
676683
}
677684
}
678685
}
679-

0 commit comments

Comments
 (0)