Sendable warning for existential

While trying to adopt Swift 6 mode I've noticed difference in behaviour for existential vs generic.

Target APIClient has adopted Swift 6 mode while target DataClient hasn't:

// swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "TestPackage",
    platforms: [.iOS(.v16), .macOS(.v14)],
    products: [
        .library(name: "APIClient", targets: ["APIClient"]),
        .library(name: "DataClient", targets: ["DataClient"]),
    ],
    targets: [
        .target(
            name: "APIClient",
            swiftSettings: [
                .swiftLanguageMode(.v6),
            ]
        ),
        .target(
            name: "DataClient",
            dependencies: ["APIClient"],
            swiftSettings: [
                .swiftLanguageMode(.v5),
            ]
        ),
    ]
)

Target APIClient defines an APIClient protocol:

import Foundation

public protocol APIClient {
    func fetch() -> String
}

Target DataClient defines and implements some data client:

import Foundation
import APIClient

struct UserClient: Sendable {
    let fetchUserId: @Sendable () async throws -> String
}

extension UserClient {
    static func liveA(
        apiClient: APIClient
    ) -> Self {
        .init(
            fetchUserId: {
                apiClient.fetch() // Capture of 'apiClient' with non-sendable type 'any APIClient' in a `@Sendable` closure; this is an error in the Swift 6 language mode
            }
        )
    }
    
    static func liveB(
        apiClient: some APIClient
    ) -> Self {
        .init(
            fetchUserId: {
                apiClient.fetch()
            }
        )
    }
    
    static func liveC<T: APIClient>(
        apiClient: T
    ) -> Self {
        .init(
            fetchUserId: {
                apiClient.fetch()
            }
        )
    }
}

Calling the APIClient when passed as existential produces the following warning: Capture of 'apiClient' with non-sendable type 'any APIClient' in a @Sendable closure; this is an error in the Swift 6 language mode, but if the APIClient is passed as generic, either with some keyword or type placeholder, the warning is not produced. I've been able to produce the warning only in this setup, when all targets are v5 compatibility mode, no warning is reported.

Could someone help me understand why is the warning not being produced for the generic?

3 Likes

I think this has something to do with warnings being off for the DataClient target.

All three sites produce errors in Swift 6, but it is really strange that you get only get some of them. UserClient has opted into a concurrency features, and that can enable diagnostics that would otherwise be suppressed. But I would have expected either none or all.

1 Like