Open
Description
Description
task1, 2 looks like isolated to isolation
's actor, but when isolation = nil
,
won't be isolated by anything. i.e. there are isolation boundary between inside and outside Task.
However, the compiler output no errors when compile the following code.
func f(
isolation: isolated (any Actor)? = #isolation
) async -> Int {
var count = 0
let task1 = Task {
_ = isolation
for _ in 0..<100_000 {
count += 1
}
}
let task2 = Task {
_ = isolation
for _ in 0..<100_000 {
count += 1
}
}
_ = await (task1.value, task2.value)
return count
}
await Task.detached {
let result = await f(isolation: nil)
print(result) // not 200000 like 182438. that means there is data race.
}.value
Reproduction
compile and run the above code.
Expected behavior
should output error like Sending value of non-Sendable type '() async -> ()' risks causing data races
at Task {
Environment
Swift version 6.0.3 (swift-6.0.3-RELEASE)
Target: aarch64-unknown-linux-gnu
Swift version 6.2-dev (LLVM 4197ac1672a278c, Swift acbdfef4f4d71b1)
Target: aarch64-unknown-linux-gnu
Build config: +assertions
Additional information
this bug is caused by behavior of @_inheritActorContext
. it treat isolation even if it's optional isolated
parameter.
this behavior also incorrectly allows compiler to treat non-isolated closure as Sendable
class NonSendable {
var count = 0
func doSomething() {
}
}
func doAsync(@_inheritActorContext _ a: @Sendable @escaping () -> Void) {
Task.detached {
a()
}
}
func f(
isolation: isolated (any Actor)? = #isolation
) async {
let ns = NonSendable()
doAsync {
_ = isolation
ns.doSomething()
}
doAsync {
_ = isolation
ns.doSomething()
}
}
await Task.detached {
await f(isolation: nil)
}.value