JDK-6932571 : Compiling Generics causing Inconvertible types
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 6,7-pool
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: generic,windows_7
  • CPU: generic,x86
  • Submitted: 2010-03-05
  • Updated: 2011-03-07
  • Resolved: 2011-03-07
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
7 b109Fixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
SYNOPSIS
Valid generic types leading to compilation problems.

OPERATING SYSTEM(S)
All Platforms.

FULL JDK VERSION(S)
Seen on all releases of Java 5.0, Java 5.0, Java 6.0 and Java 7.0

PROBLEM DESCRIPTION
javac fails to compile these below given valid generic classes.

TESTCASE:

Case-1:
public class TestGeneric2<T extends Comparable<? super T>> {
    public void test(T v) {
        Object obj = v;
        if (v instanceof Integer) {
           obj = Long.valueOf(((Integer) v).longValue());
        }
        System.out.println(obj.getClass().getName());
    }
}

Case-2:
public class TestGeneric3<T extends Comparable<? extends T>> {
    public void test(T v) {
        Object obj = v;
        if (v instanceof Integer) {
           obj = Long.valueOf(((Integer) v).longValue());
        }
        System.out.println(obj.getClass().getName());
    }
}


REPRODUCTION INSTRUCTIONS
javac fails to compile the above two cases.

FAILURE OUTPUT
/* Sun Java 1.5 and 1.6 gives
TestGeneric2.java:4: inconvertible types
found : T
required: java.lang.Integer
if (v instanceof Integer) {
^
TestGeneric2.java:5: inconvertible types
found : T
required: java.lang.Integer
obj = Long.valueOf(((Integer) v).longValue());
^
2 errors
*/

javac compiles when the above generic classes are defined as "TestGeneric2<T extends Comparable<?>>"

Comments
SUGGESTED FIX A webrev of this fix is available at the following URL: http://hg.openjdk.java.net/jdk7/tl/langtools/rev/995bcdb9a41d
23-08-2010

EVALUATION The Types.rewriteQuantifiers() routine should be cleaned up in order to perform more regularly and deal with circularities induced by recursive bounds in type-var declarations. For example, when a class type of the kind List<X> is being rewritten (where X is a type-variable whose bound is Foo<X>), the compiler will simply rewrite List<X> as List<?>. This means that the rewrital process now is able to 'give up' in problematic (and circular) cases; this will avoid most of the problems we had in the past, where we had spurious captured type-variables coming form recursive bounds being unreplaced after a rewrital round, and, consequently, making the disjointType routine to fail. Another bit of work is inside Types.notSoftSubtype. Again, in this case the compiler needs to access the upper bound of a type variable which can contain itself recursively - the recursion is now truncated because the bound is 'normalized' (this is done by calling rewriteQuantifiers). All those changes make those routines less strict and more conservative. This allows javac to reject less program, because less types are now seen as provably distinct (that is, javac only tries to guess in simple cases, which seems a sensible thing to do). There's the remote possibility that previously rejected program will now be accepted with an unchecked warning (which is what would be required by the JLS in the first place). However I never encountered such an issue in javac reg tests, and compiler jck tests.
23-08-2010

WORK AROUND Add cast to unbounded wildcard: public class TestGeneric2<T extends Comparable<? super T>> { public void test(T v) { Object obj = v; if (((Comparable<?>)v) instanceof Integer) { obj = Long.valueOf(((Integer)(Comparable<?>)v).longValue()); } System.out.println(obj.getClass().getName()); } } public class TestGeneric2<T extends Comparable<? super T>> { public void test(T v) { Object obj = v; if (((Comparable<?>)v) instanceof Integer) { obj = Long.valueOf(((Integer)(Comparable<?>)v).longValue()); } System.out.println(obj.getClass().getName()); } }
18-03-2010