I have this code

actor MyActor { var checker: @MainActor () -> Void = {} init(checker: @escaping @MainActor () -> Void) { self.checker = checker } nonisolated func noniso() { Task { let checker = await self.checker await checker() } } }

This compiles fine in Swift 6, which is a bit strange, because checker is not a @Senable closure.

the noniso function calls Task {}, which creates a non-isolated asynchronous context. Then the checker passes the the boundary from MyActor to non-isolated context. Then when I invoke it, it passes the boundary again from non-isolated context to MainActor (since it's marked as @MainActor).

This is odd since I was expecting both lines to fail since checker is not @Sendable

HL666's user avatar

3

Since SE-0434, @Sendable is inferred for global actor isolated closures.

The "Motivation" section mentions a situation very similar to what you described.

Next, under the current concurrency rules, it is possible for a function type to be both isolated to a global actor and yet not required to be Sendable:

func test(globallyIsolated: @escaping @MainActor () -> Void) { Task { // error: capture of 'globallyIsolated' with non-sendable type '@MainActor () -> Void' in a `@Sendable` closure await globallyIsolated() } }

This is not a useful combination: such a function can only be used if the current context is isolated to the global actor, and in that case the global actor annotation is unnecessary because all non-Sendable functions will run with global actor isolation. It would be better for a global actor attribute to always imply @Sendable.

Sweeper's user avatar

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.