In looking into the issues outlined here, it got me thinking â how is function isolation modeled for reabstraction thunks? It seems like they don't have the information generally present on SILFunctions that represents actor isolation (specifically the actorIsolation property). Should they?
Here's a derivation from the motivating example, where we convert a nonisolated(nonsending) function from a non-throwing to a throwing representation.
func toThrowsReabstractionThunk(
_ src: nonisolated(nonsending) @escaping () async -> Void
) -> nonisolated(nonsending) () async throws -> Void {
src
}
The thunk generated for this function conversion looks like (canonical SIL):
// thunk for @escaping @callee_guaranteed @async (@guaranteed Builtin.ImplicitActor) -> (), loc * "<compiler-generated>":0:0, scope 3
sil shared [transparent] [reabstraction_thunk] @$sBAIegHgIL_BAs5Error_pIegHgILzo_TR : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor, @guaranteed @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor) -> ()) -> @error any Error {
// %0 // user: %2
// %1 // user: %2
bb0(%0 : $Builtin.ImplicitActor, %1 : $@async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor) -> ()):
%2 = apply %1(%0) : $@async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor) -> (), loc * "<compiler-generated>":0:0, scope 3
%3 = tuple (), loc * "<compiler-generated>":0:0, scope 3 // user: %4
return %3, loc * "<compiler-generated>":0:0, scope 3 // id: %4
} // end sil function '$sBAIegHgIL_BAs5Error_pIegHgILzo_TR'
However, if we manually implement the thunk:
func toThrowsManualThunk(
_ src: nonisolated(nonsending) @escaping () async -> Void
) -> nonisolated(nonsending) () async throws -> Void {
let thunk: nonisolated(nonsending) () async throws -> Void = {
await src()
}
return thunk
}
The codegen we get is:
// closure #1 in toThrowsManualThunk(_:), loc "/app/example.swift":237:66, scope 7
// Isolation: caller_isolation_inheriting <-- đđ
sil private [isolation "caller_isolation_inheriting"] @$s6output19toThrowsManualThunkyyyYaKYCcyyYaYCcFyyYaYCcfU_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor, @guaranteed @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor) -> ()) -> @error any Error {
// %0 // users: %7, %5
// %1 "src" // users: %6, %5, %4, %3
bb0(%0 : $Builtin.ImplicitActor, %1 : @closureCapture $@async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor) -> ()):
debug_value undef : $any Error, var, name "$error", argno 1, loc "/app/example.swift":237:66, scope 7 // id: %2
debug_value %1, let, name "src", argno 2, loc "/app/example.swift":235:7, scope 8 // id: %3
strong_retain %1, loc "/app/example.swift":238:15, scope 7 // id: %4
%5 = apply %1(%0) : $@async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor) -> (), loc "/app/example.swift":238:15, scope 7
strong_release %1, loc * "/app/example.swift":238:15, scope 7 // id: %6
hop_to_executor %0, loc * "/app/example.swift":238:15, scope 7 // id: %7
%8 = tuple (), loc "/app/example.swift":239:5, scope 7 // user: %9
return %8, loc "/app/example.swift":239:5, scope 7 // id: %9
} // end sil function '$s6output19toThrowsManualThunkyyyYaKYCcyyYaYCcFyyYaYCcfU_'
I built this with the isolation printing option enabled[1], and you can see that the manually-implemented closure has explicit actor isolation set, while the synthesized reabstraction thunk does not.
I assumed these generated thunks still have a notion of function isolation, but it's just not modeled in the same way as it is for explicit functions. Is that assumption correct?
In this specific case, is it accurate to say the reabstraction thunk actually has "CallerIsolationInheriting" isolation, but it's just not represented via the actorIsolation property? If so, is it reasonable to infer that particular isolation value for the function by checking for the presence of the implicit isolated parameter?
-Xllvm -sil-print-function-isolation-infoâŠī¸