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

Inner classes of type parameters emitted as raw types in signatures

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Unresolved
    • Icon: P4 P4
    • 26
    • tools
    • None
    • source
    • minimal
    • The changes in this CSR will generally result in previously rejected code to be accepted by javac. There might be some corner cases where this change might affect overload resolution.
    • Language construct
    • SE

      Summary

      A code that names an inner class is erroneously classified as raw and as a result is erroneously rejected.

      Problem

      In the example that follows, javac determines erroneously that getter has a raw type (G.Getter). The type of getter is deduced as the raw type Getters<T>.Getter which is clearly not, since T, the type parameter of Getters<T> is not omitted. javac thinks that G is raw and raises the Object cannot be converted to T message in the following example. In this example Getter is simply an inherited member from the supertype Getters<T>:

      static abstract class Getters<T> {
          abstract class Getter {
              abstract T get();
          }
      }
      
      static class Usage<T, G extends Getters<T>> {
          public T test(G.Getter getter) {
              return getter.get();       // incompatible types: Object cannot be converted to T
          }
      }

      Not looking into the bounds of G is a compiler bug.

      A symmetrical situation occurs when there is a type application either explicitly or implicitly qualified and the enclosing type is not fully recalculated, for example the compiler crashes in the following two snippets.

      class A<T> {
        protected class B<V> {}
      
        public static <T, M extends A<T>> void f(Object g) {
          @SuppressWarnings("unchecked")
          M.B<?> mapping = (M.B<?>) g;   // explicitly qualified type application
        }
      }
      class A<T> {
          class B<W> {
              public T rett() { return null; }
          }
      }
      
      class C extends A<String> {
          static class D {
              {
                  B<?> b = null;         // implicitly qualified type application
                  String s = b.rett();
              }
          }
      }

      The last examples are related to JDK-8357472.

      Solution

      javac has the necessary functionality to normalize qualified type paths. Taken from the comment in Attr:

      // class Tree<A> { class Visitor { ... } }
      // class PointTree extends Tree<Point> { ... }
      // ...PointTree.Visitor...
      //
      // Then the type of the last expression above is
      // Tree<Point>.Visitor.

      The compiler performs the necessary traversal while calculating the qualifying type path of PointTree.Visitor with the type Tree<Point>.Visitor. In that case PointTree is a concrete class. The solution fixes the cases where the prefix of the path is not only a concrete class but a type parameter with a bound. In our case the correct type is: Getters<T>.Getter. The corresponding issue appears in the visitor method for parameterized types, in Attr, as well.

      Specification

      We believe there are no changes needed in the specification but you can find linked the JDK-8030746; a currently open spec bug around the same area -- 4.10: Define subtyping for inner classes of parameterized types.

            abimpoudis Angelos Bimpoudis
            liach Chen Liang
            Chen Liang, Vicente Arturo Romero Zaldivar
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated: