Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions stdlib/public/core/Hashable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@
/// print("New tap detected at (\(nextTap.x), \(nextTap.y)).")
/// }
/// // Prints "New tap detected at (0, 1).")
public protocol Hashable: Equatable & ~Copyable {
public protocol Hashable: Equatable & ~Copyable & ~Escapable {
/// The hash value.
///
/// Hash values are not guaranteed to be equal across different executions of
Expand Down Expand Up @@ -135,7 +135,7 @@ public protocol Hashable: Equatable & ~Copyable {
func _rawHashValue(seed: Int) -> Int
}

extension Hashable where Self: ~Copyable {
extension Hashable where Self: ~Copyable & ~Escapable {
@inlinable
@inline(__always)
@_preInverseGenerics
Expand All @@ -150,7 +150,7 @@ extension Hashable where Self: ~Copyable {
@inlinable
@inline(__always)
@_preInverseGenerics
public func _hashValue<H: Hashable & ~Copyable>(for value: borrowing H) -> Int {
public func _hashValue<H: Hashable & ~Copyable & ~Escapable>(for value: borrowing H) -> Int {
return value._rawHashValue(seed: 0)
}

Expand Down
2 changes: 1 addition & 1 deletion stdlib/public/core/Hasher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ public struct Hasher {
@inlinable
@inline(__always)
@_preInverseGenerics
public mutating func combine<H: Hashable & ~Copyable>(_ value: borrowing H) {
public mutating func combine<H: Hashable & ~Copyable & ~Escapable>(_ value: borrowing H) {
value.hash(into: &self)
}

Expand Down
2 changes: 1 addition & 1 deletion test/Frontend/dump-parse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ enum TrailingSemi {
// CHECK-AST-LABEL: (func_decl{{.*}}"generic(_:)" "<T : Hashable>" interface_type="<T where T : Hashable> (T) -> ()" access=internal captures=(<generic> {{.*}})
func generic<T: Hashable>(_: T) {}
// CHECK-AST: (pattern_binding_decl
// CHECK-AST: (processed_init=declref_expr type="(Int) -> ()" location={{.*}} range={{.*}} decl="main.(file).generic@{{.*}} [with (substitution_map generic_signature=<T where T : Copyable, T : Hashable> T -> Int)]" function_ref=unapplied))
// CHECK-AST: (processed_init=declref_expr type="(Int) -> ()" location={{.*}} range={{.*}} decl="main.(file).generic@{{.*}} [with (substitution_map generic_signature=<T where T : Copyable, T : Escapable, T : Hashable> T -> Int)]" function_ref=unapplied))
let _: (Int) -> () = generic

// Closures should be marked as escaping or not.
Expand Down
6 changes: 3 additions & 3 deletions test/SILGen/synthesized_conformance_enum.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ extension NoValues: Codable {}

// CHECK-LABEL: sil_witness_table hidden <T where T : Hashable> Enum<T>: Hashable module synthesized_conformance_enum {
// CHECK-DAG: base_protocol Equatable: <T where T : Equatable> Enum<T>: Equatable module synthesized_conformance_enum
// CHECK-DAG: method #Hashable.hashValue!getter: <Self where Self : Hashable, Self : ~Copyable> (Self) -> () -> Int : @$s28synthesized_conformance_enum4EnumOyxGSHAASHRzlSH9hashValueSivgTW // protocol witness for Hashable.hashValue.getter in conformance <A> Enum<A>
// CHECK-DAG: method #Hashable.hash: <Self where Self : Hashable, Self : ~Copyable> (Self) -> (inout Hasher) -> () : @$s28synthesized_conformance_enum4EnumOyxGSHAASHRzlSH4hash4intoys6HasherVz_tFTW // protocol witness for Hashable.hash(into:) in conformance <A> Enum<A>
// CHECK-DAG: method #Hashable._rawHashValue: <Self where Self : Hashable, Self : ~Copyable> (Self) -> (Int) -> Int : @$s28synthesized_conformance_enum4EnumOyxGSHAASHRzlSH13_rawHashValue4seedS2i_tFTW // protocol witness for Hashable._rawHashValue(seed:) in conformance <A> Enum<A>
// CHECK-DAG: method #Hashable.hashValue!getter: <Self where Self : Hashable, Self : ~Copyable, Self : ~Escapable> (Self) -> () -> Int : @$s28synthesized_conformance_enum4EnumOyxGSHAASHRzlSH9hashValueSivgTW // protocol witness for Hashable.hashValue.getter in conformance <A> Enum<A>
// CHECK-DAG: method #Hashable.hash: <Self where Self : Hashable, Self : ~Copyable, Self : ~Escapable> (Self) -> (inout Hasher) -> () : @$s28synthesized_conformance_enum4EnumOyxGSHAASHRzlSH4hash4intoys6HasherVz_tFTW // protocol witness for Hashable.hash(into:) in conformance <A> Enum<A>
// CHECK-DAG: method #Hashable._rawHashValue: <Self where Self : Hashable, Self : ~Copyable, Self : ~Escapable> (Self) -> (Int) -> Int : @$s28synthesized_conformance_enum4EnumOyxGSHAASHRzlSH13_rawHashValue4seedS2i_tFTW // protocol witness for Hashable._rawHashValue(seed:) in conformance <A> Enum<A>
// CHECK-DAG: conditional_conformance (T: Hashable): dependent
// CHECK: }

Expand Down
6 changes: 3 additions & 3 deletions test/SILGen/synthesized_conformance_struct.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ extension Struct: Codable where T: Codable {}

// CHECK-LABEL: sil_witness_table hidden <T where T : Hashable> Struct<T>: Hashable module synthesized_conformance_struct {
// CHECK-DAG: base_protocol Equatable: <T where T : Equatable> Struct<T>: Equatable module synthesized_conformance_struct
// CHECK-DAG: method #Hashable.hashValue!getter: <Self where Self : Hashable, Self : ~Copyable> (Self) -> () -> Int : @$s30synthesized_conformance_struct6StructVyxGSHAASHRzlSH9hashValueSivgTW // protocol witness for Hashable.hashValue.getter in conformance <A> Struct<A>
// CHECK-DAG: method #Hashable.hash: <Self where Self : Hashable, Self : ~Copyable> (Self) -> (inout Hasher) -> () : @$s30synthesized_conformance_struct6StructVyxGSHAASHRzlSH4hash4intoys6HasherVz_tFTW // protocol witness for Hashable.hash(into:) in conformance <A> Struct<A>
// CHECK-DAG: method #Hashable._rawHashValue: <Self where Self : Hashable, Self : ~Copyable> (Self) -> (Int) -> Int : @$s30synthesized_conformance_struct6StructVyxGSHAASHRzlSH13_rawHashValue4seedS2i_tFTW // protocol witness for Hashable._rawHashValue(seed:) in conformance <A> Struct<A>
// CHECK-DAG: method #Hashable.hashValue!getter: <Self where Self : Hashable, Self : ~Copyable, Self : ~Escapable> (Self) -> () -> Int : @$s30synthesized_conformance_struct6StructVyxGSHAASHRzlSH9hashValueSivgTW // protocol witness for Hashable.hashValue.getter in conformance <A> Struct<A>
// CHECK-DAG: method #Hashable.hash: <Self where Self : Hashable, Self : ~Copyable, Self : ~Escapable> (Self) -> (inout Hasher) -> () : @$s30synthesized_conformance_struct6StructVyxGSHAASHRzlSH4hash4intoys6HasherVz_tFTW // protocol witness for Hashable.hash(into:) in conformance <A> Struct<A>
// CHECK-DAG: method #Hashable._rawHashValue: <Self where Self : Hashable, Self : ~Copyable, Self : ~Escapable> (Self) -> (Int) -> Int : @$s30synthesized_conformance_struct6StructVyxGSHAASHRzlSH13_rawHashValue4seedS2i_tFTW // protocol witness for Hashable._rawHashValue(seed:) in conformance <A> Struct<A>
// CHECK-DAG: conditional_conformance (T: Hashable): dependent
// CHECK: }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ Protocol FixedWidthInteger has added inherited protocol Copyable
Protocol FixedWidthInteger has added inherited protocol Escapable
Protocol FloatingPoint has added inherited protocol Copyable
Protocol FloatingPoint has added inherited protocol Escapable
Protocol Hashable has added inherited protocol Escapable
Protocol Identifiable has added inherited protocol Copyable
Protocol Identifiable has added inherited protocol Escapable
Protocol IteratorProtocol has added inherited protocol Copyable
Expand Down Expand Up @@ -399,9 +398,9 @@ Func Comparable.>=(_:_:) has generic signature change from <Self where Self : Sw
Func Comparable.>=(_:_:) has parameter 0 changing from Default to Shared
Func Comparable.>=(_:_:) has parameter 1 changing from Default to Shared

// Hashable: ~Copyable
Protocol Hashable has generic signature change from <Self : Swift.Equatable> to <Self : Swift.Equatable, Self : ~Copyable>
Accessor Hashable.hashValue.Get() has generic signature change from <Self where Self : Swift.Hashable> to <Self where Self : Swift.Hashable, Self : ~Copyable>
Func Hashable.hash(into:) has generic signature change from <Self where Self : Swift.Hashable> to <Self where Self : Swift.Hashable, Self : ~Copyable>
Func Hasher.combine(_:) has generic signature change from <H where H : Swift.Hashable> to <H where H : Swift.Hashable, H : ~Copyable>
// Hashable: ~Copyable & Escapable
Protocol Hashable has generic signature change from <Self : Swift.Equatable> to <Self : Swift.Equatable, Self : ~Copyable, Self : ~Escapable>
Accessor Hashable.hashValue.Get() has generic signature change from <Self where Self : Swift.Hashable> to <Self where Self : Swift.Hashable, Self : ~Copyable, Self : ~Escapable>
Func Hashable.hash(into:) has generic signature change from <Self where Self : Swift.Hashable> to <Self where Self : Swift.Hashable, Self : ~Copyable, Self : ~Escapable>
Func Hasher.combine(_:) has generic signature change from <H where H : Swift.Hashable> to <H where H : Swift.Hashable, H : ~Copyable, H : ~Escapable>
Func Hasher.combine(_:) has parameter 0 changing from Default to Shared
21 changes: 10 additions & 11 deletions test/api-digester/stability-stdlib-abi-without-asserts.test
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,6 @@ Protocol FixedWidthInteger has added inherited protocol Copyable
Protocol FixedWidthInteger has added inherited protocol Escapable
Protocol FloatingPoint has added inherited protocol Copyable
Protocol FloatingPoint has added inherited protocol Escapable
Protocol Hashable has added inherited protocol Escapable
Protocol Identifiable has added inherited protocol Copyable
Protocol Identifiable has added inherited protocol Escapable
Protocol IteratorProtocol has added inherited protocol Copyable
Expand Down Expand Up @@ -910,19 +909,19 @@ Func Comparable.>=(_:_:) has parameter 0 changing from Default to Shared
Func Comparable.>=(_:_:) has parameter 1 changing from Default to Shared
Func Comparable.>=(_:_:) is now with @_preInverseGenerics

// Hashable: ~Copyable
Protocol Hashable has generic signature change from <Self : Swift.Equatable> to <Self : Swift.Equatable, Self : ~Copyable>
Accessor Hashable.hashValue.Get() has generic signature change from <Self where Self : Swift.Hashable> to <Self where Self : Swift.Hashable, Self : ~Copyable>
Func Hashable._rawHashValue(seed:) has generic signature change from <Self where Self : Swift.Hashable> to <Self where Self : Swift.Hashable, Self : ~Copyable>
Func Hashable._rawHashValue(seed:) has mangled name changing from '(extension in Swift):Swift.Hashable._rawHashValue(seed: Swift.Int) -> Swift.Int' to '(extension in Swift):Swift.Hashable< where A: ~Swift.Copyable>._rawHashValue(seed: Swift.Int) -> Swift.Int'
// Hashable: ~Copyable & ~Escapable
Protocol Hashable has generic signature change from <Self : Swift.Equatable> to <Self : Swift.Equatable, Self : ~Copyable, Self : ~Escapable>
Accessor Hashable.hashValue.Get() has generic signature change from <Self where Self : Swift.Hashable> to <Self where Self : Swift.Hashable, Self : ~Copyable, Self : ~Escapable>
Func Hashable._rawHashValue(seed:) has generic signature change from <Self where Self : Swift.Hashable> to <Self where Self : Swift.Hashable, Self : ~Copyable, Self : ~Escapable>
Func Hashable._rawHashValue(seed:) has mangled name changing from '(extension in Swift):Swift.Hashable._rawHashValue(seed: Swift.Int) -> Swift.Int' to '(extension in Swift):Swift.Hashable< where A: ~Swift.Copyable, A: ~Swift.Escapable>._rawHashValue(seed: Swift.Int) -> Swift.Int'
Func Hashable._rawHashValue(seed:) is now with @_preInverseGenerics
Func Hashable.hash(into:) has generic signature change from <Self where Self : Swift.Hashable> to <Self where Self : Swift.Hashable, Self : ~Copyable>
Func Hasher.combine(_:) has generic signature change from <H where H : Swift.Hashable> to <H where H : Swift.Hashable, H : ~Copyable>
Func Hasher.combine(_:) has mangled name changing from 'Swift.Hasher.combine<A where A: Swift.Hashable>(A) -> ()' to 'Swift.Hasher.combine<A where A: Swift.Hashable, A: ~Swift.Copyable>(A) -> ()'
Func Hashable.hash(into:) has generic signature change from <Self where Self : Swift.Hashable> to <Self where Self : Swift.Hashable, Self : ~Copyable, Self : ~Escapable>
Func Hasher.combine(_:) has generic signature change from <H where H : Swift.Hashable> to <H where H : Swift.Hashable, H : ~Copyable, H : ~Escapable>
Func Hasher.combine(_:) has mangled name changing from 'Swift.Hasher.combine<A where A: Swift.Hashable>(A) -> ()' to 'Swift.Hasher.combine<A where A: Swift.Hashable, A: ~Swift.Copyable, A: ~Swift.Escapable>(A) -> ()'
Func Hasher.combine(_:) has parameter 0 changing from Default to Shared
Func Hasher.combine(_:) is now with @_preInverseGenerics
Func _hashValue(for:) has generic signature change from <H where H : Swift.Hashable> to <H where H : Swift.Hashable, H : ~Copyable>
Func _hashValue(for:) has mangled name changing from 'Swift._hashValue<A where A: Swift.Hashable>(for: A) -> Swift.Int' to 'Swift._hashValue<A where A: Swift.Hashable, A: ~Swift.Copyable>(for: A) -> Swift.Int'
Func _hashValue(for:) has generic signature change from <H where H : Swift.Hashable> to <H where H : Swift.Hashable, H : ~Copyable, H : ~Escapable>
Func _hashValue(for:) has mangled name changing from 'Swift._hashValue<A where A: Swift.Hashable>(for: A) -> Swift.Int' to 'Swift._hashValue<A where A: Swift.Hashable, A: ~Swift.Copyable, A: ~Swift.Escapable>(for: A) -> Swift.Int'
Func _hashValue(for:) has parameter 0 changing from Default to Shared
Func _hashValue(for:) is now with @_preInverseGenerics

Expand Down
52 changes: 40 additions & 12 deletions test/stdlib/NoncopyableHashable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,44 @@
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
// RUN: %target-run-simple-swift
// RUN: %target-run-simple-swift(-enable-experimental-feature Lifetimes)
// REQUIRES: executable_test
// REQUIRES: swift_feature_Lifetimes

import StdlibUnittest

let NoncopyableHashableTests = TestSuite("NoncopyableHashable")

struct Noncopyable<Wrapped: ~Copyable>: ~Copyable {
struct Noncopyable<Wrapped: ~Copyable & ~Escapable>: ~Copyable {
var wrapped: Wrapped

@_lifetime(copy wrapped)
init(wrapping wrapped: consuming Wrapped) {
self.wrapped = wrapped
}
}

extension Noncopyable: Equatable where Wrapped: Equatable & ~Copyable { }
extension Noncopyable: Equatable where Wrapped: Equatable & ~Copyable & ~Escapable { }

extension Noncopyable: Hashable where Wrapped: Hashable & ~Copyable & ~Escapable { }

extension Noncopyable: Hashable where Wrapped: Hashable & ~Copyable { }
extension Noncopyable: Escapable where Wrapped: Escapable & ~Copyable { }

struct Nonescapable: ~Escapable {
let wrapped: Int
}

extension Nonescapable: Equatable { }

extension Hashable where Self: ~Copyable {
extension Nonescapable: Hashable { }

extension Hashable where Self: ~Copyable & ~Escapable {
func sameHash(as other: borrowing Self) -> Bool {
self.hashValue == other.hashValue
}
}

func differentHash<T: Hashable & ~Copyable>(_ lhs: borrowing T, _ rhs: borrowing T) -> Bool {
func differentHash<T: Hashable & ~Copyable & ~Escapable>(_ lhs: borrowing T, _ rhs: borrowing T) -> Bool {
lhs.hashValue != rhs.hashValue
}

Expand All @@ -47,9 +62,9 @@ extension InlineArray where Element: Hashable & ~Copyable {
}

NoncopyableHashableTests.test("hashing noncopyables") {
let a = Noncopyable(wrapped: 1)
let b = Noncopyable(wrapped: 2)
let c = Noncopyable(wrapped: 1)
let a = Noncopyable(wrapping: 1)
let b = Noncopyable(wrapping: 2)
let c = Noncopyable(wrapping: 1)

expectTrue(a.sameHash(as: a))
expectFalse(a.sameHash(as: b))
Expand All @@ -59,17 +74,30 @@ NoncopyableHashableTests.test("hashing noncopyables") {
expectFalse(differentHash(a,a))
expectFalse(differentHash(a,c))

let nc2 = Noncopyable(wrapped: Noncopyable(wrapped: "1"))
let nc2 = Noncopyable(wrapping: Noncopyable(wrapping: "1"))
expectTrue(nc2.sameHash(as: nc2))
expectTrue(differentHash(nc2, .init(wrapped: .init(wrapped: "2"))))
expectTrue(differentHash(nc2, .init(wrapping: .init(wrapping: "2"))))

guard #available(SwiftStdlib 6.2, *) else { return }

let a1: [_ of _] = [a,b]
let d = Noncopyable(wrapped: 2)
let d = Noncopyable(wrapping: 2)
let a2: [_ of _] = [c,d]
expectEqual(a1.combinedHashes(), a2.combinedHashes())

}

NoncopyableHashableTests.test("hashing nonescapables") {
let nc1 = Noncopyable<Nonescapable>(wrapping: .init(wrapped: 1))
let nc2 = Noncopyable<Nonescapable>(wrapping: .init(wrapped: 1))
let nc3 = Noncopyable<Nonescapable>(wrapping: .init(wrapped: 2))

expectTrue(nc1.hashValue == nc2.hashValue)
expectFalse(nc1.hashValue == nc3.hashValue)
expectTrue(nc1.sameHash(as: nc2))
expectFalse(nc1.sameHash(as: nc3))
expectTrue(differentHash(nc1, nc3))
expectFalse(differentHash(nc1, nc2))
}

runAllTests()