mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Allow Hashable: ~Copyable (#85748)
Builds on #85746 which covers Equatable.
This commit is contained in:
@@ -37,6 +37,8 @@
|
|||||||
#include "swift/AST/Expr.h"
|
#include "swift/AST/Expr.h"
|
||||||
#include "swift/AST/ForeignErrorConvention.h"
|
#include "swift/AST/ForeignErrorConvention.h"
|
||||||
#include "swift/AST/GenericEnvironment.h"
|
#include "swift/AST/GenericEnvironment.h"
|
||||||
|
#include "swift/AST/InFlightSubstitution.h"
|
||||||
|
#include "swift/AST/KnownProtocols.h"
|
||||||
#include "swift/AST/ParameterList.h"
|
#include "swift/AST/ParameterList.h"
|
||||||
#include "swift/AST/ProtocolConformance.h"
|
#include "swift/AST/ProtocolConformance.h"
|
||||||
#include "swift/AST/SubstitutionMap.h"
|
#include "swift/AST/SubstitutionMap.h"
|
||||||
@@ -2430,8 +2432,20 @@ RValue SILGenFunction::emitAnyHashableErasure(SILLocation loc,
|
|||||||
return emitUndefRValue(loc, getASTContext().getAnyHashableType());
|
return emitUndefRValue(loc, getASTContext().getAnyHashableType());
|
||||||
|
|
||||||
// Construct the substitution for T: Hashable.
|
// Construct the substitution for T: Hashable.
|
||||||
auto subMap = SubstitutionMap::getProtocolSubstitutions(
|
auto subMap = SubstitutionMap::get(convertFn->getGenericSignature(), type,
|
||||||
conformance.getProtocol(), type, conformance);
|
[&](InFlightSubstitution &ifs,
|
||||||
|
Type ty,
|
||||||
|
ProtocolDecl *proto) -> ProtocolConformanceRef {
|
||||||
|
switch (*proto->getKnownProtocolKind()) {
|
||||||
|
case KnownProtocolKind::Hashable:
|
||||||
|
return conformance;
|
||||||
|
case KnownProtocolKind::Copyable:
|
||||||
|
case KnownProtocolKind::Escapable:
|
||||||
|
return lookupConformance(type, proto);
|
||||||
|
default:
|
||||||
|
llvm_unreachable("no other conformances should be involved");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return emitApplyOfLibraryIntrinsic(loc, convertFn, subMap, value, C);
|
return emitApplyOfLibraryIntrinsic(loc, convertFn, subMap, value, C);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,7 +101,7 @@
|
|||||||
/// print("New tap detected at (\(nextTap.x), \(nextTap.y)).")
|
/// print("New tap detected at (\(nextTap.x), \(nextTap.y)).")
|
||||||
/// }
|
/// }
|
||||||
/// // Prints "New tap detected at (0, 1).")
|
/// // Prints "New tap detected at (0, 1).")
|
||||||
public protocol Hashable: Equatable {
|
public protocol Hashable: Equatable & ~Copyable {
|
||||||
/// The hash value.
|
/// The hash value.
|
||||||
///
|
///
|
||||||
/// Hash values are not guaranteed to be equal across different executions of
|
/// Hash values are not guaranteed to be equal across different executions of
|
||||||
@@ -135,9 +135,10 @@ public protocol Hashable: Equatable {
|
|||||||
func _rawHashValue(seed: Int) -> Int
|
func _rawHashValue(seed: Int) -> Int
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Hashable {
|
extension Hashable where Self: ~Copyable {
|
||||||
@inlinable
|
@inlinable
|
||||||
@inline(__always)
|
@inline(__always)
|
||||||
|
@_preInverseGenerics
|
||||||
public func _rawHashValue(seed: Int) -> Int {
|
public func _rawHashValue(seed: Int) -> Int {
|
||||||
var hasher = Hasher(_seed: seed)
|
var hasher = Hasher(_seed: seed)
|
||||||
hasher.combine(self)
|
hasher.combine(self)
|
||||||
@@ -148,7 +149,8 @@ extension Hashable {
|
|||||||
// Called by synthesized `hashValue` implementations.
|
// Called by synthesized `hashValue` implementations.
|
||||||
@inlinable
|
@inlinable
|
||||||
@inline(__always)
|
@inline(__always)
|
||||||
public func _hashValue<H: Hashable>(for value: H) -> Int {
|
@_preInverseGenerics
|
||||||
|
public func _hashValue<H: Hashable & ~Copyable>(for value: borrowing H) -> Int {
|
||||||
return value._rawHashValue(seed: 0)
|
return value._rawHashValue(seed: 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -350,7 +350,8 @@ public struct Hasher {
|
|||||||
/// - Parameter value: A value to add to the hasher.
|
/// - Parameter value: A value to add to the hasher.
|
||||||
@inlinable
|
@inlinable
|
||||||
@inline(__always)
|
@inline(__always)
|
||||||
public mutating func combine<H: Hashable>(_ value: H) {
|
@_preInverseGenerics
|
||||||
|
public mutating func combine<H: Hashable & ~Copyable>(_ value: borrowing H) {
|
||||||
value.hash(into: &self)
|
value.hash(into: &self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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> {{.*}})
|
// CHECK-AST-LABEL: (func_decl{{.*}}"generic(_:)" "<T : Hashable>" interface_type="<T where T : Hashable> (T) -> ()" access=internal captures=(<generic> {{.*}})
|
||||||
func generic<T: Hashable>(_: T) {}
|
func generic<T: Hashable>(_: T) {}
|
||||||
// CHECK-AST: (pattern_binding_decl
|
// 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 : 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 : Hashable> T -> Int)]" function_ref=unapplied))
|
||||||
let _: (Int) -> () = generic
|
let _: (Int) -> () = generic
|
||||||
|
|
||||||
// Closures should be marked as escaping or not.
|
// Closures should be marked as escaping or not.
|
||||||
|
|||||||
@@ -52,7 +52,9 @@ public struct MoveOnlyS1<T> : ~Copyable { /*deinit {}*/ }
|
|||||||
public struct MoveOnlyS2<T: Equatable> : ~Copyable { /*deinit {}*/ }
|
public struct MoveOnlyS2<T: Equatable> : ~Copyable { /*deinit {}*/ }
|
||||||
public struct MoveOnlyS3<T: ~Copyable> : ~Copyable { /*deinit {}*/ }
|
public struct MoveOnlyS3<T: ~Copyable> : ~Copyable { /*deinit {}*/ }
|
||||||
|
|
||||||
protocol Rope<Element>: Hashable, ~Copyable { // expected-error {{'Self' required to be 'Copyable' but is marked with '~Copyable'}}
|
protocol CopyHashable { }
|
||||||
|
|
||||||
|
protocol Rope<Element>: CopyHashable, ~Copyable { // expected-error {{'Self' required to be 'Copyable' but is marked with '~Copyable'}}
|
||||||
associatedtype Element: ~Copyable
|
associatedtype Element: ~Copyable
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,8 +104,8 @@ typealias Z4 = ~Rope<Int> // expected-error {{type 'Rope<Int>' cannot be suppres
|
|||||||
typealias Z5 = (~Int) -> Void // expected-error {{type 'Int' cannot be suppressed}}
|
typealias Z5 = (~Int) -> Void // expected-error {{type 'Int' cannot be suppressed}}
|
||||||
typealias Z6 = ~() -> () // expected-error {{single argument function types require parentheses}}
|
typealias Z6 = ~() -> () // expected-error {{single argument function types require parentheses}}
|
||||||
// expected-error@-1 {{type '()' cannot be suppressed}}
|
// expected-error@-1 {{type '()' cannot be suppressed}}
|
||||||
typealias Z7 = ~(Copyable & Hashable) // expected-error {{type 'Hashable' cannot be suppressed}}
|
typealias Z7 = ~(Copyable & CopyHashable) // expected-error {{type 'CopyHashable' cannot be suppressed}}
|
||||||
typealias Z8 = ~Copyable & Hashable // expected-error {{composition cannot contain '~Copyable' when another member requires 'Copyable'}}
|
typealias Z8 = ~Copyable & CopyHashable // expected-error {{composition cannot contain '~Copyable' when another member requires 'Copyable'}}
|
||||||
|
|
||||||
struct NotAProtocol {}
|
struct NotAProtocol {}
|
||||||
|
|
||||||
|
|||||||
@@ -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-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: 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) -> () -> Int : @$s28synthesized_conformance_enum4EnumOyxGSHAASHRzlSH9hashValueSivgTW // protocol witness for Hashable.hashValue.getter in conformance <A> Enum<A>
|
// 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) -> (inout Hasher) -> () : @$s28synthesized_conformance_enum4EnumOyxGSHAASHRzlSH4hash4intoys6HasherVz_tFTW // protocol witness for Hashable.hash(into:) 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) -> (Int) -> Int : @$s28synthesized_conformance_enum4EnumOyxGSHAASHRzlSH13_rawHashValue4seedS2i_tFTW // protocol witness for Hashable._rawHashValue(seed:) 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: conditional_conformance (T: Hashable): dependent
|
// CHECK-DAG: conditional_conformance (T: Hashable): dependent
|
||||||
// CHECK: }
|
// CHECK: }
|
||||||
|
|
||||||
|
|||||||
@@ -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-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: 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) -> () -> Int : @$s30synthesized_conformance_struct6StructVyxGSHAASHRzlSH9hashValueSivgTW // protocol witness for Hashable.hashValue.getter in conformance <A> Struct<A>
|
// 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) -> (inout Hasher) -> () : @$s30synthesized_conformance_struct6StructVyxGSHAASHRzlSH4hash4intoys6HasherVz_tFTW // protocol witness for Hashable.hash(into:) 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) -> (Int) -> Int : @$s30synthesized_conformance_struct6StructVyxGSHAASHRzlSH13_rawHashValue4seedS2i_tFTW // protocol witness for Hashable._rawHashValue(seed:) 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: conditional_conformance (T: Hashable): dependent
|
// CHECK-DAG: conditional_conformance (T: Hashable): dependent
|
||||||
// CHECK: }
|
// CHECK: }
|
||||||
|
|
||||||
|
|||||||
@@ -52,11 +52,11 @@ func basic_vararg(_ va: MO...) {} // expected-error {{noncopyable type 'MO' cann
|
|||||||
func illegalTypes<T>(_ t: T) {
|
func illegalTypes<T>(_ t: T) {
|
||||||
let _: Array<MO> // expected-error {{type 'MO' does not conform to protocol 'Copyable'}}
|
let _: Array<MO> // expected-error {{type 'MO' does not conform to protocol 'Copyable'}}
|
||||||
let _: Maybe<MO> // expected-error {{type 'MO' does not conform to protocol 'Copyable'}}
|
let _: Maybe<MO> // expected-error {{type 'MO' does not conform to protocol 'Copyable'}}
|
||||||
let _: Dictionary<MO, String> // expected-error {{type 'MO' does not conform to protocol 'Hashable'}}
|
let _: Dictionary<MO, String> // expected-error {{type 'MO' does not conform to protocol 'Copyable'}}
|
||||||
let _: [MO] // expected-error {{type 'MO' does not conform to protocol 'Copyable'}}
|
let _: [MO] // expected-error {{type 'MO' does not conform to protocol 'Copyable'}}
|
||||||
let _: [String : MO] // expected-error {{type 'MO' does not conform to protocol 'Copyable'}}
|
let _: [String : MO] // expected-error {{type 'MO' does not conform to protocol 'Copyable'}}
|
||||||
let _: [MO : MO] // expected-error {{type 'MO' does not conform to protocol 'Hashable'}}
|
let _: [MO : MO] // expected-error {{type 'MO' does not conform to protocol 'Copyable'}}
|
||||||
let _: [MO : T] // expected-error {{type 'MO' does not conform to protocol 'Hashable'}}
|
let _: [MO : T] // expected-error {{type 'MO' does not conform to protocol 'Copyable'}}
|
||||||
|
|
||||||
_ = t as! ValBox<MO> // expected-error {{type 'MO' does not conform to protocol 'Copyable'}}
|
_ = t as! ValBox<MO> // expected-error {{type 'MO' does not conform to protocol 'Copyable'}}
|
||||||
|
|
||||||
|
|||||||
@@ -114,7 +114,6 @@ Protocol FixedWidthInteger has added inherited protocol Copyable
|
|||||||
Protocol FixedWidthInteger has added inherited protocol Escapable
|
Protocol FixedWidthInteger has added inherited protocol Escapable
|
||||||
Protocol FloatingPoint has added inherited protocol Copyable
|
Protocol FloatingPoint has added inherited protocol Copyable
|
||||||
Protocol FloatingPoint has added inherited protocol Escapable
|
Protocol FloatingPoint has added inherited protocol Escapable
|
||||||
Protocol Hashable has added inherited protocol Copyable
|
|
||||||
Protocol Hashable 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 Copyable
|
||||||
Protocol Identifiable has added inherited protocol Escapable
|
Protocol Identifiable has added inherited protocol Escapable
|
||||||
@@ -399,3 +398,10 @@ Func Comparable.>(_:_:) has parameter 1 changing from Default to Shared
|
|||||||
Func Comparable.>=(_:_:) has generic signature change from <Self where Self : Swift.Comparable> to <Self where Self : Swift.Comparable, Self : ~Copyable>
|
Func Comparable.>=(_:_:) has generic signature change from <Self where Self : Swift.Comparable> to <Self where Self : Swift.Comparable, Self : ~Copyable>
|
||||||
Func Comparable.>=(_:_:) has parameter 0 changing from Default to Shared
|
Func Comparable.>=(_:_:) has parameter 0 changing from Default to Shared
|
||||||
Func Comparable.>=(_:_:) has parameter 1 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>
|
||||||
|
Func Hasher.combine(_:) has parameter 0 changing from Default to Shared
|
||||||
|
|||||||
@@ -232,7 +232,6 @@ Protocol FixedWidthInteger has added inherited protocol Copyable
|
|||||||
Protocol FixedWidthInteger has added inherited protocol Escapable
|
Protocol FixedWidthInteger has added inherited protocol Escapable
|
||||||
Protocol FloatingPoint has added inherited protocol Copyable
|
Protocol FloatingPoint has added inherited protocol Copyable
|
||||||
Protocol FloatingPoint has added inherited protocol Escapable
|
Protocol FloatingPoint has added inherited protocol Escapable
|
||||||
Protocol Hashable has added inherited protocol Copyable
|
|
||||||
Protocol Hashable 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 Copyable
|
||||||
Protocol Identifiable has added inherited protocol Escapable
|
Protocol Identifiable has added inherited protocol Escapable
|
||||||
@@ -911,5 +910,20 @@ Func Comparable.>=(_:_:) has parameter 0 changing from Default to Shared
|
|||||||
Func Comparable.>=(_:_:) has parameter 1 changing from Default to Shared
|
Func Comparable.>=(_:_:) has parameter 1 changing from Default to Shared
|
||||||
Func Comparable.>=(_:_:) is now with @_preInverseGenerics
|
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'
|
||||||
|
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 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 parameter 0 changing from Default to Shared
|
||||||
|
Func _hashValue(for:) is now with @_preInverseGenerics
|
||||||
|
|
||||||
// *** DO NOT DISABLE OR XFAIL THIS TEST. *** (See comment above.)
|
// *** DO NOT DISABLE OR XFAIL THIS TEST. *** (See comment above.)
|
||||||
|
|||||||
75
test/stdlib/NoncopyableHashable.swift
Normal file
75
test/stdlib/NoncopyableHashable.swift
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
//===--- NoncopyableHashable.swift - tests for Hashable: ~Copyable ----------===//
|
||||||
|
//
|
||||||
|
// This source file is part of the Swift.org open source project
|
||||||
|
//
|
||||||
|
// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors
|
||||||
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||||
|
//
|
||||||
|
// See https://swift.org/LICENSE.txt for license information
|
||||||
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// RUN: %target-run-simple-swift
|
||||||
|
// REQUIRES: executable_test
|
||||||
|
|
||||||
|
import StdlibUnittest
|
||||||
|
|
||||||
|
let NoncopyableHashableTests = TestSuite("NoncopyableHashable")
|
||||||
|
|
||||||
|
struct Noncopyable<Wrapped: ~Copyable>: ~Copyable {
|
||||||
|
var wrapped: Wrapped
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Noncopyable: Equatable where Wrapped: Equatable & ~Copyable { }
|
||||||
|
|
||||||
|
extension Noncopyable: Hashable where Wrapped: Hashable & ~Copyable { }
|
||||||
|
|
||||||
|
|
||||||
|
extension Hashable where Self: ~Copyable {
|
||||||
|
func sameHash(as other: borrowing Self) -> Bool {
|
||||||
|
self.hashValue == other.hashValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func differentHash<T: Hashable & ~Copyable>(_ lhs: borrowing T, _ rhs: borrowing T) -> Bool {
|
||||||
|
lhs.hashValue != rhs.hashValue
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(SwiftStdlib 6.2, *)
|
||||||
|
extension InlineArray where Element: Hashable & ~Copyable {
|
||||||
|
func combinedHashes() -> Int {
|
||||||
|
var hasher = Hasher()
|
||||||
|
for i in self.indices {
|
||||||
|
self[i].hash(into: &hasher)
|
||||||
|
}
|
||||||
|
return hasher.finalize()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NoncopyableHashableTests.test("hashing noncopyables") {
|
||||||
|
let a = Noncopyable(wrapped: 1)
|
||||||
|
let b = Noncopyable(wrapped: 2)
|
||||||
|
let c = Noncopyable(wrapped: 1)
|
||||||
|
|
||||||
|
expectTrue(a.sameHash(as: a))
|
||||||
|
expectFalse(a.sameHash(as: b))
|
||||||
|
expectTrue(a.sameHash(as: c))
|
||||||
|
|
||||||
|
expectTrue(differentHash(a,b))
|
||||||
|
expectFalse(differentHash(a,a))
|
||||||
|
expectFalse(differentHash(a,c))
|
||||||
|
|
||||||
|
let nc2 = Noncopyable(wrapped: Noncopyable(wrapped: "1"))
|
||||||
|
expectTrue(nc2.sameHash(as: nc2))
|
||||||
|
expectTrue(differentHash(nc2, .init(wrapped: .init(wrapped: "2"))))
|
||||||
|
|
||||||
|
guard #available(SwiftStdlib 6.2, *) else { return }
|
||||||
|
|
||||||
|
let a1: [_ of _] = [a,b]
|
||||||
|
let d = Noncopyable(wrapped: 2)
|
||||||
|
let a2: [_ of _] = [c,d]
|
||||||
|
expectEqual(a1.combinedHashes(), a2.combinedHashes())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
runAllTests()
|
||||||
Reference in New Issue
Block a user