= Solution
Apply <overload selection followed by dynamic dispatch>: <method overloading> chooses a signature from the receiver's <static type> and argument <static types>, then <dynamic dispatch> chooses an override of that signature using the receiver's <runtime type>. A `super` call selects the inherited implementation; a call on the <companion object> `B` uses that object's own methods.<Scala 2.11 expressions specification>[Static overload resolution; this and super]{ref}
The output, in order, is
``
f(x:X) in B
f(y:Y) in A
f(x:X) in A, g(x:X) in B
f(x:X) in ObjB, g(y:Y) in ObjB, h(y:Y) in B, h(z:Z) in C
f(y:Y) in C, m(a:A) in Y, k(x:X) in C
``
For `a.f(x)`, the argument's <static type> is `X`, selecting `f(X)`; the receiver's <runtime type> `B` selects `B.f(X)`. For `a.f(z)`, the receiver's <static type> `A` exposes only `f(X)` and `f(Y)`. The `Z` argument fits both, and `f(Y)` is more specific. `B` does not override that signature, so `A.f(Y)` runs. The additional overload `B.f(Z)` is invisible through `a`.
For `c.g(z)`, the inherited instance `B.g(X)` calls `super.f(x)`, which is `A.f(X)`. For `c.h(z)`, <method overloading> selects `C.h(Z)`. Its `super.h(z)` calls `B.h(Y)`, where the local parameter has <static type> `Y`. Consequently `B.g(y)` selects `g(Y)` on the <companion object>, whose only `f` signature is `f(X)`.
Finally, `c.k(x)` calls `x.m(this)`. The receiver `x` has <runtime type> `Y`, so <dynamic dispatch> enters `Y.m(A)`. Inside that method, `this` has <static type> `Y`, selecting `a.f(Y)`; the actual argument object is `c`, so <dynamic dispatch> reaches `C.f(Y)`. Therefore
$$
\boxed{\texttt{c.k(x)}\text{ produces }\texttt{f(y:Y) in C, m(a:A) in Y, k(x:X) in C}.}
$$
Back to article page