mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
- Calls to variadic-generic protocol requirements weren't applying substitutions properly, so expansion-sensitive types in the callee signature weren't pairing properly with their expansions in the caller. - emitPackTransform had an over-destroy if the transformation function actually emitted into the temporary element directly. - There were some MV ownership assertions that were wrong, which revealed that the corresponding code really didn't handle consuming/ borrowing mismatches properly at all. - We were completely mishandled consuming packs. Fixes #81002, #80995, and #81600.
246 lines
14 KiB
Swift
246 lines
14 KiB
Swift
// RUN: %target-swift-emit-silgen -target %target-swift-5.9-abi-triple -module-name test %s | %FileCheck %s
|
|
|
|
// A trivial generic type.
|
|
struct EmptyGeneric<T> {}
|
|
|
|
// A non-trivial generic type.
|
|
struct NonTrivialGeneric<T> {
|
|
var label: String
|
|
}
|
|
|
|
public protocol PackProvider<Pack> {
|
|
associatedtype Pack
|
|
|
|
func withFunction<each A>(_ encode: (repeat each A) -> Void)
|
|
where Pack == (repeat each A)
|
|
}
|
|
|
|
// #81002. Make sure we apply substitutions to the abstraction pattern when
|
|
// calling a protocol requirement with variadic generic arguments,
|
|
// because we may need them when propagating patterns down to expressions
|
|
// that are sensitive to variadic expansion --- in this case, the
|
|
// argument list of the closure.
|
|
//
|
|
// The `where` clause on the protocol requirement above isn't strictly
|
|
// necessary; we'd just need some other way to constrain the pack while
|
|
// also having a closure like this.
|
|
func testClosure<E: PackProvider<(String, Int)>>(provider: E) {
|
|
// Just check that we emitted the closure with a pack argument, which
|
|
// implies that we've done substitution into the AP and aligned the
|
|
// types properly.
|
|
// CHECK-LABEL: sil private [ossa] @$s4test0A7Closure8provideryx_tAA12PackProviderRzSS_Sit0D0RtzlFySS_SitXEfU_ : $@convention(thin) @substituted <each τ_0_0> (@pack_guaranteed Pack{repeat each τ_0_0}) -> () for <Pack{String, Int}>
|
|
provider.withFunction { (first, second) in }
|
|
}
|
|
|
|
// #80995. An assertion in reabstraction (in this case, the implicit
|
|
// reabstraction of a protocol conformance thunk) when forwarding an
|
|
// indirect tuple parameter to an expanded tuple parameter.
|
|
public protocol Schema<Value>: Sendable {
|
|
associatedtype Value
|
|
|
|
func encode(_ value: Value, to encoder: Encoder<Self>) throws
|
|
}
|
|
|
|
public struct Encoder<Schema> {}
|
|
|
|
private struct TupleSchema<each ElementSchema: Schema>: Schema {
|
|
typealias Value = (repeat (each ElementSchema).Value)
|
|
|
|
func encode(_ value: Value, to encoder: Encoder<Self>) throws {}
|
|
}
|
|
|
|
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s4test11TupleSchema33_6C2FE3D25D7EB8B34759FC7B1028DF25LLVyxxQp_QPGAA0C0A2aFP6encode_2toy5ValueQz_AA7EncoderVyxGtKFTW :
|
|
// CHECK-SAME: $@convention(witness_method: Schema) <each τ_0_0 where repeat each τ_0_0 : Schema> (@in_guaranteed (repeat (each τ_0_0).Value), Encoder<TupleSchema<repeat each τ_0_0>>, @in_guaranteed TupleSchema<repeat each τ_0_0>) -> @error any Error
|
|
|
|
// The thunk receives a tuple indirectly, but the witness receives a pack of
|
|
// elements, so we have to initialize a pack with the tuple elements.
|
|
// CHECK: bb0(%0 : $*(repeat (each τ_0_0).Value), %1 : $Encoder<TupleSchema<repeat each τ_0_0>>, %2 : $*TupleSchema<repeat each τ_0_0>):
|
|
// CHECK-NEXT: [[PACK:%.*]] = alloc_pack $Pack{repeat (each τ_0_0).Value}
|
|
// CHECK-NEXT: [[ZERO:%.*]] = integer_literal $Builtin.Word, 0
|
|
// CHECK-NEXT: [[ONE:%.*]] = integer_literal $Builtin.Word, 1
|
|
// CHECK-NEXT: [[LENGTH:%.*]] = pack_length $Pack{repeat each τ_0_0}
|
|
// CHECK-NEXT: br bb1([[ZERO]])
|
|
// CHECK: bb1([[INDEX:%.*]] : $Builtin.Word):
|
|
// CHECK-NEXT: [[DONE:%.*]] = builtin "cmp_eq_Word"([[INDEX]], [[LENGTH]])
|
|
// CHECK-NEXT: cond_br [[DONE]], bb3, bb2
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: [[PACK_INDEX:%.*]] = dynamic_pack_index [[INDEX]] of $Pack{repeat (each τ_0_0).Value}
|
|
// CHECK-NEXT: open_pack_element [[PACK_INDEX]] of <each τ_0_0 where repeat each τ_0_0 : Schema> at <Pack{repeat each τ_0_0}>, shape $each τ_0_0, uuid [[UUID:".*"]]
|
|
// CHECK-NEXT: [[ELT_ADDR:%.*]] = tuple_pack_element_addr [[PACK_INDEX]] of %0 as $*@pack_element([[UUID]]) (each τ_0_0).Value
|
|
// CHECK-NEXT: pack_element_set [[ELT_ADDR]] into [[PACK_INDEX]] of [[PACK]]
|
|
// CHECK-NEXT: [[NEXT_INDEX:%.*]] = builtin "add_Word"([[INDEX]], [[ONE]])
|
|
// CHECK-NEXT: br bb1([[NEXT_INDEX]])
|
|
|
|
// #81600. An assertion in reabstraction (again, from a witness thunk)
|
|
// when forwarding pack parameters that aren't simple `each T`s.
|
|
protocol PackAccepter {
|
|
func accept<each T>(values: repeat EmptyGeneric<each T>)
|
|
}
|
|
|
|
struct AccepterImpl: PackAccepter {
|
|
func accept<each T>(values: repeat EmptyGeneric<each T>) {}
|
|
}
|
|
|
|
// Just produce a new pack with the same contents.
|
|
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s4test12AccepterImplVAA04PackB0A2aDP6accept6valuesyAA12EmptyGenericVyqd__Gqd__Qp_tRvd__lFTW :
|
|
// CHECK: [[PACK:%.*]] = alloc_pack $Pack{repeat EmptyGeneric<each τ_0_0>}
|
|
// CHECK-NEXT: [[ZERO:%.*]] = integer_literal $Builtin.Word, 0
|
|
// CHECK-NEXT: [[ONE:%.*]] = integer_literal $Builtin.Word, 1
|
|
// CHECK-NEXT: [[LENGTH:%.*]] = pack_length $Pack{repeat each τ_0_0}
|
|
// CHECK-NEXT: br bb1([[ZERO]])
|
|
// CHECK: bb1([[INDEX:%.*]] : $Builtin.Word):
|
|
// CHECK-NEXT: [[DONE:%.*]] = builtin "cmp_eq_Word"([[INDEX]], [[LENGTH]])
|
|
// CHECK-NEXT: cond_br [[DONE]], bb3, bb2
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: [[PACK_INDEX:%.*]] = dynamic_pack_index [[INDEX]] of $Pack{repeat EmptyGeneric<each τ_0_0>}
|
|
// CHECK-NEXT: open_pack_element [[PACK_INDEX]] of <each τ_0_0> at <Pack{repeat each τ_0_0}>, shape $each τ_0_0, uuid [[UUID:".*"]]
|
|
// CHECK-NEXT: [[ARG_ADDR:%.*]] = pack_element_get [[PACK_INDEX]] of %0 as $*EmptyGeneric<@pack_element([[UUID]]) each τ_0_0>
|
|
// CHECK-NEXT: pack_element_set [[ARG_ADDR]] into [[PACK_INDEX]] of [[PACK]]
|
|
// CHECK-NEXT: [[NEXT_INDEX:%.*]] = builtin "add_Word"([[INDEX]], [[ONE]])
|
|
// CHECK-NEXT: br bb1([[NEXT_INDEX]])
|
|
|
|
protocol ConsumingAccepter {
|
|
func accept<each T>(values: repeat consuming NonTrivialGeneric<each T>)
|
|
}
|
|
|
|
struct ConsumingConsumingAccepterImpl: ConsumingAccepter {
|
|
func accept<each T>(values: repeat consuming NonTrivialGeneric<each T>) {}
|
|
}
|
|
|
|
// This is actually just checking that consuming parameter packs
|
|
// work in general.
|
|
// CHECK-LABEL: sil hidden [ossa] @$s4test09ConsumingB12AccepterImplV6accept6valuesyAA17NonTrivialGenericVyxGxQpn_tRvzlF :
|
|
// CHECK: [[ZERO:%.*]] = integer_literal $Builtin.Word, 0
|
|
// CHECK-NEXT: [[ONE:%.*]] = integer_literal $Builtin.Word, 1
|
|
// CHECK-NEXT: [[LENGTH:%.*]] = pack_length $Pack{repeat each T}
|
|
// CHECK-NEXT: br bb1([[LENGTH]])
|
|
// CHECK: bb1([[PREV_INDEX:%.*]] : $Builtin.Word):
|
|
// CHECK-NEXT: [[DONE:%.*]] = builtin "cmp_eq_Word"([[PREV_INDEX]], [[ZERO]])
|
|
// CHECK-NEXT: cond_br [[DONE]], bb3, bb2
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: [[INDEX:%.*]] = builtin "sub_Word"([[PREV_INDEX]], [[ONE]])
|
|
// CHECK-NEXT: [[PACK_INDEX:%.*]] = dynamic_pack_index [[INDEX]] of $Pack{repeat NonTrivialGeneric<each T>}
|
|
// CHECK-NEXT: open_pack_element [[PACK_INDEX]] of <each T> at <Pack{repeat each T}>, shape $each T, uuid [[UUID:".*"]]
|
|
// CHECK-NEXT: [[ARG_ADDR:%.*]] = pack_element_get [[PACK_INDEX]] of %0 as $*NonTrivialGeneric<@pack_element([[UUID]]) each T>
|
|
// CHECK-NEXT: destroy_addr [[ARG_ADDR]]
|
|
// CHECK-NEXT: br bb1([[INDEX]])
|
|
// CHECK: bb3:
|
|
// CHECK-NEXT: [[RET:%.*]] = tuple ()
|
|
// CHECK-NEXT: return [[RET]]
|
|
|
|
// Check that the witness thunk forwards the argument without a temporary.
|
|
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s4test09ConsumingB12AccepterImplVAA0bC0A2aDP6accept6valuesyAA17NonTrivialGenericVyqd__Gqd__Qpn_tRvd__lFTW :
|
|
// CHECK: bb0(%0 : $*Pack{repeat NonTrivialGeneric<each τ_0_0>}, %1 : $*ConsumingConsumingAccepterImpl):
|
|
// CHECK-NEXT: [[PACK:%.*]] = alloc_pack $Pack{repeat NonTrivialGeneric<each τ_0_0>}
|
|
// CHECK-NEXT: [[ZERO:%.*]] = integer_literal $Builtin.Word, 0
|
|
// CHECK-NEXT: [[ONE:%.*]] = integer_literal $Builtin.Word, 1
|
|
// CHECK-NEXT: [[LENGTH:%.*]] = pack_length $Pack{repeat each τ_0_0}
|
|
// CHECK-NEXT: br bb1([[ZERO]])
|
|
// CHECK: bb1([[INDEX:%.*]] : $Builtin.Word):
|
|
// CHECK-NEXT: [[DONE:%.*]] = builtin "cmp_eq_Word"([[INDEX]], [[LENGTH]])
|
|
// CHECK-NEXT: cond_br [[DONE]], bb3, bb2
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: [[PACK_INDEX:%.*]] = dynamic_pack_index [[INDEX]] of $Pack{repeat NonTrivialGeneric<each τ_0_0>}
|
|
// CHECK-NEXT: open_pack_element [[PACK_INDEX]] of <each τ_0_0> at <Pack{repeat each τ_0_0}>, shape $each τ_0_0, uuid [[UUID:".*"]]
|
|
// CHECK-NEXT: [[ARG_ADDR:%.*]] = pack_element_get [[PACK_INDEX]] of %0 as $*NonTrivialGeneric<@pack_element([[UUID]]) each τ_0_0>
|
|
// CHECK-NEXT: pack_element_set [[ARG_ADDR]] into [[PACK_INDEX]] of [[PACK]]
|
|
// CHECK-NEXT: [[NEXT_INDEX:%.*]] = builtin "add_Word"([[INDEX]], [[ONE]])
|
|
// CHECK-NEXT: br bb1([[NEXT_INDEX]])
|
|
// CHECK: bb3:
|
|
// CHECK-NEXT: load [trivial] %1
|
|
// CHECK-NEXT: // function_ref
|
|
// CHECK-NEXT: function_ref
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: tuple ()
|
|
// CHECK-NEXT: dealloc_pack [[PACK]]
|
|
// CHECK-NEXT: return
|
|
|
|
struct BorrowingConsumingAccepterImpl: ConsumingAccepter {
|
|
func accept<each T>(values: repeat NonTrivialGeneric<each T>) {}
|
|
}
|
|
|
|
// Check that the witness thunk produces a new pack with the same contents,
|
|
// but that we destroy them in the thunk after the call.
|
|
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s4test30BorrowingConsumingAccepterImplVAA0cD0A2aDP6accept6valuesyAA17NonTrivialGenericVyqd__Gqd__Qpn_tRvd__lFTW :
|
|
// CHECK: bb0(%0 : $*Pack{repeat NonTrivialGeneric<each τ_0_0>}, %1 : $*BorrowingConsumingAccepterImpl):
|
|
// CHECK-NEXT: [[PACK:%.*]] = alloc_pack $Pack{repeat NonTrivialGeneric<each τ_0_0>}
|
|
// CHECK-NEXT: [[ZERO:%.*]] = integer_literal $Builtin.Word, 0
|
|
// CHECK-NEXT: [[ONE:%.*]] = integer_literal $Builtin.Word, 1
|
|
// CHECK-NEXT: [[LENGTH:%.*]] = pack_length $Pack{repeat each τ_0_0}
|
|
// CHECK-NEXT: br bb1([[ZERO]])
|
|
// CHECK: bb1([[INDEX:%.*]] : $Builtin.Word):
|
|
// CHECK-NEXT: [[DONE:%.*]] = builtin "cmp_eq_Word"([[INDEX]], [[LENGTH]])
|
|
// CHECK-NEXT: cond_br [[DONE]], bb3, bb2
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: [[PACK_INDEX:%.*]] = dynamic_pack_index [[INDEX]] of $Pack{repeat NonTrivialGeneric<each τ_0_0>}
|
|
// CHECK-NEXT: open_pack_element [[PACK_INDEX]] of <each τ_0_0> at <Pack{repeat each τ_0_0}>, shape $each τ_0_0, uuid [[UUID:".*"]]
|
|
// CHECK-NEXT: [[ARG_ADDR:%.*]] = pack_element_get [[PACK_INDEX]] of %0 as $*NonTrivialGeneric<@pack_element([[UUID]]) each τ_0_0>
|
|
// CHECK-NEXT: pack_element_set [[ARG_ADDR]] into [[PACK_INDEX]] of [[PACK]]
|
|
// CHECK-NEXT: [[NEXT_INDEX:%.*]] = builtin "add_Word"([[INDEX]], [[ONE]])
|
|
// CHECK-NEXT: br bb1([[NEXT_INDEX]])
|
|
// CHECK: bb3:
|
|
// CHECK-NEXT: load [trivial] %1
|
|
// CHECK-NEXT: // function_ref
|
|
// CHECK-NEXT: function_ref
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: [[RET:%.*]] = tuple ()
|
|
// CHECK-NEXT: [[ZERO:%.*]] = integer_literal $Builtin.Word, 0
|
|
// CHECK-NEXT: [[ONE:%.*]] = integer_literal $Builtin.Word, 1
|
|
// CHECK-NEXT: [[LENGTH:%.*]] = pack_length $Pack{repeat each τ_0_0}
|
|
// CHECK-NEXT: br bb4([[LENGTH]])
|
|
// CHECK: bb4([[PREV_INDEX:%.*]] : $Builtin.Word):
|
|
// CHECK-NEXT: [[DONE:%.*]] = builtin "cmp_eq_Word"([[PREV_INDEX]], [[ZERO]])
|
|
// CHECK-NEXT: cond_br [[DONE]], bb6, bb5
|
|
// CHECK: bb5:
|
|
// CHECK-NEXT: [[INDEX:%.*]] = builtin "sub_Word"([[PREV_INDEX]], [[ONE]])
|
|
// CHECK-NEXT: [[PACK_INDEX:%.*]] = dynamic_pack_index [[INDEX]] of $Pack{repeat NonTrivialGeneric<each τ_0_0>}
|
|
// CHECK-NEXT: open_pack_element [[PACK_INDEX]] of <each τ_0_0> at <Pack{repeat each τ_0_0}>, shape $each τ_0_0, uuid [[UUID:".*"]]
|
|
// CHECK-NEXT: [[ARG_ADDR:%.*]] = pack_element_get [[PACK_INDEX]] of [[PACK]] as $*NonTrivialGeneric<@pack_element([[UUID]]) each τ_0_0>
|
|
// CHECK-NEXT: destroy_addr [[ARG_ADDR]]
|
|
// CHECK-NEXT: br bb4([[INDEX]])
|
|
// CHECK: bb6:
|
|
// CHECK-NEXT: dealloc_pack [[PACK]]
|
|
// CHECK-NEXT: return [[RET]]
|
|
|
|
protocol BorrowingAccepter {
|
|
func accept<each T>(values: repeat NonTrivialGeneric<each T>)
|
|
}
|
|
|
|
struct ConsumingBorrowingAccepterImpl: BorrowingAccepter {
|
|
func accept<each T>(values: repeat consuming NonTrivialGeneric<each T>) {}
|
|
}
|
|
|
|
// Check that the witness thunk copies the pack into a temporary.
|
|
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s4test30ConsumingBorrowingAccepterImplVAA0cD0A2aDP6accept6valuesyAA17NonTrivialGenericVyqd__Gqd__Qp_tRvd__lFTW :
|
|
// CHECK: bb0(%0 : $*Pack{repeat NonTrivialGeneric<each τ_0_0>}, %1 : $*ConsumingBorrowingAccepterImpl):
|
|
// CHECK-NEXT: [[PACK:%.*]] = alloc_pack $Pack{repeat NonTrivialGeneric<each τ_0_0>}
|
|
// CHECK-NEXT: [[TEMP_TUPLE:%.*]] = alloc_stack $(repeat NonTrivialGeneric<each τ_0_0>)
|
|
// CHECK-NEXT: [[ZERO:%.*]] = integer_literal $Builtin.Word, 0
|
|
// CHECK-NEXT: [[ONE:%.*]] = integer_literal $Builtin.Word, 1
|
|
// CHECK-NEXT: [[LENGTH:%.*]] = pack_length $Pack{repeat each τ_0_0}
|
|
// CHECK-NEXT: br bb1([[ZERO]])
|
|
// CHECK: bb1([[INDEX:%.*]] : $Builtin.Word):
|
|
// CHECK-NEXT: [[DONE:%.*]] = builtin "cmp_eq_Word"([[INDEX]], [[LENGTH]])
|
|
// CHECK-NEXT: cond_br [[DONE]], bb3, bb2
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: [[PACK_INDEX:%.*]] = dynamic_pack_index [[INDEX]] of $Pack{repeat NonTrivialGeneric<each τ_0_0>}
|
|
// CHECK-NEXT: open_pack_element [[PACK_INDEX]] of <each τ_0_0> at <Pack{repeat each τ_0_0}>, shape $each τ_0_0, uuid [[UUID:".*"]]
|
|
// CHECK-NEXT: [[TEMP_ELT_ADDR:%.*]] = tuple_pack_element_addr [[PACK_INDEX]] of [[TEMP_TUPLE]] as $*NonTrivialGeneric<@pack_element([[UUID]]) each τ_0_0>
|
|
// CHECK-NEXT: [[ARG_ADDR:%.*]] = pack_element_get [[PACK_INDEX]] of %0 as $*NonTrivialGeneric<@pack_element([[UUID]]) each τ_0_0>
|
|
// CHECK-NEXT: [[BORROW:%.*]] = load_borrow [[ARG_ADDR]]
|
|
// CHECK-NEXT: [[COPY:%.*]] = copy_value [[BORROW]]
|
|
// CHECK-NEXT: store [[COPY]] to [init] [[TEMP_ELT_ADDR]]
|
|
// CHECK-NEXT: pack_element_set [[TEMP_ELT_ADDR]] into [[PACK_INDEX]] of [[PACK]]
|
|
// CHECK-NEXT: end_borrow [[BORROW]]
|
|
// CHECK-NEXT: [[NEXT_INDEX:%.*]] = builtin "add_Word"([[INDEX]], [[ONE]])
|
|
// CHECK-NEXT: br bb1([[NEXT_INDEX]])
|
|
// CHECK: bb3:
|
|
// CHECK-NEXT: load [trivial] %1
|
|
// CHECK-NEXT: // function_ref
|
|
// CHECK-NEXT: function_ref
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: tuple ()
|
|
// CHECK-NEXT: dealloc_stack [[TEMP_TUPLE]]
|
|
// CHECK-NEXT: dealloc_pack [[PACK]]
|
|
// CHECK-NEXT: return
|