Skip to content

[stdlib] Improvements for AnyHashable tests #3821

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jul 28, 2016
Merged
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
2 changes: 2 additions & 0 deletions stdlib/private/StdlibUnittest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ add_swift_library(swiftStdlibUnittest ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_STD
# filename.
StdlibUnittest.swift.gyb

InspectValue.cpp
InspectValue.swift
InterceptTraps.cpp
LifetimeTracked.swift
MinimalTypes.swift.gyb
Expand Down
28 changes: 28 additions & 0 deletions stdlib/private/StdlibUnittest/InspectValue.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "swift/Runtime/Config.h"
#include "swift/Runtime/Metadata.h"

using namespace swift;

SWIFT_CC(swift)
extern "C"
uint32_t swift_StdlibUnittest_getMetadataKindOf(
OpaqueValue *value,
const Metadata *type
) {
auto result = uint32_t(type->getKind());
type->vw_destroy(value);
return result;
}

40 changes: 40 additions & 0 deletions stdlib/private/StdlibUnittest/InspectValue.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

// namespace
public enum SwiftRuntime {
public enum MetadataKind : Int {
case `class` = 0
case `struct` = 1
case `enum` = 2
case optional = 3
case opaque = 8
case tuple = 9
case function = 10
case existential = 12
case metatype = 13
case objCClassWrapper = 14
case existentialMetatype = 15
case foreignClass = 16
case heapLocalVariable = 64
case heapGenericLocalVariable = 65
case errorObject = 128
}

@_silgen_name("swift_StdlibUnittest_getMetadataKindOf")
static func _metadataKindImpl<T>(of value: T) -> UInt32

public static func metadataKind<T>(of value: T) -> MetadataKind {
return MetadataKind(rawValue: Int(_metadataKindImpl(of: value)))!
}
}

4 changes: 2 additions & 2 deletions stdlib/public/stubs/AnyHashableSupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ extern "C" void _swift_stdlib_makeAnyHashableUpcastingToHashableBaseType(
case MetadataKind::Class:
case MetadataKind::ObjCClassWrapper:
case MetadataKind::ForeignClass: {
// FIXME(id-as-any): handle ForeignClass.
_swift_stdlib_makeAnyHashableUsingDefaultRepresentation(
value, anyHashableResultPointer, findHashableBaseType(type),
hashableWT);
Expand All @@ -118,7 +117,8 @@ extern "C" void _swift_stdlib_makeAnyHashableUpcastingToHashableBaseType(
return;

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

case MetadataKind::Opaque:
Expand Down
183 changes: 157 additions & 26 deletions validation-test/stdlib/AnyHashable.swift.gyb
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
// RUN: %target-run-simple-swiftgyb
// REQUIRES: executable_test

// FIXME(id-as-any): add tests that use CF objects (is this even
// possible?)

// FIXME(id-as-any): add tests that use Swift errors and
// Objective-C errors.

// FIXME(id-as-any): add tests for enums.

// FIXME(id-as-any): add tests for unboxing.

// FIXME(id-as-any): add tests for the _ObjectiveCBridgeable conformance.

%{
import re

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

let anyHashableXs = xs.map(AnyHashable.init)
checkHashable(anyHashableXs, equalityOracle: { $0 / 2 == $1 / 2 })
checkHashable(
xs.map(AnyHashable.init),
equalityOracle: { $0 / 2 == $1 / 2 })
}
% end

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

let anyHashableXs = xs.map(AnyHashable.init)
checkHashable(anyHashableXs, equalityOracle: { $0 / 2 == $1 / 2 })
checkHashable(
xs.map(AnyHashable.init),
equalityOracle: { $0 / 2 == $1 / 2 })
}
% end
% end
Expand Down Expand Up @@ -196,7 +192,7 @@ ${kw} HasCustomRepresentation_Generic${name}<Wrapped>
% for name in [ 'Class', 'PODStruct', 'RCStruct' ]:
% wrapped = 'HasCustomRepresentation_%s' % name
% genericWrapped = 'HasCustomRepresentation_Generic%s' % name
AnyHashableTests.test("AnyHashable with ${wrapped}") {
AnyHashableTests.test("AnyHashable containing ${wrapped}") {
let xs = (-2...2).flatMap {
[ ${wrapped}(
$0, identity: 0,
Expand All @@ -207,12 +203,13 @@ AnyHashableTests.test("AnyHashable with ${wrapped}") {
}
checkHashable(xs, equalityOracle: { $0 / 2 == $1 / 2 })

let anyHashableXs = xs.map(AnyHashable.init)
checkHashable(anyHashableXs, equalityOracle: { $0 / 2 == $1 / 2 })
checkHashable(
xs.map(AnyHashable.init),
equalityOracle: { $0 / 2 == $1 / 2 })
}

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

let anyHashableXs = xs.map(AnyHashable.init)
checkHashable(anyHashableXs, equalityOracle: { $0 / 2 == $1 / 2 })
checkHashable(
xs.map(AnyHashable.init),
equalityOracle: { $0 / 2 == $1 / 2 })
}
% end
% end
Expand Down Expand Up @@ -260,7 +258,7 @@ struct HasCustomRepresentationRecursively
}
}

AnyHashableTests.test("AnyHashable with recursive custom representations") {
AnyHashableTests.test("AnyHashable containing values with recursive custom representations") {
GenericMinimalHashableValue_equalImpl.value = {
($0 as! ${payload}).value == ($1 as! ${payload}).value
}
Expand Down Expand Up @@ -390,7 +388,7 @@ class ${Self.full_name} : ${Super.full_name} {}
% end
% end

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

let anyHashableXs = xs.map(AnyHashable.init)
checkHashable(anyHashableXs, equalityOracle: equalityOracle)
checkHashable(
xs.map(AnyHashable.init),
equalityOracle: equalityOracle)
}
${'#endif' if 'ObjC' in prefix else ''}

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

AnyHashableTests.test("CFBitVector/Hashable") {
let bitVectors = interestingBitVectorArrays.map(CFBitVector.makeImmutable)
AnyHashableTests.test("AnyHashable containing CFBitVector") {
let bitVectors: [CFBitVector] =
interestingBitVectorArrays.map(CFBitVector.makeImmutable)
let arrays = bitVectors.map { $0.asArray }
func isEq(_ lhs: [[UInt8]], _ rhs: [[UInt8]]) -> Bool {
return zip(lhs, rhs).map { $0 == $1 }.reduce(true, { $0 && $1 })
}
expectEqualTest(interestingBitVectorArrays, arrays, sameValue: isEq)
checkHashable(bitVectors, equalityOracle: { $0 == $1 })

expectEqual(.foreignClass, SwiftRuntime.metadataKind(of: bitVectors.first!))

checkHashable(
bitVectors.map(AnyHashable.init),
equalityOracle: { $0 == $1 })

let bitVectorsAsAnyObjects: [NSObject] = bitVectors.map {
($0 as AnyObject) as! NSObject
}
expectEqual(
.objCClassWrapper,
SwiftRuntime.metadataKind(of: bitVectorsAsAnyObjects.first!))
checkHashable(
bitVectorsAsAnyObjects.map(AnyHashable.init),
equalityOracle: { $0 == $1 })
}

AnyHashableTests.test("CFMutableBitVector/Hashable") {
AnyHashableTests.test("AnyHashable containing CFMutableBitVector") {
// CFMutableBitVector inherits the Hashable conformance from
// CFBitVector.
let bitVectors =
let bitVectors: [CFMutableBitVector] =
interestingBitVectorArrays.map(CFMutableBitVector.makeMutable)
let arrays = bitVectors.map { $0.asArray }
func isEq(_ lhs: [[UInt8]], _ rhs: [[UInt8]]) -> Bool {
return zip(lhs, rhs).map { $0 == $1 }.reduce(true, { $0 && $1 })
}
expectEqualTest(interestingBitVectorArrays, arrays, sameValue: isEq)
checkHashable(bitVectors, equalityOracle: { $0 == $1 })

expectEqual(.foreignClass, SwiftRuntime.metadataKind(of: bitVectors.first!))

checkHashable(
bitVectors.map(AnyHashable.init),
equalityOracle: { $0 == $1 })

let bitVectorsAsAnyObjects: [NSObject] = bitVectors.map {
($0 as AnyObject) as! NSObject
}
checkHashable(bitVectors, equalityOracle: { $0 == $1 })
expectEqual(
.objCClassWrapper,
SwiftRuntime.metadataKind(of: bitVectorsAsAnyObjects.first!))
checkHashable(
bitVectorsAsAnyObjects.map(AnyHashable.init),
equalityOracle: { $0 == $1 })
}

#endif

enum MinimalHashablePODSwiftError : Error, Hashable {
case caseA
case caseB
case caseC
}

enum MinimalHashableRCSwiftError : Error, Hashable {
case caseA(LifetimeTracked)
case caseB(LifetimeTracked)
case caseC(LifetimeTracked)

var hashValue: Int {
return 0
}

static func == (
lhs: MinimalHashableRCSwiftError,
rhs: MinimalHashableRCSwiftError
) -> Bool {
switch (lhs, rhs) {
case (.caseA(let lhs), .caseA(let rhs)):
return lhs == rhs
case (.caseB(let lhs), .caseB(let rhs)):
return lhs == rhs
case (.caseC(let lhs), .caseC(let rhs)):
return lhs == rhs
default:
return false
}
}
}

AnyHashableTests.test("AnyHashable containing MinimalHashablePODSwiftError") {
let xs: [MinimalHashablePODSwiftError] = [
.caseA, .caseA,
.caseB, .caseB,
.caseC, .caseC,
]
expectEqual(.enum, SwiftRuntime.metadataKind(of: xs.first!))
checkHashable(xs, equalityOracle: { $0 / 2 == $1 / 2 })
checkHashable(
xs.map(AnyHashable.init),
equalityOracle: { $0 / 2 == $1 / 2 })
}

AnyHashableTests.test("AnyHashable containing MinimalHashableRCSwiftError") {
let xs: [MinimalHashableRCSwiftError] = [
.caseA(LifetimeTracked(1)), .caseA(LifetimeTracked(1)),
.caseA(LifetimeTracked(2)), .caseA(LifetimeTracked(2)),
.caseB(LifetimeTracked(1)), .caseB(LifetimeTracked(1)),
.caseB(LifetimeTracked(2)), .caseB(LifetimeTracked(2)),
.caseC(LifetimeTracked(1)), .caseC(LifetimeTracked(1)),
.caseC(LifetimeTracked(2)), .caseC(LifetimeTracked(2)),
]
expectEqual(.enum, SwiftRuntime.metadataKind(of: xs.first!))
checkHashable(xs, equalityOracle: { $0 / 2 == $1 / 2 })
checkHashable(
xs.map(AnyHashable.init),
equalityOracle: { $0 / 2 == $1 / 2 })
}

#if _runtime(_ObjC)
AnyHashableTests.test("AnyHashable containing _SwiftNativeNSError") {
let swiftErrors: [MinimalHashablePODSwiftError] = [
.caseA, .caseA,
.caseB, .caseB,
.caseC, .caseC,
]
let nsErrors: [NSError] = swiftErrors.map { $0 as NSError }
expectEqual(
.objCClassWrapper,
SwiftRuntime.metadataKind(of: nsErrors.first!))
expectEqual("_SwiftNativeNSError", String(nsErrors[0].dynamicType))
checkHashable(nsErrors, equalityOracle: { $0 / 2 == $1 / 2 })
checkHashable(
nsErrors.map(AnyHashable.init),
equalityOracle: { $0 / 2 == $1 / 2 })
}

AnyHashableTests.test("AnyHashable containing NSError") {
let nsErrors: [NSError] = [
NSError(domain: "Foo", code: 0),
NSError(domain: "Foo", code: 0),
NSError(domain: "Foo", code: 1),
NSError(domain: "Foo", code: 1),
NSError(domain: "Foo", code: 2),
NSError(domain: "Foo", code: 2),
]
expectEqual(
.objCClassWrapper,
SwiftRuntime.metadataKind(of: nsErrors.first!))
checkHashable(nsErrors, equalityOracle: { $0 / 2 == $1 / 2 })
checkHashable(
nsErrors.map(AnyHashable.init),
equalityOracle: { $0 / 2 == $1 / 2 })
}
#endif

runAllTests()
Expand Down