How the Swift Compiler Knows That DispatchQueue.main Implies @MainActor
A bit of experimentation reveals that it is in fact a relatively coarse source-code-based check that singles out invocations on
DispatchQueue.main
, in exactly that spelling.[…]
Fun fact: since this is a purely syntax-based check, if you define your own type named
DispatchQueue
, give it a staticmain
property and a function namedasync
that takes a closure, the compiler will apply the same “fix” to it. This is NOT recommended[…][…]
The biggest benefit of Swift’s concurrency model over what we had before is that so many things are statically known at compile time. It’s a shame that the compiler knows on which executor a particular line of code will run, but none of the tools seem to be able to show me this. Instead, I’m forced to hunt for
@MainActor
annotations and hidden attributes in superclasses, protocols, etc. This feels especially problematic during the Swift 5-to-6 transition phase we’re currently in where it’s so easy to misuse concurrency and not get a compiler error (and sometimes not even a warning if you forget to enable strict concurrency checking).
The
@MainActor
attribute is the general thing, and ifDispatchQueue.main
returned aMainDispatchQueue
type whose async method took a@MainActor
closure, we’d be all set. The problem with this specific case is thatDispatchQueue.main
already has a type (DispatchQueue
), and you can’t change that type without affecting source compatibility. So you would need some generalization that tries to carryMainActor
-ness along with the value. I suspect that such a generalization would generalize to, basically, just this API, so I didn’t pursue it. Given the choice between breaking source compatibility forDispatchQueue.main
(which is everywhere), inventing a bespoke feature for these cases alone, or allow-listing this pattern to help more code “just work”… I think this was rhetorical right call. Maybe we should have also deprecated this pattern over to move to an API that does take a@MainActor
closure, so the allow-list would become irrelevant over time.
You might be interested in this pitch which replaces
@_inheritActorContext
with a proper, non-underscored@inheritsIsolation
attribute, including replacement inTask.init
.
Everything about warnings is completely broken in Xcode.
When I turn on the concurrency warnings in 15.3ß3, I get ~40 warnings that disappear half a second after I click them (and come back when I switch away from the file).
Previously: