I'm not sure if this rises to the level of a bug, or if it's just slightly off, or is working as intended. Consider a protocol extension defined like this:
protocol P {
var isTrue: Bool { get set }
}
extension P where Self: AnyObject {
func setTrue(_ value: Bool) {
self.isTrue = value // <- error: "Cannot assign to property: 'self' is immutable"
}
}
In one sense, this seems right because P is not class-constrained, and the function is not marked mutating. OTOH, it seems wrong, because the function is declared in an extension that "knows" that Self is a reference type.
Now let's try to "fix" this by marking the function as mutating:
extension P where Self: AnyObject {
mutating func setTrue(_ value: Bool) {
self.isTrue = value
}
}
class A: P {
var isTrue = false
}
let a = A()
a.setTrue(true) // error: "Cannot use mutating member on immutable value: 'a' is a 'let' constant"
The type of a is statically known to the compiler to be class A, which means the error message is at least misleading, but more plausibly flat out wrong.
Is there a bug here somewhere, or is this what should be happening?
The fact that the class constraint is not inferred with a Self: ClassType constraint is going to be fixed by my PR shortly (see #27057). I don't think it will fix the above issue though (but feel free to file a bug if you think it should be fixed as well).
In the meantime, you need to either mark the setter as nonmutating or move the AnyObject constraint to the protocol directly.