Possible Java compiler bug! Program does not compile with some compilers
Asked Answered
O

3

5

First, a little background (or skip down a little if not interested). I'm irritated and confused! This should be a pretty simple use case, and indeed my code has been compiling just fine with the Eclipse JDT compiler, so until now I've been configuring Maven to make sure to do this. It's been bothering me too much though that it doesn't compile with the Oracle JDK and OpenJDK, as I thought it may actually have been a problem with my code, so I've looked into it again.

I thought perhaps that the bug was in the JDT compiler for allowing it to compile, not the Oracle JDK and OpenJDK for not allowing it, both of which I've also tested this with. The original code in question was considerably more complicated, so it was much more difficult for me to see where the problem was, and in fact I was very surprised to see the extent to which this could be reduced whilst still not compiling.

Either the Eclipse JDT compiler or the Oracle JDK and OpenJDK have a pretty major (imho) bug.

TL;DR

This is a fairly minimal representation of the code in question. (The type bound of Anything can be replaced by any interface and the compiler behaviour won't change):

public class Bug<X extends Property<?, ?> & Anything> {
}

interface Property<C, S extends C> extends PropertyConst<C> {
    @Override
    public S get();
}

interface PropertyConst<C> {
    public C get();
}

interface Anything {
}

To summarise, I think this should compile just fine, but the Oracle JDK 7 & 8 and OpenJDK 7 disagree. It does compile for me using Eclipse Juno.

When compiled with either of those compilers the code above gives something like the following error, but works just fine with the JDT compiler:

Bug.java:3: error: types PropertyConst<?> and Property<?,?> are incompatible; both define get(), but with unrelated return types
public class Bug<X extends Property<?, ?> & Anything> {
                 ^
1 error

This makes no sense. The return types are obviously related because one of the two methods referenced necessarily frickin' overrides the other. I'm pretty much 99% confident that this should work, in fact the only reason that last 1% is missing is that it's just too basic a use of generics for this to not have been spotted, and yet I found no bug report relating to it. (Admittedly I didn't look to hard because http://bugs.sun.com/ is just the worst. Can you even filter keyword search results by whether a bug report is still open? Ugh.)

The most confusing part for me is that it compiles just fine when you remove the type bounding for Anything on X, even though the extra interface has nothing to do with the error.

Can anybody put my mind at rest? Anyone know of a bug report which exists for this, or has had experience with it before and can tell me what the problem is? If I don't get any conclusive answers I'll file some bug reports.

Edit:

A couple of people have pointed out that I had a forward reference error with <S extends C, C>. Don't know why I wasn't getting this error, it even compiled in Eclipse with the JDT...

Anyway, it still doesn't compile for me with OpenJDK 7 or Oracle JDK 7 / 8, so I modified the question to remove the issue.

Edit 2:

A quick check confirms that this sort of forward reference is now legal in Java 7. As it should be!

Edit 3:

I've posted bug reports on http://bugs.sun.com/. I'll post links here if/when they're accepted.

Obau answered 21/11, 2012 at 20:47 Comment(12)
The problem is ? does not equal ?Handset
Did you run your tests on java 6 or 7?Cistaceous
Do you still have error, if you remove Anything interface ?Rondure
Did you also notice the "Illegal Forward Reference" error in eclipse? (see also this question) Invert the arguments on Property's generic declarationHandset
@Handset - the problem is it doesn't compile, but I think it should!Obau
@Cistaceous - 7, though I've even tried compiling with Oracle JDK 8, still doesn't compile there.Obau
@Vash - No error If I remove Anything, though the error remains if you replace it with any other interface. I'll try to make all these points clearer in the question, thanks for the feedback everyone.Obau
@Handset I didn't, is that even still in the spec? No error for it and definitely compiles in the JDT, seems like too obvious a feature for them to accidentally leave out... If I swap them round it still doesn't work anyways, I'll change the order in the question to make sure that's clear though, thanks :)Obau
Works OK for me on Windows 7, JDK 1.7.0_07, Eclipse Juno I20120608-1400 and JDT/PDE 3.8.0.v20120525Elis
@msandiford - It works for me too using the Eclipse compiler, could you please verify that you have specifically used the Oracle JDK or the OpenJDK, and that it compiles for one of those? Thanks for the feedback :)Obau
OK, read question again. Works here with JDK 1.5.0_10 (need to remove interface @Override), 1.6.0_27. Fails with 1.7.0_07 and 1.7.0_09.Elis
@msandiford - Awesome, thanks for the confirmation :). Will submit a bug report. Not gonna do it right now though, it's like 22:40 and I've not even eaten yet today...Obau
I
2

It's apparently a javac bug you should report. You probably have better luck asking on one of open jdk mailing lists. But it's Thanksgiving so ...

This is not a basic usage of generics though, it's quite complicated.

Ichthyolite answered 21/11, 2012 at 21:29 Comment(3)
Thanks for the vote of confidence! I just wanted to ask here first to save myself from embarrassment by filing a silly bug report... I'll make sure to file one at some point though. And you should see some of my other abuses of generics haha... It's criminal sometimes. I know that's probably not a good thing, but it's a personal project and I'm enjoying myself ;). If this bug is confirmed I actually might have a few others to report too, this is far from the only place the JDT disagrees with Oracle/OpenJDK. Yea I forgot about TG, I live in the UK.Obau
P.S. I'll mark this answer as correct if I don't see any disagreement over the next day or so.Obau
Meh, already looks pretty clear cut at this point, so marked as answered. Thanks for the help, and thanks everyone else who tested too :)Obau
H
0

I've entered your sample into my Eclipse Indigo (3.7.1) and it complained immediately about declaration of Property interface.

Illegal forward reference to type parameter C

And for the line public S get();

The return type is incompatible with PropertyConst.get()

Changing declaration of Property to this

interface Property<C, S extends C > extends PropertyConst<C> {
    @Override
    public S get();
}

fixed both errors, and compiles both in JDT and Sun's 1.6 compiler

Handling answered 21/11, 2012 at 21:5 Comment(2)
Cheers, doesn't fix the error for me though in Eclipse Juno, Sun 1.7 or 1.8, or OpenJDK.Obau
Sorry that comment was misleading - it compiled fine even with the forward reference in Eclipse Juno...Obau
K
0

Didn't try it out, but in

public class Bug<X extends Property<?, ?> & Anything> {

there is no restraint on both ?'s. One would need something like:

public class Bug<C, X extends Property<C, ? extends C> & Anything> {
Kristiankristiansand answered 21/11, 2012 at 22:53 Comment(1)
You shouldn't need that afaiu, the existing bounds as specified in the Property interfaces definition should be carried forward implicitly in this case. Property<?, ?> doesn't mean that Property can be parametrised with literally anything, just that we don't care about how it is parametrised here. The actual parametrisation of Property here will be verified for the type which is supplied to X when Bug is parametrised... Sorry for the awkward explanation, it's not easy to word this clearly...Obau

© 2022 - 2024 — McMap. All rights reserved.