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
|
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -parse-as-library %s -verify
import ObjectiveC
import Foundation
// REQUIRES: objc_interop
@objc class A : NSObject {
@objc var propB: B = B()
@objc var propString: String = "" // expected-note {{did you mean 'propString'}}
@objc var propArray: [String] = []
@objc var propDict: [String: B] = [:]
@objc var propSet: Set<String> = []
@objc var propNSString: NSString?
@objc var propNSArray: NSArray?
@objc var propNSDict: NSDictionary?
@objc var propNSSet: NSSet?
@objc var propAnyObject: AnyObject?
@objc var ambiguous: String? // expected-note{{'ambiguous' declared here}}
@objc func someMethod() { }
@objc var `repeat`: String?
}
@objc class B : NSObject {
@objc var propA: A?
@objc var ambiguous: String? // expected-note{{'ambiguous' declared here}}
}
class C {
var nonObjC: String? // expected-note{{add '@objc' to expose this property to Objective-C}}{{3-3=@objc }}
}
extension NSArray {
@objc class Foo : NSObject {
@objc var propString: String = ""
}
}
extension Array {
typealias Foo = NSArray.Foo
}
func testKeyPath(a: A, b: B) {
// Property
let _: String = #keyPath(A.propB)
// Chained property
let _: String = #keyPath(A.propB.propA)
// Optional property
let _: String = #keyPath(A.propB.propA.propB)
// String property
let _: String = #keyPath(A.propString)
// Property of String property (which looks on NSString)
let _: String = #keyPath(A.propString.URLsInText) // expected-warning{{'URLsInText' has been renamed to 'urlsInText'}}
// String property with a suffix
let _: String = #keyPath(A.propString).description
let _ = #keyPath(A.propString).split(separator: ".")
func keyPathSwitch(keyPath: String?) {
switch keyPath {
case (#keyPath(A.propString))?: break
case #keyPath(A.propString)?: break
default: break
}
}
// Array property (make sure we look at the array element).
let _: String = #keyPath(A.propArray)
let _: String = #keyPath(A.propArray.URLsInText) // expected-warning{{'URLsInText' has been renamed to 'urlsInText'}}
// Dictionary property (make sure we look at the value type).
let _: String = #keyPath(A.propDict.anyKeyName)
let _: String = #keyPath(A.propDict.anyKeyName.propA)
// Set property (make sure we look at the set element).
let _: String = #keyPath(A.propSet)
let _: String = #keyPath(A.propSet.URLsInText) // expected-warning{{'URLsInText' has been renamed to 'urlsInText'}}
// AnyObject property
let _: String = #keyPath(A.propAnyObject.URLsInText) // expected-warning{{'URLsInText' has been renamed to 'urlsInText'}}
let _: String = #keyPath(A.propAnyObject.propA)
let _: String = #keyPath(A.propAnyObject.propB)
let _: String = #keyPath(A.propAnyObject.description)
// NSString property
let _: String = #keyPath(A.propNSString.URLsInText) // expected-warning{{'URLsInText' has been renamed to 'urlsInText'}}
// NSArray property (AnyObject array element).
let _: String = #keyPath(A.propNSArray)
let _: String = #keyPath(A.propNSArray.URLsInText) // expected-warning{{'URLsInText' has been renamed to 'urlsInText'}}
// NSDictionary property (AnyObject value type).
let _: String = #keyPath(A.propNSDict.anyKeyName)
let _: String = #keyPath(A.propNSDict.anyKeyName.propA)
// NSSet property (AnyObject set element).
let _: String = #keyPath(A.propNSSet)
let _: String = #keyPath(A.propNSSet.URLsInText) // expected-warning{{'URLsInText' has been renamed to 'urlsInText'}}
// Property with keyword name.
let _: String = #keyPath(A.repeat)
// Nested type of a bridged type (rdar://problem/28061409).
typealias IntArray = [Int]
let _: String = #keyPath(IntArray.Foo.propString)
let dict: [String: Int] = [:]
let _: Int? = dict[#keyPath(A.propB)]
let _ = [#keyPath(A.propB)]
}
func testAsStaticString() {
let _: StaticString = #keyPath(A.propB)
}
func testSemanticErrors() {
let _: String = #keyPath(A.blarg) // expected-error{{type 'A' has no member 'blarg'}}
let _: String = #keyPath(blarg) // expected-error{{cannot find 'blarg' in scope}}
let _: String = #keyPath(AnyObject.ambiguous) // expected-error{{ambiguous reference to member 'ambiguous'}}
let _: String = #keyPath(C.nonObjC) // expected-error{{argument of '#keyPath' refers to non-'@objc' property 'nonObjC'}}
let _: String = #keyPath(A.propArray.UTF8View) // expected-error{{type 'String' has no member 'UTF8View'}}
let _: String = #keyPath(A.someMethod) // expected-error{{key path cannot refer to instance method 'someMethod()'}}
let _: String = #keyPath(A) // expected-error{{empty key path does not refer to a property}}
let _: String = #keyPath(A.propDict.anyKeyName.unknown) // expected-error{{type 'B' has no member 'unknown'}}
let _: String = #keyPath(A.propNSDict.anyKeyName.unknown) // expected-error{{type 'AnyObject' has no member 'unknown'}}
}
func testParseErrors() {
let _: String = #keyPath; // expected-error{{expected '(' following '#keyPath'}}
let _: String = #keyPath(123; // expected-error{{expected property or type name within '#keyPath(...)'}}
let _: String = #keyPath(a.123; // expected-error{{expected property or type name within '#keyPath(...)'}}
let _: String = #keyPath(A(b:c:d:).propSet); // expected-error{{an Objective-C key path cannot reference a declaration with a compound name}} expected-error{{cannot find 'propSet' in scope}}
let _: String = #keyPath(A.propString; // expected-error{{expected ')' to complete '#keyPath' expression}}
// expected-note@-1{{to match this opening '('}}
}
func testTypoCorrection() {
let _: String = #keyPath(A.proString) // expected-error {{type 'A' has no member 'proString'}}
}
// https://github.com/apple/swift/issues/52548
class C2 {
@objc let b = 1
}
class C1_52548: C2 {
let a = \AnyObject.b // expected-error {{the root type of a Swift key path cannot be 'AnyObject'}}
}
class C2_52548 {
@objc let abc: Int = 1
func doNotCrash() {
let _: KeyPath<AnyObject, Int> = \.abc // expected-error {{the root type of a Swift key path cannot be 'AnyObject'}}
}
func doNotCrash_1(_ obj: AnyObject, _ kp: KeyPath<AnyObject, Int>) {
let _ = obj[keyPath: \.abc] // expected-error {{the root type of a Swift key path cannot be 'AnyObject'}}
let _ = obj[keyPath: kp] // expected-error {{the root type of a Swift key path cannot be 'AnyObject'}}
}
}
|