Calling publishTest in the following program causes an EXC_BAD_INSTRUCTION crash in the attempt to run publishTest's closure. The program is compiled in Swift 6 mode with “nonisolated(nonsending) by Default” set to true and all other compiler options set to Xcode's default.
import Foundation
import Combine
public struct S {
nonisolated(nonsending) public func f(counter: (Int) -> Void) async {
let isolation = #isolation
print("f \(isolation, default: "∅")")
await withTaskGroup(of: Void.self) { group in
// We just create the group for a while; we never actually launch any async child tasks in it.
let isolation = #isolation
print("withTaskGroup \(isolation, default: "∅")")
for i in 1..<4 {
print("Setting counter to \(i)")
counter(i)
print("Sleeping")
try? await Task.sleep(nanoseconds: 200_000)
}
}
}
}
@MainActor public final class PublishTest: ObservableObject {
@Published public var value: Int = 0
public var s: S = S()
public var subscription: AnyCancellable?
func publishTest() async {
print("value = \(value)")
subscription = $value.sink { i in
print("Subscriber sees value = \(i)")
}
await s.f { @MainActor i in value = i }
print("value = \(value)")
subscription = nil
}
}
The output is:
value = 0
Subscriber sees value = 0
f Swift.MainActor
withTaskGroup ∅
Setting counter to 1
followed by the crash. I find it curious that the withTaskGroup body seems unaware of running on MainActor, but it happily calls the MainActor-isolated counter closure, which is not sendable, so it presumably is not actually crossing an isolation domain boundary.
If I change the nonisolated(nonsending) to @MainActor, then the code produces the expected result:
value = 0
Subscriber sees value = 0
f Swift.MainActor
withTaskGroup Swift.MainActor
Setting counter to 1
Subscriber sees value = 1
Sleeping
Setting counter to 2
Subscriber sees value = 2
Sleeping
Setting counter to 3
Subscriber sees value = 3
Sleeping
value = 3
Am I missing something about how nonisolated(nonsending) is supposed to work? The code does not escape the safe subset of Swift 6, so I'd expect a compiler error or warning if there is unsafe code in it.
I'm running in Xcode 26.3, Intel, MacOS 15.7.4.