// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s struct S { var x: T let y: String var z: C var computed: C { fatalError() } var observed: C { didSet { fatalError() } } var reabstracted: () -> () } class C { final var x: T final let y: String final var z: S var nonfinal: S var computed: S { fatalError() } var observed: S { didSet { fatalError() } } final var reabstracted: () -> () init() { fatalError() } } protocol P { var x: Int { get } var y: String { get set } } extension P { var z: String { return y } var w: String { get { return "" } nonmutating set { } } } // CHECK-LABEL: sil hidden @{{.*}}storedProperties func storedProperties(_: T) { // CHECK: keypath $WritableKeyPath, T>, <τ_0_0> (root $S<τ_0_0>; stored_property #S.x : $τ_0_0) _ = \S.x // CHECK: keypath $KeyPath, String>, <τ_0_0> (root $S<τ_0_0>; stored_property #S.y : $String) _ = \S.y // CHECK: keypath $ReferenceWritableKeyPath, T>, <τ_0_0> (root $S<τ_0_0>; stored_property #S.z : $C<τ_0_0>; stored_property #C.x : $τ_0_0) _ = \S.z.x // CHECK: keypath $ReferenceWritableKeyPath, T>, <τ_0_0> (root $C<τ_0_0>; stored_property #C.x : $τ_0_0) _ = \C.x // CHECK: keypath $KeyPath, String>, <τ_0_0> (root $C<τ_0_0>; stored_property #C.y : $String) _ = \C.y // CHECK: keypath $ReferenceWritableKeyPath, T>, <τ_0_0> (root $C<τ_0_0>; stored_property #C.z : $S<τ_0_0>; stored_property #S.x : $τ_0_0) _ = \C.z.x // CHECK: keypath $KeyPath, String>, <τ_0_0> (root $C<τ_0_0>; stored_property #C.z : $S<τ_0_0>; stored_property #S.z : $C<τ_0_0>; stored_property #C.y : $String) _ = \C.z.z.y } // CHECK-LABEL: sil hidden @{{.*}}computedProperties func computedProperties(_: T) { // CHECK: keypath $ReferenceWritableKeyPath, S>, <τ_0_0 where τ_0_0 : P> ( // CHECK-SAME: root $C<τ_0_0>; // CHECK-SAME: settable_property $S<τ_0_0>, // CHECK-SAME: id #C.nonfinal!getter.1 : (C) -> () -> S, // CHECK-SAME: getter @_T08keypaths1CC8nonfinalAA1SVyxGvpAA1PRzlACyxGTK : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in C<τ_0_0>) -> @out S<τ_0_0>, // CHECK-SAME: setter @_T08keypaths1CC8nonfinalAA1SVyxGvpAA1PRzlACyxGTk : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in S<τ_0_0>, @in C<τ_0_0>) -> () // CHECK-SAME: ) _ = \C.nonfinal // CHECK: keypath $KeyPath, S>, <τ_0_0 where τ_0_0 : P> ( // CHECK-SAME: root $C<τ_0_0>; // CHECK-SAME: gettable_property $S<τ_0_0>, // CHECK-SAME: id #C.computed!getter.1 : (C) -> () -> S, // CHECK-SAME: getter @_T08keypaths1CC8computedAA1SVyxGvpAA1PRzlACyxGTK : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in C<τ_0_0>) -> @out S<τ_0_0> // CHECK-SAME: ) _ = \C.computed // CHECK: keypath $ReferenceWritableKeyPath, S>, <τ_0_0 where τ_0_0 : P> ( // CHECK-SAME: root $C<τ_0_0>; // CHECK-SAME: settable_property $S<τ_0_0>, // CHECK-SAME: id #C.observed!getter.1 : (C) -> () -> S, // CHECK-SAME: getter @_T08keypaths1CC8observedAA1SVyxGvpAA1PRzlACyxGTK : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in C<τ_0_0>) -> @out S<τ_0_0>, // CHECK-SAME: setter @_T08keypaths1CC8observedAA1SVyxGvpAA1PRzlACyxGTk : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in S<τ_0_0>, @in C<τ_0_0>) -> () // CHECK-SAME: ) _ = \C.observed _ = \C.nonfinal.x _ = \C.computed.x _ = \C.observed.x _ = \C.z.computed _ = \C.z.observed _ = \C.observed.x // CHECK: keypath $ReferenceWritableKeyPath, () -> ()>, <τ_0_0 where τ_0_0 : P> ( // CHECK-SAME: root $C<τ_0_0>; // CHECK-SAME: settable_property $() -> (), // CHECK-SAME: id ##C.reabstracted, // CHECK-SAME: getter @_T08keypaths1CC12reabstractedyycvpAA1PRzlACyxGTK : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in C<τ_0_0>) -> @out @callee_guaranteed (@in ()) -> @out (), // CHECK-SAME: setter @_T08keypaths1CC12reabstractedyycvpAA1PRzlACyxGTk : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in @callee_guaranteed (@in ()) -> @out (), @in C<τ_0_0>) -> () // CHECK-SAME: ) _ = \C.reabstracted // CHECK: keypath $KeyPath, C>, <τ_0_0 where τ_0_0 : P> ( // CHECK-SAME: root $S<τ_0_0>; gettable_property $C<τ_0_0>, // CHECK-SAME: id @_T08keypaths1SV8computedAA1CCyxGvg : $@convention(method) <τ_0_0> (@in_guaranteed S<τ_0_0>) -> @owned C<τ_0_0>, // CHECK-SAME: getter @_T08keypaths1SV8computedAA1CCyxGvpAA1PRzlACyxGTK : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in S<τ_0_0>) -> @out C<τ_0_0> // CHECK-SAME: ) _ = \S.computed // CHECK: keypath $WritableKeyPath, C>, <τ_0_0 where τ_0_0 : P> ( // CHECK-SAME: root $S<τ_0_0>; // CHECK-SAME: settable_property $C<τ_0_0>, // CHECK-SAME: id @_T08keypaths1SV8observedAA1CCyxGvg : $@convention(method) <τ_0_0> (@in_guaranteed S<τ_0_0>) -> @owned C<τ_0_0>, // CHECK-SAME: getter @_T08keypaths1SV8observedAA1CCyxGvpAA1PRzlACyxGTK : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in S<τ_0_0>) -> @out C<τ_0_0>, // CHECK-SAME: setter @_T08keypaths1SV8observedAA1CCyxGvpAA1PRzlACyxGTk : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in C<τ_0_0>, @inout S<τ_0_0>) -> () // CHECK-SAME: ) _ = \S.observed _ = \S.z.nonfinal _ = \S.z.computed _ = \S.z.observed _ = \S.computed.x _ = \S.computed.y // CHECK: keypath $WritableKeyPath, () -> ()>, <τ_0_0 where τ_0_0 : P> ( // CHECK-SAME: root $S<τ_0_0>; // CHECK-SAME: settable_property $() -> (), // CHECK-SAME: id ##S.reabstracted, // CHECK-SAME: getter @_T08keypaths1SV12reabstractedyycvpAA1PRzlACyxGTK : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in S<τ_0_0>) -> @out @callee_guaranteed (@in ()) -> @out (), // CHECK-SAME: setter @_T08keypaths1SV12reabstractedyycvpAA1PRzlACyxGTk : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in @callee_guaranteed (@in ()) -> @out (), @inout S<τ_0_0>) -> () // CHECK-SAME: ) _ = \S.reabstracted // CHECK: keypath $KeyPath, <τ_0_0 where τ_0_0 : P> ( // CHECK-SAME: root $τ_0_0; // CHECK-SAME: gettable_property $Int, // CHECK-SAME: id #P.x!getter.1 : (Self) -> () -> Int, // CHECK-SAME: getter @_T08keypaths1PP1xSivpAaBRzlxTK : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in τ_0_0) -> @out Int // CHECK-SAME: ) _ = \T.x // CHECK: keypath $WritableKeyPath, <τ_0_0 where τ_0_0 : P> ( // CHECK-SAME: root $τ_0_0; // CHECK-SAME: settable_property $String, // CHECK-SAME: id #P.y!getter.1 : (Self) -> () -> String, // CHECK-SAME: getter @_T08keypaths1PP1ySSvpAaBRzlxTK : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in τ_0_0) -> @out String, // CHECK-SAME: setter @_T08keypaths1PP1ySSvpAaBRzlxTk : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in String, @inout τ_0_0) -> () // CHECK-SAME: ) _ = \T.y // CHECK: keypath $KeyPath, <τ_0_0 where τ_0_0 : P> ( // CHECK-SAME: root $τ_0_0; // CHECK-SAME: gettable_property $String, // CHECK-SAME: id @_T08keypaths1PPAAE1zSSvg _ = \T.z } struct Concrete: P { var x: Int var y: String } // CHECK-LABEL: sil hidden @_T08keypaths35keyPathsWithSpecificGenericInstanceyyF func keyPathsWithSpecificGenericInstance() { // CHECK: keypath $KeyPath, ( // CHECK-SAME: gettable_property $String, // CHECK-SAME: id @_T08keypaths1PPAAE1zSSvg // CHECK-SAME: getter @_T08keypaths1PPAAE1zSSvpAA8ConcreteVTK : $@convention(thin) (@in Concrete) -> @out String _ = \Concrete.z _ = \S.computed } class AA { var a: Int { get { return 0 } set { } } } class BB: AA { } func keyPathForInheritedMember() { _ = \BB.a } func keyPathForExistentialMember() { _ = \P.x _ = \P.y _ = \P.z _ = \P.w } struct OptionalFields { var x: S? } struct OptionalFields2 { var y: OptionalFields? } // CHECK-LABEL: sil hidden @_T08keypaths18keyPathForOptionalyyF func keyPathForOptional() { // CHECK: keypath $WritableKeyPath>, ( // CHECK-SAME: stored_property #OptionalFields.x : $Optional>; // CHECK-SAME: optional_force : $S) _ = \OptionalFields.x! // CHECK: keypath $KeyPath>, ( // CHECK-SAME: stored_property #OptionalFields.x : $Optional>; // CHECK-SAME: optional_chain : $S; // CHECK-SAME: stored_property #S.y : $String; // CHECK-SAME: optional_wrap : $Optional) _ = \OptionalFields.x?.y // CHECK: keypath $KeyPath>>, ( // CHECK-SAME: root $OptionalFields2; // CHECK-SAME: stored_property #OptionalFields2.y : $Optional; // CHECK-SAME: optional_chain : $OptionalFields; // CHECK-SAME: stored_property #OptionalFields.x : $Optional>) _ = \OptionalFields2.y?.x } class StorageQualified { weak var tooWeak: StorageQualified? unowned var disowned: StorageQualified init() { fatalError() } } final class FinalStorageQualified { weak var tooWeak: StorageQualified? unowned var disowned: StorageQualified init() { fatalError() } } // CHECK-LABEL: sil hidden @{{.*}}keyPathForStorageQualified func keyPathForStorageQualified() { // CHECK: = keypath $ReferenceWritableKeyPath>, // CHECK-SAME: settable_property $Optional, id #StorageQualified.tooWeak!getter.1 _ = \StorageQualified.tooWeak // CHECK: = keypath $ReferenceWritableKeyPath, // CHECK-SAME: settable_property $StorageQualified, id #StorageQualified.disowned!getter.1 _ = \StorageQualified.disowned // CHECK: = keypath $ReferenceWritableKeyPath>, // CHECK-SAME: settable_property $Optional, id ##FinalStorageQualified.tooWeak _ = \FinalStorageQualified.tooWeak // CHECK: = keypath $ReferenceWritableKeyPath, // CHECK-SAME: settable_property $StorageQualified, id ##FinalStorageQualified.disowned _ = \FinalStorageQualified.disowned } struct IUOProperty { var iuo: IUOBlob! } struct IUOBlob { var x: Int subscript(y: String) -> String { get { return y } set {} } } // CHECK-LABEL: sil hidden @{{.*}}11iuoKeyPaths func iuoKeyPaths() { // CHECK: = keypath $WritableKeyPath, // CHECK-SAME: stored_property #IUOProperty.iuo // CHECK-SAME: optional_force // CHECK-SAME: stored_property #IUOBlob.x _ = \IUOProperty.iuo.x // CHECK: = keypath $WritableKeyPath, // CHECK-SAME: stored_property #IUOProperty.iuo // CHECK-SAME: optional_force // CHECK-SAME: stored_property #IUOBlob.x _ = \IUOProperty.iuo!.x } class Bass: Hashable { static func ==(_: Bass, _: Bass) -> Bool { return false } var hashValue: Int { return 0 } } class Treble: Bass { } struct Subscripts { subscript() -> T { get { fatalError() } set { fatalError() } } subscript(generic x: T) -> T { get { fatalError() } set { fatalError() } } subscript(concrete x: String) -> String { get { fatalError() } set { fatalError() } } subscript(x: String, y: String) -> String { get { fatalError() } set { fatalError() } } subscript(subGeneric z: U) -> U { get { fatalError() } set { fatalError() } } subscript(mutable x: T) -> T { get { fatalError() } set { fatalError() } } subscript(bass: Bass) -> Bass { get { return bass } set { } } } // CHECK-LABEL: sil hidden @{{.*}}10subscripts func subscripts(x: T, y: U, s: String) { _ = \Subscripts.[] _ = \Subscripts.[generic: x] _ = \Subscripts.[concrete: s] _ = \Subscripts.[s, s] _ = \Subscripts.[subGeneric: s] _ = \Subscripts.[subGeneric: x] _ = \Subscripts.[subGeneric: y] _ = \Subscripts.[] _ = \Subscripts.[generic: y] _ = \Subscripts.[concrete: s] _ = \Subscripts.[s, s] _ = \Subscripts.[subGeneric: s] _ = \Subscripts.[subGeneric: x] _ = \Subscripts.[subGeneric: y] _ = \Subscripts.[] _ = \Subscripts.[generic: s] _ = \Subscripts.[concrete: s] _ = \Subscripts.[s, s] _ = \Subscripts.[subGeneric: s] _ = \Subscripts.[subGeneric: x] _ = \Subscripts.[subGeneric: y] _ = \Subscripts.[s, s].count _ = \Subscripts.[Bass()] _ = \Subscripts.[Treble()] }