Skip to content

Commit 8a7cf3c

Browse files
authored
Merge pull request #4003 from jckarter/foundation-overlay-post-0072-3.0
rdar://problem/27616753 Improve Foundation overlay to handle bridging subscripts and dictionary literals.
2 parents 2b85c6d + d1c3264 commit 8a7cf3c

File tree

13 files changed

+87
-48
lines changed

13 files changed

+87
-48
lines changed

stdlib/public/SDK/Foundation/Foundation.swift

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -567,11 +567,12 @@ extension Array : _ObjectiveCBridgeable {
567567

568568
extension NSDictionary : ExpressibleByDictionaryLiteral {
569569
public required convenience init(
570-
dictionaryLiteral elements: (NSCopying, AnyObject)...
570+
dictionaryLiteral elements: (Any, Any)...
571571
) {
572+
// FIXME: Unfortunate that the `NSCopying` check has to be done at runtime.
572573
self.init(
573-
objects: elements.map { $0.1 },
574-
forKeys: elements.map { $0.0 },
574+
objects: elements.map { $0.1 as AnyObject },
575+
forKeys: elements.map { $0.0 as AnyObject as! NSCopying },
575576
count: elements.count)
576577
}
577578
}
@@ -976,6 +977,18 @@ extension NSDictionary : Sequence {
976977
}
977978
}
978979

980+
// Bridging subscript.
981+
@objc
982+
public subscript(key: Any) -> Any? {
983+
@objc(_swift_objectForKeyedSubscript:)
984+
get {
985+
// Deliberately avoid the subscript operator in case the dictionary
986+
// contains non-copyable keys. This is rare since NSMutableDictionary
987+
// requires them, but we don't want to paint ourselves into a corner.
988+
return self.object(forKey: key)
989+
}
990+
}
991+
979992
/// Return an *iterator* over the elements of this *sequence*.
980993
///
981994
/// - Complexity: O(1).
@@ -984,6 +997,21 @@ extension NSDictionary : Sequence {
984997
}
985998
}
986999

