1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
|
// RUN: %target-swift-emit-silgen -disable-availability-checking %s | %FileCheck %s
func takeEscapingFunction<each Input, Output>(function: @escaping ((repeat each Input)) -> Output) {}
func returnFunction<each Input, Output>(args: (repeat each Input).Type, result: Output.Type) -> (_: (repeat each Input)) -> Output {}
// Issue #69028: Vanishing tuple in a reabstraction into a more abstract context
func catFact(num: Int) -> String { "there are more than 10 cats" }
func test0() {
takeEscapingFunction(function: catFact)
}
// CHECK-LABEL: sil hidden [ossa] @$s4main5test0yyF :
// CHECK: [[THUNK:%.*]] = function_ref @$sSiSSIegyo_Si_QSiSSIegpr_TR : $@convention(thin) (@pack_guaranteed Pack{Int}, @guaranteed @callee_guaranteed (Int) -> @owned String) -> @out String
// CHECK-NEXT: partial_apply [callee_guaranteed] [[THUNK]]
// CHECK-LABEL: sil shared {{.*}} @$sSiSSIegyo_Si_QSiSSIegpr_TR : $@convention(thin) (@pack_guaranteed Pack{Int}, @guaranteed @callee_guaranteed (Int) -> @owned String) -> @out String {
// CHECK: bb0(%0 : $*String, %1 : $*Pack{Int}, %2 : @guaranteed $@callee_guaranteed (Int) -> @owned String):
// CHECK-NEXT: [[INDEX:%.*]] = scalar_pack_index 0 of $Pack{Int}
// CHECK-NEXT: [[ARG_ADDR:%.*]] = pack_element_get [[INDEX]] of %1 : $*Pack{Int} as $*Int
// CHECK-NEXT: [[ARG:%.*]] = load [trivial] [[ARG_ADDR]] : $*Int
// CHECK-NEXT: [[RESULT:%.*]] = apply %2([[ARG]]) : $@callee_guaranteed (Int) -> @owned String
// CHECK-NEXT: store [[RESULT]] to [init] %0 : $*String
// CHECK-NEXT: [[RESULT:%.*]] = tuple ()
// CHECK-NEXT: return [[RESULT]] : $()
// CHECK-NEXT: }
// Vanishing tuple in a reabstraction out of a more abstract context
func test1() {
_ = returnFunction(args: String.self, result: [String].self)
}
// CHECK-LABEL: sil hidden [ossa] @$s4main5test1yyF :
// CHECK: [[THUNK:%.*]] = function_ref @$sSS_QSiSaySSGIegpr_SSAAIeggo_TR : $@convention(thin) (@guaranteed String, @guaranteed @callee_guaranteed (@pack_guaranteed Pack{String}) -> @out Array<String>) -> @owned Array<String>
// CHECK-NEXT: partial_apply [callee_guaranteed] [[THUNK]]
// CHECK-LABEL: sil shared {{.*}} @$sSS_QSiSaySSGIegpr_SSAAIeggo_TR : $@convention(thin) (@guaranteed String, @guaranteed @callee_guaranteed (@pack_guaranteed Pack{String}) -> @out Array<String>) -> @owned Array<String> {
// CHECK: bb0(%0 : @guaranteed $String, %1 : @guaranteed $@callee_guaranteed (@pack_guaranteed Pack{String}) -> @out Array<String>):
// CHECK-NEXT: [[PACK:%.*]] = alloc_pack $Pack{String}
// CHECK-NEXT: [[ARG_TEMP:%.*]] = alloc_stack $String
// It'd be nice to avoid this unnecessary copy.
// CHECK-NEXT: [[ARG_TEMP_BORROW:%.*]] = store_borrow %0 to [[ARG_TEMP]]
// CHECK-NEXT: [[INDEX:%.*]] = scalar_pack_index 0 of $Pack{String}
// CHECK-NEXT: pack_element_set [[ARG_TEMP_BORROW]] : $*String into [[INDEX]] of [[PACK]] : $*Pack{String}
// CHECK-NEXT: [[RESULT_TEMP:%.*]] = alloc_stack $Array<String>
// CHECK-NEXT: apply %1([[RESULT_TEMP]], [[PACK]]) : $@callee_guaranteed (@pack_guaranteed Pack{String}) -> @out Array<String>
// CHECK-NEXT: [[RESULT:%.*]] = load [take] [[RESULT_TEMP]] : $*Array<String>
// CHECK-NEXT: dealloc_stack [[RESULT_TEMP]] : $*Array<String>
// CHECK-NEXT: end_borrow [[ARG_TEMP_BORROW]]
// CHECK-NEXT: dealloc_stack [[ARG_TEMP]] : $*String
// CHECK-NEXT: dealloc_pack [[PACK]] : $*Pack{String}
// CHECK-NEXT: return [[RESULT]] : $Array<String>
// CHECK-NEXT: }
// A non-vanishing tuple in a reabstraction into a more abstract context
func lionFact(label: (String, Int)) -> String { "all lions are cats" }
func test2() {
takeEscapingFunction(function: lionFact)
}
// CHECK-LABEL: sil hidden [ossa] @$s4main5test2yyF :
// CHECK: [[THUNK:%.*]] = function_ref @$sSSSiSSIeggyo_SS_SiQSiSSIegpr_TR : $@convention(thin) (@pack_guaranteed Pack{String, Int}, @guaranteed @callee_guaranteed (@guaranteed String, Int) -> @owned String) -> @out String
// CHECK-NEXT: partial_apply [callee_guaranteed] [[THUNK]]
// CHECK-LABEL: sil shared {{.*}} @$sSSSiSSIeggyo_SS_SiQSiSSIegpr_TR : $@convention(thin) (@pack_guaranteed Pack{String, Int}, @guaranteed @callee_guaranteed (@guaranteed String, Int) -> @owned String) -> @out String {
// CHECK: bb0(%0 : $*String, %1 : $*Pack{String, Int}, %2 : @guaranteed $@callee_guaranteed (@guaranteed String, Int) -> @owned String):
// CHECK-NEXT: [[ARG0_INDEX:%.*]] = scalar_pack_index 0 of $Pack{String, Int}
// CHECK-NEXT: [[ARG0_ADDR:%.*]] = pack_element_get [[ARG0_INDEX]] of %1 : $*Pack{String, Int} as $*String
// CHECK-NEXT: [[ARG0:%.*]] = load_borrow [[ARG0_ADDR]] : $*String
// CHECK-NEXT: [[ARG1_INDEX:%.*]] = scalar_pack_index 1 of $Pack{String, Int}
// CHECK-NEXT: [[ARG1_ADDR:%.*]] = pack_element_get [[ARG1_INDEX]] of %1 : $*Pack{String, Int} as $*Int
// CHECK-NEXT: [[ARG1:%.*]] = load [trivial] [[ARG1_ADDR]] : $*Int
// CHECK-NEXT: [[RESULT:%.*]] = apply %2([[ARG0]], [[ARG1]]) : $@callee_guaranteed (@guaranteed String, Int) -> @owned String
// CHECK-NEXT: store [[RESULT]] to [init] %0 : $*String
// CHECK-NEXT: [[RESULT:%.*]] = tuple ()
// CHECK-NEXT: end_borrow [[ARG0]] : $String
// CHECK-NEXT: return [[RESULT]] : $()
// CHECK-NEXT: }
struct Args<each T> {
static func take(function: @escaping (_: (repeat each T)) -> ()) {}
}
#if false
// For some reason, this doesn't type-check
func test3(function: @escaping (_: (Int, String)?) -> ()) {
Args<Int, String>.take(function: function)
}
#endif
func test4<each T>(function: @escaping (_: Any) -> (), type: (repeat each T).Type) {
Args<repeat each T>.take(function: function)
}
// CHECK-LABEL: sil hidden [ossa] @$s4main5test48function4typeyyypc_xxQp_tmtRvzlF :
// CHECK: [[THUNK:%.*]] = function_ref @$sypIegn_xxQp_QSiIegp_RvzlTR : $@convention(thin) <each τ_0_0> (@pack_guaranteed Pack{repeat each τ_0_0}, @guaranteed @callee_guaranteed (@in_guaranteed Any) -> ()) -> ()
// CHECK-NEXT: partial_apply [callee_guaranteed] [[THUNK]]
// CHECK-LABEL: sil shared {{.*}} @$sypIegn_xxQp_QSiIegp_RvzlTR : $@convention(thin) <each T> (@pack_guaranteed Pack{repeat each T}, @guaranteed @callee_guaranteed (@in_guaranteed Any) -> ()) -> () {
// CHECK: bb0(%0 : $*Pack{repeat each T}, %1 : @guaranteed $@callee_guaranteed (@in_guaranteed Any) -> ()):
// - Set up for emitting into a temporary Any object.
// CHECK-NEXT: [[ANY_TEMP:%.*]] = alloc_stack $Any
// CHECK-NEXT: [[PAYLOAD_ADDR:%.*]] = init_existential_addr [[ANY_TEMP]] : $*Any, $(repeat each T)
// - Loop over the pack and copy the elements into the Any.
// CHECK-NEXT: [[ZERO:%.*]] = integer_literal $Builtin.Word, 0
// CHECK-NEXT: [[ONE:%.*]] = integer_literal $Builtin.Word, 1
// CHECK-NEXT: [[LEN:%.*]] = pack_length $Pack{repeat each T}
// CHECK-NEXT: br bb1([[ZERO]] : $Builtin.Word)
// CHECK: bb1([[IDX:%.*]] : $Builtin.Word)
// CHECK-NEXT: [[IDX_EQ_LEN:%.*]] = builtin "cmp_eq_Word"([[IDX]] : $Builtin.Word, [[LEN]] : $Builtin.Word) : $Builtin.Int1
// CHECK-NEXT: cond_br [[IDX_EQ_LEN]], bb3, bb2
// CHECK: bb2:
// CHECK-NEXT: [[EXPANSION_INDEX:%.*]] = dynamic_pack_index [[IDX]] of $Pack{repeat each T}
// CHECK-NEXT: open_pack_element [[EXPANSION_INDEX]] of <each T> at <Pack{repeat each T}>, shape $each T, uuid [[UUID:".*"]]
// CHECK-NEXT: [[SRC_ELT_ADDR:%.*]] = pack_element_get [[EXPANSION_INDEX]] of %0 : $*Pack{repeat each T} as $*@pack_element([[UUID]]) each T
// CHECK-NEXT: [[DEST_ELT_ADDR:%.*]] = tuple_pack_element_addr [[EXPANSION_INDEX]] of [[PAYLOAD_ADDR]] : $*(repeat each T) as $*@pack_element([[UUID]]) each T
// CHECK-NEXT: copy_addr [[SRC_ELT_ADDR]] to [init] [[DEST_ELT_ADDR]] : $*@pack_element([[UUID]]) each T
// CHECK-NEXT: [[NEXT_IDX:%.*]] = builtin "add_Word"([[IDX]] : $Builtin.Word, [[ONE]] : $Builtin.Word) : $Builtin.Word
// CHECK-NEXT: br bb1([[NEXT_IDX]] : $Builtin.Word)
// CHECK: bb3:
// - Call the thunked function.
// CHECK-NEXT: apply %1([[ANY_TEMP]])
// - Epilogue.
// CHECK-NEXT: [[VOID:%.*]] = tuple ()
// CHECK-NEXT: destroy_addr [[ANY_TEMP]] : $*Any
// CHECK-NEXT: dealloc_stack [[ANY_TEMP]] : $*Any
// CHECK-NEXT: return [[VOID]] : $()
|