SwiftNIO is unusable with the aggresive `Sendable` checking in recent toolchains

Having upgraded from an october toolchain to a more recent december toolchain, i’m experiencing a deluge of Sendable-related warnings from SwiftNIO types in my codebase. common offenders so far include:

  • MultiThreadedEventLoopGroup
  • Channel
  • NIOSSLContext (from nio-ssl)
  • HTTPClient (from async-http-client)

anybody else know of a good workaround to deal with this?

I’ve had similar compilation failures with Swift for TensorFlow as early as Swift 5.4.

Can you produce the list of warnings? This might require work on our part.

Specifically what I care about is whether the usage site that causes the warning is in your code or ours. If it's in yours, you could try using @predatesConcurrency on your import to silence the warnings.

currently, i am getting usage site warnings:

remote.swift:14:13: warning: stored property 'threads' of 'Sendable'-conforming struct 'Remote' has non-sendable type 'MultiThreadedEventLoopGroup'
        let threads:MultiThreadedEventLoopGroup, 
            ^
.build/checkouts/swift-nio/Sources/NIOPosix/MultiThreadedEventLoopGroup.swift:54:20: note: class 'MultiThreadedEventLoopGroup' does not conform to the 'Sendable' protocol
public final class MultiThreadedEventLoopGroup: EventLoopGroup {
                   ^
remote.swift:15:13: warning: stored property 'security' of 'Sendable'-conforming struct 'Remote' has non-sendable type 'NIOSSLContext'
            security:NIOSSLContext, 
            ^
.build/checkouts/swift-nio-ssl/Sources/NIOSSL/SSLContext.swift:125:20: note: class 'NIOSSLContext' does not conform to the 'Sendable' protocol
public final class NIOSSLContext {
                   ^
remote.swift:18:13: warning: stored property 'http' of 'Sendable'-conforming struct 'Remote' has non-sendable type 'HTTPClient'
        let http:HTTPClient
            ^
.build/checkouts/async-http-client/Sources/AsyncHTTPClient/HTTPClient.swift:66:14: note: class 'HTTPClient' does not conform to the 'Sendable' protocol
public class HTTPClient {
             ^
io/fix/fix.swift:259:13: warning: stored property 'channel' of 'Sendable'-conforming generic struct 'Session' has non-sendable type 'Channel'
        let channel:Channel 
            ^
.build/checkouts/swift-nio/Sources/NIOCore/Channel.swift:105:17: note: protocol 'Channel' does not conform to the 'Sendable' protocol
public protocol Channel: AnyObject, ChannelOutboundInvoker {
                ^
io/websocket/websocket.swift:176:13: warning: stored property 'channel' of 'Sendable'-conforming generic struct 'Session' has non-sendable type 'Channel'
        let channel:Channel 
            ^
.build/checkouts/swift-nio/Sources/NIOCore/Channel.swift:105:17: note: protocol 'Channel' does not conform to the 'Sendable' protocol
public protocol Channel: AnyObject, ChannelOutboundInvoker {
                ^
io/websocket/websocket.swift:176:13: warning: stored property 'channel' of 'Sendable'-conforming generic struct 'Session' has non-sendable type 'Channel'
        let channel:Channel 
            ^
.build/checkouts/swift-nio/Sources/NIOCore/Channel.swift:105:17: note: protocol 'Channel' does not conform to the 'Sendable' protocol
public protocol Channel: AnyObject, ChannelOutboundInvoker {
                ^
io/websocket/websocket.swift:214:64: warning: cannot use parameter 'channel' with a non-sendable type 'Channel' from concurrently-executed code
                        try await connected(Self.init(channel: channel), control)
                                                               ^
.build/checkouts/swift-nio/Sources/NIOCore/Channel.swift:105:17: note: protocol 'Channel' does not conform to the 'Sendable' protocol
public protocol Channel: AnyObject, ChannelOutboundInvoker {
                ^
io/fix/fix.swift:259:13: warning: stored property 'channel' of 'Sendable'-conforming generic struct 'Session' has non-sendable type 'Channel'
        let channel:Channel 
            ^
.build/checkouts/swift-nio/Sources/NIOCore/Channel.swift:105:17: note: protocol 'Channel' does not conform to the 'Sendable' protocol
public protocol Channel: AnyObject, ChannelOutboundInvoker {
                ^
remote.swift:14:13: warning: stored property 'threads' of 'Sendable'-conforming struct 'Remote' has non-sendable type 'MultiThreadedEventLoopGroup'
        let threads:MultiThreadedEventLoopGroup, 
            ^
.build/checkouts/swift-nio/Sources/NIOPosix/MultiThreadedEventLoopGroup.swift:54:20: note: class 'MultiThreadedEventLoopGroup' does not conform to the 'Sendable' protocol
public final class MultiThreadedEventLoopGroup: EventLoopGroup {
                   ^
remote.swift:15:13: warning: stored property 'security' of 'Sendable'-conforming struct 'Remote' has non-sendable type 'NIOSSLContext'
            security:NIOSSLContext, 
            ^
.build/checkouts/swift-nio-ssl/Sources/NIOSSL/SSLContext.swift:125:20: note: class 'NIOSSLContext' does not conform to the 'Sendable' protocol
public final class NIOSSLContext {
                   ^
remote.swift:18:13: warning: stored property 'http' of 'Sendable'-conforming struct 'Remote' has non-sendable type 'HTTPClient'
        let http:HTTPClient
            ^
.build/checkouts/async-http-client/Sources/AsyncHTTPClient/HTTPClient.swift:66:14: note: class 'HTTPClient' does not conform to the 'Sendable' protocol
public class HTTPClient {
             ^
ephemera.swift:106:91: warning: cannot use let 'threads' with a non-sendable type 'MultiThreadedEventLoopGroup' from concurrently-executed code
        async let service:Void      = server.bind(host: "127.0.0.1", port: 8888, threads: threads)
                                                                                          ^
.build/checkouts/swift-nio/Sources/NIOPosix/MultiThreadedEventLoopGroup.swift:54:20: note: class 'MultiThreadedEventLoopGroup' does not conform to the 'Sendable' protocol
public final class MultiThreadedEventLoopGroup: EventLoopGroup {
                   ^

most of these (except for Channel) are types i am told should be Sendable, but cannot be marked so without causing another cascade of warnings. Channel is a protocol and cannot be marked Sendable by extension.

the @predatesConcurrency attribute does not appear to be defined:

error: unknown attribute 'predatesConcurrency'
@predatesConcurrency
import class NIO.MultiThreadedEventLoopGroup

okay apparently @predatesConcurrency needed an underscore, but it is still not compiling:

error: '@_predatesConcurrency' attribute cannot be applied to this declaration
@_predatesConcurrency
import class NIO.MultiThreadedEventLoopGroup

I think @beccadax knows the current state of @_predatesConcurrency, but it is the "correct" way to solve this problem. In the meantime, most of these warnings can be fixed by adding @unchecked Sendable conformances to your own types and just asserting that ours are.

1 Like

These sendable warnings are causing a massive amount of confusion. Most of the examples from WWDC generate warnings and the guidance in the swift evolution is vague and confusing.

Right; we are in something of a transition period. The goal is to prevent data races at compile-time, and unfortunately it is difficult/impossible to just add that to a language with no churn at all.

IMO, the goal is ambitious enough and the rewards are great enough that it is worth the pain. This is just one of those things we need to go through.

3 Likes