| // 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> { |
| 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 |
| // 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 _: 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: shouldn't be ambiguous |
| // expected-error@+1{{ambiguous}} |
| 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] |
| |
| 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 _: 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 _: 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 |
| |
| 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 _: 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) |
| |
| // FIXME: shouldn't be ambiguous |
| // expected-error@+1{{ambiguous}} |
| var n = [\A.property, \.optProperty, \.[sub], \.optProperty!] |
| expect(&n, toHaveType: Exactly<[PartialKeyPath<A>]>.self) |
| |
| // FIXME: shouldn't be ambiguous |
| // expected-error@+1{{ambiguous}} |
| 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{{ambiguous}} |
| let _: AnyKeyPath = \C.value // expected-error{{cannot convert}} (need to improve diagnostic) |
| let _: AnyKeyPath = \.value // expected-error{{ambiguous}} |
| |
| 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}} expected-error{{}} |
| \(x, radix: 16) // expected-error{{string interpolation}} expected-error{{}} |
| } |
| |
| 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{{}} |
| } |
| |
| 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 {{cannot be applied}} |
| // expected-error@-3 {{cannot be applied}} |
| // expected-error@-4 {{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: 'readonly' is a 'let' constant}} |
| writable[keyPath: pkp] = anySink2 // expected-error{{cannot assign through subscript: 'writable' is immutable}} |
| |
| 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{{}} |
| concreteBase[keyPath: wkp] = s // expected-error{{}} |
| concreteBase[keyPath: rkp] = s |
| concreteBase[keyPath: pkp] = s // expected-error{{}} |
| |
| _ = existentialBase[keyPath: kp] |
| _ = existentialBase[keyPath: wkp] |
| _ = existentialBase[keyPath: rkp] |
| _ = existentialBase[keyPath: pkp] |
| |
| existentialBase[keyPath: kp] = s // expected-error{{}} |
| existentialBase[keyPath: wkp] = s |
| existentialBase[keyPath: rkp] = s |
| existentialBase[keyPath: pkp] = s // expected-error{{}} |
| } |
| |
| 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 |
| |
| // SR-6198 |
| 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{{}} |
| let _ = \AA.[keyPath: \AA.[labeled: 0]] // expected-error{{}} |
| } |
| |
| 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{{}} |
| _ = \X.Type.a // expected-error{{cannot refer to static member}} |
| _ = \X.b // expected-error{{}} |
| _ = \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 |
| struct AmbiguousSubscript { |
| subscript(sub: Sub) -> Int { get { } set { } } |
| // expected-note@-1 {{'subscript(_:)' declared here}} |
| |
| subscript(y y: Sub) -> Int { get { } set { } } |
| // expected-note@-1 {{'subscript(y:)' declared here}} |
| } |
| |
| func useAmbiguousSubscript(_ sub: Sub) { |
| let _: PartialKeyPath<AmbiguousSubscript> = \.[sub] |
| // expected-error@-1 {{ambiguous reference to member 'subscript'}} |
| } |
| |
| struct BothUnavailableSubscript { |
| @available(*, unavailable) |
| subscript(sub: Sub) -> Int { get { } set { } } |
| |
| @available(*, unavailable) |
| subscript(y y: Sub) -> Int { get { } set { } } |
| } |
| |
| func useBothUnavailableSubscript(_ sub: Sub) { |
| let _: PartialKeyPath<BothUnavailableSubscript> = \.[sub] |
| // expected-error@-1 {{type of expression is ambiguous without more context}} |
| } |
| |
| // SR-6106 |
| func sr6106() { |
| class B {} |
| class A { |
| var b: B? = nil |
| } |
| class C { |
| var a: A? |
| func myFunc() { |
| let _ = \C.a?.b |
| } |
| } |
| } |
| |
| // SR-6744 |
| func sr6744() { |
| 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) |
| } |
| |
| func sr7380() { |
| _ = ""[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 {{type 'PP' has no member 'i'}} |
| } |
| |
| // 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 interleavedIdentityComponents = \Container.self.base.self?.self.i.self |
| |
| func testSyntaxErrors() { // expected-note{{}} |
| _ = \. ; // 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{{}} |