So we're in the process of migrating to Swift 6 language mode now, we've encountered the following which seems like it should be covered by region based isolation rules, or am I missing something?
Basically the partitions returned from transactionSequence in transactions.partitions is nonSendable (it's a reference type without Sendable annotation) - but shouldn't this be covered by SE-0414?
As a sum-up of the discussion, I guess what you are looking for is being able to mark as sending elements of a collection, because otherwise, even with transactions itself marked as such, compiler won't be able to reason if non-Sendable elements are safe to capture since they might be used somewhere else as well.
I probably wasn't clear in description, currently (at least to my knowledge) there is no way to workaround this with all the concurrency checks in. The only way I can think of handling this is opt-out to unsafe wrapper:
struct _UnsafeSendable<T>: @unchecked Sendable {
let value: T
init(_ value: T) {
self.vale = value
}
}
func processTransactions<T>(_ transactions: some Sequence<T>) async {
await withDiscardingTaskGroup { group in
for transaction in transactions {
let unsafe = _UnsafeSendable(transaction)
group.addTask {
doSomething(with: unsafe.value)
}
}
}
}
But of course this has to be then ensured on its own (tbh have no idea how apart from being really careful) that the wrapped data is really safe to access.
Many thanks, will consider if we can make the partitions sendable then, it's a bit unfortunate as we're really only consuming these a single time and knows "it's ok".
One more addition: if you make function parameter transactions to be sending:
transactions: sending PartitionedSequence<_>
Compiler will at least make sure that passed-in collection is really safe to pass, consider:
class NonSendable {}
func producer() {
let a = NonSendable()
let values = [a]
consumer(of: values) // error – due to a later access to `a`
print(a) // commenting this fixes error
}
func consumer(of values: sending [NonSendable]) {
}
While with unsafe wrapper it is still possible to have concurrent access within the function, you at least have a compiler check that you don't introduce any unsafe usages outside of it narrowing down the scope to track.