blob: d5a4ac8e13dd5d851513324673ede55a39dd6a56 [file] [log] [blame]
// RUN: %target-swift-frontend -typecheck -parse-as-library -enable-experimental-keypaths %s -verify
struct Sub {}
struct OptSub {}
struct Prop {
subscript(sub: Sub) -> A { get { return A() } set { } }
subscript(optSub: OptSub) -> 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() }
var hashValue: Int { fatalError() }
}
struct B {}
struct C<T> {
var value: T
subscript(sub: Sub) -> T { get { return value } set { } }
subscript<U>(sub: U) -> U { get { return sub } set { } }
}
extension Array where Element == A {
var property: Prop { fatalError() }
}
struct Exactly<T> {}
func expect<T>(_ x: inout T, toHaveType _: Exactly<T>.Type) {}
func testKeyPath(sub: Sub, optSub: OptSub, 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
// FIXME crash let _: PartialKeyPath<A> = \.property
let _: KeyPath<A, Prop> = \.property
let _: WritableKeyPath<A, Prop> = \.property
// expected-error@+1{{ambiguous}} (need to improve diagnostic)
let _: ReferenceWritableKeyPath<A, Prop> = \.property
// FIXME crash let _: PartialKeyPath<A> = \[sub]
let _: KeyPath<A, A> = \.[sub]
let _: WritableKeyPath<A, A> = \.[sub]
// expected-error@+1{{ambiguous}} (need to improve diagnostic)
let _: ReferenceWritableKeyPath<A, A> = \.[sub]
// FIXME crash 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?
// FIXME crash 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]
// FIXME crash let _: PartialKeyPath<C<A>> = \.value
let _: KeyPath<C<A>, A> = \.value
let _: WritableKeyPath<C<A>, A> = \.value
// expected-error@+1{{ambiguous}} (need to improve diagnostic)
let _: ReferenceWritableKeyPath<C<A>, A> = \.value
// FIXME crash 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
// FIXME crash let _: PartialKeyPath<Prop> = \.nonMutatingProperty
let _: KeyPath<Prop, B> = \.nonMutatingProperty
let _: WritableKeyPath<Prop, B> = \.nonMutatingProperty
let _: ReferenceWritableKeyPath<Prop, B> = \.nonMutatingProperty
}
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 to immutable}}
writable[keyPath: kp] = sink // expected-error{{cannot assign to immutable}}
readonly[keyPath: wkp] = sink // expected-error{{cannot assign to immutable}}
writable[keyPath: wkp] = sink
readonly[keyPath: rkp] = sink
writable[keyPath: rkp] = sink
}
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 to immutable}}
writable[keyPath: kp] = sink // expected-error{{cannot assign to immutable}}
readonly[keyPath: wkp] = sink // expected-error{{cannot assign to immutable}}
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 to immutable}}
writable[keyPath: kp] = sink // expected-error{{cannot assign to immutable}}
readonly[keyPath: wkp] = sink // expected-error{{cannot assign to immutable}}
writable[keyPath: wkp] = sink
readonly[keyPath: rkp] = sink
writable[keyPath: rkp] = sink
}
func testSyntaxErrors() { // expected-note{{}}
// TODO: recovery
_ = \. ; // 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!;
} // expected-error@+1{{}}