Last active
May 28, 2025 10:45
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.