Skip to content

Commit e051c61

Browse files
authored
Merge pull request #3554 from apple/stdlib-AnyHashable
2 parents 0ed9ee8 + e9f1bcc commit e051c61

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+2722
-59
lines changed

include/swift/Runtime/Debug.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <llvm/Support/Compiler.h>
2121
#include <stdint.h>
2222
#include "swift/Runtime/Config.h"
23+
#include "swift/Runtime/Metadata.h"
2324

2425
#ifdef SWIFT_HAVE_CRASHREPORTERCLIENT
2526

@@ -78,6 +79,13 @@ static inline void crash(const char *message) {
7879
__builtin_unreachable();
7980
}
8081

82+
/// Report a corrupted type object.
83+
LLVM_ATTRIBUTE_NORETURN
84+
LLVM_ATTRIBUTE_ALWAYS_INLINE // Minimize trashed registers
85+
static inline void _failCorruptType(const Metadata *type) {
86+
swift::crash("Corrupt Swift type object");
87+
}
88+
8189
// swift::fatalError() halts with a crash log message,
8290
// but makes no attempt to preserve register state.
8391
LLVM_ATTRIBUTE_NORETURN

include/swift/Runtime/Metadata.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3447,6 +3447,10 @@ void swift_registerTypeMetadataRecords(const TypeMetadataRecord *begin,
34473447
std::string nameForMetadata(const Metadata *type,
34483448
bool qualified = true);
34493449

3450+
SWIFT_RUNTIME_STDLIB_INTERFACE
3451+
extern "C"
3452+
const Metadata *_swift_class_getSuperclass(const Metadata *theClass);
3453+
34503454
} // end namespace swift
34513455

34523456
#pragma clang diagnostic pop

