Capture conversion issue in Java, WRT reconciliation of JLS and actual JDK behaviour

388 views Asked by At

Given the following two class definitions:

class C1<T extends C1<T>> {}

class C2<U> extends C1<C2<U>> {}

Consider the following type declaration:

C1<? extends C2<String>> c;

This compiles fine in JDK-8u45, but if we examine the specification for capture conversion, it appears (to me) that this declaration should result in a compile time error.

In particular, the upper bound of the new type variable capture T#1 is given by glb(Bi, Ui[A1:=S1,...,An:=Sn]), where in this case Bi resolves to the wildcard bound C2<String> and Ui[A1:=S1,...,An:=Sn] resolves to C1<T#1>.

From this, glb(C2<?>, C1<T#1>) resolves to the intersection type C2<String> & C1<T#1>, which is invalid, because C2<String> and C1<T#1> are both class types, not interface types, but neither one of them is a subtype of the other.

This (apparent) rule violation is perhaps made more clear in the definition of the intersection type itself.

I'm sure it's not a bug and I'm just making some simple mistakes somewhere... If it is a bug, I hope it can be considered a bug in the JLS and not the JDK, such that I can expect to be able to safely emulate the behaviour...

Thanks for any help!

Edit: After talking with Radiodef yesterday I convinced myself that the issue (or one way of looking at it at least) is that C2<String> can effectively be thought of as a subtype of C1<T#1>, since T#1 can only ever be satisfied by C2<String> and so can be considered equal to it, but the containment and subtyping rules have no understanding of this relationship as written, and so the JLS will not recognise the subtype and should fail...

If you take the slightly more complex case of C1<? extends C2<?>> d;, though, it is more tricky. The problem is similar, but the intersection type which forms the upper bound on the capture comes out as C2<?> & C1<T#2>, where it doesn't seem a solution can be arrived at by the same reasoning as above.

1

There are 1 answers

0
Elias Vasylenko On BEST ANSWER

This question is answered best by Maurizio's response on compiler-dev.

(TL;DR javac is indeed out of alignment with the spec here, and the optimal solution probably lies somewhere between the two approaches)

An associated bug can be found here.

Many thanks to all who contributed to this answer.