FULL PRODUCT VERSION :
java version "1.7.0_65"
Java(TM) SE Runtime Environment (build 1.7.0_65-b19)
Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Windows 8 64-bit: Microsoft Windows [Version 6.2.9200]
Originally discovered on Ubuntu, JDK 7u45 (box not accessible at the time)
EXTRA RELEVANT SYSTEM CONFIGURATION :
Nothing relevant (pure compiler bug)
A DESCRIPTION OF THE PROBLEM :
The generic type inference seems to break down in the example code below. When a class is declared as generic with a bound on the type parameter and also implements an interface with the same parameter, the bound should also apply to the interface. Succinctly, if class C<T extend B> implements I2<T>, then C<?> should be assignable to I2<? extends B>, since the parameter is known by definition to extend B. Naturally, if I2<T> extends I1<T> as well, then C<?> should be assignable to I1<? extends B>.
The compiler inference does work for this case (as evidenced by the test3() call), but seems to break down when this exact case occurs in a generic type parameter instead. In particular, the compiler fails to verify that List<C<?>> is a subtype of List<? extends I1<? extends B>> during method invocation conversion. Oddly enough, the compiler is okay with the conversion through an intermediate type List<? extends I2<? extends B>>, which is correct, but seems to limit an arbitrary bound on the supertype type-search.
Linked original discussion: http://stackoverflow.com/questions/24817306/java-bounded-generics-type-inference-bug-method-invocation-jls-15-12-2-7
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile the following code with
javac Main.java
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The code compiles correctly.
ACTUAL -
The compilation fails with the error below.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
Main.java:12: error: method test2 in class Main cannot be applied to given types;
test2((List<BoundedI2<?>>) null);
^
required: List<? extends Interface1<? extends Bound>>
found: List<BoundedI2<?>>
reason: actual argument List<BoundedI2<?>> cannot be converted to List<? extends Interface1<? extends Bound>> by method invocation conversion
1 error
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.util.List;
public class Main {
interface Interface1<T> {}
interface Interface2<T> extends Interface1<T> {}
static class Bound {}
interface BoundedI1<T extends Bound> extends Interface1<T> {}
interface BoundedI2<T extends Bound> extends Interface2<T> {}
public static void main(String[] args) {
test((List<BoundedI2<?>>) null);
test2((List<BoundedI2<?>>) null);
test3((BoundedI2<?>) null);
}
public static void test(List<? extends Interface2<? extends Bound>> list) { test2(list); }
public static void test2(List<? extends Interface1<? extends Bound>> list) {}
public static void test3(Interface1<? extends Bound> instance) {}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
The compiler is okay if the type BoundedI2<?> is declared with the redundant bound specification BoundedI2<? extends Bound>, though the latter adds quite a bit of unnecessary verbosity if the type is widely used and if the bound in question is nontrivial to specify.