in the evolution document for 'Usability of global-actor-isolated types', there is currently this in the section on Sendable inference for global-actor-isolated closures:
To improve usability of globally-isolated functions and closures, under this proposal @Sendable is inferred...
it's unclear to me how such inference is intended to function with other isolation inference rules. specifically, on the current main and 6.2 release branch snapshots (godbolt for 6.2 branch here), the following example appears to infer Sendable for functions, but not for closures:
@MainActor
func test_gait_sendable_inference() async {
let closure = {
MainActor.assertIsolated("?")
await Task.yield()
print("on main actor")
}
_ = closure as any Sendable // 🛑
// |- error: type '() async -> ()' does not conform to the 'Sendable' protocol
// `- note: a function type must be marked '@Sendable' to conform to 'Sendable'
func localFunc() async {
MainActor.assertIsolated("?")
await Task.yield()
print("on main actor (fn)")
}
_ = localFunc as any Sendable // ✅
}
is this behavior expected, or an implementation gap with SE-0434? cc @simanerush & @hborla as implementors (i think) of this feature.
This is a known limitation due to the ordering of type inference (computed by a subsystem called the "constraint system") and actor isolation inference for closures. Actor isolation checking happens after type inference, because it depends on things like overload resolution. But the actor isolation checker is also what assigns isolation to closures based on the context they're formed in. This is why inferred actor isolation for closures cannot impact overload resolution, and why you're seeing the error about the closure type not conforming to Sendable, because that is diagnosed before the actor isolation checker has run.
I've thought about attempting to integrate closure isolation inference into the constraint system, but it would have to be done mid solving because it depends on the isolation of the enclosing context, which can changed based on different overloads that are chosen in an expression. I am not sure that it's feasible, but I also have not seriously tried. In any case, that change has the potential to be source breaking because it can change overload resolution, although I wouldn't expect it to cause serious issues in practice if we could make it work.
@hborla Could you take a look at this bug? It's about a data race that compiler fails to catch. It's related to closure's type and isolation inference, so I guess it might be caused by the above limitation too.