|
12 | 12 |
|
13 | 13 | //===--- Compiler conversion/casting entry points for Dictionary<K, V> ----===//
|
14 | 14 |
|
| 15 | +extension Dictionary { |
| 16 | + @_alwaysEmitIntoClient @inlinable // Introduced in 5.1 |
| 17 | + @inline(__always) |
| 18 | + internal init?<C: Collection>( |
| 19 | + _mapping source: C, |
| 20 | + allowingDuplicates: Bool, |
| 21 | + transform: (C.Element) -> (key: Key, value: Value)? |
| 22 | + ) { |
| 23 | + var target = _NativeDictionary<Key, Value>(capacity: source.count) |
| 24 | + if allowingDuplicates { |
| 25 | + for member in source { |
| 26 | + guard let (key, value) = transform(member) else { return nil } |
| 27 | + target._unsafeUpdate(key: key, value: value) |
| 28 | + } |
| 29 | + } else { |
| 30 | + for member in source { |
| 31 | + guard let (key, value) = transform(member) else { return nil } |
| 32 | + target._unsafeInsertNew(key: key, value: value) |
| 33 | + } |
| 34 | + } |
| 35 | + self.init(_native: target) |
| 36 | + } |
| 37 | +} |
| 38 | + |
15 | 39 | /// Perform a non-bridged upcast that always succeeds.
|
16 | 40 | ///
|
17 | 41 | /// - Precondition: `BaseKey` and `BaseValue` are base classes or base `@objc`
|
|
21 | 45 | public func _dictionaryUpCast<DerivedKey, DerivedValue, BaseKey, BaseValue>(
|
22 | 46 | _ source: Dictionary<DerivedKey, DerivedValue>
|
23 | 47 | ) -> Dictionary<BaseKey, BaseValue> {
|
24 |
| - var builder = _DictionaryBuilder<BaseKey, BaseValue>(count: source.count) |
25 |
| - |
26 |
| - for (k, v) in source { |
27 |
| - builder.add(key:k as! BaseKey, value: v as! BaseValue) |
28 |
| - } |
29 |
| - return builder.take() |
| 48 | + return Dictionary( |
| 49 | + _mapping: source, |
| 50 | + // String and NSString have different concepts of equality, so |
| 51 | + // NSString-keyed Dictionaries may generate key collisions when "upcasted" |
| 52 | + // to String. See rdar://problem/35995647 |
| 53 | + allowingDuplicates: (BaseKey.self == String.self) |
| 54 | + ) { k, v in |
| 55 | + (k as! BaseKey, v as! BaseValue) |
| 56 | + }! |
30 | 57 | }
|
31 | 58 |
|
32 | 59 | /// Called by the casting machinery.
|
@@ -66,7 +93,20 @@ public func _dictionaryDownCast<BaseKey, BaseValue, DerivedKey, DerivedValue>(
|
66 | 93 | _immutableCocoaDictionary: source._variant.asNative.bridged())
|
67 | 94 | }
|
68 | 95 | #endif
|
69 |
| - return _dictionaryDownCastConditional(source)! |
| 96 | + |
| 97 | + // Note: We can't delegate this call to _dictionaryDownCastConditional, |
| 98 | + // because we rely on as! to generate nice runtime errors when the downcast |
| 99 | + // fails. |
| 100 | + |
| 101 | + return Dictionary( |
| 102 | + _mapping: source, |
| 103 | + // String and NSString have different concepts of equality, so |
| 104 | + // NSString-keyed Dictionaries may generate key collisions when downcasted |
| 105 | + // to String. See rdar://problem/35995647 |
| 106 | + allowingDuplicates: (DerivedKey.self == String.self) |
| 107 | + ) { k, v in |
| 108 | + (k as! DerivedKey, v as! DerivedValue) |
| 109 | + }! |
70 | 110 | }
|
71 | 111 |
|
72 | 112 | /// Called by the casting machinery.
|
@@ -97,12 +137,19 @@ public func _dictionaryDownCastConditional<
|
97 | 137 | >(
|
98 | 138 | _ source: Dictionary<BaseKey, BaseValue>
|
99 | 139 | ) -> Dictionary<DerivedKey, DerivedValue>? {
|
100 |
| - |
101 |
| - var builder = _DictionaryBuilder<DerivedKey, DerivedValue>(count: source.count) |
102 |
| - for (k, v) in source { |
103 |
| - guard let k1 = k as? DerivedKey, let v1 = v as? DerivedValue |
104 |
| - else { return nil } |
105 |
| - builder.add(key: k1, value: v1) |
| 140 | + return Dictionary( |
| 141 | + _mapping: source, |
| 142 | + // String and NSString have different concepts of equality, so |
| 143 | + // NSString-keyed Dictionaries may generate key collisions when downcasted |
| 144 | + // to String. See rdar://problem/35995647 |
| 145 | + allowingDuplicates: (DerivedKey.self == String.self) |
| 146 | + ) { k, v in |
| 147 | + guard |
| 148 | + let key = k as? DerivedKey, |
| 149 | + let value = v as? DerivedValue |
| 150 | + else { |
| 151 | + return nil |
| 152 | + } |
| 153 | + return (key, value) |
106 | 154 | }
|
107 |
| - return builder.take() |
108 | 155 | }
|
0 commit comments