[Tests] Add tests.

This commit is contained in:
Amritpan Kaur
2024-12-16 16:51:06 -08:00
parent 78e7f6a72d
commit 15c219cd70
9 changed files with 529 additions and 25 deletions

View File

@@ -41,8 +41,10 @@ let some = Some(keyPath: \Demo.here)
func testFunc() {
let _: (S) -> Int = \.i
_ = ([S]()).map(\.i)
_ = \S.init // expected-error {{key path cannot refer to initializer 'init()'}}
_ = ([S]()).map(\.init) // expected-error {{key path cannot refer to initializer 'init()'}}
_ = \S.Type.init
_ = \S.init // expected-error {{static member 'init()' cannot be used on instance of type 'S'}}
_ = ([S.Type]()).map(\.init)
_ = ([S]()).map(\.init) // expected-error {{static member 'init()' cannot be used on instance of type 'S'}}
let kp = \S.i
let _: KeyPath<S, Int> = kp // works, because type defaults to KeyPath nominal

View File

@@ -368,6 +368,8 @@ $sSUss17FixedWidthIntegerRzrlEyxqd__cSzRd__lufCSu_SiTg5 ---> generic specializat
$s4test7genFuncyyx_q_tr0_lFSi_SbTtt1g5 ---> generic specialization <Swift.Int, Swift.Bool> of test.genFunc<A, B>(A, B) -> ()
$sSD5IndexVy__GD ---> $sSD5IndexVy__GD
$s4test3StrCACycfC ---> {T:$s4test3StrCACycfc} test.Str.__allocating_init() -> test.Str
@$s8keypaths1KV3valACSi_tcfcACmTkmu : $@convention(keypath_accessor_getter) (@in_guaranteed @thick K.Type) -> @out @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <Int, K>)
@$s8keypaths1KVACycfcACmTkMA : $@convention(keypath_accessor_getter) (@in_guaranteed @thick K.Type) -> @out K)
$s18keypaths_inlinable13KeypathStructV8computedSSvpACTKq ---> key path getter for keypaths_inlinable.KeypathStruct.computed : Swift.String : keypaths_inlinable.KeypathStruct, serialized
$s18resilient_protocol24ResilientDerivedProtocolPxAA0c4BaseE0Tn --> associated conformance descriptor for resilient_protocol.ResilientDerivedProtocol.A: resilient_protocol.ResilientBaseProtocol
$s3red4testyAA3ResOyxSayq_GAEs5ErrorAAq_sAFHD1__HCg_GADyxq_GsAFR_r0_lF ---> red.test<A, B where B: Swift.Error>(red.Res<A, B>) -> red.Res<A, [B]>

View File

