File: keypath-objc.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (168 lines) | stat: -rw-r--r-- 6,455 bytes parent folder | download
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'}}
  }
}