The standard output is three lines:
A
2.3
B
This is program output, excluding any interactive interpreter's display of returned values. The calls a.m(1) and b.m(5.6) compute squares without printing. In A, the concrete m(Int) wins over the generic method at argument 1; the string and 2.3 use m[T] and print their arguments.
For b: B[Any], the class type parameter has already become Any, so the two alternatives are m(Any) and m(Double), rather than a method with its own freely inferred type parameter. The Double alternative is more specific. It accepts 4 by numeric widening, so b.m(4) computes 16.0 without printing; b.m("B") prints B; b.m(5.6) computes a square without printing. These are applications of the Scala 2.11 method overloading rules, with the arithmetic return values discarded in statement position.[ref]
The output is 1, with no newline. The Any in class B[Any] and class C[Any] is a type parameter name that shadows the standard type scala.Any inside those class bodies. Renaming it to T preserves the program's meaning. Thus new B[Int] has an inherited m(Double) and its own m(Int); obj1.m(1) selects the latter and prints 1. The call with 2.3 can only use the inherited m(Double), which computes a sum without printing.
For new C[Any], the supplied type argument is the standard scala.Any, so the overloads are m(Double) and m(scala.Any). The more-specific Double alternative accepts 4 by numeric widening, and accepts 5.6 directly. Both return sums without printing. A computed result is not automatically screen output. This reasoning uses the Scala 2.11 overload conventions of Question 5(a); type erasure does not turn either class's generic-argument overload into an method overriding of m(Double).
The output is BADDCD, without a newline. Method overloading chooses a signature using static types, including the instantiated class type parameter; numeric widening can make a Double parameter applicable to an Int argument.
  • a.m(o1) chooses m(Int), which is more specific than the polymorphic method: B.
  • a.m(o2) uses m[Double](Double): A.
  • b.m(o1) compares m(Any) and m(Double). Int can widen to Double, and Double is more specific than Any: D.
  • b.m(o2) chooses m(Double) over m(Any): D.
  • c.m(o1) compares the instantiated m(Int) with m(Double) and chooses m(Int): C.
  • c.m(o2) can use only m(Double): D.
The third call is the subtle one: the existence of m(Any) does not prevent the more specific numeric overload from winning. These are Scala 2 method overloading and numeric widening rules. [ref]
The compiler's methodSig, typesFromOverridden, and assignTypeToTree use an inherited return type as an expected type when checking an overriding method body. This permits numeric widening of a literal in that body while still inferring more specific reference result types where appropriate.