It's not dynamic dispatch. It's a much simpler* shadowing. Let's jump onto your new code. P has only one definition of foo, the protocol requirement, while A has three:
- The unconstrained one (
foo), - The one constrained to
T == Int(bar), and - The one used for protocol conformance.
When you do A<Int>.foo, the compiler chooses the most specific one among the three, which is (bar). In fact, if the compiler doesn't know that T == Int, it can only choose among the first and the third ones, both of which are foo.
func x<T>(_: A<T>.Type) {
A<T>.foo()
}
x(A<Int>.self) // foo
Swift needs to be able to generate unspecialized function correctly. It needs to be able to generate a binary for my x(_:) function with unknown T, i.e. unspecialized x, which is usable by any x<T>, including x<Int>. That's why, inside x, the compiler can't use the second definition of foo.
As a rule of thumb, if you didn't write override, they are different, unrelated functions.
Covariance plays very little role here (A<String> and A<Int> are unrelated regardless of variance support). There are a lot of constraints going into the design around this area (not to mention there are actual bugs riddled around). Unfortunately, it leads to a somewhat complex behaviour.
That's a different one.
* Well, I said simpler, but the precise shadowing rule is elusive to even the most veteran. We did explore a lot of corners a while back, though I think we ended up running around in circle.