Swift 5.10 was overly conservative regarding passing non-Sendable
types to different contexts. Specifically, we might create a non-Sendable
instance, and pass it to some other context, but not use it outside of that new context. Swift 6 (specifically SE-0414) has improved this. As WWDC 2024 video What’s new in Swift says:
To ensure safety, complete concurrency checking in Swift 5.10 banned passing all non-Sendable
values across actor isolation boundaries. Swift 6 can recognize that it is safe to pass non-Sendable
values, in scenarios where they can no longer be referenced from their original isolation boundary.
So, as you noted, in Swift 6 (in Xcode 16 beta 3), you will get a warning with the following code:
In this case, though, it is the presence of the reference to nonSendable
in the for
-in
loop that affects its isolation region. E.g., remove that reference and the error goes away:
actor MyActor {
func foo() {
let nonSendable = NonSendable()
// for _ in 1...3 {
// bar(nonSendable)
// }
(1...3).forEach { _ in
// ✅ Compiles fine
bar(nonSendable)
}
}
func bar(_ object: NonSendable) { }
}
This Swift 6 behavior is an improvement over Swift 5.10. See SE-0414 – Region based Isolation for a lengthy discussion regarding what improvements Swift 6 provides and the limitations that are still imposed.
For the sake of clarity, your original example (with both the for
-in
loop and the forEach
closure) did not actually manifest a data race. But the question is whether the compiler can guarantee that the code is free from races: At this point it cannot.
In terms of work-arounds, either avoid attempting to use the nonSendable
instance from two different regions, or make the object Sendable
.