My experience with Swift 6 strict concurrency so far doesn't match my understanding of implicit MainActor
isolation semantics.
Build succeeds when testing a struct declared in the test module, but fails when the struct is moved to the main module:
Main actor-isolated property … cannot be accessed from outside the actor.
WhatTheSwift
.Update the default test file to be this:
import Testing
@testable import WhatTheSwift
struct WhatTheSwiftTests {
@Test func example() async throws {
let thing = Thing(foo: "bar")
#expect(thing.foo == "bar")
}
}
struct Thing {
let foo: String
}
That should build fine, and the tests should pass.
Now, move the Thing
declaration into its own Thing.swift
file in the WhatTheSwift
module, and try running the test again. You should see this:
@MainActor
allows the test to pass, suggesting the compiler actually wants to isolate Thing.foo
to the main actor.SWIFT_DEFAULT_ACTOR_ISOLATION
on the WhatTheSwift
module to nonisolated
also allows tests to pass.Why? And why only when Thing
is in a different module?
It looks like the explanation has two parts.
The difference between the struct being declared in the test module and the main module is the SWIFT_DEFAULT_ACTOR_ISOLATION
setting. It is set to MainActor
in the main module, but isn't available in the test module, presumably because the test framework would break if it was set that way.
The assumption that Thing
shouldn't be affected by this setting was false, due in no small part to ChatGPT being supremely convincing in its hallucinatory responses while I've been chewing over this peculiarity the last couple of days. Default actor isolation affects everything.