stdlib/private/StdlibUnittest/MinimalTypes.swift.gyb

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,51 @@ public func == (
148148

149149
% end
150150

151+
% for kind in [ 'Value', 'Class' ]:
152+
% Self = 'GenericMinimalHashable%s' % kind
153+
154+
public var ${Self}_timesEqualEqualWasCalled: Int = 0
155+
public var ${Self}_timesHashValueWasCalled: Int = 0
156+
157+
public var ${Self}_equalImpl = ResettableValue<(Any, Any) -> Bool>(
158+
{ _, _ in fatalError("${Self}_equalImpl is not set yet"); () })
159+
public var ${Self}_hashValueImpl = ResettableValue<(Any) -> Int>(
160+
{ _ in fatalError("${Self}_hashValueImpl is not set yet"); () })
161+
162+
/// A type that conforms only to `Equatable` and `Hashable`.
163+
///
164+
/// This type can be used to check that generic functions don't rely on any
165+
/// other conformances.
166+
public struct ${Self}<Wrapped> : Equatable, Hashable {
167+
public var value: Wrapped
168+
public var identity: Int
169+
170+
public init(_ value: Wrapped) {
171+
self.value = value
172+
self.identity = 0
173+
}
174+
175+
public init(_ value: Wrapped, identity: Int) {
176+
self.value = value
177+
self.identity = identity
178+
}
179+
180+
public var hashValue: Int {
181+
${Self}_timesHashValueWasCalled += 1
182+
return ${Self}_hashValueImpl.value(value)
183+
}
184+
}
185+
186+
public func == <Wrapped>(
187+
lhs: ${Self}<Wrapped>,
188+
rhs: ${Self}<Wrapped>
189+
) -> Bool {
190+
${Self}_timesEqualEqualWasCalled += 1
191+
return ${Self}_equalImpl.value(lhs.value, rhs.value)
192+
}
193+
194+
% end
195+
151196
/// A type that conforms only to `Equatable`, `Comparable`, and `Strideable`.
152197
///
153198
/// This type can be used to check that generic functions don't rely on any

stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1939,56 +1939,71 @@ public func checkEquatable<Instances : Collection>(
19391939
Instances.Iterator.Element : Equatable,
19401940
// FIXME(compiler limitation): these constraints should be applied to
19411941
// associated types of Collection.
1942-
Instances.Indices.Iterator.Element == Instances.Index {
1942+
Instances.Indices.Iterator.Element == Instances.Index
1943+
{
1944+
let indices = Array(instances.indices)
1945+
_checkEquatableImpl(
1946+
Array(instances),
1947+
oracle: { oracle(indices[$0], indices[$1]) })
1948+
}
1949+
1950+
internal func _checkEquatableImpl<Instance : Equatable>(
1951+
_ instances: [Instance],
1952+
oracle: (Int, Int) -> Bool,
1953+
${TRACE}
1954+
) {
1955+
// For each index (which corresponds to an instance being tested) track the
1956+
// set of equal instances.
1957+
var transitivityScoreboard: [Box<Set<Int>>] =
1958+
instances.indices.map { _ in Box(Set()) }
19431959

19441960
// TODO: swift-3-indexing-model: add tests for this function.
19451961
for i in instances.indices {
1946-
expectTrue(oracle(i, i), "bad oracle: broken reflexivity at index \(i)")
19471962
let x = instances[i]
1948-
// Reflexivity
1949-
expectEqual(x, x, ${trace})
1963+
expectTrue(oracle(i, i), "bad oracle: broken reflexivity at index \(i)")
1964+
19501965
for j in instances.indices {
1966+
let y = instances[j]
1967+
19511968
let predictedXY = oracle(i, j)
19521969
expectEqual(
19531970
predictedXY, oracle(j, i),
19541971
"bad oracle: broken symmetry between indices \(i), \(j)")
1955-
1956-
let y = instances[j]
19571972

1958-
let xy = x == y
1973+
let isEqualXY = x == y
19591974
expectEqual(
1960-
predictedXY, xy,
1975+
predictedXY, isEqualXY,
19611976
"lhs (at index \(i)): \(x)\nrhs (at index \(j)): \(y)",
19621977
stackTrace: ${stackTrace})
19631978

1964-
// Not-equal is an inverse of equal
1979+
// Not-equal is an inverse of equal.
19651980
expectNotEqual(
1966-
xy, x != y,
1967-
"lhs (at index \(i)): \(x)\nrhs (at index \(j)): \(y)",
1968-
stackTrace: ${stackTrace})
1969-
1970-
// Symmetry
1971-
expectEqual(
1972-
xy, y == x,
1981+
isEqualXY, x != y,
19731982
"lhs (at index \(i)): \(x)\nrhs (at index \(j)): \(y)",
19741983
stackTrace: ${stackTrace})
19751984

1976-
for k in instances.indices {
1977-
let z = instances[k]
1978-
// Transitivity
1979-
let predictedYZ = oracle(j, k)
1980-
if predictedXY && predictedYZ {
1985+
// Check transitivity of the predicate represented by the oracle.
1986+
// If we are adding the instance `j` into an equivalence set, check that
1987+
// it is equal to every other instance in the set.
1988+
if predictedXY && i < j && transitivityScoreboard[i].value.insert(j).inserted {
1989+
if transitivityScoreboard[i].value.count == 1 {
1990+
transitivityScoreboard[i].value.insert(i)
1991+
}
1992+
for k in transitivityScoreboard[i].value {
19811993
expectTrue(
1982-
oracle(i, k),
1994+
oracle(j, k),
19831995
"bad oracle: broken transitivity at indices \(i), \(j), \(k)")
1984-
expectEqual(y, z, ${trace})
1985-
expectEqual(x, z, ${trace})
1996+
// No need to check equality between actual values, we will check
1997+
// them with the checks above.
19861998
}
1999+
precondition(transitivityScoreboard[j].value.isEmpty)
2000+
transitivityScoreboard[j] = transitivityScoreboard[i]
19872001
}
19882002
}
19892003
}
19902004
}
19912005

2006+
19922007
public func checkEquatable<T : Equatable>(
19932008
_ expectedEqual: Bool, _ lhs: T, _ rhs: T, ${TRACE}
19942009
) {

stdlib/public/SDK/Foundation/AffineTransform.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,4 +293,10 @@ extension AffineTransform : _ObjectiveCBridgeable {
293293
}
294294
}
295295

296+
extension NSAffineTransform : _HasCustomAnyHashableRepresentation {
297+
public func _toCustomAnyHashable() -> AnyHashable? {
298+
return AnyHashable(self as AffineTransform)
299+
}
300+
}
301+
296302
#endif

stdlib/public/SDK/Foundation/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ add_swift_library(swiftFoundation ${SWIFT_SDK_OVERLAY_LIBRARY_BUILD_TYPES} IS_SD
2727
NotificationThunks.m
2828
NSStringEncodings.swift
2929
PersonNameComponents.swift
30+
TypePreservingNSNumber.mm
3031
URL.swift
3132
URLComponents.swift
3233
URLRequest.swift

stdlib/public/SDK/Foundation/Calendar.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,3 +1128,9 @@ extension Calendar : _ObjectiveCBridgeable {
11281128
}
11291129
}
11301130

1131+
extension NSCalendar : _HasCustomAnyHashableRepresentation {
1132+
public func _toCustomAnyHashable() -> AnyHashable? {
1133+
return AnyHashable(self as Calendar)
1134+
}
1135+
}
1136+

stdlib/public/SDK/Foundation/CharacterSet.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,12 @@ extension CharacterSet : _ObjectiveCBridgeable {
463463

464464
}
465465

466+
extension NSCharacterSet : _HasCustomAnyHashableRepresentation {
467+
public func _toCustomAnyHashable() -> AnyHashable? {
468+
return AnyHashable(self as CharacterSet)
469+
}
470+
}
471+
466472
extension _SwiftNSCharacterSet {
467473

468474
// Stubs

stdlib/public/SDK/Foundation/Data.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,12 @@ extension Data : _ObjectiveCBridgeable {
723723
}
724724
}
725725

726+
extension NSData : _HasCustomAnyHashableRepresentation {
727+
public func _toCustomAnyHashable() -> AnyHashable? {
728+
return AnyHashable(self as Data)
729+
}
730+
}
731+
726732
/// A NSData subclass that uses Swift reference counting.
727733
///
728734
/// This subclass implements the API of NSData by holding an instance and forwarding all implementation to that object.

stdlib/public/SDK/Foundation/Date.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,12 @@ extension Date : _ObjectiveCBridgeable {
262262
}
263263
}
264264

265+
extension NSDate : _HasCustomAnyHashableRepresentation {
266+
public func _toCustomAnyHashable() -> AnyHashable? {
267+
return AnyHashable(self as Date)
268+
}
269+
}
270+
265271
extension Date : CustomPlaygroundQuickLookable {
266272
var summary: String {
267273
let df = DateFormatter()

stdlib/public/SDK/Foundation/DateComponents.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,3 +345,9 @@ extension DateComponents : _ObjectiveCBridgeable {
345345
}
346346
}
347347

348+
extension NSDateComponents : _HasCustomAnyHashableRepresentation {
349+
public func _toCustomAnyHashable() -> AnyHashable? {
350+
return AnyHashable(self as DateComponents)
351+
}
352+
}
353+

stdlib/public/SDK/Foundation/DateInterval.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,3 +219,11 @@ extension DateInterval : _ObjectiveCBridgeable {
219219
return result!
220220
}
221221
}
222+
223+
@available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
224+
extension NSDateInterval : _HasCustomAnyHashableRepresentation {
225+
public func _toCustomAnyHashable() -> AnyHashable? {
226+
return AnyHashable(self as DateInterval)
227+
}
228+
}
229+

0 commit comments

Comments
 (0)