Let\'s compile the following code with ECJ compiler from Eclipse Mars.2 bundle:
import java.util.stream.*;
public class Test {
String test(Stream&g
The token !
is used by ecj to encode a capture type in generic signatures. Hence !*
signifies a capture of an unbounded wildcard.
Internally, ecj uses two flavours of CaptureBinding
, one to implement, what JLS 18.4 calls "fresh type variables", the other to implement captures a la JLS 5.1.10 (which uses the same lingo of "free type variables"). Both produce a signature using !
. At a closer look, in this example we have an "old-style" capture: t
has type capture#1-of ?
, capturing the <T>
in Stream<T>
.
The problem is: JVMS 4.7.9.1. doesn't seem to define an encoding for such fresh type variables (which among other properties have no correspondence in source code and hence no name).
I couldn't get javac
to emit any LocalVariableTypeTable
for the lambda, so they might simply avoid answering this question.
Given that both compilers agree on inferring t
to a capture, why does one compiler generate a LVTT, where the other does not? JVMS 4.7.14 has this
This difference is only significant for variables whose type uses a type variable or parameterized type.
According to JLS, captures are fresh type variables, so an LVTT entry is significant, and it is an omission in JVMS not to specify a format for this type.
The above only describes and explains the status quo, demonstrating that no specification tells a compiler to behave differently from current status. Obviously, this is not an entirely desirable situation.
Update: Meanwhile someone has reported an example where a regular Signature attribute (which cannot be opportunistically omitted) is required to encode a type which cannot be encoded according to JVMS. In that case also javac creates unspecified byte code. According to a follow-up no variable should ever have such a type, but I don't think that this discussion is over, yet (and admittedly JLS doesn't yet ensure this goal).
Update 2: After receiving advice from a spec author I see three parts to the ultimate solution:
(1) Every type signature in any bytecode attribute must adhere to the grammar in JVMS 4.7.9.1. Neither ecj's !
nor javac's <captured wildcard>
is legal.
(2) Compilers should approximate type signatures where no legal encoding exists, e.g., by using the erasure instead of a capture. For an LVTT entry, such approximation should be considered as legitimate.
(3) JLS must ensure that only types encodable using JVMS 4.7.9.1 appear in positions where generating a Signature attribute is mandatory.
For future versions of ecj items (1) and (2) have been resolved. I cannot speak about schedules when javac and JLS will be fixed accordingly.