I've come across some behavior in default @MainActor isolation targets that I can't explain. Consider the following protocol defined in a @MainActor module, and an actor that conforms to the protocol:
// Default main actor isolation module
protocol P {
func perform() async
}
actor A: P {
func perform() async {}
}
I was surprised this compiled. It seems that P is effectively @MainActor P, and so an arbitrary actor shouldn't be allowed to conform. And if I explicitly make P into @MainActor, that is what happens:
@MainActor protocol P {
func perform() async
}
actor A: P { // ๐ Actor 'A' cannot conform to global-actor-isolated protocol 'P'
func perform() async {}
}
Now the first code snippet only compiles when perform is async, and I think for that reason there isn't really a soundness hole. If you were to erase an instance of A to an any P and then invoke perform(), you would be forced to await and so isolation to the actor can be guaranteed. If the code compiled with perform() being non-async, then there definitely would be a soundness problem since you would be able to invoke perform() synchronously from a main actor context. So luckily that is not the case.
But things get weird when you move A to a separate module:
// Module P, default main actor isolation
protocol P {
func perform() async
}
// Module A, default isolation doesn't matter
import P
actor A: P::P { // ๐ Actor 'A' cannot conform to global-actor-isolated protocol 'P'
func perform() async {}
}
Now I do get the diagnostic I expected in the first code snippet. So I'm not sure how to make sense of this. Is this mentioned in any of the proposals about default main actor isolation?
Part of me thinks that the first code snippet should be rejected since I thought a protocol P in a main actor module would be equivalent to @MainActor protocol P, but that does not seem to be the case. But then the other part of me could accept that the first code snippet is legit because there is not a real soundness hole.
So, does this code work as expected, or is there something missing from default main actor isolation?