first i want to highlight some recent similar topics that may be of interest:
now, on to my speculations as to what's going on here...
note that this behavior is not limited to Mutex
; you can end up with the same diagnostic from this reduced example with a subset of the Mutex
API:
struct NC: ~Copyable {}
extension NC: @unchecked Sendable {}
func f() async {
let nc = NC()
await withTaskGroup(of: Void.self) { taskGroup in
taskGroup.addTask {
`- error: passing closure as a 'sending' parameter risks causing data races between code in the current task and concurrent execution of the closure
_ = nc
`- note: closure captures reference to mutable let 'nc' which is accessible to code in the current task
}
}
}
now, removing the ~Copyable
suppression syntax resolves the issue[1], so presumably the diagnostic has something to do with the type being non-copyable.
consider a similar configuration, where we have a mutable capture of a Sendable
type, e.g.
func f() async {
var i = 0
await withTaskGroup(of: Void.self) { taskGroup in
taskGroup.addTask {
`- error: passing closure as a 'sending' parameter risks causing data races between code in the current task and concurrent execution of the closure
_ = i
`- note: closure captures reference to mutable var 'i' which is accessible to code in the current task
}
}
}
the diagnostics are essentially identical, which suggests the region-based isolation checking is perhaps treating these two cases as equivalent. i can imagine why this might happen; a mutable capture of a Sendable
type is sort of like wrapping the sendable entity in a (non-sendable) 'box' of sorts. similarly, a non-copyable type can perhaps be thought of as a value contained in a 'mutable box', with some additional requirements about how things can move in and out of it.
it seems like this is probably a bug – a Sendable
type (and in particular Mutex
) should be able to be passed across these isolation boundaries without issue.
as does the addition of an explicit
@Sendable
annotation on the closure, as you illustrate in your example. ↩︎