Skip to content

Instantly share code, notes, and snippets.

@ole
Last active May 28, 2025 10:45
Show Gist options
  • Save ole/76d326a43a271475ceb20add5b78a6e4 to your computer and use it in GitHub Desktop.
Save ole/76d326a43a271475ceb20add5b78a6e4 to your computer and use it in GitHub Desktop.
Why does this compile in Swift 6 language mode? (Xcode 16.3/Swift 6.1). Update: apparently a bug in the Swift 6.1 compiler. Swift 6.2 correctly raises errors.
import Foundation
extension Thread {
/// Helper for debugging (because Thread.current is noasync)
static var currentThread: Thread {
current
}
}
nonisolated class NonSendable {
var value = 0
func increment() {
value += 1
}
}
nonisolated class Model {
var state: NonSendable = .init()
// Upcoming feature: "NonisolatedNonsendingByDefault"
//nonisolated(nonsending) (in Swift 6.2, post SE-0461)
func doSomethingWithCallerIsolation(isolation: isolated (any Actor)? = #isolation) async {
print(#function, Thread.currentThread)
// Mutate non-Sendable state
self.state = NonSendable()
}
//@concurrent (in Swift 6.2, post SE-0461)
func doSomethingOnGlobalExecutor() async {
print(#function, Thread.currentThread)
// Mutate non-Sendable state
self.state.increment()
}
}
// @concurrent
func freeNonisolatedFunction(model: Model) async {
print(#function, Thread.currentThread)
model.state = NonSendable()
}
@main
struct Main {
@MainActor // make @MainActor explicit, but `main()` is always implicitly @MainActor
static func main() async {
MainActor.assertIsolated()
print(#function, Thread.currentThread)
// A local variable. What isolation does this have? @MainActor?
let model = Model()
// Works. Makes sense because we're staying on the current isolation.
await model.doSomethingWithCallerIsolation()
// Works. Why??? Aren't we sending the non-Sendable model from MainActor to the global executor?
await model.doSomethingOnGlobalExecutor()
// Works. Why??? Aren't we sending the non-Sendable model from MainActor to the global executor?
await freeNonisolatedFunction(model: model)
// Use model here to make sure region-based isolation can't send it
print(#function, model)
}
}
@ole
Copy link
Author

ole commented May 17, 2025

Turns out this is a bug in Swift 6.1. Compiling with a current 6.2 toolchain fails with the 2 expected sendability errors on lines 54 and 56.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment