mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Remove keypath subtype asserts; always use cached root type Add tests for keypaths converted to funcs with inout param Add unit test for overload selection
1319 lines
49 KiB
Swift
1319 lines
49 KiB
Swift
// RUN: %target-swift-frontend -typecheck -parse-as-library %s -verify
|
|
|
|
struct Sub: Hashable {
|
|
static func ==(_: Sub, _: Sub) -> Bool { return true }
|
|
func hash(into hasher: inout Hasher) {}
|
|
}
|
|
struct OptSub: Hashable {
|
|
static func ==(_: OptSub, _: OptSub) -> Bool { return true }
|
|
func hash(into hasher: inout Hasher) {}
|
|
}
|
|
struct NonHashableSub {}
|
|
|
|
struct Prop {
|
|
subscript(sub: Sub) -> A { get { return A() } set { } }
|
|
subscript(optSub: OptSub) -> A? { get { return A() } set { } }
|
|
subscript(nonHashableSub: NonHashableSub) -> A { get { return A() } set { } }
|
|
subscript(a: Sub, b: Sub) -> A { get { return A() } set { } }
|
|
subscript(a: Sub, b: NonHashableSub) -> A { get { return A() } set { } }
|
|
|
|
var nonMutatingProperty: B {
|
|
get { fatalError() }
|
|
nonmutating set { fatalError() }
|
|
}
|
|
}
|
|
|
|
struct A: Hashable {
|
|
init() { fatalError() }
|
|
|
|
var property: Prop
|
|
var optProperty: Prop?
|
|
let optLetProperty: Prop?
|
|
|
|
subscript(sub: Sub) -> A { get { return self } set { } }
|
|
|
|
static func ==(_: A, _: A) -> Bool { fatalError() }
|
|
func hash(into hasher: inout Hasher) { fatalError() }
|
|
}
|
|
struct B {}
|
|
struct C<T> { // expected-note 4 {{'T' declared as parameter to type 'C'}}
|
|
var value: T
|
|
subscript() -> T { get { return value } }
|
|
subscript(sub: Sub) -> T { get { return value } set { } }
|
|
subscript<U: Hashable>(sub: U) -> U { get { return sub } set { } }
|
|
subscript<X>(noHashableConstraint sub: X) -> X { get { return sub } set { } }
|
|
}
|
|
|
|
struct Unavailable {
|
|
@available(*, unavailable)
|
|
var unavailableProperty: Int { 0 }
|
|
// expected-note@-1 {{'unavailableProperty' has been explicitly marked unavailable here}}
|
|
|
|
@available(*, unavailable)
|
|
subscript(x: Sub) -> Int { get { } set { } }
|
|
// expected-note@-1 {{'subscript(_:)' has been explicitly marked unavailable here}}
|
|
}
|
|
|
|
struct Deprecated {
|
|
@available(*, deprecated)
|
|
var deprecatedProperty: Int
|
|
|
|
@available(*, deprecated)
|
|
subscript(x: Sub) -> Int { get { } set { } }
|
|
}
|
|
|
|
@available(*, deprecated)
|
|
func getDeprecatedSub() -> Sub {
|
|
return Sub()
|
|
}
|
|
|
|
extension Array where Element == A {
|
|
var property: Prop { fatalError() }
|
|
}
|
|
|
|
protocol P { var member: String { get } }
|
|
extension B : P { var member : String { return "Member Value" } }
|
|
|
|
struct Exactly<T> {}
|
|
|
|
func expect<T>(_ x: inout T, toHaveType _: Exactly<T>.Type) {}
|
|
|
|
func testKeyPath(sub: Sub, optSub: OptSub,
|
|
nonHashableSub: NonHashableSub, x: Int) {
|
|
var a = \A.property
|
|
expect(&a, toHaveType: Exactly<WritableKeyPath<A, Prop>>.self)
|
|
|
|
var b = \A.[sub]
|
|
expect(&b, toHaveType: Exactly<WritableKeyPath<A, A>>.self)
|
|
|
|
var c = \A.[sub].property
|
|
expect(&c, toHaveType: Exactly<WritableKeyPath<A, Prop>>.self)
|
|
|
|
var d = \A.optProperty?
|
|
expect(&d, toHaveType: Exactly<KeyPath<A, Prop?>>.self)
|
|
|
|
var e = \A.optProperty?[sub]
|
|
expect(&e, toHaveType: Exactly<KeyPath<A, A?>>.self)
|
|
|
|
var f = \A.optProperty!
|
|
expect(&f, toHaveType: Exactly<WritableKeyPath<A, Prop>>.self)
|
|
|
|
var g = \A.property[optSub]?.optProperty![sub]
|
|
expect(&g, toHaveType: Exactly<KeyPath<A, A?>>.self)
|
|
|
|
var h = \[A].property
|
|
expect(&h, toHaveType: Exactly<KeyPath<[A], Prop>>.self)
|
|
|
|
var i = \[A].property.nonMutatingProperty
|
|
expect(&i, toHaveType: Exactly<ReferenceWritableKeyPath<[A], B>>.self)
|
|
|
|
var j = \[A].[x]
|
|
expect(&j, toHaveType: Exactly<WritableKeyPath<[A], A>>.self)
|
|
|
|
var k = \[A: B].[A()]
|
|
expect(&k, toHaveType: Exactly<WritableKeyPath<[A: B], B?>>.self)
|
|
|
|
var l = \C<A>.value
|
|
expect(&l, toHaveType: Exactly<WritableKeyPath<C<A>, A>>.self)
|
|
|
|
// expected-error@+1{{generic parameter 'T' could not be inferred}}
|
|
_ = \C.value
|
|
|
|
// expected-error@+1{{}}
|
|
_ = \(() -> ()).noMember
|
|
|
|
let _: (A) -> Prop = \.property
|
|
let _: (A) -> Prop? = \.property
|
|
let _: PartialKeyPath<A> = \.property
|
|
let _: KeyPath<A, Prop> = \.property
|
|
let _: WritableKeyPath<A, Prop> = \.property
|
|
let _: ReferenceWritableKeyPath<A, Prop> = \.property
|
|
//expected-error@-1 {{cannot convert key path type 'WritableKeyPath<A, Prop>' to contextual type 'ReferenceWritableKeyPath<A, Prop>'}}
|
|
|
|
let _: (A) -> A? = \.[sub]
|
|
let _: (A) -> A = \.[sub]
|
|
let _: PartialKeyPath<A> = \.[sub]
|
|
let _: KeyPath<A, A> = \.[sub]
|
|
let _: WritableKeyPath<A, A> = \.[sub]
|
|
let _: ReferenceWritableKeyPath<A, A> = \.[sub]
|
|
//expected-error@-1 {{cannot convert key path type 'WritableKeyPath<A, A>' to contextual type 'ReferenceWritableKeyPath<A, A>'}}
|
|
|
|
let _: (A) -> Prop?? = \.optProperty?
|
|
let _: (A) -> Prop? = \.optProperty?
|
|
let _: PartialKeyPath<A> = \.optProperty?
|
|
let _: KeyPath<A, Prop?> = \.optProperty?
|
|
// expected-error@+1{{cannot convert}}
|
|
let _: WritableKeyPath<A, Prop?> = \.optProperty?
|
|
// expected-error@+1{{cannot convert}}
|
|
let _: ReferenceWritableKeyPath<A, Prop?> = \.optProperty?
|
|
|
|
let _: (A) -> A?? = \.optProperty?[sub]
|
|
let _: (A) -> A? = \.optProperty?[sub]
|
|
let _: PartialKeyPath<A> = \.optProperty?[sub]
|
|
let _: KeyPath<A, A?> = \.optProperty?[sub]
|
|
// expected-error@+1{{cannot convert}}
|
|
let _: WritableKeyPath<A, A?> = \.optProperty?[sub]
|
|
// expected-error@+1{{cannot convert}}
|
|
let _: ReferenceWritableKeyPath<A, A?> = \.optProperty?[sub]
|
|
|
|
let _: KeyPath<A, Prop> = \.optProperty!
|
|
let _: KeyPath<A, Prop> = \.optLetProperty!
|
|
let _: KeyPath<A, Prop?> = \.property[optSub]?.optProperty!
|
|
let _: KeyPath<A, A?> = \.property[optSub]?.optProperty![sub]
|
|
|
|
let _: (C<A>) -> A? = \.value
|
|
let _: (C<A>) -> A = \.value
|
|
let _: PartialKeyPath<C<A>> = \.value
|
|
let _: KeyPath<C<A>, A> = \.value
|
|
let _: WritableKeyPath<C<A>, A> = \.value
|
|
let _: ReferenceWritableKeyPath<C<A>, A> = \.value
|
|
// expected-error@-1 {{cannot convert key path type 'WritableKeyPath<C<A>, A>' to contextual type 'ReferenceWritableKeyPath<C<A>, A>'}}
|
|
|
|
let _: (C<A>) -> A? = \C.value
|
|
let _: (C<A>) -> A = \C.value
|
|
let _: PartialKeyPath<C<A>> = \C.value
|
|
let _: KeyPath<C<A>, A> = \C.value
|
|
let _: WritableKeyPath<C<A>, A> = \C.value
|
|
// expected-error@+1{{cannot convert}}
|
|
let _: ReferenceWritableKeyPath<C<A>, A> = \C.value
|
|
|
|
let _: (Prop) -> B? = \.nonMutatingProperty
|
|
let _: (Prop) -> B = \.nonMutatingProperty
|
|
let _: PartialKeyPath<Prop> = \.nonMutatingProperty
|
|
let _: KeyPath<Prop, B> = \.nonMutatingProperty
|
|
let _: WritableKeyPath<Prop, B> = \.nonMutatingProperty
|
|
let _: ReferenceWritableKeyPath<Prop, B> = \.nonMutatingProperty
|
|
|
|
var m = [\A.property, \A.[sub], \A.optProperty!]
|
|
expect(&m, toHaveType: Exactly<[PartialKeyPath<A>]>.self)
|
|
|
|
// \.optProperty returns an optional of Prop and `\.[sub]` returns `A`, all this unifies into `[PartialKeyPath<A>]`
|
|
var n = [\A.property, \.optProperty, \.[sub], \.optProperty!]
|
|
expect(&n, toHaveType: Exactly<[PartialKeyPath<A>]>.self)
|
|
|
|
let _: [PartialKeyPath<A>] = [\.property, \.optProperty, \.[sub], \.optProperty!]
|
|
|
|
var o = [\A.property, \C<A>.value]
|
|
expect(&o, toHaveType: Exactly<[AnyKeyPath]>.self)
|
|
|
|
let _: AnyKeyPath = \A.property
|
|
let _: AnyKeyPath = \C<A>.value
|
|
let _: AnyKeyPath = \.property // expected-error {{'AnyKeyPath' does not provide enough context for root type to be inferred; consider explicitly specifying a root type}} {{24-24=<#Root#>}}
|
|
let _: AnyKeyPath = \C.value // expected-error{{generic parameter 'T' could not be inferred}}
|
|
let _: AnyKeyPath = \.value // expected-error {{'AnyKeyPath' does not provide enough context for root type to be inferred; consider explicitly specifying a root type}} {{24-24=<#Root#>}}
|
|
|
|
let _ = \Prop.[nonHashableSub] // expected-error{{subscript index of type 'NonHashableSub' in a key path must be Hashable}}
|
|
let _ = \Prop.[sub, sub]
|
|
let _ = \Prop.[sub, nonHashableSub] // expected-error{{subscript index of type 'NonHashableSub' in a key path must be Hashable}}
|
|
|
|
let _ = \C<Int>.[]
|
|
let _ = \C<Int>.[sub]
|
|
let _ = \C<Int>.[noHashableConstraint: sub]
|
|
let _ = \C<Int>.[noHashableConstraint: nonHashableSub] // expected-error{{subscript index of type 'NonHashableSub' in a key path must be Hashable}}
|
|
|
|
let _ = \Unavailable.unavailableProperty // expected-error {{'unavailableProperty' is unavailable}}
|
|
let _ = \Unavailable.[sub] // expected-error {{'subscript(_:)' is unavailable}}
|
|
|
|
let _ = \Deprecated.deprecatedProperty // expected-warning {{'deprecatedProperty' is deprecated}}
|
|
let _ = \Deprecated.[sub] // expected-warning {{'subscript(_:)' is deprecated}}
|
|
|
|
let _ = \A.[getDeprecatedSub()] // expected-warning {{'getDeprecatedSub()' is deprecated}}
|
|
}
|
|
|
|
func testKeyPathInGenericContext<H: Hashable, X>(hashable: H, anything: X) {
|
|
let _ = \C<Int>.[hashable]
|
|
let _ = \C<Int>.[noHashableConstraint: hashable]
|
|
let _ = \C<Int>.[noHashableConstraint: anything] // expected-error{{subscript index of type 'X' in a key path must be Hashable}}
|
|
}
|
|
|
|
func testDisembodiedStringInterpolation(x: Int) {
|
|
\(x) // expected-error{{string interpolation can only appear inside a string literal}}
|
|
\(x, radix: 16) // expected-error{{string interpolation can only appear inside a string literal}}
|
|
}
|
|
|
|
func testNoComponents() {
|
|
let _: KeyPath<A, A> = \A // expected-error{{must have at least one component}}
|
|
let _: KeyPath<C, A> = \C // expected-error{{must have at least one component}}
|
|
// expected-error@-1 {{generic parameter 'T' could not be inferred}}
|
|
let _: KeyPath<A, C> = \A // expected-error{{must have at least one component}}
|
|
// expected-error@-1 {{generic parameter 'T' could not be inferred}}
|
|
_ = \A // expected-error {{key path must have at least one component}}
|
|
}
|
|
|
|
struct TupleStruct {
|
|
var unlabeled: (Int, String)
|
|
var labeled: (foo: Int, bar: String)
|
|
}
|
|
|
|
typealias UnlabeledGenericTuple<T, U> = (T, U)
|
|
typealias LabeledGenericTuple<T, U> = (a: T, b: U)
|
|
|
|
func tupleComponent<T, U>(_: T, _: U) {
|
|
let _ = \(Int, String).0
|
|
let _ = \(Int, String).1
|
|
let _ = \TupleStruct.unlabeled.0
|
|
let _ = \TupleStruct.unlabeled.1
|
|
|
|
let _ = \(foo: Int, bar: String).0
|
|
let _ = \(foo: Int, bar: String).1
|
|
let _ = \(foo: Int, bar: String).foo
|
|
let _ = \(foo: Int, bar: String).bar
|
|
let _ = \TupleStruct.labeled.0
|
|
let _ = \TupleStruct.labeled.1
|
|
let _ = \TupleStruct.labeled.foo
|
|
let _ = \TupleStruct.labeled.bar
|
|
|
|
let _ = \(T, U).0
|
|
let _ = \(T, U).1
|
|
let _ = \UnlabeledGenericTuple<T, U>.0
|
|
let _ = \UnlabeledGenericTuple<T, U>.1
|
|
|
|
let _ = \(a: T, b: U).0
|
|
let _ = \(a: T, b: U).1
|
|
let _ = \(a: T, b: U).a
|
|
let _ = \(a: T, b: U).b
|
|
let _ = \LabeledGenericTuple<T, U>.0
|
|
let _ = \LabeledGenericTuple<T, U>.1
|
|
let _ = \LabeledGenericTuple<T, U>.a
|
|
let _ = \LabeledGenericTuple<T, U>.b
|
|
}
|
|
|
|
func tuple_el_0<T, U>() -> KeyPath<(T, U), T> {
|
|
return \.0
|
|
}
|
|
|
|
func tuple_el_1<T, U>() -> KeyPath<(T, U), U> {
|
|
return \.1
|
|
}
|
|
|
|
func tupleGeneric<T, U>(_ v: (T, U)) {
|
|
_ = (1, "hello")[keyPath: tuple_el_0()]
|
|
_ = (1, "hello")[keyPath: tuple_el_1()]
|
|
|
|
_ = v[keyPath: tuple_el_0()]
|
|
_ = v[keyPath: tuple_el_1()]
|
|
|
|
_ = ("tuple", "too", "big")[keyPath: tuple_el_1()]
|
|
// expected-note@-12 {{}}
|
|
// expected-error@-2 {{generic parameter 'T' could not be inferred}}
|
|
// expected-error@-3 {{generic parameter 'U' could not be inferred}}
|
|
}
|
|
|
|
struct Z { }
|
|
|
|
func testKeyPathSubscript(readonly: Z, writable: inout Z,
|
|
kp: KeyPath<Z, Int>,
|
|
wkp: WritableKeyPath<Z, Int>,
|
|
rkp: ReferenceWritableKeyPath<Z, Int>) {
|
|
var sink: Int
|
|
sink = readonly[keyPath: kp]
|
|
sink = writable[keyPath: kp]
|
|
sink = readonly[keyPath: wkp]
|
|
sink = writable[keyPath: wkp]
|
|
sink = readonly[keyPath: rkp]
|
|
sink = writable[keyPath: rkp]
|
|
|
|
readonly[keyPath: kp] = sink // expected-error{{cannot assign through subscript: 'kp' is a read-only key path}}
|
|
writable[keyPath: kp] = sink // expected-error{{cannot assign through subscript: 'kp' is a read-only key path}}
|
|
readonly[keyPath: wkp] = sink // expected-error{{cannot assign through subscript: 'readonly' is a 'let' constant}}
|
|
writable[keyPath: wkp] = sink
|
|
readonly[keyPath: rkp] = sink
|
|
writable[keyPath: rkp] = sink
|
|
|
|
let pkp: PartialKeyPath = rkp
|
|
|
|
var anySink1 = readonly[keyPath: pkp]
|
|
expect(&anySink1, toHaveType: Exactly<Any>.self)
|
|
var anySink2 = writable[keyPath: pkp]
|
|
expect(&anySink2, toHaveType: Exactly<Any>.self)
|
|
|
|
readonly[keyPath: pkp] = anySink1 // expected-error{{cannot assign through subscript: 'pkp' is a read-only key path}}
|
|
writable[keyPath: pkp] = anySink2 // expected-error{{cannot assign through subscript: 'pkp' is a read-only key path}}
|
|
|
|
let akp: AnyKeyPath = pkp
|
|
|
|
var anyqSink1 = readonly[keyPath: akp]
|
|
expect(&anyqSink1, toHaveType: Exactly<Any?>.self)
|
|
var anyqSink2 = writable[keyPath: akp]
|
|
expect(&anyqSink2, toHaveType: Exactly<Any?>.self)
|
|
|
|
readonly[keyPath: akp] = anyqSink1 // expected-error{{cannot assign through subscript: 'readonly' is a 'let' constant}}
|
|
writable[keyPath: akp] = anyqSink2 // expected-error{{cannot assign through subscript: 'writable' is immutable}}
|
|
}
|
|
|
|
struct ZwithSubscript {
|
|
subscript(keyPath kp: KeyPath<ZwithSubscript, Int>) -> Int { return 0 }
|
|
subscript(keyPath kp: WritableKeyPath<ZwithSubscript, Int>) -> Int { return 0 }
|
|
subscript(keyPath kp: ReferenceWritableKeyPath<ZwithSubscript, Int>) -> Int { return 0 }
|
|
subscript(keyPath kp: PartialKeyPath<ZwithSubscript>) -> Any { return 0 }
|
|
}
|
|
|
|
struct NotZ {}
|
|
|
|
func testKeyPathSubscript(readonly: ZwithSubscript, writable: inout ZwithSubscript,
|
|
wrongType: inout NotZ,
|
|
kp: KeyPath<ZwithSubscript, Int>,
|
|
wkp: WritableKeyPath<ZwithSubscript, Int>,
|
|
rkp: ReferenceWritableKeyPath<ZwithSubscript, Int>) {
|
|
var sink: Int
|
|
sink = readonly[keyPath: kp]
|
|
sink = writable[keyPath: kp]
|
|
sink = readonly[keyPath: wkp]
|
|
sink = writable[keyPath: wkp]
|
|
sink = readonly[keyPath: rkp]
|
|
sink = writable[keyPath: rkp]
|
|
readonly[keyPath: kp] = sink // expected-error {{cannot assign through subscript: subscript is get-only}}
|
|
writable[keyPath: kp] = sink // expected-error {{cannot assign through subscript: subscript is get-only}}
|
|
readonly[keyPath: wkp] = sink // expected-error {{cannot assign through subscript: subscript is get-only}}
|
|
// FIXME: silently falls back to keypath application, which seems inconsistent
|
|
writable[keyPath: wkp] = sink
|
|
// FIXME: silently falls back to keypath application, which seems inconsistent
|
|
readonly[keyPath: rkp] = sink
|
|
// FIXME: silently falls back to keypath application, which seems inconsistent
|
|
writable[keyPath: rkp] = sink
|
|
|
|
let pkp: PartialKeyPath = rkp
|
|
|
|
var anySink1 = readonly[keyPath: pkp]
|
|
expect(&anySink1, toHaveType: Exactly<Any>.self)
|
|
var anySink2 = writable[keyPath: pkp]
|
|
expect(&anySink2, toHaveType: Exactly<Any>.self)
|
|
|
|
readonly[keyPath: pkp] = anySink1 // expected-error{{cannot assign through subscript: subscript is get-only}}
|
|
writable[keyPath: pkp] = anySink2 // expected-error{{cannot assign through subscript: subscript is get-only}}
|
|
|
|
let akp: AnyKeyPath = pkp
|
|
|
|
var anyqSink1 = readonly[keyPath: akp]
|
|
expect(&anyqSink1, toHaveType: Exactly<Any?>.self)
|
|
var anyqSink2 = writable[keyPath: akp]
|
|
expect(&anyqSink2, toHaveType: Exactly<Any?>.self)
|
|
|
|
// FIXME: silently falls back to keypath application, which seems inconsistent
|
|
readonly[keyPath: akp] = anyqSink1 // expected-error{{cannot assign through subscript: 'readonly' is a 'let' constant}}
|
|
// FIXME: silently falls back to keypath application, which seems inconsistent
|
|
writable[keyPath: akp] = anyqSink2 // expected-error{{cannot assign through subscript: 'writable' is immutable}}
|
|
|
|
_ = wrongType[keyPath: kp] // expected-error{{cannot be applied}}
|
|
_ = wrongType[keyPath: wkp] // expected-error{{cannot be applied}}
|
|
_ = wrongType[keyPath: rkp] // expected-error{{cannot be applied}}
|
|
_ = wrongType[keyPath: pkp] // expected-error{{cannot be applied}}
|
|
_ = wrongType[keyPath: akp]
|
|
}
|
|
|
|
func testKeyPathSubscriptMetatype(readonly: Z.Type, writable: inout Z.Type,
|
|
kp: KeyPath<Z.Type, Int>,
|
|
wkp: WritableKeyPath<Z.Type, Int>,
|
|
rkp: ReferenceWritableKeyPath<Z.Type, Int>) {
|
|
var sink: Int
|
|
sink = readonly[keyPath: kp]
|
|
sink = writable[keyPath: kp]
|
|
sink = readonly[keyPath: wkp]
|
|
sink = writable[keyPath: wkp]
|
|
sink = readonly[keyPath: rkp]
|
|
sink = writable[keyPath: rkp]
|
|
|
|
readonly[keyPath: kp] = sink // expected-error{{cannot assign through subscript: 'kp' is a read-only key path}}
|
|
writable[keyPath: kp] = sink // expected-error{{cannot assign through subscript: 'kp' is a read-only key path}}
|
|
readonly[keyPath: wkp] = sink // expected-error{{cannot assign through subscript: 'readonly' is a 'let' constant}}
|
|
writable[keyPath: wkp] = sink
|
|
readonly[keyPath: rkp] = sink
|
|
writable[keyPath: rkp] = sink
|
|
}
|
|
|
|
func testKeyPathSubscriptTuple(readonly: (Z,Z), writable: inout (Z,Z),
|
|
kp: KeyPath<(Z,Z), Int>,
|
|
wkp: WritableKeyPath<(Z,Z), Int>,
|
|
rkp: ReferenceWritableKeyPath<(Z,Z), Int>) {
|
|
var sink: Int
|
|
sink = readonly[keyPath: kp]
|
|
sink = writable[keyPath: kp]
|
|
sink = readonly[keyPath: wkp]
|
|
sink = writable[keyPath: wkp]
|
|
sink = readonly[keyPath: rkp]
|
|
sink = writable[keyPath: rkp]
|
|
|
|
readonly[keyPath: kp] = sink // expected-error{{cannot assign through subscript: 'kp' is a read-only key path}}
|
|
writable[keyPath: kp] = sink // expected-error{{cannot assign through subscript: 'kp' is a read-only key path}}
|
|
readonly[keyPath: wkp] = sink // expected-error{{cannot assign through subscript: 'readonly' is a 'let' constant}}
|
|
writable[keyPath: wkp] = sink
|
|
readonly[keyPath: rkp] = sink
|
|
writable[keyPath: rkp] = sink
|
|
}
|
|
|
|
func testKeyPathSubscriptLValue(base: Z, kp: inout KeyPath<Z, Z>) {
|
|
_ = base[keyPath: kp]
|
|
}
|
|
|
|
func testKeyPathSubscriptExistentialBase(concreteBase: inout B,
|
|
existentialBase: inout P,
|
|
kp: KeyPath<P, String>,
|
|
wkp: WritableKeyPath<P, String>,
|
|
rkp: ReferenceWritableKeyPath<P, String>,
|
|
pkp: PartialKeyPath<P>,
|
|
s: String) {
|
|
_ = concreteBase[keyPath: kp]
|
|
_ = concreteBase[keyPath: wkp]
|
|
_ = concreteBase[keyPath: rkp]
|
|
_ = concreteBase[keyPath: pkp]
|
|
|
|
concreteBase[keyPath: kp] = s // expected-error {{cannot assign through subscript: 'kp' is a read-only key path}}
|
|
concreteBase[keyPath: wkp] = s // expected-error {{key path with root type 'any P' cannot be applied to a base of type 'B'}}
|
|
concreteBase[keyPath: rkp] = s
|
|
concreteBase[keyPath: pkp] = s // expected-error {{cannot assign through subscript: 'pkp' is a read-only key path}}
|
|
|
|
_ = existentialBase[keyPath: kp]
|
|
_ = existentialBase[keyPath: wkp]
|
|
_ = existentialBase[keyPath: rkp]
|
|
_ = existentialBase[keyPath: pkp]
|
|
|
|
existentialBase[keyPath: kp] = s // expected-error {{cannot assign through subscript: 'kp' is a read-only key path}}
|
|
existentialBase[keyPath: wkp] = s
|
|
existentialBase[keyPath: rkp] = s
|
|
existentialBase[keyPath: pkp] = s // expected-error {{cannot assign through subscript: 'pkp' is a read-only key path}}
|
|
}
|
|
|
|
struct AA {
|
|
subscript(x: Int) -> Int { return x }
|
|
subscript(labeled x: Int) -> Int { return x }
|
|
var c: CC? = CC()
|
|
}
|
|
|
|
class CC {
|
|
var i = 0
|
|
}
|
|
|
|
func testKeyPathOptional() {
|
|
_ = \AA.c?.i
|
|
_ = \AA.c!.i
|
|
|
|
// https://github.com/apple/swift/issues/48750
|
|
let path: KeyPath<CC,Int>! = \CC.i
|
|
let cc = CC()
|
|
_ = cc[keyPath: path]
|
|
}
|
|
|
|
func testLiteralInAnyContext() {
|
|
let _: AnyKeyPath = \A.property
|
|
let _: AnyObject = \A.property
|
|
let _: Any = \A.property
|
|
let _: Any? = \A.property
|
|
}
|
|
|
|
func testMoreGeneralContext<T, U>(_: KeyPath<T, U>, with: T.Type) {}
|
|
|
|
func testLiteralInMoreGeneralContext() {
|
|
testMoreGeneralContext(\.property, with: A.self)
|
|
}
|
|
|
|
func testLabeledSubscript() {
|
|
let _: KeyPath<AA, Int> = \AA.[labeled: 0]
|
|
let _: KeyPath<AA, Int> = \.[labeled: 0]
|
|
let k = \AA.[labeled: 0]
|
|
|
|
// TODO: These ought to work without errors.
|
|
let _ = \AA.[keyPath: k]
|
|
// expected-error@-1 {{cannot convert value of type 'KeyPath<AA, Int>' to expected argument type 'Int'}}
|
|
// expected-error@-2 {{extraneous argument label 'keyPath:' in call}}
|
|
|
|
let _ = \AA.[keyPath: \AA.[labeled: 0]] // expected-error {{extraneous argument label 'keyPath:' in call}}
|
|
// expected-error@-1 {{cannot convert value of type 'KeyPath<AA, Int>' to expected argument type 'Int'}}
|
|
}
|
|
|
|
func testInvalidKeyPathComponents() {
|
|
let _ = \.{return 0} // expected-error* {{}}
|
|
}
|
|
|
|
class X {
|
|
class var a: Int { return 1 }
|
|
static var b = 2
|
|
}
|
|
|
|
func testStaticKeyPathComponent() {
|
|
_ = \X.a // expected-error{{cannot refer to static member}}
|
|
_ = \X.Type.a // expected-error{{cannot refer to static member}}
|
|
_ = \X.b // expected-error{{cannot refer to static member}}
|
|
_ = \X.Type.b // expected-error{{cannot refer to static member}}
|
|
}
|
|
|
|
class Bass: Hashable {
|
|
static func ==(_: Bass, _: Bass) -> Bool { return false }
|
|
func hash(into hasher: inout Hasher) {}
|
|
}
|
|
|
|
class Treble: Bass { }
|
|
|
|
struct BassSubscript {
|
|
subscript(_: Bass) -> Int { fatalError() }
|
|
subscript(_: @autoclosure () -> String) -> Int { fatalError() }
|
|
}
|
|
|
|
func testImplicitConversionInSubscriptIndex() {
|
|
_ = \BassSubscript.[Treble()]
|
|
_ = \BassSubscript.["hello"] // expected-error{{must be Hashable}}
|
|
}
|
|
|
|
// Crash in diagnostics + https://github.com/apple/swift/issues/53839
|
|
|
|
struct UnambiguousSubscript {
|
|
subscript(sub: Sub) -> Int { get { } set { } }
|
|
subscript(y y: Sub) -> Int { get { } set { } }
|
|
}
|
|
|
|
func useUnambiguousSubscript(_ sub: Sub) {
|
|
let _: PartialKeyPath<UnambiguousSubscript> = \.[sub]
|
|
}
|
|
|
|
struct BothUnavailableSubscript {
|
|
@available(*, unavailable)
|
|
subscript(sub: Sub) -> Int { get { } set { } } // expected-note {{'subscript(_:)' has been explicitly marked unavailable here}}
|
|
|
|
@available(*, unavailable)
|
|
subscript(y y: Sub) -> Int { get { } set { } }
|
|
}
|
|
|
|
func useBothUnavailableSubscript(_ sub: Sub) {
|
|
let _: PartialKeyPath<BothUnavailableSubscript> = \.[sub]
|
|
// expected-error@-1 {{'subscript(_:)' is unavailable}}
|
|
}
|
|
|
|
// https://github.com/apple/swift/issues/48661
|
|
func f_48661() {
|
|
class B {}
|
|
class A {
|
|
var b: B? = nil
|
|
}
|
|
class C {
|
|
var a: A?
|
|
func myFunc() {
|
|
let _ = \C.a?.b
|
|
}
|
|
}
|
|
}
|
|
|
|
// https://github.com/apple/swift/issues/49293
|
|
func f_49293() {
|
|
struct ABC {
|
|
let value: Int
|
|
func value(adding i: Int) -> Int { return value + i }
|
|
}
|
|
|
|
let abc = ABC(value: 0)
|
|
func get<T>(for kp: KeyPath<ABC, T>) -> T {
|
|
return abc[keyPath: kp]
|
|
}
|
|
_ = get(for: \.value)
|
|
}
|
|
|
|
// https://github.com/apple/swift/issues/49928
|
|
func f_49928() {
|
|
_ = ""[keyPath: \.count]
|
|
_ = ""[keyPath: \String.count]
|
|
|
|
let arr1 = [1]
|
|
_ = arr1[keyPath: \.[0]]
|
|
_ = arr1[keyPath: \[Int].[0]]
|
|
|
|
let dic1 = [1:"s"]
|
|
_ = dic1[keyPath: \.[1]]
|
|
_ = dic1[keyPath: \[Int: String].[1]]
|
|
|
|
var arr2 = [1]
|
|
arr2[keyPath: \.[0]] = 2
|
|
arr2[keyPath: \[Int].[0]] = 2
|
|
|
|
var dic2 = [1:"s"]
|
|
dic2[keyPath: \.[1]] = ""
|
|
dic2[keyPath: \[Int: String].[1]] = ""
|
|
|
|
_ = [""][keyPath: \.[0]]
|
|
_ = [""][keyPath: \[String].[0]]
|
|
|
|
_ = ["": ""][keyPath: \.["foo"]]
|
|
_ = ["": ""][keyPath: \[String: String].["foo"]]
|
|
|
|
class A {
|
|
var a: String = ""
|
|
}
|
|
_ = A()[keyPath: \.a]
|
|
_ = A()[keyPath: \A.a]
|
|
A()[keyPath: \.a] = ""
|
|
A()[keyPath: \A.a] = ""
|
|
}
|
|
|
|
struct VisibilityTesting {
|
|
private(set) var x: Int
|
|
fileprivate(set) var y: Int
|
|
let z: Int
|
|
|
|
// Key path exprs should not get special dispensation to write to lets
|
|
// in init contexts
|
|
init() {
|
|
var xRef = \VisibilityTesting.x
|
|
var yRef = \VisibilityTesting.y
|
|
var zRef = \VisibilityTesting.z
|
|
expect(&xRef,
|
|
toHaveType: Exactly<WritableKeyPath<VisibilityTesting, Int>>.self)
|
|
expect(&yRef,
|
|
toHaveType: Exactly<WritableKeyPath<VisibilityTesting, Int>>.self)
|
|
// Allow WritableKeyPath for Swift 3/4 only.
|
|
expect(&zRef,
|
|
toHaveType: Exactly<WritableKeyPath<VisibilityTesting, Int>>.self)
|
|
}
|
|
|
|
func inPrivateContext() {
|
|
var xRef = \VisibilityTesting.x
|
|
var yRef = \VisibilityTesting.y
|
|
var zRef = \VisibilityTesting.z
|
|
expect(&xRef,
|
|
toHaveType: Exactly<WritableKeyPath<VisibilityTesting, Int>>.self)
|
|
expect(&yRef,
|
|
toHaveType: Exactly<WritableKeyPath<VisibilityTesting, Int>>.self)
|
|
expect(&zRef,
|
|
toHaveType: Exactly<KeyPath<VisibilityTesting, Int>>.self)
|
|
}
|
|
}
|
|
|
|
struct VisibilityTesting2 {
|
|
func inFilePrivateContext() {
|
|
var xRef = \VisibilityTesting.x
|
|
var yRef = \VisibilityTesting.y
|
|
var zRef = \VisibilityTesting.z
|
|
// Allow WritableKeyPath for Swift 3/4 only.
|
|
expect(&xRef,
|
|
toHaveType: Exactly<WritableKeyPath<VisibilityTesting, Int>>.self)
|
|
expect(&yRef,
|
|
toHaveType: Exactly<WritableKeyPath<VisibilityTesting, Int>>.self)
|
|
expect(&zRef,
|
|
toHaveType: Exactly<KeyPath<VisibilityTesting, Int>>.self)
|
|
}
|
|
}
|
|
|
|
protocol PP {}
|
|
class Base : PP { var i: Int = 0 }
|
|
class Derived : Base {}
|
|
|
|
func testSubtypeKeypathClass(_ keyPath: ReferenceWritableKeyPath<Base, Int>) {
|
|
testSubtypeKeypathClass(\Derived.i)
|
|
}
|
|
|
|
func testSubtypeKeypathProtocol(_ keyPath: ReferenceWritableKeyPath<PP, Int>) {
|
|
testSubtypeKeypathProtocol(\Base.i)
|
|
// expected-error@-1 {{cannot convert value of type 'ReferenceWritableKeyPath<Base, Int>' to expected argument type 'ReferenceWritableKeyPath<any PP, Int>'}}
|
|
// expected-note@-2 {{arguments to generic parameter 'Root' ('Base' and 'any PP') are expected to be equal}}
|
|
}
|
|
|
|
// rdar://problem/32057712
|
|
struct Container {
|
|
let base: Base? = Base()
|
|
}
|
|
|
|
var rdar32057712 = \Container.base?.i
|
|
|
|
var identity1 = \Container.self
|
|
var identity2: WritableKeyPath = \Container.self
|
|
var identity3: WritableKeyPath<Container, Container> = \Container.self
|
|
var identity4: WritableKeyPath<Container, Container> = \.self
|
|
var identity5: KeyPath = \Container.self
|
|
var identity6: KeyPath<Container, Container> = \Container.self
|
|
var identity7: KeyPath<Container, Container> = \.self
|
|
var identity8: PartialKeyPath = \Container.self
|
|
var identity9: PartialKeyPath<Container> = \Container.self
|
|
var identity10: PartialKeyPath<Container> = \.self
|
|
var identity11: AnyKeyPath = \Container.self
|
|
var identity12: (Container) -> Container = \Container.self
|
|
var identity13: (Container) -> Container = \.self
|
|
var identity14: (Container) -> Container? = \Container.self
|
|
var identity15: (Container) -> Container? = \.self
|
|
|
|
var interleavedIdentityComponents = \Container.self.base.self?.self.i.self
|
|
|
|
protocol P_With_Static_Members {
|
|
static var x: Int { get }
|
|
static var arr: [Int] { get }
|
|
}
|
|
|
|
func test_keypath_with_static_members(_ p: P_With_Static_Members) {
|
|
let _ = p[keyPath: \.x]
|
|
// expected-error@-1 {{key path cannot refer to static member 'x'}}
|
|
let _: KeyPath<P_With_Static_Members, Int> = \.x
|
|
// expected-error@-1 {{key path cannot refer to static member 'x'}}
|
|
let _ = \P_With_Static_Members.arr.count
|
|
// expected-error@-1 {{key path cannot refer to static member 'arr'}}
|
|
let _ = p[keyPath: \.arr.count]
|
|
// expected-error@-1 {{key path cannot refer to static member 'arr'}}
|
|
|
|
struct S {
|
|
static var foo: String = "Hello"
|
|
var bar: Bar
|
|
}
|
|
|
|
struct Bar {
|
|
static var baz: Int = 42
|
|
}
|
|
|
|
func foo(_ s: S) {
|
|
let _ = \S.Type.foo
|
|
// expected-error@-1 {{key path cannot refer to static member 'foo'}}
|
|
let _ = s[keyPath: \.foo]
|
|
// expected-error@-1 {{key path cannot refer to static member 'foo'}}
|
|
let _: KeyPath<S, String> = \.foo
|
|
// expected-error@-1 {{key path cannot refer to static member 'foo'}}
|
|
let _ = \S.foo
|
|
// expected-error@-1 {{key path cannot refer to static member 'foo'}}
|
|
let _ = \S.bar.baz
|
|
// expected-error@-1 {{key path cannot refer to static member 'baz'}}
|
|
let _ = s[keyPath: \.bar.baz]
|
|
// expected-error@-1 {{key path cannot refer to static member 'baz'}}
|
|
}
|
|
}
|
|
|
|
func test_keypath_with_mutating_getter() {
|
|
struct S {
|
|
var foo: Int {
|
|
mutating get { return 42 }
|
|
}
|
|
|
|
subscript(_: Int) -> [Int] {
|
|
mutating get { return [] }
|
|
}
|
|
}
|
|
|
|
_ = \S.foo
|
|
// expected-error@-1 {{key path cannot refer to 'foo', which has a mutating getter}}
|
|
let _: KeyPath<S, Int> = \.foo
|
|
// expected-error@-1 {{key path cannot refer to 'foo', which has a mutating getter}}
|
|
_ = \S.[0]
|
|
// expected-error@-1 {{key path cannot refer to 'subscript(_:)', which has a mutating getter}}
|
|
_ = \S.[0].count
|
|
// expected-error@-1 {{key path cannot refer to 'subscript(_:)', which has a mutating getter}}
|
|
|
|
func test_via_subscript(_ s: S) {
|
|
_ = s[keyPath: \.foo]
|
|
// expected-error@-1 {{key path cannot refer to 'foo', which has a mutating getter}}
|
|
_ = s[keyPath: \.[0].count]
|
|
// expected-error@-1 {{key path cannot refer to 'subscript(_:)', which has a mutating getter}}
|
|
}
|
|
}
|
|
|
|
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/52867
|
|
// Argument type 'KeyPath<String, Int>' does not conform to expected type 'Any'
|
|
func test_keypath_in_any_context() {
|
|
func foo(_: Any) {}
|
|
foo(\String.count) // Ok
|
|
}
|
|
|
|
protocol PWithTypeAlias {
|
|
typealias Key = WritableKeyPath<Self, Int?>
|
|
static var fooKey: Key? { get }
|
|
static var barKey: Key! { get }
|
|
static var fazKey: Key?? { get }
|
|
static var bazKey: Key?! { get }
|
|
}
|
|
|
|
func test_keypath_inference_with_optionals() {
|
|
final class S : PWithTypeAlias {
|
|
static var fooKey: Key? { return \.foo }
|
|
static var barKey: Key! { return \.foo }
|
|
static var fazKey: Key?? { return \.foo }
|
|
static var bazKey: Key?! { return \.foo }
|
|
|
|
var foo: Int? = nil
|
|
}
|
|
}
|
|
|
|
// https://github.com/apple/swift/issues/53967
|
|
func f_53967() {
|
|
struct S1 {
|
|
subscript(x x: Int) -> Int { x }
|
|
}
|
|
|
|
_ = \S1.[5] // expected-error {{missing argument label 'x:' in call}} {{12-12=x: }}
|
|
|
|
struct S2 {
|
|
subscript(x x: Int) -> Int { x } // expected-note {{incorrect labels for candidate (have: '(_:)', expected: '(x:)')}}
|
|
subscript(y y: Int) -> Int { y } // expected-note {{incorrect labels for candidate (have: '(_:)', expected: '(y:)')}}
|
|
}
|
|
|
|
_ = \S2.[5] // expected-error {{no exact matches in call to subscript}}
|
|
|
|
struct S3 {
|
|
subscript(x x: Int, y y: Int) -> Int { x }
|
|
}
|
|
|
|
_ = \S3.[y: 5, x: 5] // expected-error {{argument 'x' must precede argument 'y'}}
|
|
|
|
struct S4 {
|
|
subscript(x: (Int, Int)) -> Int { x.0 }
|
|
}
|
|
|
|
_ = \S4.[1, 4] // expected-error {{subscript expects a single parameter of type '(Int, Int)'}} {{12-12=(}} {{16-16=)}}
|
|
// expected-error@-1 {{subscript index of type '(Int, Int)' in a key path must be Hashable}}
|
|
}
|
|
|
|
// https://github.com/apple/swift/issues/54718
|
|
// Ban keypaths with contextual root and without a leading dot.
|
|
struct S_54718 {
|
|
let property: [Int] = []
|
|
let kp1: KeyPath<S_54718, Int> = \property.count // expected-error {{a Swift key path with contextual root must begin with a leading dot}}{{37-37=.}}
|
|
let kp2: KeyPath<S_54718, Int> = \.property.count // Ok
|
|
let kp3: KeyPath<S_54718, Int> = \S_54718.property.count // Ok
|
|
|
|
func foo1(_: KeyPath<S_54718, Int> = \property.count) {} // expected-error {{a Swift key path with contextual root must begin with a leading dot}}{{41-41=.}}
|
|
func foo2(_: KeyPath<S_54718, Int> = \.property.count) {} // Ok
|
|
func foo3(_: KeyPath<S_54718, Int> = \S_54718.property.count) {} // Ok
|
|
|
|
func foo4<T>(_: KeyPath<S_54718, T>) {}
|
|
func useFoo4() {
|
|
foo4(\property.count) // expected-error {{a Swift key path with contextual root must begin with a leading dot}}{{11-11=.}}
|
|
foo4(\.property.count) // Ok
|
|
foo4(\S_54718.property.count) // Ok
|
|
}
|
|
}
|
|
|
|
func testKeyPathHole() {
|
|
_ = \.x // expected-error {{cannot infer key path type from context; consider explicitly specifying a root type}} {{8-8=<#Root#>}}
|
|
_ = \.x.y // expected-error {{cannot infer key path type from context; consider explicitly specifying a root type}} {{8-8=<#Root#>}}
|
|
|
|
let _ : AnyKeyPath = \.x
|
|
// expected-error@-1 {{'AnyKeyPath' does not provide enough context for root type to be inferred; consider explicitly specifying a root type}} {{25-25=<#Root#>}}
|
|
let _ : AnyKeyPath = \.x.y
|
|
// expected-error@-1 {{'AnyKeyPath' does not provide enough context for root type to be inferred; consider explicitly specifying a root type}} {{25-25=<#Root#>}}
|
|
|
|
func f(_ i: Int) {}
|
|
f(\.x) // expected-error {{cannot infer key path type from context; consider explicitly specifying a root type}} {{6-6=<#Root#>}}
|
|
f(\.x.y) // expected-error {{cannot infer key path type from context; consider explicitly specifying a root type}} {{6-6=<#Root#>}}
|
|
|
|
func provideValueButNotRoot<T>(_ fn: (T) -> String) {} // expected-note 2 {{in call to function 'provideValueButNotRoot'}}
|
|
provideValueButNotRoot(\.x) // expected-error {{cannot infer key path type from context; consider explicitly specifying a root type}}
|
|
// expected-error@-1 {{generic parameter 'T' could not be inferred}}
|
|
provideValueButNotRoot(\.x.y) // expected-error {{cannot infer key path type from context; consider explicitly specifying a root type}}
|
|
// expected-error@-1 {{generic parameter 'T' could not be inferred}}
|
|
provideValueButNotRoot(\String.foo) // expected-error {{value of type 'String' has no member 'foo'}}
|
|
|
|
func provideKPValueButNotRoot<T>(_ kp: KeyPath<T, String>) {}
|
|
provideKPValueButNotRoot(\.x) // expected-error {{cannot infer key path type from context; consider explicitly specifying a root type}}
|
|
provideKPValueButNotRoot(\.x.y) // expected-error {{cannot infer key path type from context; consider explicitly specifying a root type}}
|
|
|
|
provideKPValueButNotRoot(\String.foo)
|
|
// expected-error@-1 {{value of type 'String' has no member 'foo'}}
|
|
}
|
|
|
|
func testMissingMember() {
|
|
let _: KeyPath<String, String> = \.foo // expected-error {{value of type 'String' has no member 'foo'}}
|
|
let _: KeyPath<String, String> = \.foo.bar // expected-error {{value of type 'String' has no member 'foo'}}
|
|
|
|
let _: PartialKeyPath<String> = \.foo // expected-error {{value of type 'String' has no member 'foo'}}
|
|
let _: PartialKeyPath<String> = \.foo.bar // expected-error {{value of type 'String' has no member 'foo'}}
|
|
|
|
_ = \String.x.y // expected-error {{value of type 'String' has no member 'x'}}
|
|
}
|
|
|
|
// https://github.com/apple/swift/issues/48258
|
|
func testMemberAccessOnOptionalKeyPathComponent() {
|
|
struct S1a {
|
|
var b: S1b
|
|
var b_opt: S1b?
|
|
}
|
|
|
|
struct S1b {
|
|
var m: Int
|
|
var c: S1c?
|
|
}
|
|
|
|
struct S1c {
|
|
var d: Int
|
|
}
|
|
|
|
_ = \S1a.b_opt.m
|
|
// expected-error@-1 {{value of optional type 'S1b?' must be unwrapped to refer to member 'm' of wrapped base type 'S1b'}}
|
|
// expected-note@-2 {{chain the optional using '?' to access member 'm' only for non-'nil' base values}} {{17-17=?}}
|
|
// expected-note@-3 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{17-17=!}}
|
|
|
|
// FIXME(diagnostics): Ideally there should be two errors here - one for `b_opt` and one for `c` but since there is
|
|
// no contextual type it means that both `!` and `?` could work to reference `.d` and that creates ambiguity which
|
|
// is not possible to diagnose at the moment.
|
|
_ = \S1a.b_opt.c.d
|
|
// expected-error@-1 {{value of optional type 'S1b?' must be unwrapped to refer to member 'c' of wrapped base type 'S1b'}}
|
|
// expected-note@-2 {{chain the optional using '?' to access member 'c' only for non-'nil' base values}} {{17-17=?}}
|
|
let _: KeyPath<S1a, Int> = \S1a.b_opt.c.d
|
|
// expected-error@-1 {{value of optional type 'S1b?' must be unwrapped to refer to member 'c' of wrapped base type 'S1b'}}
|
|
// expected-note@-2 {{chain the optional using '?' to access member 'c' only for non-'nil' base values}} {{40-40=?}}
|
|
// expected-error@-3 {{value of optional type 'S1c?' must be unwrapped to refer to member 'd' of wrapped base type 'S1c'}}
|
|
// expected-note@-4 {{chain the optional using '?' to access member 'd' only for non-'nil' base values}} {{42-42=?}}
|
|
// expected-note@-5 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{42-42=!}}
|
|
_ = \S1a.b_opt?.c.d
|
|
// expected-error@-1 {{value of optional type 'S1c?' must be unwrapped to refer to member 'd' of wrapped base type 'S1c'}}
|
|
// expected-note@-2 {{chain the optional using '?' to access member 'd' only for non-'nil' base values}} {{20-20=?}}
|
|
|
|
_ = \S1a.b.c.d
|
|
// expected-error@-1 {{value of optional type 'S1c?' must be unwrapped to refer to member 'd' of wrapped base type 'S1c'}}
|
|
// expected-note@-2 {{chain the optional using '?' to access member 'd' only for non-'nil' base values}} {{15-15=?}}
|
|
// expected-note@-3 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{15-15=!}}
|
|
|
|
struct S2 {
|
|
subscript(_ x: Int) -> String? { get {} }
|
|
}
|
|
|
|
struct S3 {
|
|
struct Nested {
|
|
var foo = ""
|
|
}
|
|
}
|
|
|
|
\String?.count
|
|
// expected-error@-1 {{value of optional type 'String?' must be unwrapped to refer to member 'count' of wrapped base type 'String'}}
|
|
// expected-note@-2 {{use unwrapped type 'String' as key path root}} {{4-11=String}}
|
|
|
|
\Optional<String>.count
|
|
// expected-error@-1 {{value of optional type 'Optional<String>' must be unwrapped to refer to member 'count' of wrapped base type 'String'}}
|
|
// expected-note@-2 {{use unwrapped type 'String' as key path root}} {{4-20=String}}
|
|
|
|
\S2.[5].count
|
|
// expected-error@-1 {{value of optional type 'String?' must be unwrapped to refer to member 'count' of wrapped base type 'String'}}
|
|
// expected-note@-2 {{chain the optional using '?' to access member 'count' only for non-'nil' base values}}{{10-10=?}}
|
|
// expected-note@-3 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}}{{10-10=!}}
|
|
|
|
|
|
\S3.Nested?.foo.count
|
|
// expected-error@-1 {{value of optional type 'S3.Nested?' must be unwrapped to refer to member 'foo' of wrapped base type 'S3.Nested'}}
|
|
// expected-note@-2 {{use unwrapped type 'S3.Nested' as key path root}}{{4-14=S3.Nested}}
|
|
|
|
\(Int, Int)?.0
|
|
// expected-error@-1 {{value of optional type '(Int, Int)?' must be unwrapped to refer to member '0' of wrapped base type '(Int, Int)'}}
|
|
// expected-note@-2 {{use unwrapped type '(Int, Int)' as key path root}}{{4-15=(Int, Int)}}
|
|
|
|
func kp(_: KeyPath<String?, Int>) {}
|
|
|
|
kp(\.count) // expected-error {{key path root inferred as optional type 'String?' must be unwrapped to refer to member 'count' of unwrapped type 'String'}}
|
|
let _ : KeyPath<String?, Int> = \.count // expected-error {{key path root inferred as optional type 'String?' must be unwrapped to refer to member 'count' of unwrapped type 'String'}}
|
|
|
|
let _ : KeyPath<String?, Int> = \.utf8.count
|
|
// expected-error@-1 {{key path root inferred as optional type 'String?' must be unwrapped to refer to member 'utf8' of unwrapped type 'String'}}
|
|
}
|
|
|
|
func testSyntaxErrors() {
|
|
_ = \. ; // expected-error{{expected member name following '.'}}
|
|
_ = \.a ;
|
|
_ = \[a ;
|
|
_ = \[a];
|
|
_ = \? ;
|
|
_ = \! ;
|
|
_ = \. ; // expected-error{{expected member name following '.'}}
|
|
_ = \.a ;
|
|
_ = \[a ;
|
|
_ = \[a,;
|
|
_ = \[a:;
|
|
_ = \[a];
|
|
_ = \.a?;
|
|
_ = \.a!;
|
|
_ = \A ;
|
|
_ = \A, ;
|
|
_ = \A< ;
|
|
_ = \A. ; // expected-error{{expected member name following '.'}}
|
|
_ = \A.a ;
|
|
_ = \A[a ;
|
|
_ = \A[a];
|
|
_ = \A? ;
|
|
_ = \A! ;
|
|
_ = \A. ; // expected-error{{expected member name following '.'}}
|
|
_ = \A.a ;
|
|
_ = \A[a ;
|
|
_ = \A[a,;
|
|
_ = \A[a:;
|
|
_ = \A[a];
|
|
_ = \A.a?;
|
|
_ = \A.a!;
|
|
}
|
|
|
|
// https://github.com/apple/swift/issues/56996
|
|
func f_56996() {
|
|
_ = \Int.byteSwapped.signum() // expected-error {{invalid component of Swift key path}}
|
|
_ = \Int.byteSwapped.init() // expected-error {{invalid component of Swift key path}}
|
|
_ = \Int // expected-error {{key path must have at least one component}}
|
|
_ = \Int? // expected-error {{key path must have at least one component}}
|
|
_ = \Int. // expected-error {{invalid component of Swift key path}}
|
|
// expected-error@-1 {{expected member name following '.'}}
|
|
}
|
|
|
|
// https://github.com/apple/swift/issues/55805
|
|
// Key-path missing optional crashes compiler: Inactive constraints left over?
|
|
func f_55805() {
|
|
let _: KeyPath<String?, Int?> = \.utf8.count
|
|
// expected-error@-1 {{key path root inferred as optional type 'String?' must be unwrapped to refer to member 'utf8' of unwrapped type 'String'}}
|
|
// expected-error@-2 {{cannot assign value of type 'KeyPath<String?, Int>' to type 'KeyPath<String?, Int?>'}}
|
|
// expected-note@-3 {{arguments to generic parameter 'Value' ('Int' and 'Int?') are expected to be equal}}
|
|
}
|
|
|
|
// rdar://74711236 - crash due to incorrect member access in key path
|
|
func rdar74711236() {
|
|
struct S {
|
|
var arr: [V] = []
|
|
}
|
|
|
|
struct V : Equatable {
|
|
}
|
|
|
|
enum Type {
|
|
case store
|
|
}
|
|
|
|
struct Context {
|
|
func supported() -> [Type] {
|
|
return []
|
|
}
|
|
}
|
|
|
|
func test(context: Context?) {
|
|
var s = S()
|
|
|
|
s.arr = {
|
|
if let type = context?.store { // expected-error {{value of type 'Context' has no member 'store'}}
|
|
// `isSupported` should be an invalid declaration to trigger a crash in `map(\.option)`
|
|
let isSupported = context!.supported().contains(type)
|
|
return (isSupported ? [type] : []).map(\.option)
|
|
}
|
|
return []
|
|
}()
|
|
}
|
|
}
|
|
|
|
extension String {
|
|
var filterOut : (Self) throws -> Bool {
|
|
{ $0.contains("a") }
|
|
}
|
|
}
|
|
|
|
func test_kp_as_function_mismatch() {
|
|
let a : [String] = [ "asd", "bcd", "def" ]
|
|
|
|
let _ : (String) -> Bool = \.filterOut // expected-error{{key path value type '(String) throws -> Bool' cannot be converted to contextual type 'Bool'}}
|
|
_ = a.filter(\.filterOut) // expected-error{{key path value type '(String) throws -> Bool' cannot be converted to contextual type 'Bool'}}
|
|
let _ : (String) -> Bool = \String.filterOut // expected-error{{key path value type '(String) throws -> Bool' cannot be converted to contextual type 'Bool'}}
|
|
_ = a.filter(\String.filterOut) // expected-error{{key path value type '(String) throws -> Bool' cannot be converted to contextual type 'Bool'}}
|
|
|
|
}
|
|
|
|
func test_partial_keypath_inference() {
|
|
// rdar://problem/34144827
|
|
|
|
struct S { var i: Int = 0 }
|
|
enum E { case A(pkp: PartialKeyPath<S>) }
|
|
|
|
_ = E.A(pkp: \.i) // Ok
|
|
|
|
// rdar://problem/36472188
|
|
|
|
class ThePath {
|
|
var isWinding:Bool?
|
|
}
|
|
|
|
func walk<T>(aPath: T, forKey: PartialKeyPath<T>) {}
|
|
func walkThePath(aPath: ThePath, forKey: PartialKeyPath<ThePath>) {}
|
|
|
|
func test(path: ThePath) {
|
|
walkThePath(aPath: path, forKey: \.isWinding) // Ok
|
|
walk(aPath: path, forKey: \.isWinding) // Ok
|
|
}
|
|
}
|
|
|
|
// https://github.com/apple/swift/issues/56854
|
|
func f_56854() {
|
|
struct S1 {}
|
|
struct S2 {}
|
|
|
|
func reproduceA() -> [(S1, S2)] {
|
|
[
|
|
(true, .init(), S2.init()) // expected-error {{cannot infer contextual base in reference to member 'init'}}
|
|
]
|
|
.filter(\.0) // expected-error {{value of type 'Any' has no member '0'}}
|
|
// expected-note@-1 {{cast 'Any' to 'AnyObject' or use 'as!' to force downcast to a more specific type to access members}}
|
|
.prefix(3)
|
|
.map { ($0.1, $0.2) } // expected-error {{value of type 'Any' has no member '1'}} expected-error{{value of type 'Any' has no member '2'}}
|
|
// expected-note@-1 2 {{cast 'Any' to 'AnyObject' or use 'as!' to force downcast to a more specific type to access members}}
|
|
}
|
|
|
|
func reproduceB() -> [(S1, S2)] {
|
|
[
|
|
(true, S1.init(), .init()) // expected-error {{cannot infer contextual base in reference to member 'init'}}
|
|
]
|
|
.filter(\.0) // expected-error {{value of type 'Any' has no member '0'}}
|
|
// expected-note@-1 {{cast 'Any' to 'AnyObject' or use 'as!' to force downcast to a more specific type to access members}}
|
|
.prefix(3)
|
|
.map { ($0.1, $0.2) } // expected-error {{value of type 'Any' has no member '1'}} expected-error{{value of type 'Any' has no member '2'}}
|
|
// expected-note@-1 2 {{cast 'Any' to 'AnyObject' or use 'as!' to force downcast to a more specific type to access members}}
|
|
}
|
|
|
|
func reproduceC() -> [(S1, S2)] {
|
|
[
|
|
(true, .init(), .init()) // expected-error 2 {{cannot infer contextual base in reference to member 'init'}}
|
|
]
|
|
.filter(\.0) // expected-error {{value of type 'Any' has no member '0'}}
|
|
// expected-note@-1 {{cast 'Any' to 'AnyObject' or use 'as!' to force downcast to a more specific type to access members}}
|
|
.prefix(3)
|
|
.map { ($0.1, $0.2) } // expected-error {{value of type 'Any' has no member '1'}} expected-error{{value of type 'Any' has no member '2'}}
|
|
// expected-note@-1 2 {{cast 'Any' to 'AnyObject' or use 'as!' to force downcast to a more specific type to access members}}
|
|
}
|
|
}
|
|
|
|
// rdar://93103421 - Key path type inference doesn't work when the context is an existential type with a key-path superclass
|
|
extension KeyPath : P {
|
|
var member: String { "" }
|
|
}
|
|
|
|
func test_keypath_inference_from_existentials() {
|
|
struct A<T> : P {
|
|
var member: String { "a" }
|
|
var other: T { fatalError() }
|
|
}
|
|
|
|
func test<T, U>(_: any P & KeyPath<A<T>, U>, _: T) {
|
|
}
|
|
|
|
let _: any P & KeyPath<A<Int>, String> = \.member // Ok
|
|
let _: (any P & KeyPath<A<Int>, String>) = \.member // Ok
|
|
|
|
test(\.other, 42) // Ok
|
|
test(\.member, "") // Ok
|
|
}
|
|
|
|
// rdar://116376651 - key path type is bound before context is fully resolved.
|
|
func keypath_to_func_conversion_as_arg_to_overloaded_func() {
|
|
struct Data {
|
|
var value: Int = 42
|
|
}
|
|
|
|
func test<S: Sequence>(_: S, _: (S.Element) -> Int) {}
|
|
func test<C: Collection>(_: C, _: (C.Element) -> Int) {}
|
|
|
|
func test(arr: [Data]) {
|
|
test(arr, \Data.value) // Ok
|
|
}
|
|
}
|
|
|
|
// https://github.com/apple/swift/issues/55436
|
|
func test_keypath_coercion_to_function() {
|
|
struct User {
|
|
let email: String
|
|
}
|
|
|
|
let users = [User]()
|
|
let fn = \User.email as (User) -> String // Ok
|
|
_ = users.map(fn) // Ok
|
|
}
|
|
|
|
func test_keypath_application_with_composition(v: String, kp: any KeyPath<String, Int> & PP) {
|
|
_ = v[keyPath: kp] // Ok
|
|
}
|
|
|
|
func test_leading_dot_key_path_without_context() {
|
|
func test(_: AnyKeyPath?) {}
|
|
test(\.utf8)
|
|
// expected-error@-1 {{cannot infer key path type from context; consider explicitly specifying a root type}}
|
|
}
|
|
|
|
func keypath_function_transitive_conversions() {
|
|
class Base {
|
|
var derived: Derived { Derived() }
|
|
var base: Base { Base() }
|
|
var int: Int { 0 }
|
|
}
|
|
|
|
class Derived: Base {
|
|
override var derived: Derived { Derived() }
|
|
override var base: Base { Base() }
|
|
}
|
|
|
|
struct S {
|
|
var base: Base { Base() }
|
|
var derived: Derived { Derived() }
|
|
}
|
|
|
|
let _: (Base) -> Base = \Base.base
|
|
let _: (Base) -> Base = \Derived.base
|
|
let _: (Base) -> Base? = \Base?.self
|
|
let _: (Base) -> Base? = \Base?.self?.base
|
|
// FIXME: This error text is bogus due to KeyPath base covariance.
|
|
let _: (Base?) -> Base = \Base.base // expected-error {{value of optional type 'Base?' must be unwrapped to refer to member 'base' of wrapped base type 'Base'}} expected-note {{use unwrapped type 'Base' as key path root}} {{29-33=Base}}
|
|
let _: (Base) -> Base = \.base
|
|
let _: (Base) -> Base = \Base.derived
|
|
let _: (Base) -> Base = \.derived
|
|
let _: (Base) -> Int = \Base.int
|
|
let _: (Derived) -> Base = \Base.base
|
|
let _: (Derived) -> Base = \Derived.base
|
|
let _: (Derived) -> Base = \.base
|
|
let _: (Derived) -> Int = \Base.int
|
|
let _: (Derived) -> Int = \Derived.int
|
|
let _: (Derived) -> Int = \.int
|
|
let _: (Base) async throws -> Int = \.int
|
|
|
|
let _: (Derived) -> Base = \Base.derived
|
|
|
|
let _: (S) -> Base = \.derived
|
|
let _: (S) -> Derived = \.base // expected-error {{key path value type 'Base' cannot be converted to contextual type 'Derived'}}
|
|
}
|
|
|
|
func testMinimalKeypaths(_ arr: [Int?]) {
|
|
// These keypaths don't have any components that need 'resolving'. We still
|
|
// should not eagerly turn them into keypaths; they should get converted to
|
|
// functions instead
|
|
let _: [Int] = arr.compactMap(\.self)
|
|
let _: [Int] = arr.compactMap(\.?)
|
|
let _: [Int] = arr.map(\.!)
|
|
}
|
|
|
|
func testKeyPathInout() {
|
|
let _: (inout String) -> Int = \.count
|
|
let _: (inout String) -> Int = \String.count
|
|
let _: (inout String) -> Int? = \.count
|
|
|
|
func takesInout(_: (inout String) -> Int) {}
|
|
func takesInoutOpt(_: (inout String) -> Int?) {}
|
|
|
|
takesInout(\.count)
|
|
takesInout(\String.count)
|
|
takesInoutOpt(\.count)
|
|
takesInoutOpt(\String.count)
|
|
}
|