Skip to content

Commit 805b150

Browse files
committed
Merge pull request #2552 from apple/stdlib-bridged-dictionary-allow-querying-for-mismatched-type
2 parents ece9c49 + 0868b6f commit 805b150

File tree

4 files changed

+71
-6
lines changed

4 files changed

+71
-6
lines changed

stdlib/public/core/HashedCollections.swift.gyb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3275,7 +3275,9 @@ final internal class _Native${Self}StorageOwner<${TypeParametersDecl}>
32753275
@warn_unused_result
32763276
internal func bridgingObjectForKey(_ aKey: AnyObject)
32773277
-> AnyObject? {
3278-
let nativeKey = _forceBridgeFromObjectiveC(aKey, Key.self)
3278+
guard let nativeKey = _conditionallyBridgeFromObjectiveC(aKey, Key.self)
3279+
else { return nil }
3280+
32793281
let (i, found) = nativeStorage._find(
32803282
nativeKey, startBucket: nativeStorage._bucket(nativeKey))
32813283
if found {

test/1_stdlib/Inputs/DictionaryKeyValueTypesObjC.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,39 @@ class TestObjCKeyTy : NSObject, NSCopying {
113113
var serial: Int
114114
}
115115

116+
// A type that satisfies the requirements of an NSDictionary key (or an NSSet
117+
// member), but traps when any of its methods are called.
118+
class TestObjCInvalidKeyTy {
119+
init() {
120+
_objcKeyCount.fetchAndAdd(1)
121+
serial = _objcKeySerial.addAndFetch(1)
122+
}
123+
124+
deinit {
125+
assert(serial > 0, "double destruction")
126+
_objcKeyCount.fetchAndAdd(-1)
127+
serial = -serial
128+
}
129+
130+
@objc
131+
var description: String {
132+
assert(serial > 0, "dead TestObjCInvalidKeyTy")
133+
fatalError()
134+
}
135+
136+
@objc
137+
func isEqual(_ object: AnyObject!) -> Bool {
138+
fatalError()
139+
}
140+
141+
@objc
142+
var hash : Int {
143+
fatalError()
144+
}
145+
146+
var serial: Int
147+
}
148+
116149
var _objcValueCount = _stdlib_AtomicInt(0)
117150
var _objcValueSerial = _stdlib_AtomicInt(0)
118151

validation-test/stdlib/Dictionary.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2558,6 +2558,11 @@ DictionaryTestSuite.test("BridgedToObjC.Verbatim.ObjectForKey") {
25582558

25592559
expectEmpty(d.object(forKey: TestObjCKeyTy(40)))
25602560

2561+
// NSDictionary can store mixed key types. Swift's Dictionary is typed, but
2562+
// when bridged to NSDictionary, it should behave like one, and allow queries
2563+
// for mismatched key types.
2564+
expectEmpty(d.object(forKey: TestObjCInvalidKeyTy()))
2565+
25612566
for i in 0..<3 {
25622567
expectEqual(idValue10, unsafeBitCast(
25632568
d.object(forKey: TestObjCKeyTy(10)), to: UInt.self))

validation-test/stdlib/Set.swift

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2154,12 +2154,37 @@ SetTestSuite.test("BridgedToObjC.Verbatim.Count") {
21542154
}
21552155

21562156
SetTestSuite.test("BridgedToObjC.Verbatim.Contains") {
2157-
let nss = getBridgedNSSetOfRefTypesBridgedVerbatim()
2157+
let s = getBridgedNSSetOfRefTypesBridgedVerbatim()
21582158

2159-
expectNotEmpty(nss.member(TestObjCKeyTy(1010)))
2160-
expectNotEmpty(nss.member(TestObjCKeyTy(2020)))
2161-
expectNotEmpty(nss.member(TestObjCKeyTy(3030)))
2162-
expectEmpty(nss.member(TestObjCKeyTy(4040)))
2159+
var v: AnyObject? = s.member(TestObjCKeyTy(1010))
2160+
expectEqual(1010, (v as! TestObjCKeyTy).value)
2161+
let idValue10 = unsafeBitCast(v, to: UInt.self)
2162+
2163+
v = s.member(TestObjCKeyTy(2020))
2164+
expectEqual(2020, (v as! TestObjCKeyTy).value)
2165+
let idValue20 = unsafeBitCast(v, to: UInt.self)
2166+
2167+
v = s.member(TestObjCKeyTy(3030))
2168+
expectEqual(3030, (v as! TestObjCKeyTy).value)
2169+
let idValue30 = unsafeBitCast(v, to: UInt.self)
2170+
2171+
expectEmpty(s.member(TestObjCKeyTy(4040)))
2172+
2173+
// NSSet can store mixed key types. Swift's Set is typed, but when bridged
2174+
// to NSSet, it should behave like one, and allow queries for mismatched key
2175+
// types.
2176+
expectEmpty(s.member(TestObjCInvalidKeyTy()))
2177+
2178+
for i in 0..<3 {
2179+
expectEqual(idValue10,
2180+
unsafeBitCast(s.member(TestObjCKeyTy(1010)), to: UInt.self))
2181+
2182+
expectEqual(idValue20,
2183+
unsafeBitCast(s.member(TestObjCKeyTy(2020)), to: UInt.self))
2184+
2185+
expectEqual(idValue30,
2186+
unsafeBitCast(s.member(TestObjCKeyTy(3030)), to: UInt.self))
2187+
}
21632188

21642189
expectAutoreleasedKeysAndValues(unopt: (3, 0))
21652190
}

0 commit comments

Comments
 (0)