Community
Participate
Working Groups
Created attachment 89534 [details] Sample code showing the problem. Build ID: M20070921-1145 Steps To Reproduce: 1. Compile code sample in eclipse, works 2. Compile using sun jdk1.5.0_06 compiler, fails 3. Error is: .\TestUpCast.java:19: incompatible types found : java.util.List<testcases.TestUpCast.B> required: java.util.List<testcases.TestUpCast.A> List<A> a = moreGeneric(b); ^ 1 error More information: Following class produces the error. package testcases; import java.util.ArrayList; import java.util.List; public class TestUpCast { public static <B, E extends B> List<B> moreGeneric(List<E> list) { List<B> result = new ArrayList<B>(); result.addAll( list ); return result; } class A {} class B extends A {} public static void main( String[] args ) { List<B> b = new ArrayList<B>(); List<A> a = moreGeneric(b); } } It seems like eclipse uses information from the calling context to resolve generic parameter B, where the sun jdk does not. Changing moreGeneric's signature to public static <B, E extends B> List<B> moreGeneric(Class<B> class, List<E> list) does work for sun as it then can figure out what B should be (the class is supplied in the call). I am not sure, but suspect eclipse supports some 1.6 features here. Settings for eclipse are to use the Java 1.5.0_06 JDK with Java 5.0 compliance (all other values default from the installed JDK). I would expect the eclipse compiler to behave the same as sun's.
reproduced with HEAD
When inferring generic method arguments, the compiler has to use contextual information from argument types, expected type etc... Inference performs in 2 steps: JLS 15.12.2.7 and JLS 15.12.2.8 (if previous did not solve the problem entirely). For clarity purpose, I renamed type param B into D (since name is confusing with member type B). Here it is (this doesn't change the behavior observed): import java.util.ArrayList; import java.util.List; public class TestUpCast { public static <D, E extends D> List<D> moreGeneric(List<E> list) { List<D> result = new ArrayList<D>(); result.addAll( list ); return result; } class A {} class B extends A {} public static void main( String[] args ) { List<B> b = new ArrayList<B>(); List<A> a = moreGeneric(b); } } Stage 1 - According to 15.12.2.7, inference is going to be fed with invocation arguments, i.e. inject the following constraints: List <B> << List<E> which yields E == B This leaves D unbound, hence need to involve more inference. Stage 2 - According to 15.12.2.8, inference now considers expected type and bounds of type variables, i.e. inject the following constraints: List<A> >> List<D> B << D which yields D == A So in the end, our behavior looks correct, and I would rather question javac's behavior.
fyi - javac 1.7.0-ea-b24 agrees with us Closing as invalid. This is a javac bug.
Added GenericTypeTest#test1292-1293
Erratum, tests are Added GenericTypeTest#test1291-1292
Verified for 3.4M6 using I20080324-1300.