Are existential types Sendable?

I ran into an interesting warning from Xcode 14 beta 3 when trying to fetch some data for a UIImageView in a UIViewRepresentable, whilst using targeted concurrency checking:

private struct MyView: UIViewRepresentable {
    // ...
    func updateUIView(_ uiView: View, context: Context) {
        Task {
            let (data, _) = try await URLSession.shared.data(from: imageURL)
            uiView.imageView.image = UIImage(data: data)
        }
    }
}

It’s a pretty vanilla code snippet, but the call to URLSession.shared.data(from:delegate) generates this warning:

Non-sendable type '(any URLSessionTaskDelegate)?' exiting main actor-isolated context in call to non-isolated instance method 'data(from:delegate:)' cannot cross actor boundary

This makes sense in my head. But checking the documentation for URLSessionDataTask claims that it is indeed Sendable. And Optionals provide Sendable conformance when their wrapped element also conforms.

So it must be the existential qualifier here that is “blocking” Sendable conformance. I couldn’t find any information on this after a quick search online, so I’m assuming the answer to this topic’s question is “no”.

But more concretely, how should we deal with this in the URLSession APIs? Does this imply that their definitions in Foundation need to change to account for this?

I’m confused by your line of reasoning here. How does URLSessionDataTask being Sendable influence whether URLSessionTaskDelegate is Sendable?

I see my mistake, I misread URLSessionDataTask as URLSessionDataTaskDelegate.

If that’s the case then, how can I convince the Swift typechecker that nil passed into an (any T)? is Sendable?

Although your reasoning is malformed (as @xwu pointed out), you're still correct that protocol URLSessionTaskDelegate indirectly inherits from Sendable (via its inheritance from URLSessionDelegate).

The error message is a consequence of the fact that "protocols don't conform to themselves", or more precisely: the existential type any P itself doesn't conform to the protocol P.

As far as I know, the only exception is Error (any Error does conform to Error), which is hardcoded into the compiler. I don't remember whether a similar exception was discussed (and rejected?) for Sendable.

As to how to silence the warning in your example, I don't know. Good question.

1 Like

Existential types where the protocols imply Sendable should conform to Sendable, so this looks like a bug. CC @Douglas_Gregor.

7 Likes