Skip to content

Commit 21aa399

Browse files
committed
Allow Hashable: ~Copyable
1 parent b7ba1c0 commit 21aa399

File tree

12 files changed

+75
-21
lines changed

12 files changed

+75
-21
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
#include "swift/AST/Expr.h"
3838
#include "swift/AST/ForeignErrorConvention.h"
3939
#include "swift/AST/GenericEnvironment.h"
40+
#include "swift/AST/InFlightSubstitution.h"
41+
#include "swift/AST/KnownProtocols.h"
4042
#include "swift/AST/ParameterList.h"
4143
#include "swift/AST/ProtocolConformance.h"
4244
#include "swift/AST/SubstitutionMap.h"
@@ -2381,8 +2383,20 @@ RValue SILGenFunction::emitAnyHashableErasure(SILLocation loc,
23812383
return emitUndefRValue(loc, getASTContext().getAnyHashableType());
23822384

23832385
// Construct the substitution for T: Hashable.
2384-
auto subMap = SubstitutionMap::getProtocolSubstitutions(
2385-
conformance.getProtocol(), type, conformance);
2386+
auto subMap = SubstitutionMap::get(convertFn->getGenericSignature(), type,
2387+
[&](InFlightSubstitution &ifs,
2388+
Type ty,
2389+
ProtocolDecl *proto) -> ProtocolConformanceRef {
2390+
switch (*proto->getKnownProtocolKind()) {
2391+
case KnownProtocolKind::Hashable:
2392+
return conformance;
2393+
case KnownProtocolKind::Copyable:
2394+
case KnownProtocolKind::Escapable:
2395+
return lookupConformance(type, proto);
2396+
default:
2397+
llvm_unreachable("no other conformances should be involved");
2398+
}
2399+
});
23862400

23872401
return emitApplyOfLibraryIntrinsic(loc, convertFn, subMap, value, C);
23882402
}

