SE-0316 Global actors has this to say about the main actor (emphasis mine):
For systems that use the Apple's Dispatch library as the underlying concurrency implementation, the main actor uses a custom executor that wraps the main dispatch queue. It also determines when code is dynamically executing on the main actor to avoid an extra "hop" when performing an asynchronous call to a
@MainActor
function.
I've been trying to find the place in the Swift source code where this dynamic check to avoid extra hops is performed. The text in the proposal makes it sound (to me) that this is a check that's specific to the main actor, but I couldn't find any specific check like this.
What I did find (I think) is a generic check that works for all executors/actors, main actor or not. In swift_task_switchImpl
, there's a check if the new task's the new job's executor is the current executor:
static void swift_task_switchImpl(SWIFT_ASYNC_CONTEXT AsyncContext *resumeContext,
TaskContinuationFunction *resumeFunction,
ExecutorRef newExecutor) SWIFT_OPTNONE {
...
// If the current executor is compatible with running the new executor,
// we can just immediately continue running with the resume function
// we were passed in.
if (!currentExecutor.mustSwitchToRun(newExecutor)) {
return resumeFunction(resumeContext); // 'return' forces tail call
}
...
Is this what SE-0316 means, or did I miss something in the MainActor
implementation?