// RUN: %target-run-simple-swift(-Xfrontend -enable-experimental-feature -Xfrontend KeyPathWithMethodMembers) | %FileCheck %s // REQUIRES: executable_test // REQUIRES: swift_feature_KeyPathWithMethodMembers // UNSUPPORTED: use_os_stdlib // UNSUPPORTED: back_deployment_runtime class MyLabel: Hashable { var text = "label" static var isVisible = true func x(val value: Int) -> Int { return value } static func y(val value: Int) -> Int { return value } func saveClosure(_ closure: @escaping () -> Void) { storedClosure = closure } func executeStoredClosure() { storedClosure?() } private var storedClosure: (() -> Void)? required init() {} required init(customText: String) { text = customText } static func == (lhs: MyLabel, rhs: MyLabel) -> Bool { return lhs === rhs } func hash(into hasher: inout Hasher) { hasher.combine(ObjectIdentifier(self)) } } class Controller { fileprivate let label = MyLabel() fileprivate var secondLabel: MyLabel? = MyLabel() public var thirdLabel: MyLabel? = MyLabel() fileprivate var fourthLabel: MyLabel.Type? { return MyLabel.self } public var fifthLabel: MyLabel.Type? { return MyLabel.self } subscript(string: String) -> String { get { "" } set { } } subscript(int int: Int, str str: String, otherInt: Int) -> Int { get { 0 } set { } } subscript() -> Int { 0 } subscript(array: [T]) -> T? { array.first } subscript(array: [T], array2: [U]) -> T? { array.first } subscript(array array: [T]) -> T? { array.first } subscript(array array: [T], array2 array2: [U]) -> T? { array.first } } struct Container { var v : V init(_ v: V) { self.v = v } func useKeyPath(_ keyPath: KeyPath) -> String { return (v[keyPath: keyPath] as! MyLabel).text } func invokeKeyPathMethod( _ keyPath: KeyPath, method: KeyPath R>, arg: Int ) -> R { let instance = v[keyPath: keyPath] return instance[keyPath: method](arg) } } extension Container where V: Controller { func test() -> String { return useKeyPath(\.label) } func testKeyPathMethod() -> Int { let result = invokeKeyPathMethod(\.label, method: \MyLabel.x(val:), arg: 10) return result } } // CHECK: label print(Container(Controller()).test()) // CHECK: 10 print(Container(Controller()).testKeyPathMethod()) struct MetatypeContainer { var v : V.Type init(_ v: V.Type) { self.v = v } func useMetatypeKeyPath() -> Bool { if let labelType = v as? MyLabel.Type { return labelType.isVisible } return false } func getKeyPathMethodVal() -> Int { if let labelType = v as? MyLabel.Type { return labelType.y(val: 20) } return 0 } func createInstanceWithDefaultInit() -> MyLabel? { if let labelType = v as? MyLabel.Type { return labelType.init() } return nil } func createInstanceWithCustomInit(customText: String) -> MyLabel? { if let labelType = v as? MyLabel.Type { return labelType.init(customText: customText) } return nil } } // CHECK: true print(MetatypeContainer(MyLabel.self).useMetatypeKeyPath()) // CHECK: 20 print(MetatypeContainer(MyLabel.self).getKeyPathMethodVal()) // CHECK: label if let instance = MetatypeContainer(MyLabel.self).createInstanceWithDefaultInit() { print(instance.text) } // CHECK: Custom Label if let customInstance = MetatypeContainer(MyLabel.self).createInstanceWithCustomInit(customText: "Custom Label") { print(customInstance.text) } public class GenericController { init(_ u: U) { self.u = u } var u : U fileprivate let label = MyLabel() } public func generic_class_constrained_keypath(_ c: V) where V : GenericController { let kp = \V.label print(kp) print(c[keyPath: kp].text) } // CHECK: GenericController.label // CHECK: label generic_class_constrained_keypath(GenericController(5)) struct S { var year = 2024 static let millenium: Int = 3 init() {} init(val value: Int = 2024) { year = value } var add: (Int, Int) -> Int { return { $0 + $1 } } func add(this: Int) -> Int { this + this} func add(that: Int) -> Int { that + that } static func subtract(_ val: Int) -> Int { return millenium - val } nonisolated func nonisolatedNextYear() -> Int { year + 1 } consuming func consume() { print(year) } subscript(index: Int) -> Int { return year + index} } // CHECK: {{\\Controller\.secondLabel!\.text|\\Controller\.\)>!\.}} print(\Controller.secondLabel!.text) // CHECK: {{\\Controller\.subscript\(_: String\)|\\Controller\.}} print(\Controller["abc"]) // CHECK: \S.year print(\S.year) // CHECK: {{\\Controller\.subscript\(int: Int, str: String, _: Int\)|\\Controller\.}} print(\Controller[int: 0, str: "", 0]) // CHECK: {{\\Controller\.thirdLabel|\\Controller\.\)>}} print(\Controller.thirdLabel) // CHECK: {{\\Controller\.subscript\(\)|\\Controller\.}} print(\Controller.[]) // CHECK: \Controller.self print(\Controller.self) // Subscripts with dependent generic types don't produce good output currently, // so we're just checking to make sure they don't crash. // CHECK: \Controller. print(\Controller[[42]]) // CHECK: Controller. print(\Controller[[42], [42]]) // CHECK: \Controller. print(\Controller[array: [42]]) // CHECK: \Controller. print(\Controller[array: [42], array2: [42]]) // CHECK: {{\\Controller\.(fourthLabel|\)>)!\.}} print(\Controller.fourthLabel!.isVisible) // CHECK: \S.Type. print(\S.Type.millenium) // CHECK: {{\\Controller\.(fifthLabel|\)>)\?\.?}} print(\Controller.fifthLabel?.isVisible) // CHECK: \Int.Type. print(\Int.Type.zero) // CHECK: \S.Type. S)> print(\S.Type.init) // CHECK: \S.Type. print(\S.Type.init()) // CHECK: \S.Type. S)> print(\S.Type.init(val:)) // CHECK: \S.Type. print(\S.Type.init(val: 2025)) // CHECK: \S.Type..year print(\S.Type.init(val: 2025).year) // CHECK: 2024 let kp = \S.Type.init()[0] let result = S.self[keyPath: kp] print(result) // CHECK: 7 let kpAdd = \S.add let resultAdd = S()[keyPath: kpAdd](3, 4) print(resultAdd) // CHECK: \S. Int)> print(\S.add(this:)) // CHECK: \S. print(\S.add(that: 1)) // CHECK: \S.Type. Int)> print(\S.Type.subtract) // CHECK: \S.Type. print(\S.Type.subtract(1)) // CHECK: \S. Int)> print(\S.nonisolatedNextYear) // CHECK: \S. print(\S.nonisolatedNextYear()) // CHECK: \S.Type.. print(\S.Type.init(val:2025).nonisolatedNextYear()) // CHECK: 2026 let kpMethodProperty = \S.Type.init(val:2025).nonisolatedNextYear().description let resultMethodProperty = S.self[keyPath: kpMethodProperty] print(resultMethodProperty) // CHECK: \S.Type... print(\S.Type.init(val:2025).nonisolatedNextYear().signum()) // // CHECK: \S. print(\S.consume()) // CHECK: false print(\S.add(that: 1) == \S.add(this: 1)) // CHECK: false print(\S.add(that: 1) == \S.add(this: 2)) // CHECK: false print(\S.Type.init(val: 2024) == \S.Type.init(val: 2025)) // CHECK: false print(\S.Type.init(val: 2024).nonisolatedNextYear() == \S.Type.init(val: 2025)) // CHECK: true print(\S.Type.init(val: 2024).add(this: 1) != \S.Type.init(val: 2025)) class E: Hashable { static func == (lhs: E, rhs: E) -> Bool { return lhs === rhs } func hash(into hasher: inout Hasher) { hasher.combine(ObjectIdentifier(self)) } } struct BaseType { func foo(hashableParam e: E) {} } let hashableInstance = E() // CHECK: \BaseType. print(\BaseType.foo(hashableParam: hashableInstance)) protocol Describable { func describe() -> String } struct C: Describable { var name: String func describe() -> String { return "\(name)" } } // CHECK: \C. String)> print(\C.describe) // CHECK: false print(\S.Type.init(val:2025) == \S.Type.init(val:2026)) // CHECK: false print(\S.Type.init(val:2025).nonisolatedNextYear() == \S.Type.init(val:2026).nonisolatedNextYear()) // CHECK: true print(\S.Type.init(val:2025).nonisolatedNextYear() == \S.Type.init(val:2025).nonisolatedNextYear()) // CHECK: false print(\MyLabel.x(val:10) == \MyLabel.x(val:20)) // CHECK: true print(\MyLabel.Type.y(val:10) == \MyLabel.Type.y(val:10)) do { struct S { var i: Int } func test(v: T, _ kp: any KeyPath & Sendable) { print(v[keyPath: kp]) } // CHECK: 42 test(v: S(i: 42), \.i) } do { @dynamicMemberLookup struct Test { var obj: T subscript(dynamicMember member: KeyPath & Sendable) -> U { get { obj[keyPath: member] } } } // CHECK: 5 print(Test(obj: "Hello").utf8.count) } do { struct S1: Hashable {} struct S2 { subscript(param: S1) -> String { "Subscript with private type" } } let kp = \S2[S1()] // CHECK: Subscript with private type print(S2()[keyPath: kp]) // CHECK: {{\\S2\.subscript\(_: S1 #[0-9]+\)|\S2\.}} print(kp) } do { struct Weekday { static let day = "Monday" } @dynamicMemberLookup struct StaticExample { subscript(dynamicMember keyPath: KeyPath) -> U { return T.self[keyPath: keyPath] } } // CHECK: true print(StaticExample().isVisible) } do { @dynamicMemberLookup struct InstanceDynamicMemberLookup { var obj: T subscript(dynamicMember member: KeyPath U>) -> (Int) -> U { get { obj[keyPath: member] } } } // CHECK: 50 let instanceDynamicLookup = InstanceDynamicMemberLookup(obj: MyLabel()) print(instanceDynamicLookup.x(50)) } extension MyLabel { static var defaultInitializer: () -> MyLabel { return MyLabel.init } static var customInitializer: (String) -> MyLabel { return MyLabel.init(customText:) } } do { @dynamicMemberLookup struct StaticDynamicMemberLookup { subscript(dynamicMember keyPath: KeyPath U>) -> (Int) -> U { return T.self[keyPath: keyPath] } subscript(dynamicMember keyPath: KeyPath U>) -> () -> U { return T.self[keyPath: keyPath] } subscript(dynamicMember keyPath: KeyPath U>) -> (String) -> U { return T.self[keyPath: keyPath] } } // CHECK: 60 let staticDynamicLookup = StaticDynamicMemberLookup() print(staticDynamicLookup.y(60)) // CHECK: label let defaultInstance = staticDynamicLookup.defaultInitializer() print(defaultInstance.text) // CHECK: Custom Label let customInstance = staticDynamicLookup.customInitializer("Custom Label") print(customInstance.text) }