stdlib/public/core/Hashable.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@
101101
/// print("New tap detected at (\(nextTap.x), \(nextTap.y)).")
102102
/// }
103103
/// // Prints "New tap detected at (0, 1).")
104-
public protocol Hashable: Equatable {
104+
public protocol Hashable: Equatable & ~Copyable {
105105
/// The hash value.
106106
///
107107
/// Hash values are not guaranteed to be equal across different executions of
@@ -135,9 +135,10 @@ public protocol Hashable: Equatable {
135135
func _rawHashValue(seed: Int) -> Int
136136
}
137137

138-
extension Hashable {
138+
extension Hashable where Self: ~Copyable {
139139
@inlinable
140140
@inline(__always)
141+
@_preInverseGenerics
141142
public func _rawHashValue(seed: Int) -> Int {
142143
var hasher = Hasher(_seed: seed)
143144
hasher.combine(self)
@@ -148,7 +149,8 @@ extension Hashable {
148149
// Called by synthesized `hashValue` implementations.
149150
@inlinable
150151
@inline(__always)
151-
public func _hashValue<H: Hashable>(for value: H) -> Int {
152+
@_preInverseGenerics
153+
public func _hashValue<H: Hashable & ~Copyable>(for value: borrowing H) -> Int {
152154
return value._rawHashValue(seed: 0)
153155
}
154156

stdlib/public/core/Hasher.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,8 @@ public struct Hasher {
350350
/// - Parameter value: A value to add to the hasher.
351351
@inlinable
352352
@inline(__always)
353-
public mutating func combine<H: Hashable>(_ value: H) {
353+
@_preInverseGenerics
354+
public mutating func combine<H: Hashable & ~Copyable>(_ value: borrowing H) {
354355
value.hash(into: &self)
355356
}
356357

stdlib/public/core/Optional.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -586,13 +586,15 @@ extension Optional: Equatable where Wrapped: Equatable & ~Copyable {
586586
}
587587
}
588588

589-
extension Optional: Hashable where Wrapped: Hashable {
589+
@_preInverseGenerics
590+
extension Optional: Hashable where Wrapped: Hashable & ~Copyable {
590591
/// Hashes the essential components of this value by feeding them into the
591592
/// given hasher.
592593
///
593594
/// - Parameter hasher: The hasher to use when combining the components
594595
/// of this instance.
595596
@inlinable
597+
@_preInverseGenerics
596598
public func hash(into hasher: inout Hasher) {
597599
switch self {
598600
case .none:
@@ -602,6 +604,13 @@ extension Optional: Hashable where Wrapped: Hashable {
602604
hasher.combine(wrapped)
603605
}
604606
}
607+
608+
@_preInverseGenerics
609+
public var hashValue: Int {
610+
var hasher = Hasher()
611+
hash(into: &hasher)
612+
return hasher.finalize()
613+
}
605614
}
606615

607616
// Enable pattern matching against the nil literal, even if the element type

test/Frontend/dump-parse.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ enum TrailingSemi {
5858
// CHECK-AST-LABEL: (func_decl{{.*}}"generic(_:)" "<T : Hashable>" interface_type="<T where T : Hashable> (T) -> ()" access=internal captures=(<generic> {{.*}})
5959
func generic<T: Hashable>(_: T) {}
6060
// CHECK-AST: (pattern_binding_decl
61-
// 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))
61+
// 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))
6262
let _: (Int) -> () = generic
6363

6464
// Closures should be marked as escaping or not.

test/IRGen/keypaths.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ sil_vtable C2 {}
311311
// CHECK-SAME: <i32 0x3fffffe>
312312

313313
// CHECK-LABEL: @"generic environment SHRzSHR_r0_l" = linkonce_odr hidden constant
314-
// CHECK-SAME: i32 8193, i16 2, i8 -128, i8 -128, i32 128
314+
// CHECK-SAME: i32 16385, i16 2, i8 -128, i8 -128, i32 128
315315

316316
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @stored_property_fixed_offsets()
317317
sil @stored_property_fixed_offsets : $@convention(thin) () -> () {

test/Parse/inverses.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ public struct MoveOnlyS1<T> : ~Copyable { /*deinit {}*/ }
5252
public struct MoveOnlyS2<T: Equatable> : ~Copyable { /*deinit {}*/ }
5353
public struct MoveOnlyS3<T: ~Copyable> : ~Copyable { /*deinit {}*/ }
5454

55-
protocol Rope<Element>: Hashable, ~Copyable { // expected-error {{'Self' required to be 'Copyable' but is marked with '~Copyable'}}
55+
protocol CopyHashable { }
56+
57+
protocol Rope<Element>: CopyHashable, ~Copyable { // expected-error {{'Self' required to be 'Copyable' but is marked with '~Copyable'}}
5658
associatedtype Element: ~Copyable
5759
}
5860

@@ -102,8 +104,8 @@ typealias Z4 = ~Rope<Int> // expected-error {{type 'Rope<Int>' cannot be suppres
102104
typealias Z5 = (~Int) -> Void // expected-error {{type 'Int' cannot be suppressed}}
103105
typealias Z6 = ~() -> () // expected-error {{single argument function types require parentheses}}
104106
// expected-error@-1 {{type '()' cannot be suppressed}}
105-
typealias Z7 = ~(Copyable & Hashable) // expected-error {{type 'Hashable' cannot be suppressed}}
106-
typealias Z8 = ~Copyable & Hashable // expected-error {{composition cannot contain '~Copyable' when another member requires 'Copyable'}}
107+
typealias Z7 = ~(Copyable & CopyHashable) // expected-error {{type 'CopyHashable' cannot be suppressed}}
108+
typealias Z8 = ~Copyable & CopyHashable // expected-error {{composition cannot contain '~Copyable' when another member requires 'Copyable'}}
107109

108110
struct NotAProtocol {}
109111

test/SILGen/synthesized_conformance_enum.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,9 @@ extension NoValues: Codable {}
8383

8484
// CHECK-LABEL: sil_witness_table hidden <T where T : Hashable> Enum<T>: Hashable module synthesized_conformance_enum {
8585
// CHECK-DAG: base_protocol Equatable: <T where T : Equatable> Enum<T>: Equatable module synthesized_conformance_enum
86-
// 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>
87-
// 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>
88-
// 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>
86+
// 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>
87+
// 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>
88+
// 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>
8989
// CHECK-DAG: conditional_conformance (T: Hashable): dependent
9090
// CHECK: }
9191

test/SILGen/synthesized_conformance_struct.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,9 @@ extension Struct: Codable where T: Codable {}
6969

7070
// CHECK-LABEL: sil_witness_table hidden <T where T : Hashable> Struct<T>: Hashable module synthesized_conformance_struct {
7171
// CHECK-DAG: base_protocol Equatable: <T where T : Equatable> Struct<T>: Equatable module synthesized_conformance_struct
72-
// 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>
73-
// 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>
74-
// 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>
72+
// 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>
73+
// 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>
74+
// 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>
7575
// CHECK-DAG: conditional_conformance (T: Hashable): dependent
7676
// CHECK: }
7777

test/Sema/moveonly_illegal_types.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func basic_vararg(_ va: MO...) {} // expected-error {{noncopyable type 'MO' cann
5252
func illegalTypes<T>(_ t: T) {
5353
let _: Array<MO> // expected-error {{type 'MO' does not conform to protocol 'Copyable'}}
5454
let _: Maybe<MO> // expected-error {{type 'MO' does not conform to protocol 'Copyable'}}
55-
let _: Dictionary<MO, String> // expected-error {{type 'MO' does not conform to protocol 'Hashable'}}
55+
let _: Dictionary<MO, String> // expected-error {{type 'MO' does not conform to protocol 'Copyable'}}
5656
let _: [MO] // expected-error {{type 'MO' does not conform to protocol 'Copyable'}}
5757
let _: [String : MO] // expected-error {{type 'MO' does not conform to protocol 'Copyable'}}
5858
let _: [MO : MO] // expected-error {{type 'MO' does not conform to protocol 'Hashable'}}

0 commit comments

Comments
 (0)