Question about @Sendable checking

We've been trying out -Xfrontend -warn-concurrency, and I'm getting a warning that I don't understand.


class SendabilityTester {
    var name: String = ""

    @MainActor
    func test() {
        print("name outside: \(name)")
        Task {
            // Capture of 'self' with non-sendable type 'SendabilityTester' in a `@Sendable` closure
            print("name inside: \(name)")
        }
    }
}

SendabilityTester itself is not Sendable, nor is it isolated to @MainActor. However, as I understand it, the nested Task here is going to inherit @MainActor isolation from the surrounding function. We don't get a warning when accessing self.name outside the Task, and it seems like it should be equally safe to access name from within another @MainActor-isolated task.

The warning the compiler emits is accurate in a sense—we are capturing self within a @Sendable closure, and self is not marked as Sendable. But should this warning be disabled when declared within an actor-isolated function, if the closure itself is known to also run on that same actor?

Properties of this class are not isolated. While test() func is running, this class instance can also be accessed from other Tasks, queues or threads, So, it is potentially unsafe.

1 Like

I agree. But is it not also equally unsafe to access name on the "name outside" line? Why does the compiler warn inside the Task, but not outside it?

As I understand it complier can not prove is it safe or not, so it doesn't make any assumptions. This property can be read serially, from serial queue for example. It is safe. But Task {} is guaranteed to perform work concurrently.

Task {} declared inside a @MainActor func inherits the actor from the surrounding context, so the Task is going to be executed serially on the main queue just like the rest of the function body is. It's no more concurrent than the rest of the body; the only difference is that it's happening later.

2 Likes