United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-7062745 : Regression: difference in overload resolution when two methods are maximally specific

Details
Type:
Bug
Submit Date:
2011-07-05
Status:
Resolved
Updated Date:
2011-12-07
Project Name:
JDK
Resolved Date:
2011-09-02
Component:
tools
OS:
generic
Sub-Component:
javac
CPU:
unknown
Priority:
P3
Resolution:
Fixed
Affected Versions:
7
Fixed Versions:
7u2 (b06)

Related Reports
Backport:
Relates:
Relates:

Sub Tasks

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
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.
                                     
2011-07-05
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).
                                     
2011-07-05
WORK AROUND

Insert a cast, as follows:

      Number n = ((A)ab).getList().get(1); //ok
                                     
2011-07-05
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.
                                     
2011-07-05
SUGGESTED FIX

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



Hardware and Software, Engineered to Work Together