// RUN: %target-sil-opt %s | %target-sil-opt | %FileCheck %s sil_stage canonical import Swift struct S: Hashable { var x: Int let y: String var z: C func hash(into hasher: inout Hasher) static func ==(x: S, y: S) -> Bool } class C: Hashable { final var x: Int final let y: String final var z: S init() var overridable: Int { get set } func hash(into hasher: inout Hasher) static func ==(x: C, y: C) -> Bool } protocol P {} protocol Q {} protocol R {} struct Gen { var x: A let y: B var z: C } public struct External { var ro: T subscript(ro _: U) -> T { get } } struct T { var x: (Int, Int) var y: (a: Int, b: Int, c: Int) let z: (Int, Int) let w: (Int, C) } // CHECK-LABEL: sil shared @stored_properties sil shared @stored_properties : $@convention(thin) () -> () { entry: // CHECK: keypath $WritableKeyPath, (root $S; stored_property #S.x : $Int) %a = keypath $WritableKeyPath, (root $S; stored_property #S.x : $Int) // CHECK: keypath $ReferenceWritableKeyPath, (root $C; stored_property #C.x : $Int) %b = keypath $ReferenceWritableKeyPath, (root $C; stored_property #C.x : $Int) // CHECK: keypath $KeyPath, (root $S; stored_property #S.y : $String) %c = keypath $KeyPath, (root $S; stored_property #S.y : $String) // CHECK: keypath $ReferenceWritableKeyPath, (root $S; stored_property #S.z : $C; stored_property #C.x : $Int) %d = keypath $ReferenceWritableKeyPath, (root $S; stored_property #S.z : $C; stored_property #C.x : $Int) return undef : $() } // CHECK-LABEL: sil shared @stored_properties_generic sil shared @stored_properties_generic : $@convention(thin) () -> () { entry: // CHECK: keypath $WritableKeyPath, D>, <τ_0_0, τ_0_1, τ_0_2 where {{.*}}> (root $Gen<τ_0_0, τ_0_1, τ_0_2>; stored_property #Gen.x : $τ_0_0) %a = keypath $WritableKeyPath, D>, (root $Gen; stored_property #Gen.x : $G) // CHECK: keypath $KeyPath, E>, <τ_0_0, τ_0_1, τ_0_2 where {{.*}}> (root $Gen<τ_0_0, τ_0_1, τ_0_2>; stored_property #Gen.y : $τ_0_1) %b = keypath $KeyPath, E>, (root $Gen; stored_property #Gen.y : $H) return undef : $() } // CHECK-LABEL: sil shared @tuple_elements sil shared @tuple_elements : $@convention(thin) () -> () { entry: // CHECK: keypath $WritableKeyPath, (root $T; stored_property #T.x : $(Int, Int); tuple_element #0 : $Int) %a = keypath $WritableKeyPath, (root $T; stored_property #T.x : $(Int, Int); tuple_element #0 : $Int) // CHECK: keypath $WritableKeyPath, (root $T; stored_property #T.y : $(a: Int, b: Int, c: Int); tuple_element #2 : $Int) %b = keypath $WritableKeyPath, (root $T; stored_property #T.y : $(a: Int, b: Int, c: Int); tuple_element #2 : $Int) // CHECK: keypath $KeyPath, (root $T; stored_property #T.z : $(Int, Int); tuple_element #1 : $Int) %c = keypath $KeyPath, (root $T; stored_property #T.z : $(Int, Int); tuple_element #1 : $Int) // CHECK: keypath $ReferenceWritableKeyPath, (root $T; stored_property #T.w : $(Int, C); tuple_element #1 : $C) %d = keypath $ReferenceWritableKeyPath, (root $T; stored_property #T.w : $(Int, C); tuple_element #1 : $C) return undef : $() } sil @id_a : $@convention(thin) () -> () sil @get_s_int : $@convention(keypath_accessor_getter) (@in_guaranteed S) -> @out Int sil @set_s_int : $@convention(keypath_accessor_setter) (@in_guaranteed Int, @in_guaranteed S) -> () sil @get_c_int : $@convention(keypath_accessor_getter) (@in_guaranteed C) -> @out Int sil @set_c_int : $@convention(keypath_accessor_setter) (@in_guaranteed Int, @in_guaranteed C) -> () sil @get_fns_fnc : $@convention(keypath_accessor_getter) (@in_guaranteed @callee_guaranteed @substituted (@in_guaranteed A) -> @out B for ) -> @out @callee_guaranteed @substituted (@in_guaranteed A) -> @out B for sil @set_fns_fnc : $@convention(keypath_accessor_setter) (@in_guaranteed @callee_guaranteed @substituted (@in_guaranteed A) -> @out B for , @in_guaranteed @callee_guaranteed @substituted (@in_guaranteed A) -> @out B for ) -> () sil @get_s_int_subs : $@convention(keypath_accessor_getter) (@in_guaranteed S, @in_guaranteed (S, C)) -> @out Int sil @set_s_int_subs : $@convention(keypath_accessor_setter) (@in_guaranteed Int, @in_guaranteed S, @in_guaranteed (S, C)) -> () sil @subs_eq : $@convention(keypath_accessor_equals) (@in_guaranteed (S, C), @in_guaranteed (S, C)) -> Bool sil @subs_hash : $@convention(keypath_accessor_hash) (@in_guaranteed (S, C)) -> Int sil @get_gen_int_subs : $@convention(keypath_accessor_getter) (@in_guaranteed A, @in_guaranteed (S, C)) -> @out C sil @set_gen_int_subs : $@convention(keypath_accessor_setter) (@in_guaranteed C, @in_guaranteed A, @in_guaranteed (S, C)) -> () sil @gen_subs_eq : $@convention(keypath_accessor_equals) (@in_guaranteed (S, C), @in_guaranteed (S, C)) -> Bool sil @gen_subs_hash : $@convention(keypath_accessor_hash) (@in_guaranteed (S, C)) -> Int // CHECK-LABEL: sil shared @computed_properties sil shared @computed_properties : $@convention(thin) () -> () { entry: // CHECK: keypath $KeyPath, (root $S; gettable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int : $@convention(keypath_accessor_getter) (@in_guaranteed S) -> @out Int) %a = keypath $KeyPath, (root $S; gettable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int : $@convention(keypath_accessor_getter) (@in_guaranteed S) -> @out Int) // CHECK: keypath $WritableKeyPath, (root $S; settable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int : $@convention(keypath_accessor_getter) (@in_guaranteed S) -> @out Int, setter @set_s_int : $@convention(keypath_accessor_setter) (@in_guaranteed Int, @in_guaranteed S) -> ()) %b = keypath $WritableKeyPath, (root $S; settable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int : $@convention(keypath_accessor_getter) (@in_guaranteed S) -> @out Int, setter @set_s_int : $@convention(keypath_accessor_setter) (@in_guaranteed Int, @in_guaranteed S) -> ()) // CHECK: keypath $WritableKeyPath<(S) -> S, (C) -> C>, (root $(S) -> S; settable_property $(C) -> C, id @id_a : $@convention(thin) () -> (), getter @get_fns_fnc : $@convention(keypath_accessor_getter) (@in_guaranteed @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> @out @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for , setter @set_fns_fnc : $@convention(keypath_accessor_setter) (@in_guaranteed @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for , @in_guaranteed @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> ()) %c = keypath $WritableKeyPath<(S) -> S, (C) -> C>, ( root $(S) -> S; settable_property $(C) -> C, id @id_a : $@convention(thin) () -> (), getter @get_fns_fnc : $@convention(keypath_accessor_getter) (@in_guaranteed @callee_guaranteed @substituted (@in_guaranteed A) -> @out B for ) -> @out @callee_guaranteed @substituted (@in_guaranteed A) -> @out B for , setter @set_fns_fnc : $@convention(keypath_accessor_setter) (@in_guaranteed @callee_guaranteed @substituted (@in_guaranteed A) -> @out B for , @in_guaranteed @callee_guaranteed @substituted (@in_guaranteed A) -> @out B for ) -> ()) // CHECK: keypath $WritableKeyPath, (root $C; settable_property $Int, id #C.overridable!getter : (C) -> () -> Int, getter @get_c_int : $@convention(keypath_accessor_getter) (@in_guaranteed C) -> @out Int, setter @set_c_int : $@convention(keypath_accessor_setter) (@in_guaranteed Int, @in_guaranteed C) -> ()) %d = keypath $WritableKeyPath, (root $C; settable_property $Int, id #C.overridable!getter : (C) -> () -> Int, getter @get_c_int : $@convention(keypath_accessor_getter) (@in_guaranteed C) -> @out Int, setter @set_c_int : $@convention(keypath_accessor_setter) (@in_guaranteed Int, @in_guaranteed C) -> ()) return undef : $() } sil @get_gen_a : $@convention(keypath_accessor_getter) (@in_guaranteed Gen) -> @out X1 sil @set_gen_a : $@convention(keypath_accessor_setter) (@in_guaranteed X2, @in_guaranteed Gen) -> () // CHECK-LABEL: sil shared @computed_properties_generic sil shared @computed_properties_generic : $@convention(thin) () -> () { entry: // CHECK: keypath $KeyPath, D>, <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : P, τ_0_1 : Q, τ_0_2 : R> (root $Gen<τ_0_0, τ_0_1, τ_0_2>; settable_property $τ_0_0, id @id_a : $@convention(thin) () -> (), getter @get_gen_a : $@convention(keypath_accessor_getter) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : P, τ_0_1 : Q, τ_0_2 : R> (@in_guaranteed Gen<τ_0_0, τ_0_1, τ_0_2>) -> @out τ_0_0, setter @set_gen_a : $@convention(keypath_accessor_setter) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : P, τ_0_1 : Q, τ_0_2 : R> (@in_guaranteed τ_0_0, @in_guaranteed Gen<τ_0_0, τ_0_1, τ_0_2>) -> ()) %a = keypath $KeyPath, D>, (root $Gen; settable_property $G, id @id_a : $@convention(thin) () -> (), getter @get_gen_a : $@convention(keypath_accessor_getter) (@in_guaranteed Gen) -> @out X3, setter @set_gen_a : $@convention(keypath_accessor_setter) (@in_guaranteed X4, @in_guaranteed Gen) -> ()) return undef : $() } // CHECK-LABEL: sil shared @tuple_generic sil shared @ tuple_generic : $@convention(thin) () -> () { entry: // CHECK: keypath $WritableKeyPath<(T, U), T>, <τ_0_0, τ_0_1> (root $(τ_0_0, τ_0_1); tuple_element #0 : $τ_0_0) %a = keypath $WritableKeyPath<(T, U), T>, <τ_0_0, τ_0_1> (root $(τ_0_0, τ_0_1); tuple_element #0 : $τ_0_0) // CHECK: keypath $WritableKeyPath<(T, U), U>, <τ_0_0, τ_0_1> (root $(τ_0_0, τ_0_1); tuple_element #1 : $τ_0_1) %b = keypath $WritableKeyPath<(T, U), U>, <τ_0_0, τ_0_1> (root $(τ_0_0, τ_0_1); tuple_element #1 : $τ_0_1) return undef : $() } // CHECK-LABEL: sil @optional sil @optional : $@convention(thin) () -> () { entry: // CHECK: keypath $KeyPath, Optional>, (root $Optional; optional_chain : $Int; optional_wrap : $Optional) %a = keypath $KeyPath, Optional>, (root $Optional; optional_chain : $Int; optional_wrap : $Optional) // CHECK: keypath $KeyPath, Int>, (root $Optional; optional_force : $Int) %b = keypath $KeyPath, Int>, (root $Optional; optional_force : $Int) return undef : $() } // CHECK-LABEL: sil @indexes sil @indexes : $@convention(thin) (S, C) -> () { // CHECK: bb0([[S:%.*]] : $S, [[C:%.*]] : $C): entry(%s : $S, %c : $C): // CHECK: keypath $KeyPath, (root $S; settable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int_subs : $@convention(keypath_accessor_getter) (@in_guaranteed S, @in_guaranteed (S, C)) -> @out Int, setter @set_s_int_subs : $@convention(keypath_accessor_setter) (@in_guaranteed Int, @in_guaranteed S, @in_guaranteed (S, C)) -> (), indices [%$0 : $S : $S, %$1 : $C : $C], indices_equals @subs_eq : $@convention(keypath_accessor_equals) (@in_guaranteed (S, C), @in_guaranteed (S, C)) -> Bool, indices_hash @subs_hash : $@convention(keypath_accessor_hash) (@in_guaranteed (S, C)) -> Int) ([[S]], [[C]]) %a = keypath $KeyPath, (root $S; settable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int_subs : $@convention(keypath_accessor_getter) (@in_guaranteed S, @in_guaranteed (S, C)) -> @out Int, setter @set_s_int_subs : $@convention(keypath_accessor_setter) (@in_guaranteed Int, @in_guaranteed S, @in_guaranteed (S, C)) -> (), indices [%$0 : $S : $S, %$1 : $C : $C], indices_equals @subs_eq : $@convention(keypath_accessor_equals) (@in_guaranteed (S, C), @in_guaranteed (S, C)) -> Bool, indices_hash @subs_hash : $@convention(keypath_accessor_hash) (@in_guaranteed (S, C)) -> Int) (%s, %c) // CHECK: [[T:%.*]] = alloc_stack %t = alloc_stack $S // CHECK: [[D:%.*]] = alloc_stack %d = alloc_stack $C // CHECK: keypath $KeyPath, <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : Hashable, τ_0_1 : Hashable, τ_0_2 : Hashable> (root $τ_0_0; settable_property $τ_0_2, id @id_a : $@convention(thin) () -> (), getter @get_gen_int_subs : $@convention(keypath_accessor_getter) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : Hashable, τ_0_1 : Hashable, τ_0_2 : Hashable> (@in_guaranteed τ_0_0, @in_guaranteed (S, τ_0_2)) -> @out τ_0_2, setter @set_gen_int_subs : $@convention(keypath_accessor_setter) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : Hashable, τ_0_1 : Hashable, τ_0_2 : Hashable> (@in_guaranteed τ_0_2, @in_guaranteed τ_0_0, @in_guaranteed (S, τ_0_2)) -> (), indices [%$0 : $τ_0_0 : $*τ_0_0, %$1 : $τ_0_1 : $*τ_0_1], indices_equals @gen_subs_eq : $@convention(keypath_accessor_equals) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : Hashable, τ_0_1 : Hashable, τ_0_2 : Hashable> (@in_guaranteed (S, τ_0_2), @in_guaranteed (S, τ_0_2)) -> Bool, indices_hash @gen_subs_hash : $@convention(keypath_accessor_hash) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : Hashable, τ_0_1 : Hashable, τ_0_2 : Hashable> (@in_guaranteed (S, τ_0_2)) -> Int) ([[T]], [[D]]) %b = keypath $KeyPath, <τ_0_0: Hashable, Y: Hashable, Z: Hashable> (root $τ_0_0; settable_property $Z, id @id_a : $@convention(thin) () -> (), getter @get_gen_int_subs : $@convention(keypath_accessor_getter) (@in_guaranteed A, @in_guaranteed (S, C)) -> @out C, setter @set_gen_int_subs : $@convention(keypath_accessor_setter) (@in_guaranteed C, @in_guaranteed A, @in_guaranteed (S, C)) -> (), indices [%$0 : $τ_0_0 : $*τ_0_0, %$1 : $Y : $*Y], indices_equals @gen_subs_eq : $@convention(keypath_accessor_equals) (@in_guaranteed (S, C), @in_guaranteed (S, C)) -> Bool, indices_hash @gen_subs_hash : $@convention(keypath_accessor_hash) (@in_guaranteed (S, C)) -> Int) (%t, %d) dealloc_stack %d : $*C dealloc_stack %t : $*S return undef : $() } // CHECK-LABEL: sil @external sil @external : $@convention(thin) () -> () { entry: // CHECK: keypath $KeyPath, D>, <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : P, τ_0_1 : Q, τ_0_2 : R> (root $Gen<τ_0_0, τ_0_1, τ_0_2>; settable_property $τ_0_0, id @id_a : $@convention(thin) () -> (), getter @get_gen_a : $@convention(keypath_accessor_getter) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : P, τ_0_1 : Q, τ_0_2 : R> (@in_guaranteed Gen<τ_0_0, τ_0_1, τ_0_2>) -> @out τ_0_0, setter @set_gen_a : $@convention(keypath_accessor_setter) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : P, τ_0_1 : Q, τ_0_2 : R> (@in_guaranteed τ_0_0, @in_guaranteed Gen<τ_0_0, τ_0_1, τ_0_2>) -> (), external #Gen.x<τ_0_0, τ_0_1, τ_0_2>) %a = keypath $KeyPath, D>, (root $Gen; settable_property $G, id @id_a : $@convention(thin) () -> (), getter @get_gen_a : $@convention(keypath_accessor_getter) (@in_guaranteed Gen) -> @out X3, setter @set_gen_a : $@convention(keypath_accessor_setter) (@in_guaranteed X4, @in_guaranteed Gen) -> (), external #Gen.x) return undef : $() } sil @get_external_subscript : $@convention(keypath_accessor_getter) (@in_guaranteed External, @in_guaranteed U) -> @out T sil @equals_external_subscript : $@convention(keypath_accessor_equals) (@in_guaranteed U, @in_guaranteed U) -> Bool sil @hash_external_subscript : $@convention(keypath_accessor_hash) (@in_guaranteed U) -> Int // CHECK-LABEL: sil_property #External.ro<τ_0_0> (stored_property #External.ro : $τ_0_0) sil_property #External.ro (stored_property #External.ro : $T) // CHECK-LABEL: sil_property #External.subscript<τ_0_0><τ_1_0 where τ_1_0 : Hashable> (gettable_property $τ_0_0, // CHECK-SAME: id @id_a : $@convention(thin) () -> (), // CHECK-SAME: getter @get_external_subscript : $@convention(keypath_accessor_getter) <τ_0_0, τ_0_1 where τ_0_1 : Hashable> (@in_guaranteed External<τ_0_0>, @in_guaranteed τ_0_1) -> @out τ_0_0 sil_property #External.subscript (gettable_property $T, id @id_a : $@convention(thin) () -> (), getter @get_external_subscript : $@convention(keypath_accessor_getter) (@in_guaranteed External, @in_guaranteed U) -> @out T)