1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
|
//===--- SwiftObjectNSObject.swift - Test SwiftObject's NSObject interop --===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
// RUN: %empty-directory(%t)
//
// RUN: %target-clang %S/Inputs/SwiftObjectNSObject/SwiftObjectNSObject.m -c -o %t/SwiftObjectNSObject.o -g
// RUN: %target-build-swift %s -g -I %S/Inputs/SwiftObjectNSObject/ -Xlinker %t/SwiftObjectNSObject.o -o %t/SwiftObjectNSObject
// RUN: %target-codesign %t/SwiftObjectNSObject
// RUN: %target-run %t/SwiftObjectNSObject 2> %t/log.txt
// RUN: cat %t/log.txt 1>&2
// RUN: %FileCheck %s < %t/log.txt
// REQUIRES: executable_test
// REQUIRES: objc_interop
// rdar://problem/56959761
// UNSUPPORTED: OS=watchos
// UNSUPPORTED: use_os_stdlib
// UNSUPPORTED: back_deployment_runtime
import Foundation
class C {
@objc func cInstanceMethod() -> Int { return 1 }
@objc class func cClassMethod() -> Int { return 2 }
@objc func cInstanceOverride() -> Int { return 3 }
@objc class func cClassOverride() -> Int { return 4 }
}
class D : C {
@objc func dInstanceMethod() -> Int { return 5 }
@objc class func dClassMethod() -> Int { return 6 }
@objc override func cInstanceOverride() -> Int { return 7 }
@objc override class func cClassOverride() -> Int { return 8 }
}
class E : Equatable, CustomStringConvertible {
var i : Int
static func ==(lhs: E, rhs: E) -> Bool { lhs.i == rhs.i }
init(i: Int) { self.i = i }
var description: String { "\(type(of:self))(i:\(self.i))" }
}
class E1: E {
}
class E2: E {
}
class F : CustomStringConvertible {
var i : Int
init(i: Int) { self.i = i }
var description: String { "\(type(of:self))(i:\(self.i))" }
}
class F1: F, Equatable {
static func ==(lhs: F1, rhs: F1) -> Bool { lhs.i == rhs.i }
}
class F2: F, Equatable {
static func ==(lhs: F2, rhs: F2) -> Bool { lhs.i == rhs.i }
}
class H : E, Hashable {
static func ==(lhs: H, rhs: H) -> Bool { lhs.i == rhs.i }
func hash(into hasher: inout Hasher) { hasher.combine(i + 17) }
}
@_silgen_name("TestSwiftObjectNSObject")
func TestSwiftObjectNSObject(_ c: C, _ d: D)
@_silgen_name("TestSwiftObjectNSObjectEquals")
func TestSwiftObjectNSObjectEquals(_: AnyObject, _: AnyObject)
@_silgen_name("TestSwiftObjectNSObjectNotEquals")
func TestSwiftObjectNSObjectNotEquals(_: AnyObject, _: AnyObject)
@_silgen_name("TestSwiftObjectNSObjectHashValue")
func TestSwiftObjectNSObjectHashValue(_: AnyObject, _: Int)
@_silgen_name("TestSwiftObjectNSObjectDefaultHashValue")
func TestSwiftObjectNSObjectDefaultHashValue(_: AnyObject)
@_silgen_name("TestSwiftObjectNSObjectAssertNoErrors")
func TestSwiftObjectNSObjectAssertNoErrors()
// Verify that Obj-C isEqual: provides same answer as Swift ==
func TestEquatableEquals<T: Equatable & AnyObject>(_ e1: T, _ e2: T) {
if e1 == e2 {
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) || os(visionOS)
// Legacy behavior: Equatable Swift does not imply == in ObjC
TestSwiftObjectNSObjectNotEquals(e1, e2)
#else
TestSwiftObjectNSObjectEquals(e1, e2)
#endif
} else {
TestSwiftObjectNSObjectNotEquals(e1, e2)
}
}
func TestNonEquatableEquals(_ e1: AnyObject, _ e2: AnyObject) {
TestSwiftObjectNSObjectNotEquals(e1, e2)
}
// Verify that Obj-C hashValue matches Swift hashValue for Hashable types
func TestHashable(_ h: H)
{
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) || os(visionOS)
// Legacy behavior: Hash value is identity in ObjC
TestSwiftObjectNSObjectDefaultHashValue(h)
#else
// New behavior: Hashable in Swift, same hash value in ObjC
TestSwiftObjectNSObjectHashValue(h, h.hashValue)
#endif
}
// Test Obj-C hashValue for Swift types that are Equatable but not Hashable
func TestEquatableHash(_ e: AnyObject)
{
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) || os(visionOS)
// Legacy behavior: Equatable in Swift => ObjC hashes with identity
TestSwiftObjectNSObjectDefaultHashValue(e)
fakeEquatableWarning(e)
#else
// New behavior: These should have a constant hash value
TestSwiftObjectNSObjectHashValue(e, 1)
#endif
}
func TestNonEquatableHash(_ e: AnyObject)
{
TestSwiftObjectNSObjectDefaultHashValue(e)
}
// Check NSLog() output from TestSwiftObjectNSObject().
// CHECK: c ##SwiftObjectNSObject.C##
// CHECK-NEXT: d ##SwiftObjectNSObject.D##
// CHECK-NEXT: S ##{{.*}}SwiftObject##
// Verify that the runtime emits the warning that we expected...
// CHECK-NEXT: Obj-C `-hash` {{.*}} type `SwiftObjectNSObject.E` {{.*}} Equatable but not Hashable
// CHECK-NEXT: Obj-C `-hash` {{.*}} type `SwiftObjectNSObject.E1` {{.*}} Equatable but not Hashable
// CHECK-NEXT: Obj-C `-hash` {{.*}} type `SwiftObjectNSObject.E2` {{.*}} Equatable but not Hashable
// If we're checking legacy behavior or unsupported platform, then
// the warning above won't be emitted. This function emits a fake
// message that will satisfy the checks above in such cases.
func fakeEquatableWarning(_ e: AnyObject) {
let msg = "Obj-C `-hash` ... type `SwiftObjectNSObject.\(type(of: e))` ... Equatable but not Hashable\n"
fputs(msg, stderr)
}
// Temporarily disable this test on older OSes until we have time to
// look into why it's failing there. rdar://problem/47870743
if #available(OSX 10.12, iOS 10.0, *) {
// Test a large number of Obj-C APIs
TestSwiftObjectNSObject(C(), D())
// ** Equatable types with an Equatable parent class
// Same type and class
TestEquatableEquals(E(i: 1), E(i: 1))
TestEquatableEquals(E(i: 790), E(i: 790))
TestEquatableEquals(E1(i: 1), E1(i: 1))
TestEquatableEquals(E1(i: 18), E1(i: 18))
TestEquatableEquals(E2(i: 1), E2(i: 1))
TestEquatableEquals(E2(i: 2), E2(i: 2))
// Different class
TestEquatableEquals(E1(i: 1), E2(i: 1))
TestEquatableEquals(E1(i: 1), E(i: 1))
TestEquatableEquals(E2(i: 1), E(i: 1))
// Different value
TestEquatableEquals(E(i: 1), E(i: 2))
TestEquatableEquals(E1(i: 1), E1(i: 2))
TestEquatableEquals(E2(i: 1), E2(i: 2))
// ** Non-Equatable parent class
// Same class and value
TestEquatableEquals(F1(i: 1), F1(i: 1))
TestEquatableEquals(F1(i: 1), F1(i: 2))
TestEquatableEquals(F2(i: 1), F2(i: 1))
TestEquatableEquals(F2(i: 1), F2(i: 2))
// Different class and/or value
TestNonEquatableEquals(F(i: 1), F(i: 2))
TestNonEquatableEquals(F(i: 1), F(i: 1))
TestNonEquatableEquals(F1(i: 1), F2(i: 1))
TestNonEquatableEquals(F1(i: 1), F(i: 1))
// Two equatable types with no common parent class
TestNonEquatableEquals(F1(i: 1), E(i: 1))
TestEquatableEquals(H(i:1), E(i:1))
// Equatable but not Hashable: alway have the same Obj-C hashValue
TestEquatableHash(E(i: 1))
TestEquatableHash(E1(i: 3))
TestEquatableHash(E2(i: 8))
// Neither Equatable nor Hashable
TestNonEquatableHash(C())
TestNonEquatableHash(D())
// Hashable types are also Equatable
TestEquatableEquals(H(i:1), H(i:1))
TestEquatableEquals(H(i:1), H(i:2))
TestEquatableEquals(H(i:2), H(i:1))
// Verify Obj-C hash value agrees with Swift
TestHashable(H(i:1))
TestHashable(H(i:2))
TestHashable(H(i:18))
TestSwiftObjectNSObjectAssertNoErrors()
} else {
// Horrible hack to satisfy FileCheck
fputs("c ##SwiftObjectNSObject.C##\n", stderr)
fputs("d ##SwiftObjectNSObject.D##\n", stderr)
fputs("S ##Swift._SwiftObject##\n", stderr)
fakeEquatableWarning(E(i:1))
fakeEquatableWarning(E1(i:1))
fakeEquatableWarning(E2(i:1))
}
|