interface Pong<T> {}
class Ping<T> implements Pong<Pong<? super Ping<Ping<T>>>> {
static void Ping() {
Pong<? super Ping<Long>> Ping = new Ping<Long>();
}
}
Trying to compile this gives the error:
The system is out of resources.
Consult the following stack trace for details.
java.lang.StackOverflowError
at com.sun.tools.javac.code.Types$23.visitClassType(Types.java:2579)
at com.sun.tools.javac.code.Type$ClassType.accept(Type.java:554)
at com.sun.tools.javac.code.Types$UnaryVisitor.visit(Types.java:3260)
at com.sun.tools.javac.code.Types$23.visitClassType(Types.java:2592)
at com.sun.tools.javac.code.Types$23.visitClassType(Types.java:2579)
at com.sun.tools.javac.code.Type$ClassType.accept(Type.java:554)
...
I have a collegue which has a similar problem in real code. There, he has an abstract base class with 2 type parameters that has two subclasses fixing them to concrete types. Basically, this allows for defining the complete logic in the abstract class instead of having to duplicate the code in both subclasses with swapped concrete types.
Basically, the code is something along these lines:
This code actually compiles. In reality, there are not just 2 subclasses, but a deeper type hierarchy, e.g., three variants of VImpl and EImpl, each of which have arbitrary many subclasses. Well, and actually, there are 3 type parameters, and the restrictions are a bit more complicated as shown above.
When there were only two variants of VImpl and EImpl, it still compiled fine. As soon as the third variants were added, he got that stack overflow in the compiler. That said, the Eclipse compiler is still able to compile the code, so it seems that it's simply javac doing something recursively which it should better do iteratively.
Unfortunately, we are not able to reduce the complete code base to some minimal example suitable for a bug report...
Clearly, it is a bug in the Java compiler. The compiler shouldn't crash, especially on a program so small.
It could even be a hole in the Java Language Specification; i.e. an obscure edge case in generics that the JLS authors haven't considered.
But (IMO) this is nothing more than a curiosity, unless you can come up with an example that isn't so obviously contrived to break the compiler. I mean, this example code isn't exactly meaningful ...
Someone with a deep understanding of the Java compiler's implementation could probably figure out why this causes a stack overflow. But it is hardly relevant unless that person is also going to fix the bug. And unless someone can come up with a meaningful example that triggers the same problem, I can't see any value in fixing it.
I experienced the same with some generic stuff in JDK 8_u25, updating to JDK 8u_65 resolved the issue.
Because the compiler cannot decide whether a
Long
is aPong
that is thesuper
of aPing
of aPing
of aLong
or whether it is aPing
of aPing
of something that extends aPong
of aPong
... but I may be wrong.