Should Swift 6 prevent sharing a non-Sendable value via Mutex?

The following code produces no warnings or errors under Swift 6, even though NonSendable is being effectively shared across concurrency domains. Is this expected?

import Synchronization

class NonSendable {
    var name = "Fred"
}

let m = Mutex(NonSendable())

func test() {
    Task { @concurrent in
        let ns = m.withLock { $0 }
        ns.name = "joe"
    }
    
    Task { @concurrent in
        let ns = m.withLock { $0 }
        ns.name = "fred"
    }
}

It seems to me that returning $0 from the withLock closure should produce some sort of warning. The closure is -> sending Result, and if I understand sending correctly, we shouldn't be allowed to send $0 while still holding onto a reference to it.

So either there's something missing in the compiler (Swift 6.3), or in Mutex, or there's something missing in my understanding.

4 Likes

I believe @stephencelis called this out recently as a regression. A previous version of the compiler did correctly catch this case.

1 Like

Your understanding aligns with mine. This looks like a bug to me.

3 Likes

I am taking a look at it.

3 Likes

Could you also take a look at this issue: [RBI] Capturing and returning non-Sendable values in closures can cause data races · Issue #87918 · swiftlang/swift · GitHub

I believe there's already at least one GitHub issue for this.

1 Like