The compiler ensures that all calls to @MainActor methods are implicitly async unless called from something that is also @MainActor. However, that checking is being phased in over multiple releases to avoid breaking existing code that looks like this:
// Existing code that calls the completion on the main thread,
// but is not yet annotated with `@MainActor`
func fetchUser(_ completion: @escaping (User)->Void) {
// ...
}
func viewDidAppear() {
fetchUser() { (user) in
// We know that this always runs on the main thread,
// but `fetchUser`'s parameter has not been annotated
// with @MainActor, so the *compiler* doesn't know it
// yet.
//
// If the compiler enforced an 'await' here, it would
// break too much existing code
self.label.text = user.name
}
}
I believe that the plan is to produce a warning about the above code in Swift 5.7, and then upgrade it to a hard error whenever Swift 6.0 comes out. It would also be an error right now, in Swift 5.6, if the surrounding code uses any other concurrency annotations to indicate that it is concurrency-aware.
But yes, for the moment @MainActor is a suggestion but not yet a guarantee.
Yes, with the Swift 6 compiler (Xcode 16.2), even in the Swift 5 language mode with "Minimal" concurrency checking enabled, this code now produces an error: