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.
- csr of
-
JDK-8357653 Inner classes of type parameters emitted as raw types in signatures
-
- In Progress
-
- relates to
-
JDK-8030746 4.10: Define subtyping for inner classes of parameterized types
-
- Open
-
-
JDK-8357472 NPE in Types.containsType for type variable used as a qualifier
-
- In Progress
-