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

Javac converts <? super FormalUpperBound> to <FormalUpperBound> against jls.

XMLWordPrintable

      ADDITIONAL SYSTEM INFORMATION :
      Windows 10 1903
      openjdk 14 2020-03-17
      OpenJDK Runtime Environment (build 14+36-1461)
      OpenJDK 64-Bit Server VM (build 14+36-1461, mixed mode, sharing)

      A DESCRIPTION OF THE PROBLEM :
      Javac allows a type conversion which is very reasonable, but which is forbidden by JLS.
      This report recommends JLS to be fixed. (But not sure whether it is a bug of JLS or of javac, but surely it is a bug.)
      (by the way, why can't I choose Component=specification Subcomponent=language?)

      public class MyClass <X extends Runnable> {}

      MyClass<? super Runnable> x = null;
      MyClass<Runnable> y = x; //allowed by javac, forbidden by jls.

      Yes, this conversion is very reasonable. Should be allowed. But unfortunately, jls is forbidding it.

      Jls 5_2 says, in short, a ref-to-ref assignation is allowed basically iff it is a widening reference conversion.
      A widening reference conversion exists if the src is subtype of the dst, as specified in 5_1_5.
      Subtyping among ref types is defined in 4_10_2. To justify the above assignation, <Runnable> must contain
      <CAPTURE>, where CAPTURE is a fresh variable whose lower bound and upper bound both are Runnable.
      But the definition of 'containing' in 4_5_1 states that a type only contains itself. Unless jls introduces something like equivalence of types or specifies a condition based on which two apparantly different types can be treated as the same thing, <Runnable> does not contain <CAPTURE>. The conversion is wrong.

      javac seems to be regarding MyClass<? super Runnable> and MyClass<Runnable> as the same. Moreover, List<MyClass<? super Runnable>> and List<MyClass<Runnable>> as the same. (Each can be converted into the other.) When do these equations occur?

      Whoa! The rule is far from trivial! See another example I've just found!

      class Second <X extends Runnable, Y extends X> {}
      <U extends Thread> void f() {
          List<Second<U, ? super Thread>> c0 = null;
          List<Second<U, U>> c1 = c0;
          List<Second<U, ? super Thread>> c2 = c1;
      }

      Surprisingly, c1 = c0 is allowed but c2 = c1 is a copile-time error! What is going on?
      4_5_1 says two types have containing relation between them only through "T and Second<U, U> can be 'T' at the same time, but when c2 = c1, not? Now I am thinking jls is really buggy around this.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      If you are curious about my second example, compile the following and see how it will fail. Then comment the line c2 = c1 out, compile, and see that it will succeeds. No need to execute it.


      ---------- BEGIN SOURCE ----------
      import java.util.*;

      public class JlsSux{

      class First <X extends Runnable> {}
      class Second <X extends Runnable, Y extends X> {}


      public static void main(String... args){
      List<First<? super Runnable>> a0 = null;
      List<First<Runnable>> a1 = a0;
      List<First<? super Runnable>> a2 = a1;
      }


      static <U extends Thread> void u(){
      List<Second<U, ? super Thread>> c0 = null;
      List<Second<U, U>> c1 = c0;
      List<Second<U, ? super Thread>> c2 = c1;
      }

      }
      ---------- END SOURCE ----------

      FREQUENCY : always


            Unassigned Unassigned
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: