Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8073129

The result of lub(C<U>, C<? super V>) is incorrect

XMLWordPrintable

      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.

            dlsmith Dan Smith
            grakov Georgiy Rakov (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated: