This code is compiled and have no warning.
even though State is shared between different actor which is unSendable and even not makred as sending
.
func bar(isolation actor: isolated any Actor = #isolation) async {
var value = 0
// this is allowed because we are taking copy of Sendable?
await foo(isolation: MainActor.shared) {
return 100
} body: { mutableNumber in
mutableNumber += 100
value += 100
}
// NonSendable is shared between, MainActor and current Actor
await foo(isolation: MainActor.shared) {
return NonSendable()
} body: { unSendable in
value += 100
unSendable.doUnsafe()
unSendable = NonSendable()
}
// mutate TaskGroup from MainActor and current Actor
await foo2 (isolation: MainActor.shared) { group in
value += 100
group.addTask {
}
}
}
func foo<T:~Copyable>(
isolation actor: isolated any Actor = #isolation,
provider: @Sendable () -> sending T,
body: (inout T) async -> Void
) async -> Void {
var ref = provider()
await body(&ref)
}
func foo2(
isolation actor: isolated any Actor = #isolation,
body: (inout TaskGroup<Void>) async -> Void
) async -> Void {
await withTaskGroup(of: Void.self) { group in
// this is actor context
group.addTask {
}
// body is caller's context ( actor != caller )
await body(&group)
}
}
struct NonSendable: ~Copyable { }
@available(*, unavailable)
extension NonSendable: Sendable {
}
for now NonSendable state is shared in Swift 6.
At least in the code above there is no data race in runtime.
I think pattern like above could potentionally make data race, or did I miss something?
Above pattern is inspired by new TaskGroup implementation
Edited for to use valid case since Actor instance method somehow not works