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.
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
.
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
-