1000+
extension NSMutableDictionary {
1001+
// Bridging subscript.
1002+
override public subscript(key: Any) -> Any? {
1003+
get {
1004+
return self.object(forKey: key)
1005+
}
1006+
@objc(_swift_setObject:forKeyedSubscript:)
1007+
set {
1008+
// FIXME: Unfortunate that the `NSCopying` check has to be done at
1009+
// runtime.
1010+
self.setObject(newValue, forKey: key as AnyObject as! NSCopying)
1011+
}
1012+
}
1013+
}
1014+
9871015
extension NSEnumerator : Sequence {
9881016
/// Return an *iterator* over the *enumerator*.
9891017
///

stdlib/public/SDK/XCTest/XCTest.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,13 @@ func _XCTRunThrowableBlock(_ block: @noescape () throws -> Void) -> _XCTThrowabl
7070
if let blockError = blockErrorOptional {
7171
return .failedWithError(error: blockError)
7272
} else if d.count > 0 {
73-
let t: String = d["type" as NSString] as! String
73+
let t: String = d["type"] as! String
7474

7575
if t == "objc" {
7676
return .failedWithException(
77-
className: d["className" as NSString] as! String,
78-
name: d["name" as NSString] as! String,
79-
reason: d["reason" as NSString] as! String)
77+
className: d["className"] as! String,
78+
name: d["name"] as! String,
79+
reason: d["reason"] as! String)
8080
} else {
8181
return .failedWithUnknownException
8282
}

test/1_stdlib/NSArrayAPI.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ var NSArrayAPI = TestSuite("NSArrayAPI")
1212

1313
NSArrayAPI.test("mixed types with AnyObject") {
1414
do {
15-
let result: AnyObject = [1 as NSNumber, "two" as NSString] as NSArray
16-
let expect: NSArray = [1 as NSNumber, "two" as NSString]
15+
let result: AnyObject = [1, "two"] as NSArray
16+
let expect: NSArray = [1, "two"]
1717
expectEqual(expect, result as! NSArray)
1818
}
1919
do {
20-
let result: AnyObject = [1 as NSNumber, 2 as NSNumber] as NSArray
21-
let expect: NSArray = [1 as NSNumber, 2 as NSNumber]
20+
let result: AnyObject = [1, 2] as NSArray
21+
let expect: NSArray = [1, 2]
2222
expectEqual(expect, result as! NSArray)
2323
}
2424
}

test/ClangModules/objc_parse.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,8 @@ func keyedSubscripting(_ b: B, idx: A, a: A) {
170170
dict[NSString()] = a
171171
let value = dict[NSString()]
172172

173-
dict[nil] = a // expected-error {{nil is not compatible with expected argument type 'NSCopying'}}
174-
let q = dict[nil] // expected-error {{nil is not compatible with expected argument type 'NSCopying'}}
173+
dict[nil] = a // expected-error {{ambiguous reference}}
174+
let q = dict[nil] // expected-error {{ambiguous subscript}}
175175
_ = q
176176
}
177177

test/Constraints/bridging.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ func dictionaryToNSDictionary() {
171171

172172
// <rdar://problem/17134986>
173173
var bcOpt: BridgedClass?
174-
nsd = [BridgedStruct() : bcOpt] // expected-error{{value of type 'BridgedStruct' does not conform to expected dictionary key type 'NSCopying'}}
174+
nsd = [BridgedStruct() : bcOpt]
175175
bcOpt = nil
176176
_ = nsd
177177
}

test/Constraints/casts_objc.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ func nsobject_as_class_cast<T>(_ x: NSObject, _: T) {
3232

3333
// <rdar://problem/20294245> QoI: Error message mentions value rather than key for subscript
3434
func test(_ a : CFString!, b : CFString) {
35-
var dict = NSMutableDictionary()
35+
let dict = NSMutableDictionary()
3636
let object = NSObject()
37-
dict[a] = object // expected-error {{argument type 'CFString!' does not conform to expected type 'NSCopying'}}
37+
dict[a] = object
3838

3939

40-
dict[b] = object // expected-error {{argument type 'CFString' does not conform to expected type 'NSCopying'}}
40+
dict[b] = object
4141
}
4242

4343

test/Inputs/clang-importer-sdk/swift-modules/Foundation.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,3 +327,17 @@ public extension _BridgedStoredNSError
327327
self.init(_nsError: NSError(domain: "", code: 0, userInfo: [:]))
328328
}
329329
}
330+
331+
extension NSDictionary {
332+
public subscript(_: Any) -> Any? {
333+
@objc(_swift_objectForKeyedSubscript:)
334+
get { fatalError() }
335+
}
336+
}
337+
extension NSMutableDictionary {
338+
public override subscript(_: Any) -> Any? {
339+
get { fatalError() }
340+
@objc(_swift_setObject:forKeyedSubscript:)
341+
set { }
342+
}
343+
}

