| // RUN: %empty-directory(%t) |
| // RUN: %target-build-swift %s -o %t/a.out_Debug -Onone |
| // RUN: %target-build-swift %s -o %t/a.out_Release -O |
| // RUN: %target-codesign %t/a.out_Debug |
| // RUN: %target-codesign %t/a.out_Release |
| // |
| // RUN: %target-run %t/a.out_Debug |
| // RUN: %target-run %t/a.out_Release |
| // REQUIRES: executable_test |
| // REQUIRES: objc_interop |
| // REQUIRES: rdar49026133 |
| |
| import StdlibUnittest |
| import Foundation |
| |
| let testSuiteSuffix = _isDebugAssertConfiguration() ? "_debug" : "_release" |
| |
| var DictionaryTraps = TestSuite("DictionaryTraps" + testSuiteSuffix) |
| |
| struct NotBridgedKeyTy : Equatable, Hashable { |
| var value: Int |
| |
| init(_ value: Int) { |
| self.value = value |
| } |
| |
| func hash(into hasher: inout Hasher) { |
| hasher.combine(value) |
| } |
| } |
| |
| func == (lhs: NotBridgedKeyTy, rhs: NotBridgedKeyTy) -> Bool { |
| return lhs.value == rhs.value |
| } |
| |
| assert(!_isBridgedToObjectiveC(NotBridgedKeyTy.self)) |
| |
| struct NotBridgedValueTy {} |
| |
| assert(!_isBridgedToObjectiveC(NotBridgedValueTy.self)) |
| |
| class BridgedVerbatimRefTy : Equatable, Hashable { |
| var value: Int |
| |
| init(_ value: Int) { |
| self.value = value |
| } |
| func hash(into hasher: inout Hasher) { |
| hasher.combine(value) |
| } |
| } |
| |
| func == (lhs: BridgedVerbatimRefTy, rhs: BridgedVerbatimRefTy) -> Bool { |
| return lhs.value == rhs.value |
| } |
| |
| assert(_isBridgedToObjectiveC(BridgedVerbatimRefTy.self)) |
| assert(_isBridgedVerbatimToObjectiveC(BridgedVerbatimRefTy.self)) |
| |
| DictionaryTraps.test("sanity") { |
| // Sanity checks. This code should not trap. |
| let d = Dictionary<BridgedVerbatimRefTy, BridgedVerbatimRefTy>() |
| _ = d as NSDictionary |
| } |
| |
| class TestObjCKeyTy : NSObject { |
| init(_ value: Int) { |
| self.value = value |
| } |
| |
| override func isEqual(_ object: Any?) -> Bool { |
| if let other = object { |
| if let otherObjcKey = other as? TestObjCKeyTy { |
| return self.value == otherObjcKey.value |
| } |
| } |
| return false |
| } |
| |
| override var hash : Int { |
| return value |
| } |
| |
| var value: Int |
| } |
| |
| struct TestBridgedKeyTy : Hashable, _ObjectiveCBridgeable { |
| var value: Int |
| |
| init(_ value: Int) { self.value = value } |
| |
| func hash(into hasher: inout Hasher) { |
| hasher.combine(value) |
| } |
| |
| func _bridgeToObjectiveC() -> TestObjCKeyTy { |
| return TestObjCKeyTy(value) |
| } |
| |
| static func _forceBridgeFromObjectiveC( |
| _ x: TestObjCKeyTy, |
| result: inout TestBridgedKeyTy? |
| ) { |
| result = TestBridgedKeyTy(x.value) |
| } |
| |
| static func _conditionallyBridgeFromObjectiveC( |
| _ x: TestObjCKeyTy, |
| result: inout TestBridgedKeyTy? |
| ) -> Bool { |
| result = TestBridgedKeyTy(x.value) |
| return true |
| } |
| |
| static func _unconditionallyBridgeFromObjectiveC(_ source: TestObjCKeyTy?) |
| -> TestBridgedKeyTy { |
| var result: TestBridgedKeyTy? |
| _forceBridgeFromObjectiveC(source!, result: &result) |
| return result! |
| } |
| } |
| |
| func ==(x: TestBridgedKeyTy, y: TestBridgedKeyTy) -> Bool { |
| return x.value == y.value |
| } |
| |
| DictionaryTraps.test("BridgedKeyIsNotNSCopyable1") |
| .skip(.custom( |
| { _isFastAssertConfiguration() }, |
| reason: "this trap is not guaranteed to happen in -Ounchecked")) |
| .crashOutputMatches("unrecognized selector sent to instance").code { |
| // This Dictionary is bridged in O(1). |
| let d = [ TestObjCKeyTy(10): NSObject() ] |
| let nsd = d as NSDictionary |
| expectCrashLater() |
| nsd.mutableCopy() |
| } |
| |
| DictionaryTraps.test("BridgedKeyIsNotNSCopyable2") |
| .skip(.custom( |
| { _isFastAssertConfiguration() }, |
| reason: "this trap is not guaranteed to happen in -Ounchecked")) |
| .code { |
| // This Dictionary is bridged in O(1). |
| let d = [ TestObjCKeyTy(10): 10 ] |
| let nsd = d as NSDictionary |
| expectCrashLater() |
| nsd.mutableCopy() |
| } |
| |
| DictionaryTraps.test("ForcedNonverbatimBridge.StringKey") |
| .skip(.custom( |
| { _isFastAssertConfiguration() }, |
| reason: "this trap is not guaranteed to happen in -Ounchecked")) |
| .crashOutputMatches("Could not cast value of type") |
| .code { |
| let d1: NSDictionary = [ |
| "Gordon" as NSString: NSObject(), |
| "William" as NSString: NSObject(), |
| "Katherine" as NSString: NSObject(), |
| "Lynn" as NSString: NSObject(), |
| "Brian" as NSString: NSObject(), |
| 1756 as NSNumber: NSObject()] |
| |
| expectCrashLater() |
| _ = d1 as! Dictionary<String, Any> |
| } |
| |
| DictionaryTraps.test("ForcedNonverbatimBridge.IntKey") |
| .skip(.custom( |
| { _isFastAssertConfiguration() }, |
| reason: "this trap is not guaranteed to happen in -Ounchecked")) |
| .crashOutputMatches("Could not cast value of type") |
| .code { |
| |
| let d1: NSDictionary = [ |
| 4 as NSNumber: NSObject(), |
| 8 as NSNumber: NSObject(), |
| 15 as NSNumber: NSObject(), |
| 16 as NSNumber: NSObject(), |
| 23 as NSNumber: NSObject(), |
| 42 as NSNumber: NSObject(), |
| "John" as NSString: NSObject()] |
| |
| expectCrashLater() |
| _ = d1 as! Dictionary<Int, Any> |
| } |
| |
| DictionaryTraps.test("ForcedNonverbatimBridge.Value") |
| .skip(.custom( |
| { _isFastAssertConfiguration() }, |
| reason: "this trap is not guaranteed to happen in -Ounchecked")) |
| .crashOutputMatches("Could not cast value of type") |
| .code { |
| |
| let d1: NSDictionary = [ |
| 4 as NSNumber: "Jack" as NSString, |
| 8 as NSNumber: "Kate" as NSString, |
| 15 as NSNumber: "Hurley" as NSString, |
| 16 as NSNumber: "Sawyer" as NSString, |
| 23 as NSNumber: "John" as NSString, |
| 42 as NSNumber: NSObject()] |
| |
| expectCrashLater() |
| _ = d1 as! Dictionary<NSObject, String> |
| } |
| |
| |
| DictionaryTraps.test("ForcedVerbatimBridge.StringKey") |
| .skip(.custom( |
| { _isFastAssertConfiguration() }, |
| reason: "this trap is not guaranteed to happen in -Ounchecked")) |
| .crashOutputMatches("Could not cast value of type") |
| .code { |
| let d1: NSDictionary = [ |
| "Gordon" as NSString: NSObject(), |
| "William" as NSString: NSObject(), |
| "Katherine" as NSString: NSObject(), |
| "Lynn" as NSString: NSObject(), |
| "Brian" as NSString: NSObject(), |
| 1756 as NSNumber: NSObject()] |
| |
| // With the ObjC runtime, the verbatim downcast is O(1); it performs no |
| // runtime checks. |
| let d2 = d1 as! Dictionary<NSString, NSObject> |
| // Element access goes through the bridged path and performs forced downcasts. |
| // This is where the odd numeric value is caught. |
| expectCrashLater() |
| for (key, value) in d2 { |
| _ = (key, value) |
| } |
| } |
| |
| DictionaryTraps.test("ForcedVerbatimBridge.IntKey") |
| .skip(.custom( |
| { _isFastAssertConfiguration() }, |
| reason: "this trap is not guaranteed to happen in -Ounchecked")) |
| .crashOutputMatches("Could not cast value of type") |
| .code { |
| |
| let d1: NSDictionary = [ |
| 4 as NSNumber: NSObject(), |
| 8 as NSNumber: NSObject(), |
| 15 as NSNumber: NSObject(), |
| 16 as NSNumber: NSObject(), |
| 23 as NSNumber: NSObject(), |
| 42 as NSNumber: NSObject(), |
| "John" as NSString: NSObject()] |
| |
| // With the ObjC runtime, the verbatim downcast is O(1); it performs no |
| // runtime checks. |
| let d2 = d1 as! Dictionary<NSNumber, NSObject> |
| // Element access goes through the bridged path and performs forced downcasts. |
| // This is where the odd numeric value is caught. |
| expectCrashLater() |
| for (key, value) in d2 { |
| _ = (key, value) |
| } |
| } |
| |
| DictionaryTraps.test("ForcedVerbatimBridge.Value") |
| .skip(.custom( |
| { _isFastAssertConfiguration() }, |
| reason: "this trap is not guaranteed to happen in -Ounchecked")) |
| .crashOutputMatches("Could not cast value of type") |
| .code { |
| |
| let d1: NSDictionary = [ |
| 4 as NSNumber: "Jack" as NSString, |
| 8 as NSNumber: "Kate" as NSString, |
| 15 as NSNumber: "Hurley" as NSString, |
| 16 as NSNumber: "Sawyer" as NSString, |
| 23 as NSNumber: "John" as NSString, |
| 42 as NSNumber: NSObject()] |
| |
| // With the ObjC runtime, the verbatim downcast is O(1); it performs no |
| // runtime checks. |
| let d2 = d1 as! Dictionary<NSObject, NSString> |
| // Element access goes through the bridged path and performs forced downcasts. |
| // This is where the odd numeric value is caught. |
| expectCrashLater() |
| for (key, value) in d2 { |
| _ = (key, value) |
| } |
| } |
| |
| DictionaryTraps.test("Downcast1") { |
| let d: Dictionary<NSObject, NSObject> = [ TestObjCKeyTy(10): NSObject(), |
| NSObject() : NSObject() ] |
| let d2: Dictionary<TestObjCKeyTy, NSObject> = _dictionaryDownCast(d) |
| expectCrashLater() |
| _ = d2[TestObjCKeyTy(10)] |
| _ = d2[TestObjCKeyTy(20)] |
| |
| // This triggers failure. |
| for (_, _) in d2 { } |
| } |
| |
| DictionaryTraps.test("Downcast2") |
| .skip(.custom( |
| { _isFastAssertConfiguration() }, |
| reason: "this trap is not guaranteed to happen in -Ounchecked")) |
| .code { |
| let d: Dictionary<NSObject, NSObject> = [ TestObjCKeyTy(10): NSObject(), |
| NSObject() : NSObject() ] |
| |
| expectCrashLater() |
| let d2 = d as! Dictionary<TestBridgedKeyTy, NSObject> |
| _ = d2[TestBridgedKeyTy(10)] |
| } |
| |
| runAllTests() |