@@ -5,9 +5,30 @@
// UNSUPPORTED: use_os_stdlib
// UNSUPPORTED: back_deployment_runtime
class MyLabel {
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 {
@@ -57,11 +78,6 @@ class Controller {
}
}
struct S {
var a: Int
static let b: Double = 100.0
}
struct Container<V> {
var v : V
init(_ v: V) {
@@ -70,16 +86,30 @@ struct Container<V> {
func useKeyPath<V2: AnyObject>(_ keyPath: KeyPath<V, V2>) -> String {
return (v[keyPath: keyPath] as! MyLabel).text
}
func invokeKeyPathMethod<V2, R>(
_ keyPath: KeyPath<V, V2>,
method: KeyPath<V2, (Int) -> 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<V> {
var v : V.Type
@@ -92,10 +122,38 @@ struct MetatypeContainer<V> {
}
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<U> {
init(_ u: U) {
@@ -116,13 +174,28 @@ public func generic_class_constrained_keypath<U, V>(_ c: V) where V : GenericCon
// 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\.<computed 0x.* \(Optional<MyLabel>\)>!\.<computed 0x.* \(String\)>}}
print(\Controller.secondLabel!.text)
// CHECK: {{\\Controller\.subscript\(_: String\)|\\Controller\.<computed 0x.* \(String\)>}}
print(\Controller["abc"])
// CHECK: \S.a
print(\S.a)
// CHECK: \S.year
print(\S.year)
// CHECK: {{\\Controller\.subscript\(int: Int, str: String, _: Int\)|\\Controller\.<computed 0x.* \(Int\)>}}
print(\Controller[int: 0, str: "", 0])
// CHECK: {{\\Controller\.thirdLabel|\\Controller\.<computed 0x.* \(Optional<MyLabel>\)>}}
@@ -146,13 +219,98 @@ print(\Controller[array: [42], array2: [42]])
// CHECK: {{\\Controller\.(fourthLabel|<computed .* \(Optional<MyLabel\.Type>\)>)!\.<computed .* \(Bool\)>}}
print(\Controller.fourthLabel!.isVisible)
// CHECK: \S.Type.<computed {{.*}} (Double)>
print(\S.Type.b)
// CHECK: \S.Type.<computed {{.*}} (Int)>
print(\S.Type.millenium)
// CHECK: {{\\Controller\.(fifthLabel|<computed .* \(Optional<MyLabel\.Type>\)>)\?\.<computed .* \(Bool\)>?}}
print(\Controller.fifthLabel?.isVisible)
// CHECK: \Int.Type.<computed {{.*}} (Int)>
print(\Int.Type.zero)
// CHECK: \S.Type.<computed {{.*}} (() -> S)>
print(\S.Type.init)
// CHECK: \S.Type.<computed {{.*}} (S)>
print(\S.Type.init())
// CHECK: \S.Type.<computed {{.*}} ((Int) -> S)>
print(\S.Type.init(val:))
// CHECK: \S.Type.<computed {{.*}} (S)>
print(\S.Type.init(val: 2025))
// CHECK: \S.Type.<computed {{.*}} (S)>.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.<computed {{.*}} ((Int) -> Int)>
print(\S.add(this:))
// CHECK: \S.<computed {{.*}} (Int)>
print(\S.add(that: 1))
// CHECK: \S.Type.<computed {{.*}} ((Int) -> Int)>
print(\S.Type.subtract)
// CHECK: \S.Type.<computed {{.*}} (Int)>
print(\S.Type.subtract(1))
// CHECK: \S.<computed {{.*}} (() -> Int)>
print(\S.nonisolatedNextYear)
// CHECK: \S.<computed {{.*}} (Int)>
print(\S.nonisolatedNextYear())
// CHECK: \S.Type.<computed {{.*}} (S)>.<computed {{.*}} (Int)>
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.<computed {{.*}} (S)>.<computed {{.*}} (Int)>.<computed {{.*}} (Int)>
print(\S.Type.init(val:2025).nonisolatedNextYear().signum())
// // CHECK: \S.<computed {{.*}} (())>
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.<computed {{.*}} (())>
print(\BaseType.foo(hashableParam: hashableInstance))
protocol Describable {
func describe() -> String
}
struct C: Describable {
var name: String
func describe() -> String { return "\(name)" }
}
// CHECK: \C.<computed {{.*}} (() -> 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 {
@@ -208,3 +366,48 @@ do {
// CHECK: true
print(StaticExample<MyLabel>().isVisible)
}
do {
@dynamicMemberLookup
struct InstanceDynamicMemberLookup<T> {
var obj: T
subscript<U>(dynamicMember member: KeyPath<T, (Int) -> 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<T> {
subscript<U>(dynamicMember keyPath: KeyPath<T.Type, (Int) -> U>) -> (Int) -> U {
return T.self[keyPath: keyPath]
}
subscript<U>(dynamicMember keyPath: KeyPath<T.Type, () -> U>) -> () -> U {
return T.self[keyPath: keyPath]
}
subscript<U>(dynamicMember keyPath: KeyPath<T.Type, (String) -> U>) -> (String) -> U {
return T.self[keyPath: keyPath]
}
}
// CHECK: 60
let staticDynamicLookup = StaticDynamicMemberLookup<MyLabel>()
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)
}

View File

@@ -30,6 +30,13 @@ public struct AStruct {
public static var property2: Int = 2
private(set) public static var property3: Int = 1
private(set) public static var property4: Int = 4
public static func x(val value: Int) -> Int { return value }
public static func y(val value: Int) -> Int { return value }
public init(val value: Int = 2024) {
year = value
}
public var year: Int
}
//--- LibB.swift
@@ -41,6 +48,10 @@ public let keyPath3FromLibB = \AStruct.Type.property3
public let keyPath4FromLibB = \AStruct.Type.property4
public var keyPath5FromLibB = \AStruct.Type.property1 // WritableKeyPath with public setter
public var keyPath6FromLibB = \Int.Type.zero
public let keyPath7FromLibB = \AStruct.Type.x(val: 10)
public let keyPath8FromLibB = \AStruct.Type.y(val: 10)
public let keyPath9FromLibB = \AStruct.Type.init
public let keyPath10FromLibB = \AStruct.Type.init(val: 2025)
//--- LibC.swift
import LibA
@@ -51,6 +62,9 @@ public let keyPath3FromLibC = \AStruct.Type.property3 // Read-only with private
public let keyPath4FromLibC = \AStruct.Type.property4
public var keyPath5FromLibC = \Int.Type.zero
public var keyPath6FromLibC = \Int.Type.max
public let keyPath7FromLibC = \AStruct.Type.x(val: 10)
public let keyPath8FromLibC = \AStruct.Type.init
public let keyPath9FromLibC = \AStruct.Type.init(val: 2026)
//--- main.swift
import LibB
@@ -73,3 +87,12 @@ print(keyPath5FromLibB == keyPath3FromLibC)
print(keyPath6FromLibB == keyPath5FromLibC)
// Check: false
print(keyPath6FromLibB == keyPath6FromLibC)
// CHECK: true
print(keyPath7FromLibB == keyPath7FromLibC)
// CHECK: false
print(keyPath8FromLibB == keyPath7FromLibC)
// CHECK: true
print(keyPath9FromLibB == keyPath8FromLibC)
// CHECK: true
print(keyPath10FromLibB != keyPath9FromLibC)

View File

@@ -1,6 +1,5 @@
// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types -target %target-swift-5.1-abi-triple -parse-stdlib -module-name keypaths %s | %FileCheck %s
import Swift
struct S<T> {
@@ -639,6 +638,88 @@ struct TestKeyPathWithSomeType : DefineSomeType {
}
}
class J: Hashable {
static func == (lhs: J, rhs: J) -> Bool { return lhs === rhs }
func hash(into hasher: inout Hasher) {
hasher.combine(ObjectIdentifier(self))
}
}
struct K {
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 }
func doubleValue(_ value: inout Int) { value *= 2 }
func foo(hashableParam j: J) {}
subscript(index: Int) -> Int { return year + index}
}
protocol Describable {
func describe() -> String
}
struct L: Describable {
var name: String
func describe() -> String { return "\(name)" }
}
// CHECK-LABEL: // test_method_and_initializer_keypaths()
// CHECK-LABEL: sil hidden [ossa] @{{.*}} : $@convention(thin) () -> () {
func test_method_and_initializer_keypaths() {
// CHECK: %0 = keypath $WritableKeyPath<K.Type, () -> K>
// CHECK-SAME: root $K.Type; gettable_property $() -> K, id @$s8keypaths1KVACycfC : $@convention(method) (@thin K.Type) -> K, getter @$s8keypaths1KVACycfcACmTkmu : $@convention(keypath_accessor_getter) (@in_guaranteed @thick K.Type) -> @out @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <K>)
let _ = \K.Type.init
// CHECK: keypath $WritableKeyPath<K.Type, K>, (root $K.Type; gettable_property $K, id @$s8keypaths1KVACycfC : $@convention(method) (@thin K.Type) -> K, getter @$s8keypaths1KVACycfcACmTkMA : $@convention(keypath_accessor_getter) (@in_guaranteed @thick K.Type) -> @out K)
let _ = \K.Type.init()
// CHECK: keypath $WritableKeyPath<K.Type, (Int) -> K>
// CHECK-SAME: root $K.Type; gettable_property $(Int) -> K, id @$s8keypaths1KV3valACSi_tcfC : $@convention(method) (Int, @thin K.Type) -> K, getter @$s8keypaths1KV3valACSi_tcfcACmTkmu : $@convention(keypath_accessor_getter) (@in_guaranteed @thick K.Type) -> @out @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <Int, K>)
let _ = \K.Type.init(val:)
// CHECK: keypath $WritableKeyPath<K.Type, K>, (root $K.Type; gettable_property $K, id @$s8keypaths1KV3valACSi_tcfC : $@convention(method) (Int, @thin K.Type) -> K, getter @$s8keypaths1KV3valACSi_tcfcACmTkMA : $@convention(keypath_accessor_getter) (@in_guaranteed @thick K.Type, @in_guaranteed Int) -> @out K, indices [%$0 : $Int : $Int], indices_equals @$sSiTH : $@convention(keypath_accessor_equals) (@in_guaranteed Int, @in_guaranteed Int) -> Bool, indices_hash @$sSiTh : $@convention(keypath_accessor_hash) (@in_guaranteed Int) -> Int)
let _ = \K.Type.init(val: 2025)
// CHECK: keypath $WritableKeyPath<K.Type, Int>, (root $K.Type; gettable_property $K, id @$s8keypaths1KV3valACSi_tcfC : $@convention(method) (Int, @thin K.Type) -> K, getter @$s8keypaths1KV3valACSi_tcfcACmTkMA : $@convention(keypath_accessor_getter) (@in_guaranteed @thick K.Type, @in_guaranteed Int) -> @out K, indices [%$0 : $Int : $Int], indices_equals @$sSiTH : $@convention(keypath_accessor_equals) (@in_guaranteed Int, @in_guaranteed Int) -> Bool, indices_hash @$sSiTh : $@convention(keypath_accessor_hash) (@in_guaranteed Int) -> Int; stored_property #K.year : $Int)
let _ = \K.Type.init(val: 2025).year
// CHECK: keypath $KeyPath<K.Type, Int>, (root $K.Type; gettable_property $K, id @$s8keypaths1KVACycfC : $@convention(method) (@thin K.Type) -> K, getter @$s8keypaths1KVACycfcACmTkMA : $@convention(keypath_accessor_getter) (@in_guaranteed @thick K.Type) -> @out K; gettable_property $Int, id @$s8keypaths1KVyS2icig : $@convention(method) (Int, K) -> Int, getter @$s8keypaths1KVyS2icipACTK : $@convention(keypath_accessor_getter) (@in_guaranteed K, @in_guaranteed Int) -> @out Int, indices [%$0 : $Int : $Int], indices_equals @$sSiTH : $@convention(keypath_accessor_equals) (@in_guaranteed Int, @in_guaranteed Int) -> Bool, indices_hash @$sSiTh : $@convention(keypath_accessor_hash) (@in_guaranteed Int) -> Int)
let _ = \K.Type.init()[0]
// CHECK: keypath $KeyPath<K, (Int, Int) -> Int>, (root $K; gettable_property $(Int, Int) -> Int, id @$s8keypaths1KV3addyS2i_Sitcvg : $@convention(method) (K) -> @owned @callee_guaranteed (Int, Int) -> Int, getter @$s8keypaths1KV3addyS2i_SitcvpACTK : $@convention(keypath_accessor_getter) (@in_guaranteed K) -> @out @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_1) -> @out τ_0_2 for <Int, Int, Int>)
let _ = \K.add
// CHECK: keypath $WritableKeyPath<K, (Int) -> Int>
// CHECK-SAME: root $K; gettable_property $(Int) -> Int, id @$s8keypaths1KV3add4thisS2i_tF : $@convention(method) (Int, K) -> Int, getter @$s8keypaths1KV3add4thisS2i_tFACTkmu : $@convention(keypath_accessor_getter) (@in_guaranteed K) -> @out @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <Int, Int>)
let _ = \K.add(this:)
// CHECK: keypath $WritableKeyPath<K, Int>, (root $K; gettable_property $Int, id @$s8keypaths1KV3add4thatS2i_tF : $@convention(method) (Int, K) -> Int, getter @$s8keypaths1KV3add4thatS2i_tFACTkMA : $@convention(keypath_accessor_getter) (@in_guaranteed K, @in_guaranteed Int) -> @out Int, indices [%$0 : $Int : $Int], indices_equals @$sSiTH : $@convention(keypath_accessor_equals) (@in_guaranteed Int, @in_guaranteed Int) -> Bool, indices_hash @$sSiTh : $@convention(keypath_accessor_hash) (@in_guaranteed Int) -> Int)
let _ = \K.add(that: 1)
// CHECK: keypath $WritableKeyPath<K.Type, (Int) -> Int>
// CHECK-SAME: root $K.Type; gettable_property $(Int) -> Int, id @$s8keypaths1KV8subtractyS2iFZ : $@convention(method) (Int, @thin K.Type) -> Int, getter @$s8keypaths1KV8subtractyS2iFZACmTkmu : $@convention(keypath_accessor_getter) (@in_guaranteed @thick K.Type) -> @out @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <Int, Int>)
let _ = \K.Type.subtract
// CHECK: keypath $WritableKeyPath<K.Type, Int>, (root $K.Type; gettable_property $Int, id @$s8keypaths1KV8subtractyS2iFZ : $@convention(method) (Int, @thin K.Type) -> Int, getter @$s8keypaths1KV8subtractyS2iFZACmTkMA : $@convention(keypath_accessor_getter) (@in_guaranteed @thick K.Type, @in_guaranteed Int) -> @out Int, indices [%$0 : $Int : $Int], indices_equals @$sSiTH : $@convention(keypath_accessor_equals) (@in_guaranteed Int, @in_guaranteed Int) -> Bool, indices_hash @$sSiTh : $@convention(keypath_accessor_hash) (@in_guaranteed Int) -> Int)
let _ = \K.Type.subtract(1)
// CHECK: keypath $WritableKeyPath<K, () -> Int>
// CHECK-SAME: root $K; gettable_property $() -> Int, id @$s8keypaths1KV19nonisolatedNextYearSiyF : $@convention(method) (K) -> Int, getter @$s8keypaths1KV19nonisolatedNextYearSiyFACTkmu : $@convention(keypath_accessor_getter) (@in_guaranteed K) -> @out @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <Int>)
let _ = \K.nonisolatedNextYear
// CHECK: keypath $WritableKeyPath<K, Int>, (root $K; gettable_property $Int, id @$s8keypaths1KV19nonisolatedNextYearSiyF : $@convention(method) (K) -> Int, getter @$s8keypaths1KV19nonisolatedNextYearSiyFACTkMA : $@convention(keypath_accessor_getter) (@in_guaranteed K) -> @out Int)
let _ = \K.nonisolatedNextYear()
// CHECK: keypath $WritableKeyPath<K.Type, Int>, (root $K.Type; gettable_property $K, id @$s8keypaths1KV3valACSi_tcfC : $@convention(method) (Int, @thin K.Type) -> K, getter @$s8keypaths1KV3valACSi_tcfcACmTkMA : $@convention(keypath_accessor_getter) (@in_guaranteed @thick K.Type, @in_guaranteed Int) -> @out K, indices [%$0 : $Int : $Int], indices_equals @$sSiTH : $@convention(keypath_accessor_equals) (@in_guaranteed Int, @in_guaranteed Int) -> Bool, indices_hash @$sSiTh : $@convention(keypath_accessor_hash) (@in_guaranteed Int) -> Int; gettable_property $Int, id @$s8keypaths1KV19nonisolatedNextYearSiyF : $@convention(method) (K) -> Int, getter @$s8keypaths1KV19nonisolatedNextYearSiyFACTkMA : $@convention(keypath_accessor_getter) (@in_guaranteed K) -> @out Int)
let _ = \K.Type.init(val:2025).nonisolatedNextYear()
// CHECK: keypath $KeyPath<K.Type, String>, (root $K.Type; gettable_property $K, id @$s8keypaths1KV3valACSi_tcfC : $@convention(method) (Int, @thin K.Type) -> K, getter @$s8keypaths1KV3valACSi_tcfcACmTkMA : $@convention(keypath_accessor_getter) (@in_guaranteed @thick K.Type, @in_guaranteed Int) -> @out K, indices [%$0 : $Int : $Int], indices_equals @$sSiTH : $@convention(keypath_accessor_equals) (@in_guaranteed Int, @in_guaranteed Int) -> Bool, indices_hash @$sSiTh : $@convention(keypath_accessor_hash) (@in_guaranteed Int) -> Int; gettable_property $Int, id @$s8keypaths1KV19nonisolatedNextYearSiyF : $@convention(method) (K) -> Int, getter @$s8keypaths1KV19nonisolatedNextYearSiyFACTkMA : $@convention(keypath_accessor_getter) (@in_guaranteed K) -> @out Int; gettable_property $String, id @$sSzsE11descriptionSSvg : $@convention(method) <τ_0_0 where τ_0_0 : BinaryInteger> (@in_guaranteed τ_0_0) -> @owned String, getter @$sSzsE11descriptionSSvpSiTK : $@convention(keypath_accessor_getter) (@in_guaranteed Int) -> @out String, external #BinaryInteger.description<Int>)
let _ = \K.Type.init(val:2025).nonisolatedNextYear().description
// CHECK: keypath $WritableKeyPath<K.Type, Int>, (root $K.Type; gettable_property $K, id @$s8keypaths1KV3valACSi_tcfC : $@convention(method) (Int, @thin K.Type) -> K, getter @$s8keypaths1KV3valACSi_tcfcACmTkMA : $@convention(keypath_accessor_getter) (@in_guaranteed @thick K.Type, @in_guaranteed Int) -> @out K, indices [%$0 : $Int : $Int], indices_equals @$sSiTH : $@convention(keypath_accessor_equals) (@in_guaranteed Int, @in_guaranteed Int) -> Bool, indices_hash @$sSiTh : $@convention(keypath_accessor_hash) (@in_guaranteed Int) -> Int; gettable_property $Int, id @$s8keypaths1KV19nonisolatedNextYearSiyF : $@convention(method) (K) -> Int, getter @$s8keypaths1KV19nonisolatedNextYearSiyFACTkMA : $@convention(keypath_accessor_getter) (@in_guaranteed K) -> @out Int; gettable_property $Int, id @$sSi6signumSiyF : $@convention(method) (Int) -> Int, getter @$sSi6signumSiyFSiTkMA : $@convention(keypath_accessor_getter) (@in_guaranteed Int) -> @out Int)
let _ = \K.Type.init(val:2025).nonisolatedNextYear().signum()
// CHECK: keypath $WritableKeyPath<K, ()>, (root $K; gettable_property $(), id @$s8keypaths1KV3foo13hashableParamyAA1JC_tF : $@convention(method) (@guaranteed J, K) -> (), getter @$s8keypaths1KV3foo13hashableParamyAA1JC_tFACTkMA : $@convention(keypath_accessor_getter) (@in_guaranteed K, @in_guaranteed J) -> @out (), indices [%$0 : $J : $J], indices_equals @$s8keypaths1JCTH : $@convention(keypath_accessor_equals) (@in_guaranteed J, @in_guaranteed J) -> Bool, indices_hash @$s8keypaths1JCTh : $@convention(keypath_accessor_hash) (@in_guaranteed J) -> Int)
let hashableInstance = J()
let _ = \K.foo(hashableParam: hashableInstance)
// CHECK: keypath $WritableKeyPath<L, () -> String>
// CHECK-SAME: root $L; gettable_property $() -> String, id @$s8keypaths1LV8describeSSyF : $@convention(method) (@guaranteed L) -> @owned String, getter @$s8keypaths1LV8describeSSyFACTkmu : $@convention(keypath_accessor_getter) (@in_guaranteed L) -> @out @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <String>)
let _ = \L.describe
// CHECK: keypath $WritableKeyPath<L, String>, (root $L; gettable_property $String, id @$s8keypaths1LV8describeSSyF : $@convention(method) (@guaranteed L) -> @owned String, getter @$s8keypaths1LV8describeSSyFACTkMA : $@convention(keypath_accessor_getter) (@in_guaranteed L) -> @out String)
let _ = \L.describe()
}
struct N {
static let kelvin = 293
}

View File

@@ -407,7 +407,8 @@ _ = /\()/
// expected-error@-1 {{'/' is not a prefix unary operator}}
// expected-error@-2 {{'/' is not a postfix unary operator}}
// expected-error@-3 {{invalid component of Swift key path}}
// expected-error@-4 {{type of expression is ambiguous without a type annotation}}
do {
let _: Regex = (/whatever\)/
// expected-note@-1 {{to match this opening '('}}

View File

@@ -475,6 +475,44 @@ var namedTupleLens = Lens<(question: String, answer: Int)>((question: "ultimate
_ = namedTupleLens.question.count
_ = namedTupleLens.answer
struct MethodAndInitializerTest {
let value: Int
init(value: Int) { self.value = value }
func instanceMethod() -> String { return "InstanceMethod" }
static func staticMethod() -> Int { return 42 }
}
@dynamicMemberLookup
struct MethodAndInitializerLens<T> {
var value: T
var type: T.Type
subscript<U>(dynamicMember member: KeyPath<T, U>) -> U {
return value[keyPath: member]
}
subscript<U>(dynamicMember member: (T) -> () -> U) -> () -> U {
return { member(self.value)() }
}
subscript<U>(dynamicMember member: (T.Type) -> () -> U) -> () -> U {
return { member(self.type)() }
}
}
func test_method_and_init_lens() {
let instance = MethodAndInitializerTest(value: 10)
let methodLens = MethodAndInitializerLens(value: instance, type: MethodAndInitializerTest.self)
let _ = methodLens[dynamicMember: MethodAndInitializerTest.instanceMethod]()
let staticMethodClosure = methodLens[dynamicMember: { $0.staticMethod }]
let _ = staticMethodClosure()
let initializer = MethodAndInitializerTest.init
let _ = MethodAndInitializerLens(value: initializer(20), type: MethodAndInitializerTest.self)
}
@dynamicMemberLookup
class A<T> {
var value: T
@@ -488,6 +526,19 @@ class A<T> {
}
}
@dynamicMemberLookup
class AMetatype<T> {
var value: T.Type
init(_ v: T.Type) {
self.value = v
}
subscript<U>(dynamicMember member: KeyPath<T.Type, U>) -> U {
get { return value[keyPath: member] }
}
}
// Let's make sure that keypath dynamic member lookup
// works with inheritance
@@ -687,6 +738,11 @@ func invalid_refs_through_dynamic_lookup() {
_ = lens.bar().faz + 1
_ = lens.baz("hello") // expected-error {{static member 'baz' cannot be used on instance of type 'S'}}
}
func testStatic(_ lens: AMetatype<S>) {
_ = lens.foo
_ = lens.baz("hello")
}
}
// https://github.com/apple/swift/issues/52997

View File

@@ -0,0 +1,48 @@
// RUN: %target-typecheck-verify-swift -disable-experimental-parser-round-trip
func test_keypath_with_method_refs() {
struct S {
func foo() -> Int { return 42 }
static func bar() -> Int { return 0 }
}
let _: KeyPath<S, Int> = \.foo // expected-error {{key path cannot refer to instance method 'foo()'}}
// expected-error@-1 {{cannot assign value of type 'KeyPath<S, () -> Int>' to type 'KeyPath<S, Int>'}}
// expected-note@-2 {{arguments to generic parameter 'Value' ('() -> Int' and 'Int') are expected to be equal}}
let _: KeyPath<S, Int> = \.bar // expected-error {{key path cannot refer to static method 'bar()'}}
// expected-error@-1 {{cannot assign value of type 'KeyPath<S, () -> Int>' to type 'KeyPath<S, Int>'}}
// expected-note@-2 {{arguments to generic parameter 'Value' ('() -> Int' and 'Int') are expected to be equal}}
let _ = \S.Type.bar // expected-error {{key path cannot refer to static method 'bar()'}}
struct A {
func foo() -> B { return B() }
static func faz() -> B { return B() }
}
struct B {
var bar: Int = 42
}
let _: KeyPath<A, Int> = \.foo.bar // expected-error {{key path cannot refer to instance method 'foo()'}}
let _: KeyPath<A, Int> = \.faz.bar // expected-error {{key path cannot refer to static method 'faz()'}}
let _ = \A.foo.bar // expected-error {{key path cannot refer to instance method 'foo()'}}
let _ = \A.Type.faz.bar // expected-error {{key path cannot refer to static method 'faz()'}}
}
// https://github.com/apple/swift/issues/54961
// Compiler crash on invalid method reference in key path.
protocol Zonk {
func wargle()
}
typealias Blatz = (gloop: String, zoop: Zonk?)
func f_54961(fleep: [Blatz]) {
fleep.compactMap(\.zoop?.wargle) // expected-error {{key path cannot refer to instance method 'wargle()'}}
}
// https://github.com/apple/swift/issues/56996
func f_56996() {
_ = \Int.byteSwapped.signum() // expected-error {{key path cannot refer to instance method 'signum()'}}
_ = \Int.byteSwapped.init() // expected-error {{key path cannot refer to initializer 'init()'}}
}

View File

@@ -31,6 +31,8 @@ struct A: Hashable {
let optLetProperty: Prop?
subscript(sub: Sub) -> A { get { return self } set { } }
func foo(_ b: NonHashableSub) {}
static func foo(_ b: Sub) {}
static func ==(_: A, _: A) -> Bool { fatalError() }
func hash(into hasher: inout Hasher) { fatalError() }
@@ -115,6 +117,11 @@ func testKeyPath(sub: Sub, optSub: OptSub,
var l = \C<A>.value
expect(&l, toHaveType: Exactly<WritableKeyPath<C<A>, A>>.self)
var hashableCapture = \A.Type.foo(Sub())
expect(&hashableCapture, toHaveType: Exactly<WritableKeyPath<A.Type, ()>>.self)
// expected-error@+1 {{method argument of type 'NonHashableSub' in a key path must be Hashable}}
_ = \A.foo(NonHashableSub())
// expected-error@+1{{generic parameter 'T' could not be inferred}}
_ = \C.value
@@ -486,6 +493,7 @@ class CC {
func testKeyPathOptional() {
_ = \AA.c?.i
_ = \AA.c!.i
_ = \AA.c?.i.hashValue
// https://github.com/apple/swift/issues/48750
let path: KeyPath<CC,Int>! = \CC.i
@@ -819,18 +827,90 @@ func test_keypath_with_mutating_getter() {
}
func test_keypath_with_method_refs() {
enum ValidationError: Error {
case invalidYear
}
struct S {
func foo() -> Int { return 42 }
static func bar() -> Int { return 0 }
static let millenium = 3
var year = 2024
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 { return year + 1 }
consuming func consume() { print(year) }
func validateYear() throws {
if year < 0 { throw ValidationError.invalidYear }
}
func doubleValue(_ value: inout Int) { value *= 2 }
mutating func updateYear(to newYear: Int) { self.year = newYear }
func calculateFutureYear(after seconds: UInt64) async -> Int {
try? await Task.sleep(nanoseconds: seconds)
return year + 10
}
func validateAndCalculateFutureYear(after seconds: UInt64) async throws -> Int {
try validateYear()
try await Task.sleep(nanoseconds: seconds)
return year + 10
}
subscript(index: Int) -> Int { return year + index }
}
let _: KeyPath<S, Int> = \.foo
// expected-error@-1 {{cannot assign value of type 'KeyPath<S, () -> Int>' to type 'KeyPath<S, Int>'}}
// expected-note@-2 {{arguments to generic parameter 'Value' ('() -> Int' and 'Int') are expected to be equal}}
let _: KeyPath<S, Int> = \.bar // expected-error {{static member 'bar()' cannot be used on instance of type 'S'}}
// expected-error@-1 {{cannot assign value of type 'KeyPath<S, () -> Int>' to type 'KeyPath<S, Int>'}}
// expected-note@-2 {{arguments to generic parameter 'Value' ('() -> Int' and 'Int') are expected to be equal}}
let _ = \S.Type.bar
let _: KeyPath<S, (Int, Int) -> Int> = \.add
let _: KeyPath<S, (Int, Int) -> Int> = \.add()
// expected-error@-1 {{cannot assign value of type 'KeyPath<S, Int>' to type 'KeyPath<S, (Int, Int) -> Int>'}}
// expected-note@-2 {{arguments to generic parameter 'Value' ('Int' and '(Int, Int) -> Int') are expected to be equal}}
let _: KeyPath<S, Int> = \.add() // expected-error {{type of expression is ambiguous without a type annotation}}
let _: KeyPath<S, (Int) -> Int> = \.add(this:)
let _: KeyPath<S, Int> = \.add(that: 1)
let _: KeyPath<S, (Int) -> Int> = \.subtract // expected-error {{static member 'subtract' cannot be used on instance of type 'S'}}
let _ = \S.Type.subtract(1)
let _: KeyPath<S, () -> Int> = \S.nonisolatedNextYear
let _: KeyPath<S, Int> = \S.nonisolatedNextYear()
do {
try S()[keyPath: \S.validateYear]() // expected-error {{cannot form key path to instance method with 'throws' or 'async'}}
} catch {
print("Validation failed: \(error)")
}
var value = 2025
let _ = \S.doubleValue(&value) // expected-error {{cannot pass an inout argument to a keypath method}}
let _: KeyPath<S, ()> = \S.updateYear(to: 2025) // expected-error {{key path cannot refer to mutating method 'updateYear(to:)}}
let _: KeyPath<S, Int> = \S.calculateFutureYear(after: 5) // expected-error {{cannot form key path to instance method with 'throws' or 'async'}}
let _: KeyPath<S, Int> = \S.validateAndCalculateFutureYear(after: 5) // expected-error {{cannot form key path to instance method with 'throws' or 'async'}}
let _: KeyPath<S, () -> S> = \.init // expected-error {{static member 'init()' cannot be used on instance of type 'S'}}
let _: KeyPath<S, (Int) -> S> = \.init(val:) // expected-error {{static member 'init(val:)' cannot be used on instance of type 'S'}}
let _: KeyPath<S, S> = \.init(val: 2025) // expected-error {{static member 'init(val:)' cannot be used on instance of type 'S'}}
let _: KeyPath<S.Type, () -> S> = \S.Type.init
let _: KeyPath<S.Type, (Int) -> S> = \S.Type.init(val:)
let _: KeyPath<S.Type, S> = \S.Type.init(val: 2025)
let _: KeyPath<S.Type, Int> = \.init(val:2025).year
let _ = \S.Type.init(val: 2025).nonisolatedNextYear()
let _ = \S.Type.init()[0]
let _ = \S.Type.init(val: 2025).nonisolatedNextYear().signum()
let _ = \S.Type.init(val: 2025).nonisolatedNextYear().description
let _: KeyPath<S, ()> = \S.consume()
let _: AnyKeyPath = \S.add(this:)
let _: PartialKeyPath = \S.add
class E: Hashable {
static func == (lhs: E, rhs: E) -> Bool { return lhs === rhs }
func hash(into hasher: inout Hasher) { hasher.combine(ObjectIdentifier(self)) }
private var storedClosure: (() -> Void)?
func saveClosure(_ closure: @escaping () -> Void) { storedClosure = closure }
}
class NonhashableE {}
struct BaseType {
func foo(_ e: E) {}
func foo(_ e: NonhashableE) {}
}
let hashableInstance = E()
let nonhashableInstance = NonhashableE()
let _ = \BaseType.foo(hashableInstance)
let _ = \BaseType.foo(nonhashableInstance) // expected-error {{method argument of type 'NonhashableE' in a key path must be Hashable}}
struct A {
func foo() -> B { return B() }
@@ -839,17 +919,25 @@ func test_keypath_with_method_refs() {
struct B {
var bar: Int = 42
func baz() -> Int { return 42 }
subscript(index: Int) -> Int { return index }
}
let _: KeyPath<A, Int> = \.foo.bar // expected-error {{type of expression is ambiguous without a type annotation}}
let _: KeyPath<A, Int> = \.faz.bar // expected-error {{static member 'faz()' cannot be used on instance of type 'A'}}
let _ = \A.foo.bar // expected-error {{type of expression is ambiguous without a type annotation}}
let _ = \A.Type.faz.bar // expected-error {{type of expression is ambiguous without a type annotation}}
let _: KeyPath<A, Int> = \.foo().bar
let _: KeyPath<A.Type, Int> = \.faz().bar
let _ = \A.foo().bar
let _ = \A.Type.faz().bar
let _: KeyPath<A.Type, Int> = \.faz().bar
let _: KeyPath<A, Int> = \.foo().baz()
let _: KeyPath<A, Int> = \.foo().baz()
let _: KeyPath<A.Type, Int> = \A.Type.faz()[0]
}
// https://github.com/apple/swift/issues/54961
// Compiler crash on invalid method reference in key path.
protocol Zonk {
func wargle()
}