Skip to content

Commit 4507da4

Browse files
authored
Merge pull request #3821 from apple/stdlib-anyhashable-test-improvements
[stdlib] Improvements for AnyHashable tests
2 parents 2a422ae + f4944f4 commit 4507da4

File tree

5 files changed

+229
-28
lines changed

5 files changed

+229
-28
lines changed

stdlib/private/StdlibUnittest/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ add_swift_library(swiftStdlibUnittest ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_STD
1515
# filename.
1616
StdlibUnittest.swift.gyb
1717

18+
InspectValue.cpp
19+
InspectValue.swift
1820
InterceptTraps.cpp
1921
LifetimeTracked.swift
2022
MinimalTypes.swift.gyb
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "swift/Runtime/Config.h"
14+
#include "swift/Runtime/Metadata.h"
15+
16+
using namespace swift;
17+
18+
SWIFT_CC(swift)
19+
extern "C"
20+
uint32_t swift_StdlibUnittest_getMetadataKindOf(
21+
OpaqueValue *value,
22+
const Metadata *type
23+
) {
24+
auto result = uint32_t(type->getKind());
25+
type->vw_destroy(value);
26+
return result;
27+
}
28+
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
// namespace
14+
public enum SwiftRuntime {
15+
public enum MetadataKind : Int {
16+
case `class` = 0
17+
case `struct` = 1
18+
case `enum` = 2
19+
case optional = 3
20+
case opaque = 8
21+
case tuple = 9
22+
case function = 10
23+
case existential = 12
24+
case metatype = 13
25+
case objCClassWrapper = 14
26+
case existentialMetatype = 15
27+
case foreignClass = 16
28+
case heapLocalVariable = 64
29+
case heapGenericLocalVariable = 65
30+
case errorObject = 128
31+
}
32+
33+
@_silgen_name("swift_StdlibUnittest_getMetadataKindOf")
34+
static func _metadataKindImpl<T>(of value: T) -> UInt32
35+
36+
public static func metadataKind<T>(of value: T) -> MetadataKind {
37+
return MetadataKind(rawValue: Int(_metadataKindImpl(of: value)))!
38+
}
39+
}
40+

stdlib/public/stubs/AnyHashableSupport.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ extern "C" void _swift_stdlib_makeAnyHashableUpcastingToHashableBaseType(
103103
case MetadataKind::Class:
104104
case MetadataKind::ObjCClassWrapper:
105105
case MetadataKind::ForeignClass: {
106-
// FIXME(id-as-any): handle ForeignClass.
107106
_swift_stdlib_makeAnyHashableUsingDefaultRepresentation(
108107
value, anyHashableResultPointer, findHashableBaseType(type),
109108
hashableWT);
@@ -118,7 +117,8 @@ extern "C" void _swift_stdlib_makeAnyHashableUpcastingToHashableBaseType(
118117
return;
119118

120119
case MetadataKind::ErrorObject:
121-
// FIXME(id-as-any): handle ErrorObject.
120+
// ErrorObject metadata is not used for any Swift-level values, so
121+
// this case is unreachable.
122122
_failCorruptType(type);
123123

124124
case MetadataKind::Opaque:

validation-test/stdlib/AnyHashable.swift.gyb

Lines changed: 157 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
11
// RUN: %target-run-simple-swiftgyb
22
// REQUIRES: executable_test
33

4-
// FIXME(id-as-any): add tests that use CF objects (is this even
5-
// possible?)
6-
7-
// FIXME(id-as-any): add tests that use Swift errors and
8-
// Objective-C errors.
9-
10-
// FIXME(id-as-any): add tests for enums.
11-
124
// FIXME(id-as-any): add tests for unboxing.
135

6+
// FIXME(id-as-any): add tests for the _ObjectiveCBridgeable conformance.
7+
148
%{
159
import re
1610

@@ -81,8 +75,9 @@ AnyHashableTests.test("AnyHashable(${wrapped})/Hashable") {
8175
}
8276
checkHashable(xs, equalityOracle: { $0 / 2 == $1 / 2 })
8377

84-
let anyHashableXs = xs.map(AnyHashable.init)
85-
checkHashable(anyHashableXs, equalityOracle: { $0 / 2 == $1 / 2 })
78+
checkHashable(
79+
xs.map(AnyHashable.init),
80+
equalityOracle: { $0 / 2 == $1 / 2 })
8681
}
8782
% end
8883

@@ -101,8 +96,9 @@ AnyHashableTests.test("AnyHashable(${wrapped}<OpaqueValue<Int>>)/Hashable") {
10196
}
10297
checkHashable(xs, equalityOracle: { $0 / 2 == $1 / 2 })
10398

104-
let anyHashableXs = xs.map(AnyHashable.init)
105-
checkHashable(anyHashableXs, equalityOracle: { $0 / 2 == $1 / 2 })
99+
checkHashable(
100+
xs.map(AnyHashable.init),
101+
equalityOracle: { $0 / 2 == $1 / 2 })
106102
}
107103
% end
108104
% end
@@ -196,7 +192,7 @@ ${kw} HasCustomRepresentation_Generic${name}<Wrapped>
196192
% for name in [ 'Class', 'PODStruct', 'RCStruct' ]:
197193
% wrapped = 'HasCustomRepresentation_%s' % name
198194
% genericWrapped = 'HasCustomRepresentation_Generic%s' % name
199-
AnyHashableTests.test("AnyHashable with ${wrapped}") {
195+
AnyHashableTests.test("AnyHashable containing ${wrapped}") {
200196
let xs = (-2...2).flatMap {
201197
[ ${wrapped}(
202198
$0, identity: 0,
@@ -207,12 +203,13 @@ AnyHashableTests.test("AnyHashable with ${wrapped}") {
207203
}
208204
checkHashable(xs, equalityOracle: { $0 / 2 == $1 / 2 })
209205

210-
let anyHashableXs = xs.map(AnyHashable.init)
211-
checkHashable(anyHashableXs, equalityOracle: { $0 / 2 == $1 / 2 })
206+
checkHashable(
207+
xs.map(AnyHashable.init),
208+
equalityOracle: { $0 / 2 == $1 / 2 })
212209
}
213210

214211
% for payload in [ 'OpaqueValue<Int>', 'LifetimeTracked' ]:
215-
AnyHashableTests.test("AnyHashable with ${genericWrapped} with ${payload}") {
212+
AnyHashableTests.test("AnyHashable containing ${genericWrapped} with ${payload}") {
216213
GenericMinimalHashableValue_equalImpl.value = {
217214
($0 as! ${payload}).value == ($1 as! ${payload}).value
218215
}
@@ -229,8 +226,9 @@ AnyHashableTests.test("AnyHashable with ${genericWrapped} with ${payload}") {
229226
}
230227
checkHashable(xs, equalityOracle: { $0 / 2 == $1 / 2 })
231228

232-
let anyHashableXs = xs.map(AnyHashable.init)
233-
checkHashable(anyHashableXs, equalityOracle: { $0 / 2 == $1 / 2 })
229+
checkHashable(
230+
xs.map(AnyHashable.init),
231+
equalityOracle: { $0 / 2 == $1 / 2 })
234232
}
235233
% end
236234
% end
@@ -260,7 +258,7 @@ struct HasCustomRepresentationRecursively
260258
}
261259
}
262260

263-
AnyHashableTests.test("AnyHashable with recursive custom representations") {
261+
AnyHashableTests.test("AnyHashable containing values with recursive custom representations") {
264262
GenericMinimalHashableValue_equalImpl.value = {
265263
($0 as! ${payload}).value == ($1 as! ${payload}).value
266264
}
@@ -390,7 +388,7 @@ class ${Self.full_name} : ${Super.full_name} {}
390388
% end
391389
% end
392390

393-
AnyHashableTests.test("AnyHashable with classes from the ${prefix} hierarchy") {
391+
AnyHashableTests.test("AnyHashable containing classes from the ${prefix} hierarchy") {
394392
typealias T = Int
395393
let xs = [
396394
% for (i, (Self, _)) in enumerate(types):
@@ -416,8 +414,9 @@ AnyHashableTests.test("AnyHashable with classes from the ${prefix} hierarchy") {
416414
}
417415
checkHashable(xs, equalityOracle: equalityOracle)
418416

419-
let anyHashableXs = xs.map(AnyHashable.init)
420-
checkHashable(anyHashableXs, equalityOracle: equalityOracle)
417+
checkHashable(
418+
xs.map(AnyHashable.init),
419+
equalityOracle: equalityOracle)
421420
}
422421
${'#endif' if 'ObjC' in prefix else ''}
423422

@@ -466,29 +465,161 @@ let interestingBitVectorArrays: [[UInt8]] = [
466465
[0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88],
467466
]
468467

469-
AnyHashableTests.test("CFBitVector/Hashable") {
470-
let bitVectors = interestingBitVectorArrays.map(CFBitVector.makeImmutable)
468+
AnyHashableTests.test("AnyHashable containing CFBitVector") {
469+
let bitVectors: [CFBitVector] =
470+
interestingBitVectorArrays.map(CFBitVector.makeImmutable)
471471
let arrays = bitVectors.map { $0.asArray }
472472
func isEq(_ lhs: [[UInt8]], _ rhs: [[UInt8]]) -> Bool {
473473
return zip(lhs, rhs).map { $0 == $1 }.reduce(true, { $0 && $1 })
474474
}
475475
expectEqualTest(interestingBitVectorArrays, arrays, sameValue: isEq)
476476
checkHashable(bitVectors, equalityOracle: { $0 == $1 })
477+
478+
expectEqual(.foreignClass, SwiftRuntime.metadataKind(of: bitVectors.first!))
479+
480+
checkHashable(
481+
bitVectors.map(AnyHashable.init),
482+
equalityOracle: { $0 == $1 })
483+
484+
let bitVectorsAsAnyObjects: [NSObject] = bitVectors.map {
485+
($0 as AnyObject) as! NSObject
486+
}
487+
expectEqual(
488+
.objCClassWrapper,
489+
SwiftRuntime.metadataKind(of: bitVectorsAsAnyObjects.first!))
490+
checkHashable(
491+
bitVectorsAsAnyObjects.map(AnyHashable.init),
492+
equalityOracle: { $0 == $1 })
477493
}
478494

479-
AnyHashableTests.test("CFMutableBitVector/Hashable") {
495+
AnyHashableTests.test("AnyHashable containing CFMutableBitVector") {
480496
// CFMutableBitVector inherits the Hashable conformance from
481497
// CFBitVector.
482-
let bitVectors =
498+
let bitVectors: [CFMutableBitVector] =
483499
interestingBitVectorArrays.map(CFMutableBitVector.makeMutable)
484500
let arrays = bitVectors.map { $0.asArray }
485501
func isEq(_ lhs: [[UInt8]], _ rhs: [[UInt8]]) -> Bool {
486502
return zip(lhs, rhs).map { $0 == $1 }.reduce(true, { $0 && $1 })
487503
}
488504
expectEqualTest(interestingBitVectorArrays, arrays, sameValue: isEq)
489505
checkHashable(bitVectors, equalityOracle: { $0 == $1 })
506+
507+
expectEqual(.foreignClass, SwiftRuntime.metadataKind(of: bitVectors.first!))
508+
509+
checkHashable(
510+
bitVectors.map(AnyHashable.init),
511+
equalityOracle: { $0 == $1 })
512+
513+
let bitVectorsAsAnyObjects: [NSObject] = bitVectors.map {
514+
($0 as AnyObject) as! NSObject
515+
}
516+
checkHashable(bitVectors, equalityOracle: { $0 == $1 })
517+
expectEqual(
518+
.objCClassWrapper,
519+
SwiftRuntime.metadataKind(of: bitVectorsAsAnyObjects.first!))
520+
checkHashable(
521+
bitVectorsAsAnyObjects.map(AnyHashable.init),
522+
equalityOracle: { $0 == $1 })
523+
}
524+
525+
#endif
526+
527+
enum MinimalHashablePODSwiftError : Error, Hashable {
528+
case caseA
529+
case caseB
530+
case caseC
490531
}
491532

533+
enum MinimalHashableRCSwiftError : Error, Hashable {
534+
case caseA(LifetimeTracked)
535+
case caseB(LifetimeTracked)
536+
case caseC(LifetimeTracked)
537+
538+
var hashValue: Int {
539+
return 0
540+
}
541+
542+
static func == (
543+
lhs: MinimalHashableRCSwiftError,
544+
rhs: MinimalHashableRCSwiftError
545+
) -> Bool {
546+
switch (lhs, rhs) {
547+
case (.caseA(let lhs), .caseA(let rhs)):
548+
return lhs == rhs
549+
case (.caseB(let lhs), .caseB(let rhs)):
550+
return lhs == rhs
551+
case (.caseC(let lhs), .caseC(let rhs)):
552+
return lhs == rhs
553+
default:
554+
return false
555+
}
556+
}
557+
}
558+
559+
AnyHashableTests.test("AnyHashable containing MinimalHashablePODSwiftError") {
560+
let xs: [MinimalHashablePODSwiftError] = [
561+
.caseA, .caseA,
562+
.caseB, .caseB,
563+
.caseC, .caseC,
564+
]
565+
expectEqual(.enum, SwiftRuntime.metadataKind(of: xs.first!))
566+
checkHashable(xs, equalityOracle: { $0 / 2 == $1 / 2 })
567+
checkHashable(
568+
xs.map(AnyHashable.init),
569+
equalityOracle: { $0 / 2 == $1 / 2 })
570+
}
571+
572+
AnyHashableTests.test("AnyHashable containing MinimalHashableRCSwiftError") {
573+
let xs: [MinimalHashableRCSwiftError] = [
574+
.caseA(LifetimeTracked(1)), .caseA(LifetimeTracked(1)),
575+
.caseA(LifetimeTracked(2)), .caseA(LifetimeTracked(2)),
576+
.caseB(LifetimeTracked(1)), .caseB(LifetimeTracked(1)),
577+
.caseB(LifetimeTracked(2)), .caseB(LifetimeTracked(2)),
578+
.caseC(LifetimeTracked(1)), .caseC(LifetimeTracked(1)),
579+
.caseC(LifetimeTracked(2)), .caseC(LifetimeTracked(2)),
580+
]
581+
expectEqual(.enum, SwiftRuntime.metadataKind(of: xs.first!))
582+
checkHashable(xs, equalityOracle: { $0 / 2 == $1 / 2 })
583+
checkHashable(
584+
xs.map(AnyHashable.init),
585+
equalityOracle: { $0 / 2 == $1 / 2 })
586+
}
587+
588+
#if _runtime(_ObjC)
589+
AnyHashableTests.test("AnyHashable containing _SwiftNativeNSError") {
590+
let swiftErrors: [MinimalHashablePODSwiftError] = [
591+
.caseA, .caseA,
592+
.caseB, .caseB,
593+
.caseC, .caseC,
594+
]
595+
let nsErrors: [NSError] = swiftErrors.map { $0 as NSError }
596+
expectEqual(
597+
.objCClassWrapper,
598+
SwiftRuntime.metadataKind(of: nsErrors.first!))
599+
expectEqual("_SwiftNativeNSError", String(nsErrors[0].dynamicType))
600+
checkHashable(nsErrors, equalityOracle: { $0 / 2 == $1 / 2 })
601+
checkHashable(
602+
nsErrors.map(AnyHashable.init),
603+
equalityOracle: { $0 / 2 == $1 / 2 })
604+
}
605+
606+
AnyHashableTests.test("AnyHashable containing NSError") {
607+
let nsErrors: [NSError] = [
608+
NSError(domain: "Foo", code: 0),
609+
NSError(domain: "Foo", code: 0),
610+
NSError(domain: "Foo", code: 1),
611+
NSError(domain: "Foo", code: 1),
612+
NSError(domain: "Foo", code: 2),
613+
NSError(domain: "Foo", code: 2),
614+
]
615+
expectEqual(
616+
.objCClassWrapper,
617+
SwiftRuntime.metadataKind(of: nsErrors.first!))
618+
checkHashable(nsErrors, equalityOracle: { $0 / 2 == $1 / 2 })
619+
checkHashable(
620+
nsErrors.map(AnyHashable.init),
621+
equalityOracle: { $0 / 2 == $1 / 2 })
622+
}
492623
#endif
493624

494625
runAllTests()

0 commit comments

Comments
 (0)