mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
85 lines
2.5 KiB
Swift
85 lines
2.5 KiB
Swift
// RUN: %target-run-simple-swift
|
|
// REQUIRES: executable_test
|
|
|
|
import StdlibUnittest
|
|
|
|
let suite = TestSuite("RawRepresentable")
|
|
|
|
extension Hasher {
|
|
static func hash<H: Hashable>(_ value: H) -> Int {
|
|
var hasher = Hasher()
|
|
hasher.combine(value)
|
|
return hasher.finalize()
|
|
}
|
|
}
|
|
|
|
|
|
|
|
struct TrickyRawRepresentable: RawRepresentable, Hashable {
|
|
var value: [Unicode.Scalar]
|
|
|
|
var rawValue: String {
|
|
return String(String.UnicodeScalarView(value))
|
|
}
|
|
|
|
init?(rawValue: String) {
|
|
self.value = Array(rawValue.unicodeScalars)
|
|
}
|
|
}
|
|
|
|
suite.test("Tricky hashing") {
|
|
// RawRepresentable is not Equatable itself, but it does provide a generic
|
|
// implementation of == based on rawValue. This gets picked up as the
|
|
// implementation of Equatable.== when a concrete RawRepresentable type
|
|
// conforms to Equatable without providing its own implementation.
|
|
//
|
|
// However, RawRepresentable used to not provide equivalent implementations
|
|
// for hashing, allowing the compiler to synthesize hashing as usual, based on
|
|
// the actual contents of the type rather than its rawValue. Thus, the
|
|
// definitions of equality and hashing did not actually match in some cases,
|
|
// leading to broken behavior.
|
|
//
|
|
// The difference between rawValue and the actual contents is subtle, and it
|
|
// only causes problems in custom RawRepresentable implementations where the
|
|
// rawValue isn't actually the storage representation, like the weird struct
|
|
// above.
|
|
//
|
|
// rdar://problem/45308741
|
|
|
|
let s1 = TrickyRawRepresentable(rawValue: "café")!
|
|
let s2 = TrickyRawRepresentable(rawValue: "cafe\u{301}")!
|
|
|
|
expectEqual(s1, s2)
|
|
expectEqual(s1.hashValue, s2.hashValue)
|
|
expectEqual(Hasher.hash(s1), Hasher.hash(s2))
|
|
expectEqual(s1._rawHashValue(seed: 42), s2._rawHashValue(seed: 42))
|
|
}
|
|
|
|
struct CustomRawRepresentable: RawRepresentable, Hashable {
|
|
var rawValue: Int
|
|
|
|
init?(rawValue: Int) {
|
|
self.rawValue = rawValue
|
|
}
|
|
|
|
func hash(into hasher: inout Hasher) {
|
|
hasher.combine(23)
|
|
}
|
|
}
|
|
|
|
suite.test("Custom hashing") {
|
|
// In 5.0, RawRepresentable had a bogus default implementation for
|
|
// _rawHashValue(seed:) that interfered with custom hashing for
|
|
// RawRepresentable types. Adding a custom hash(into:) implementation should
|
|
// always be enough to customize hashing.
|
|
//
|
|
// See https://bugs.swift.org/browse/SR-10734
|
|
|
|
if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) {
|
|
let r = CustomRawRepresentable(rawValue: 42)!
|
|
expectEqual(Hasher.hash(r), Hasher.hash(23))
|
|
}
|
|
}
|
|
|
|
runAllTests()
|