SR-14064: Accessing Static Member on Downcast Type not Calling Overridden Implementation

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.

1 Like