test/Interpreter/SDK/Foundation_test.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,13 @@ FoundationTestSuite.test("arrayConversions") {
122122
//===----------------------------------------------------------------------===//
123123

124124
FoundationTestSuite.test("NSDictionary") {
125-
var nsDict : NSDictionary = [1 as NSNumber : "Hello" as NSString, 2 as NSNumber : "World" as NSString]
126-
assert((nsDict[1 as NSNumber]! as! NSString).isEqual("Hello"))
127-
assert((nsDict[2 as NSNumber]! as! NSString).isEqual("World"))
125+
var nsDict : NSDictionary = [1 : "Hello", 2 : "World"]
126+
assert((nsDict[1]! as! NSString).isEqual("Hello"))
127+
assert((nsDict[2]! as! NSString).isEqual("World"))
128128

129-
let nsMutableDict: NSMutableDictionary = ["Hello" as NSString : 1 as NSNumber, "World" as NSString : 2 as NSNumber]
130-
assert((nsMutableDict["Hello" as NSString]! as AnyObject).isEqual(1))
131-
assert((nsMutableDict["World" as NSString]! as AnyObject).isEqual(2))
129+
let nsMutableDict: NSMutableDictionary = ["Hello" : 1, "World" : 2 as NSNumber]
130+
assert((nsMutableDict["Hello"]! as AnyObject).isEqual(1))
131+
assert((nsMutableDict["World"]! as AnyObject).isEqual(2))
132132
}
133133

134134
//===----------------------------------------------------------------------===//
@@ -189,8 +189,8 @@ class ClassWithDtor : NSObject {
189189
FoundationTestSuite.test("rdar://17584531") {
190190
// <rdar://problem/17584531>
191191
// Type checker used to be confused by this.
192-
var dict: NSDictionary = ["status" as NSString: 200 as NSNumber, "people" as NSString: [["id" as NSString: 255 as NSNumber, "name" as NSString: ["first" as NSString: "John" as NSString, "last" as NSString: "Appleseed" as NSString] as NSDictionary] as NSDictionary] as NSArray] as NSDictionary
193-
var dict2 = dict["people" as NSString].map { $0 as AnyObject }?[0] as! NSDictionary
192+
var dict: NSDictionary = ["status": 200, "people": [["id": 255, "name": ["first": "John", "last": "Appleseed"] as NSDictionary] as NSDictionary] as NSArray]
193+
var dict2 = dict["people"].flatMap { $0 as? NSArray }?[0] as! NSDictionary
194194
expectEqual("Optional(255)", String(describing: dict2["id" as NSString]))
195195
}
196196

test/Interpreter/SDK/objc_dynamic_lookup.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import Foundation
77

88
// Dynamic subscripting of NSArray, dynamic method dispatch
99
// CHECK: {{^3$}}
10-
var array : AnyObject = [1 as NSNumber, 2 as NSNumber, 3 as NSNumber, 4 as NSNumber, 5 as NSNumber] as NSArray
10+
var array : AnyObject = [1, 2, 3, 4, 5] as NSArray
1111
print((array[2] as AnyObject).description)
1212

1313
// Dynamic subscripting on an array using an object (fails)
@@ -21,7 +21,7 @@ if optVal1 != nil {
2121

2222
// Dynamic subscripting of NSDictionary, dynamic method dispatch
2323
// CHECK: {{^2$}}
24-
var nsdict : NSDictionary = ["Hello" as NSString : 1 as NSNumber, "World" as NSString : 2 as NSNumber]
24+
var nsdict : NSDictionary = ["Hello" : 1, "World" : 2]
2525
var dict : AnyObject = nsdict
2626
print(((dict["World" as NSString]!)! as AnyObject).description)
2727

test/Interpreter/SDK/objc_fast_enumeration.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ autoreleasepool {
6060
// CHECK: exited
6161
print("exited")
6262

63-
var d : NSDictionary = [415 as NSNumber : "Giants" as NSString, 510 as NSNumber : "A's" as NSString]
64-
var d_m : NSMutableDictionary = [1415 as NSNumber : "Big Giants" as NSString, 11510 as NSNumber : "B's" as NSString]
63+
var d : NSDictionary = [415 : "Giants" , 510 : "A's"]
64+
var d_m : NSMutableDictionary = [1415 : "Big Giants", 11510 : "B's"]
6565

6666
// CHECK: 510 => A's
6767
for (key, value) in d {

test/Interpreter/SDK/objc_switch.swift

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@
33

44
// REQUIRES: objc_interop
55

6-
// rdar://problem/27616753
7-
// XFAIL: *
8-
96
import Foundation
107

118
func testAnyObjectIsa(_ obj: AnyObject) {
@@ -33,19 +30,19 @@ print("testing...")
3330

3431

3532
// CHECK-NEXT: (String)
36-
testAnyObjectIsa("hello")
33+
testAnyObjectIsa("hello" as NSString)
3734

3835
// CHECK-NEXT: (Int)
39-
testAnyObjectIsa(5)
36+
testAnyObjectIsa(5 as NSNumber)
4037

4138
// CHECK-NEXT: ([NSString])
42-
testAnyObjectIsa(["hello", "swift", "world"])
39+
testAnyObjectIsa(["hello", "swift", "world"] as NSArray)
4340

4441
// CHECK-NEXT: ([Int])
45-
testAnyObjectIsa([1, 2, 3, 4, 5])
42+
testAnyObjectIsa([1, 2, 3, 4, 5] as NSArray)
4643

4744
// CHECK-NEXT: (Dictionary<String, Int>)
48-
testAnyObjectIsa(["hello" : 1, "world" : 2])
45+
testAnyObjectIsa(["hello" : 1, "world" : 2] as NSDictionary)
4946

5047
func testNSArrayIsa(_ nsArr: NSArray) {
5148
print("(", terminator: "")
@@ -67,7 +64,7 @@ testNSArrayIsa([1, 2, 3])
6764
// CHECK-NEXT: ()
6865
testNSArrayIsa([[1, 2], [3, 4], [5, 6]])
6966

70-
func testArrayIsa(_ arr: Array<AnyObject>) {
67+
func testArrayIsa(_ arr: Array<Any>) {
7168
print("(", terminator: "")
7269
if arr is [NSString] {
7370
print("[NSString]", terminator: "")
@@ -87,7 +84,7 @@ testArrayIsa([1, 2, 3])
8784
// CHECK-NEXT: ()
8885
testArrayIsa([[1, 2], [3, 4], [5, 6]])
8986

90-
func testArrayIsaBridged(_ arr: Array<AnyObject>) {
87+
func testArrayIsaBridged(_ arr: Array<Any>) {
9188
print("(", terminator: "")
9289
if arr is [String] {
9390
print("[String]", terminator: "")
@@ -145,22 +142,22 @@ func testAnyObjectDowncast(_ obj: AnyObject!) {
145142
}
146143

147144
// CHECK-NEXT: String: hello
148-
testAnyObjectDowncast("hello")
145+
testAnyObjectDowncast("hello" as NSString)
149146

150147
// CHECK-NEXT: Int: 5
151-
testAnyObjectDowncast(5)
148+
testAnyObjectDowncast(5 as NSNumber)
152149

153150
// CHECK-NEXT: NSString array: [hello, swift, world]
154151
testAnyObjectDowncast(["hello", "swift", "world"] as NSArray)
155152

156153
// CHECK-NEXT: Int array: [1, 2, 3, 4, 5]
157-
testAnyObjectDowncast([1, 2, 3, 4, 5])
154+
testAnyObjectDowncast([1, 2, 3, 4, 5] as NSArray)
158155

159156
// CHECK: Dictionary<String, Int>: [
160157
// CHECK-DAG: "hello": 1
161158
// CHECK-DAG: "world": 2
162159
// CHECK: ]
163-
testAnyObjectDowncast(["hello" : 1, "world" : 2])
160+
testAnyObjectDowncast(["hello" : 1, "world" : 2] as NSDictionary)
164161

165162
// CHECK-NEXT: Did not match
166163
testAnyObjectDowncast(nil)

test/SILOptimizer/bridged_casts_folding.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,9 @@ public func testCondCastNStoSwiftArrayString() -> [String]? {
188188

189189
// Check optimization of casts from NSDictionary to Swift Dictionary
190190

191-
var nsDictInt: NSDictionary = [1 as NSNumber:1 as NSNumber, 2 as NSNumber:2 as NSNumber, 3 as NSNumber:3 as NSNumber, 4 as NSNumber:4 as NSNumber]
192-
var nsDictDouble: NSDictionary = [1.1 as NSNumber : 1.1 as NSNumber, 2.2 as NSNumber : 2.2 as NSNumber, 3.3 as NSNumber : 3.3 as NSNumber, 4.4 as NSNumber : 4.4 as NSNumber]
193-
var nsDictString: NSDictionary = ["One" as NSString:"One" as NSString, "Two" as NSString:"Two" as NSString, "Three" as NSString:"Three" as NSString, "Four" as NSString:"Four" as NSString]
191+
var nsDictInt: NSDictionary = [1:1, 2:2, 3:3, 4:4]
192+
var nsDictDouble: NSDictionary = [1.1 : 1.1, 2.2 : 2.2, 3.3 : 3.3, 4.4 : 4.4]
193+
var nsDictString: NSDictionary = ["One":"One", "Two":"Two", "Three":"Three", "Four":"Four"]
194194

195195
// CHECK-LABEL: sil [noinline] @_TF21bridged_casts_folding30testForcedCastNStoSwiftDictIntFT_GVs10DictionarySiSi_
196196
// CHECK-NOT: unconditional_checked

validation-test/stdlib/XCTest.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,8 @@ XCTestTestSuite.test("XCTAssertEqual/Dictionary<T, U>") {
161161
}
162162

163163
dynamic func test_whenDictionariesAreNotEqual_fails() {
164-
XCTAssertEqual(["foo": ["bar": "baz"] as Dictionary as NSDictionary],
165-
["foo": ["bar": "flim"] as Dictionary as NSDictionary])
164+
XCTAssertEqual(["foo": ["bar": "baz"] as NSDictionary],
165+
["foo": ["bar": "flim"] as NSDictionary])
166166
}
167167
}
168168

0 commit comments

Comments
 (0)