16

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.

Elias Vasylenko
  • 1,524
  • 11
  • 21
  • I may take a closer look at this problem later; but off the top of my head, JLS#4.9 seems quite problematic. I once asked Dan Smith and he said this area is poorly specified. – ZhongYu Jun 11 '15 at 19:30
  • I agree with your interpretation. I posted the question to compiler-dev: http://mail.openjdk.java.net/pipermail/compiler-dev/2015-June/009604.html – ZhongYu Jun 11 '15 at 23:41
  • I'm also beginning to agree this is iffy. I think you should unaccept my answer, at least the way it is now. – Radiodef Jun 12 '15 at 00:01
  • Maurizio's response - http://mail.openjdk.java.net/pipermail/compiler-dev/2015-June/009621.html – ZhongYu Jun 24 '15 at 12:42
  • Dan Smith - https://bugs.openjdk.java.net/browse/JDK-8054937 – ZhongYu Jun 29 '15 at 22:14
  • Thanks for the discussion and interest from everyone, much appreciated! Very interested in how the spec might evolve in the future here, as touched upon in Maurizio's response. Cheers. – Elias Vasylenko Dec 07 '15 at 15:30
  • 1
    Can you answer your own question and accept it as a correct answer? Otherwise it will be shown as unanswered and will attract more people who want to help. In any case, what you found out deserves the reputation points of an accepted answer :) – Maurice Müller Jun 10 '16 at 10:31

1 Answers1

0

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.

Elias Vasylenko
  • 1,524
  • 11
  • 21