I believe in this particular case it's incidental. If you look at the SIL for the implementation of foo() without the explicit @MainActor annotations, you'll see that it "hops" to the generic executor, so there's no ordering guarantee there. Additionally, empirically it seems if you "clog up" the available threads with some extra work you'll be more likely to see the different orderings manifest. For example, if you run this compiler explorer example a few times you'll generally see some ordering changes Edit: see below for a better example.
SIL output:
// A.foo()
// Isolation: actor_instance. name: 'self'
sil hidden @$s6output1AC3fooyyF : $@convention(method) (@sil_isolated @guaranteed A) -> () {
// %0 "self" // user: %1
bb0(%0 : $A):
debug_value %0, let, name "self", argno 1 // id: %1
%2 = metatype $@thin Task<(), Never>.Type // user: %10
%3 = enum $Optional<String>, #Optional.none!enumelt // user: %10
%4 = alloc_stack $Optional<TaskPriority> // users: %12, %10, %5
inject_enum_addr %4, #Optional.none!enumelt // id: %5
// function_ref closure #1 in A.foo()
%6 = function_ref @$s6output1AC3fooyyFyyYacfU_ : $@convention(thin) @async @substituted <τ_0_0> (@guaranteed Optional<any Actor>) -> @out τ_0_0 for <()> // user: %8
%7 = enum $Optional<any Actor>, #Optional.none!enumelt // 👈‼️ user: %8
%8 = partial_apply [callee_guaranteed] [isolated_any] %6(%7) : $@convention(thin) @async @substituted <τ_0_0> (@guaranteed Optional<any Actor>) -> @out τ_0_0 for <()> // user: %10
// function_ref Task<>.init(name:priority:operation:)
%9 = function_ref @$sScTss5NeverORs_rlE4name8priority9operationScTyxABGSSSg_ScPSgxyYaYAcntcfC : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Sendable, τ_0_1 == Never> (@owned Optional<String>, @in Optional<TaskPriority>, @sil_sending @owned @isolated(any) @async @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <τ_0_0>, @thin Task<τ_0_0, Never>.Type) -> @owned Task<τ_0_0, Never> // user: %10
%10 = apply %9<(), Never>(%3, %4, %8, %2) : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Sendable, τ_0_1 == Never> (@owned Optional<String>, @in Optional<TaskPriority>, @sil_sending @owned @isolated(any) @async @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <τ_0_0>, @thin Task<τ_0_0, Never>.Type) -> @owned Task<τ_0_0, Never> // user: %11
release_value %10 // id: %11
dealloc_stack %4 // id: %12
%13 = metatype $@thin Task<(), Never>.Type // user: %21
%14 = enum $Optional<String>, #Optional.none!enumelt // user: %21
%15 = alloc_stack $Optional<TaskPriority> // users: %23, %21, %16
inject_enum_addr %15, #Optional.none!enumelt // id: %16
// function_ref closure #2 in A.foo()
%17 = function_ref @$s6output1AC3fooyyFyyYacfU0_ : $@convention(thin) @async @substituted <τ_0_0> (@guaranteed Optional<any Actor>) -> @out τ_0_0 for <()> // user: %19
%18 = enum $Optional<any Actor>, #Optional.none!enumelt // user: %19
%19 = partial_apply [callee_guaranteed] [isolated_any] %17(%18) : $@convention(thin) @async @substituted <τ_0_0> (@guaranteed Optional<any Actor>) -> @out τ_0_0 for <()> // user: %21
// function_ref Task<>.init(name:priority:operation:)
%20 = function_ref @$sScTss5NeverORs_rlE4name8priority9operationScTyxABGSSSg_ScPSgxyYaYAcntcfC : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Sendable, τ_0_1 == Never> (@owned Optional<String>, @in Optional<TaskPriority>, @sil_sending @owned @isolated(any) @async @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <τ_0_0>, @thin Task<τ_0_0, Never>.Type) -> @owned Task<τ_0_0, Never> // user: %21
%21 = apply %20<(), Never>(%14, %15, %19, %13) : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Sendable, τ_0_1 == Never> (@owned Optional<String>, @in Optional<TaskPriority>, @sil_sending @owned @isolated(any) @async @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <τ_0_0>, @thin Task<τ_0_0, Never>.Type) -> @owned Task<τ_0_0, Never> // user: %22
release_value %21 // id: %22
dealloc_stack %15 // id: %23
%24 = tuple () // user: %25
return %24 // id: %25
} // end sil function '$s6output1AC3fooyyF'