Skip to content

Commit 26ab276

Browse files
authored
Casting from AnyHashable to AnyHashable should never create another wrapper (#36470)
* Casting from AnyHashable to AnyHashable should never create another wrapper This adds a conformance for _HasCustomAnyHashableRepresentation to AnyHashable that simply returns self. This ensures that anytime you try to create a new AnyHashable wrapper for an existing AnyHashable, you just get back the original. Resolves rdar://75180619 * Move the `Struct AnyHashable` change to `without-asserts` list As suggested by @lorentey
1 parent 3d2fd56 commit 26ab276

File tree

3 files changed

+31
-0
lines changed

3 files changed

+31
-0
lines changed

stdlib/public/core/AnyHashable.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,13 @@ extension AnyHashable: CustomReflectable {
260260
}
261261
}
262262

263+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
264+
extension AnyHashable: _HasCustomAnyHashableRepresentation {
265+
public __consuming func _toCustomAnyHashable() -> AnyHashable? {
266+
return self
267+
}
268+
}
269+
263270
/// Returns a default (non-custom) representation of `self`
264271
/// as `AnyHashable`.
265272
///

test/Casting/Casts.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -924,4 +924,27 @@ CastsTests.test("Optional cast to AnyHashable") {
924924
expectNotEqual(xh, yh)
925925
}
926926

927+
// Repeatedly casting to AnyHashable should still test equal.
928+
// (This was broken for a while because repeatedly casting to
929+
// AnyHashable could end up with multiple nested AnyHashables.)
930+
// rdar://75180619
931+
CastsTests.test("Recursive AnyHashable") {
932+
struct P: Hashable {
933+
var x: Int
934+
}
935+
struct S {
936+
var x: AnyHashable?
937+
init<T: Hashable>(_ x: T?) {
938+
self.x = x
939+
}
940+
}
941+
let p = P(x: 0)
942+
let hp = p as AnyHashable?
943+
print(hp.debugDescription)
944+
let s = S(hp)
945+
print(s.x.debugDescription)
946+
expectEqual(s.x, hp)
947+
expectEqual(s.x, p)
948+
}
949+
927950
runAllTests()

test/api-digester/stability-stdlib-abi-without-asserts.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ Func Collection.subranges(where:) has been removed
4848
Func MutableCollection.moveSubranges(_:to:) has been removed
4949
Func MutableCollection.removeSubranges(_:) has been removed
5050
Func RangeReplaceableCollection.removeSubranges(_:) has been removed
51+
Struct AnyHashable has added a conformance to an existing protocol _HasCustomAnyHashableRepresentation
5152
Struct DiscontiguousSlice has been removed
5253
Struct RangeSet has been removed
5354
Subscript Collection.subscript(_:) has been removed

0 commit comments

Comments
 (0)