Let's consider following example:
class MyList<T> {
T add(T v) {return null;}
T get(int i) {return null;};
}
class ClassA { }
class ClassA1 extends ClassA { }
public class Test62 {
public static <T> MyList<T> foo(MyList<? extends T> list1, MyList<? extends T> list2) {
return null;
}
public static void main(String argv[]) {
foo(new MyList<MyList<ClassA1>>(), new MyList<MyList<? super ClassA>>()).get(0).add(new ClassA1());
}
}
it should compile, but actually it fails on JDK9b47 with following error:
D:\langworks\smalltests2\src\Test62.java:15: error: incompatible types: ClassA1 cannot be converted to CAP#1
foo(new MyList<MyList<ClassA1>>(), new MyList<MyList<? super ClassA>>()).get(0).add(new ClassA1());
^
where CAP#1 is a fresh type-variable:
CAP#1 extends Object from capture of ? extends Object
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
According to my understanding it should compile because:
1. As a result of reduction during type inference following bounds are created:
MyList<ClassA1> :< T, MyList<? super ClassA> :< T
2. As a result of resolution T is instantiated as:
lub(MyList<ClassA1>, MyList<? super ClassA>)
3. The result of this lub should be:
MyList<lcta(ClassA1, ? super ClassA)>
4. jls-4.10.4-210-D.6-C states:
lcta(U, ? super V) = ? super glb(U, V) (jls-4.10.4-210-D.6-C)
thus:
T =
MyList<lcta(ClassA1, ? super ClassA)> =
MyList<? super glb(ClassA1, ClassA)> =
MyList<? super ClassA1>
5. For this reason the type of foo(...) invocation is:
capture of MyList<MyList<? super ClassA1>>
6. The type of invocation of ...get(0) is:
capture of MyList<? super ClassA1> is MyList<CAP#1> where
ClassA1 :< CAP#1
7. Thus the formal parameter type when invoking ...add(...) is:
CAP#1, where ClassA1 :< CAP#1
8. ClassA1 is a subtype of #CAP1 for this reason passing new ClassA1() as actual argument should be Ok.