Maybe this is a silly question, but why does this code compiles?
// main.swift
class A {
var val = 0
func increase() async {
for _ in 0..<10 {
val += 1
}
}
}
await Task.detached {
let a = A()
// start 2 parallel tasks
async let val1: () = Task.detached {
await a.increase() // <- my question on this line
}.value
async let val2: () = Task.detached {
await a.increase() // <- and on this line
}.value
await val
await val2
}.value
In my understanding, Task.detached requires an @Sendable block, which can only capture Sendable objects. And A is clearly not Sendable.
The above code compiles with no warnings with the latest Xcode 15.3 (Swift 5.10), with "Strict Concurrency Checking" set to "Completed".
However, when run with thread sanitizer enabled, an (almost guaranteed) issue will arise.
Can someone enlighten me?
2 Likes
jamieQ
(Jamie)
2
this is perhaps not a satisfying answer, but i think this is likely just a bug in the diagnostics for that compiler version that results in a false negative. additionally, i think it's probably somewhat related to the relevant logic being present in 'top-level' code (there are numerous known issues with the behavioral differences in top-level code). if you run a similar example with one of the recent nightly toolchains (like this) or wrap the example in a function (like this), then you get the expected warnings along the lines of:
warning: capture of 'a' with non-sendable type 'A' in 'async let' binding; this is an error in the Swift 6 language mode
1 Like
Really helpful, thanks.
Guess I would stay with nightly builds when I want to test features in the future.