Solution (source code)

= Solution

Ignoring predefined ancestors as permitted, the <Scala trait linearizations> are
$$
\boxed{D1,B2,B1,A\qquad\text{and}\qquad D2,B1,B2,A.}
$$
A `super` call in a <trait> continues to the next applicable implementation in the receiver's <Scala trait linearization>. It is not permanently bound to the parent named when that <trait> was declared.

For `d1.h`, enter `B2.h`. Its `super.g` reaches `B1.g`, and that method's `super.f` reaches `A.f`. For `d2.h`, enter `B1.h`; its `super.g` reaches `B2.g`, whose `super.f` again reaches `A.f`. Therefore the two output lines are
``
h in B2, g in B1, f in A
h in B1, g in B2, f in A
``
The shared ancestor `A` occurs once in each <Scala trait linearization>, after the two specialized <traits>. This accounts for the final `f in A` in both lines.