Community
Participate
Working Groups
Given the following class declarations: class SelfType<T extends SelfType<T>> class SuperType extends SelfType<SuperType> class SubType extends SuperType and the following method declaration: public static <T extends SelfType<T>> List<T> makeSingletonList(T t) The following method-call compiles: makeSingletonList(new SuperType()); But this one does not: makeSingletonList(new SubType()); The error given is: Bound mismatch: The generic method makeSingletonList(T) of type TestGenerics is not applicable for the arguments (TestGenerics.SubType) since the type TestGenerics.SubType is not a valid substitute for the bounded parameter <T extends TestGenerics.SelfType<T>> See corresponding bug in sun's javac: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6278587
Created attachment 22429 [details] Full source code that exhibits compilation errors Full source code for the examples in the original description, along with some others along the same lines. This fails with 3.1M7 and 3.1RC1.
Thanks for the testcase. Is it really copyrighted ?
That's just a standard header that I have eclipse configured to insert in all new .java files; you can probably safely ignore it in this case, since there's nothing proprietary or specific to my company in there. :)
Remember that inference performs in 2 passes. One pass using invocation arguments (15.12.2.7), and if some variables are still unresolved it will consider return types and variable formal bounds in a second iteration (15.12.2.8). Now let's look at each case: /*making lists of super types works fine ...*/ makeSingletonList(new SuperType()); This one is fine. T gets inferred to be 'SuperType' in first pass, no further inference needed, and T boundcheck is happy, since: SuperType <: SelfType<SuperType> per construction. List<SuperType> lsup = makeSingletonList(new SuperType()); Fine as well, though some expectation is set on return type, it isn't used since second pass is unneeded. Same resolution as above. /*but we can't make a list of sub types; seems weird ...*/ List<SubType> lsub = makeSingletonList(new SubType()); //ERROR Error. First pass is all you need. It infers T to be 'SubType'. But T boundcheck fails, since: SubType is not compatible with: SelfType<SubType> as mandated by T extends SelfType<T>. SubType is only compatible with: SelfType<SuperType> like List<String> is not compatible with List<Object>. /*can't even call it w/o assigning the return value:*/ makeSingletonList(new SubType()); //ERROR Same as above. As said already first pass on arguments is all you needed anyway. To be continued...
Reposting to improve line wrapping. Remember that inference performs in 2 passes. One pass using invocation arguments (15.12.2.7), and if some variables are still unresolved it will consider return types and variable formal bounds in a second iteration (15.12.2.8). Now let's look at each case: /*making lists of super types works fine ...*/ makeSingletonList(new SuperType()); This one is fine. T gets inferred to be 'SuperType' in first pass, no further inference needed, and T boundcheck is happy, since: SuperType <: SelfType<SuperType> per construction. List<SuperType> lsup = makeSingletonList(new SuperType()); Fine as well, though some expectation is set on return type, it isn't used since second pass is unneeded. Same resolution as above. /*but we can't make a list of sub types; seems weird ...*/ List<SubType> lsub = makeSingletonList(new SubType()); //ERROR Error. First pass is all you need. It infers T to be 'SubType'. But T boundcheck fails, since: SubType is not compatible with: SelfType<SubType> as mandated by T extends SelfType<T>. SubType is only compatible with: SelfType<SuperType> like List<String> is not compatible with List<Object>. /*can't even call it w/o assigning the return value:*/ makeSingletonList(new SubType()); //ERROR Same as above. As said already first pass on arguments is all you needed anyway. To be continued...
+1 for RC3.
Will not address within RC3. Too risky. import java.util.*; public class X { static abstract class SelfType<T extends SelfType<T>>{ } static class SuperType extends SelfType<SuperType>{ } static class SubType extends SuperType{} static <T extends SelfType<T>> List<T> makeSingletonList(T t){ return Collections.singletonList(t); } static <T extends SelfType<T>,S extends T> List<T> makeSingletonList2(S s){ return Collections.singletonList((T)s); // #0 } public static void main(String[] args){ makeSingletonList(new SuperType()); // #1 - OK List<SuperType> lsup = makeSingletonList(new SuperType()); // #2 - OK List<SubType> lsub = makeSingletonList(new SubType()); // #3 - ERROR makeSingletonList(new SubType()); // #4 - ERROR makeSingletonList2(new SubType()); // #5 - ERROR lsup = makeSingletonList2(new SubType()); // #6 - OK lsub = makeSingletonList2(new SubType()); // #7 - ERROR makeSingletonList2(new SuperType()); // #8 - OK lsup = makeSingletonList2(new SuperType()); // #9 - OK } } Also our first discrepancy (#6) with javac got assessed to be a bug in javac (see javac bug). The remaining one (#8) is likely a bug in our land due. This is not critical for 3.1, however worth considering for some 3.1.1 update.
Created attachment 23536 [details] Patch for ParameterizedGenericMethodBinding
Patch has 2 parts in generic method inference. 1. in absence of explicit expected return type (from assignment conversion) Object should be picked up. Old code was using the upperbound instead when return type is a type variable, which is redundant with what the inference will do anyway. Simply removed upper bound access (as mandated by the spec). This part is trivial, and removes unnecessary complexity (cleanup). 2. our inference on type parameter formal bounds was performing backwards: Ti << Bi, instead of Bi >> Ti as described in the spec. Fix is to make it consistent with the spec, but still preserve Ti << Bi in cases type parameter got resolved, to exploit possible type information for building constraints. This behavior matches javac expectation as well (though disagrees slightly with the spec).
Created attachment 23598 [details] Patch for GenericTypeTest
Fixed in 3.1 maintenance branch
Verified in 3.2 M1 with build I20050808-2000.
Verified using M20050923-1430 for 3.1.1