JDK-7062745 : Regression: difference in overload resolution when two methods are maximally specific
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 7
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: unknown
  • Submitted: 2011-07-05
  • Updated: 2011-12-07
  • Resolved: 2011-09-02
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7 JDK 8
7u2 b06Fixed 8Fixed
Related Reports
Relates :  
Relates :  
Description
This program no longer compiles in JDK 7:

import java.util.*;

interface A { List<Number> getList(); }
interface B { List getList(); }
interface AB extends A, B {}

class Test {
   void test(AB ab) {
      Number n = ab.getList().get(1); //error here
   }
}


OUTPUT:

Test.java:17: error: incompatible types
        Number n = ab.getList().get(1);
                   ^
  required: Number
  found:    Object
1 error

Comments
SUGGESTED FIX A webrev of this fix is available at the following URL: http://hg.openjdk.java.net/jdk7u/jdk7u-dev/langtools/rev/e296280b4e77
26-08-2011

EVALUATION This is a manifestation of a spec bug. See 7034913. The spec does not define "most specific return type," and if it defined it in terms of "return-type-substitutable," the answer would be ambiguous: A.get is RTS for B.get, but also B.get is RTS for A.get. I've had to think about RTS a lot in my work on SAM types. I think the right answer, as I say in my last 7034913 comment, is to choose the logical return type by preferring proper subtypes over unchecked subtypes. But we also need to think about how erased signatures might interact with the choice.
05-07-2011

WORK AROUND Insert a cast, as follows: Number n = ((A)ab).getList().get(1); //ok
05-07-2011

EVALUATION Note that, on the other hand, this slightly modified example: import java.util.*; interface A {List<Number> getList();} interface B {ArrayList getList();} ///////////////// ArrayList instead of List interface AB extends A, B {} class Test { void test(AB ab) { Number n = ab.getList().get(1); } } Works correctly in JDK 7 (used to fail in JDK 6).
05-07-2011

EVALUATION The reason is that 'ab.get()' used to return Number and now returns Object. The problem is that the spec is a bit ambivalent on this point - it says that when two methods are most specific, the return type is choosen arbitrarily among the set of 'most specific' return type. Now, javac used to say that List<Number> is more specific than List - but the JLS is not crystal clear about what 'most specific return type' means. This bug has been introduced when another bug in this area has been fixed (7034019) - note that in that case, javac failed with a crash when determining the most specific return type between a generic and a non-generic method. This area needs to be clarified.
05-07-2011