blob: 4eaaf507c427e3ca0467e985aac4fef9c7d3b6e6 [file] [log] [blame]
// RUN: %empty-directory(%t)
//
// RUN: %gyb %s -o %t/AnyHashableCasts.swift
// RUN: %target-build-swift -g -module-name a %t/AnyHashableCasts.swift -o %t.out
// RUN: %target-run %t.out
// RUN: %target-build-swift -g -O -module-name a %t/AnyHashableCasts.swift -o %t.out.optimized
// RUN: %target-run %t.out.optimized
// REQUIRES: executable_test
import StdlibUnittest
#if _runtime(_ObjC)
import Foundation
#endif
var AnyHashableCasts = TestSuite("AnyHashableCasts")
protocol Implemented {}
protocol Unimplemented {}
extension Int : Implemented {}
struct HashableStruct : Hashable {
var value : Int
static func ==(lhs: HashableStruct, rhs: HashableStruct) -> Bool {
return lhs.value == rhs.value
}
var hashValue : Int { return value }
}
class HashableClass : Hashable {
var value : Int
init(value v: Int) { self.value = v }
static func ==(lhs: HashableClass, rhs: HashableClass) -> Bool {
return lhs.value == rhs.value
}
var hashValue : Int { return value }
}
enum HashableEnum : Hashable {
case value(Int)
static func ==(lhs: HashableEnum, rhs: HashableEnum) -> Bool {
switch (lhs, rhs) {
case (.value(let l), .value(let r)): return l == r
}
}
var hashValue : Int {
switch self {
case .value(let v): return v
}
}
}
func opaqueCast<T, U>(_ lhs: T, _ rhs: U.Type) -> U? {
return lhs as? U
}
func matches<T: Equatable>(_ lhs: T, _ rhs: T) -> Bool {
return lhs == rhs
}
func matches<T: Equatable, U>(_ lhs: U, _ rhs: T) -> Bool {
if let x = lhs as? T {
return x == rhs
} else {
return false
}
}
%{
testCases = [
("5", "AnyHashable", "Int", "5"),
("5", "AnyHashable", "Any", "5"),
("5", "AnyHashable", "Implemented", "5"),
("5", "AnyHashable", "Unimplemented", False),
("5", "Int", "AnyHashable", "5"),
("5", "Any", "AnyHashable", "5"),
("AnyHashable(5)", "Any", "Int", "5"),
("HashableStruct(value: 5)", "HashableStruct", "AnyHashable",
"AnyHashable(HashableStruct(value: 5))"),
("HashableClass(value: 5)", "HashableClass", "AnyHashable",
"AnyHashable(HashableClass(value: 5))"),
("HashableEnum.value(5)", "HashableEnum", "AnyHashable",
"AnyHashable(HashableEnum.value(5))"),
]
}%
% for valueExpr, coercedType, castType, expected in testCases:
AnyHashableCasts.test("${valueExpr} as ${coercedType} as? ${castType}") {
do {
let x = ${valueExpr}
let y : ${coercedType} = x
if let z = y as? ${castType} {
%if expected:
expectTrue(matches(z, ${expected}))
%else:
expectUnreachable()
%end
} else {
%if expected:
expectUnreachable()
%end
}
if let z = opaqueCast(y, (${castType}).self) {
%if expected:
expectTrue(matches(z, ${expected}))
%else:
expectUnreachable()
%end
} else {
%if expected:
expectUnreachable()
%end
}
}
}
% end
#if _runtime(_ObjC)
// A wrapper type around a String that bridges to NSString.
struct StringWrapper1 : _SwiftNewtypeWrapper, Hashable, _ObjectiveCBridgeable {
let rawValue: String
}
// A wrapper type around a String that bridges to NSString.
struct StringWrapper2 : _SwiftNewtypeWrapper, Hashable, _ObjectiveCBridgeable {
let rawValue: String
}
AnyHashableCasts.test("Wrappers around bridged types") {
let wrapper1Hello: AnyHashable = StringWrapper1(rawValue: "hello")
let stringHello: AnyHashable = "hello" as String
let nsStringHello: AnyHashable = "hello" as NSString
// Casting from Swift wrapper maintains type identity
expectNotNil(wrapper1Hello as? StringWrapper1)
expectNil(wrapper1Hello as? StringWrapper2)
expectNil(wrapper1Hello as? String)
expectNotNil(wrapper1Hello as? NSString)
// Casting from String maintains type identity
expectNil(stringHello as? StringWrapper1)
expectNil(stringHello as? StringWrapper2)
expectNotNil(stringHello as? String)
expectNotNil(stringHello as? NSString)
// Casting form NSString works with anything.
expectNotNil(nsStringHello as? StringWrapper1)
expectNotNil(nsStringHello as? StringWrapper2)
expectNotNil(nsStringHello as? String)
expectNotNil(nsStringHello as? NSString)
}
#endif
runAllTests()