Skip to content

Commit 8e5ccec

Browse files
authored
Merge pull request #39155 from lorentey/RawRepresentable-hashing-fix
[stdlib] Allow RawRepresentable types to customize their hashing without implementing hashValue
2 parents 0b656b6 + d8427a6 commit 8e5ccec

File tree

2 files changed

+38
-2
lines changed

2 files changed

+38
-2
lines changed

stdlib/public/core/CompilerProtocols.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,11 @@ public func != <T: Equatable>(lhs: T, rhs: T) -> Bool
185185
extension RawRepresentable where RawValue: Hashable, Self: Hashable {
186186
@inlinable // trivial
187187
public var hashValue: Int {
188-
return rawValue.hashValue
188+
// Note: in Swift 5.5 and below, this used to return `rawValue.hashValue`.
189+
// The current definition matches the default `hashValue` implementation,
190+
// so that RawRepresentable types don't need to implement both `hashValue`
191+
// and `hash(into:)` to customize their hashing.
192+
_hashValue(for: self)
189193
}
190194

191195
@inlinable // trivial

test/stdlib/RawRepresentable-tricky-hashing.swift

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ struct CustomRawRepresentable: RawRepresentable, Hashable {
6767
}
6868
}
6969

70-
suite.test("Custom hashing") {
70+
suite.test("_rawHashValue forwarding") {
7171
// In 5.0, RawRepresentable had a bogus default implementation for
7272
// _rawHashValue(seed:) that interfered with custom hashing for
7373
// RawRepresentable types. Adding a custom hash(into:) implementation should
@@ -81,4 +81,36 @@ suite.test("Custom hashing") {
8181
}
8282
}
8383

84+
struct Bogus: Hashable {
85+
var hashValue: Int { 42 }
86+
static func ==(left: Self, right: Self) -> Bool { true }
87+
}
88+
89+
struct CustomRawRepresentable2: RawRepresentable, Hashable {
90+
var rawValue: Bogus
91+
92+
init?(rawValue: Bogus) {
93+
self.rawValue = rawValue
94+
}
95+
96+
func hash(into hasher: inout Hasher) {
97+
hasher.combine(23)
98+
}
99+
}
100+
101+
102+
suite.test("hashValue forwarding") {
103+
// In versions up to and including 5.5, RawRepresentable had a bogus default
104+
// implementation for `hashValue` that forwarded directly to
105+
// `rawValue.hashValue`, instead of `self.hash(into:)`. Adding a custom
106+
// hash(into:) implementation should always be enough to customize hashing.
107+
//
108+
// See https://github.com/apple/swift/pull/39155
109+
110+
if #available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *) {
111+
let r = CustomRawRepresentable2(rawValue: Bogus())!
112+
expectEqual(r.hashValue, 23.hashValue)
113+
}
114+
}
115+
84116
runAllTests()

0 commit comments

Comments
 (0)