mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Tests] Add tests.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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]>
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 '('}}
|
||||
|
||||
@@ -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
|
||||
|
||||
48
test/expr/unary/keypath/keypath-unsupported-methods.swift
Normal file
48
test/expr/unary/keypath/keypath-unsupported-methods.swift
Normal 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()'}}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user