I stumbled over something in my code that compiles just fine in Swift 6, but I think it really shouldn't.
Here is a stripped down version:
protocol P {
func doIt()
}
protocol F: AnyObject {
var x: Int { get set }
}
class NonSendable: F {
var x = 0
}
extension NonSendable: P {} // is this a bug?
extension F where Self: Sendable {
func doIt() {
Task { print(self.x) }
x += 1
}
}
func test() {
let f: P = NonSendable()
f.doIt()
}
I think the where Self: Sendable combined with the separate protocol conformance extension is tripping up Swift.
Am I missing something super clever that the compiler knows, or is this a bug?
Definitely doesn't seem like it. You could try testing on a recent development toolchain and see if it's a bug that's been fixed, otherwise you may want to report it, if one of the Swift devs doesn't chime in in the meantime.
It looks like a bug in availability checking. Here is a minimal test case (note that it doesn't involve Sendable):
public protocol M {}
public protocol P {
func doIt()
}
public class NonSendable: P {
}
@available(*, unavailable)
extension NonSendable: M {}
extension P where Self: M {
public func doIt() {}
}
The choice of the doIt() witness depends on the unavailable conformance to M, but we just miss this case in availability checking. If you comment out the extension to M entirely, we diagnose:
14 | public func doIt() {}
| `- note: candidate would match if 'NonSendable' conformed to 'M'
Your code doesn't declare a Sendable conformance though, but with Sendable specifically, even if your type doesn't conform to it explicitly, the compiler will essentially synthesize the equivalent of that unavailable conformance on the extension. (That's what allows the -swift-version 5 mode to emit warnings about Sendable.)