8
votes

I am currently writing a Java compiler and have implemented section 15.12.2.7. of the JLS7 (http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2.7) , one of the most annoying sections of the spec. I still have one problem since the spec somehow seems underspecified or ambiguous. My problem is this line:

lcta(U) = ? if U's upper bound is Object, otherwise ? extends lub(U,Object)

U is an arbitrary type expression. What is the upper bound of a type expression? In addition, why is the lcta always a wildcard?

The spec defines

CandidateInvocation(G) = lci(Inv(G)).

Now, for example, consider the case that Inv(G) = { List<String> }, i.e., the only possible candidate invocation is a single parameterized type. Now, due to the rule

lci(G<X1, ..., Xn>) = G<lcta(X1), ..., lcta(Xn)>,

the result of CandidateInvocation( G ) = lci( { List<String> } ) would be defined as:

List<lcta(String)>

in my opinion, lcta should simply return String here, because if List<String> is the only possible invocation, it is a good idea to infer List<String> as the argument. However, the definition of lcta(U) dictates that the result is either ? or ? extends lub(...), so the result IS ALWAYS a wildcard. This seems strange. What am I misinterpreting here?

2

2 Answers

6
votes

This looks like a bug of the spec. The clause of lcta(U) didn't exist in JSL3. Apparently JLS3's definition of lci(e1..en) is incomplete when n=1, and the new spec tries to fix it. But the fix seems gibberish, as you reasoned.

Javac7 calculates lci( { List<String> } ) as List<String>, ignoring the added clauses.

This problem should be raised to spec maintainers; not sure how to contact them. You could try openjdk compiler-dev mailing list; there are some knowledgeable people on it.

1
votes

I have asked in the compiler-dev mailing list and received the answer:

Yes, the specification is wrong here. The rule for lcta(U) is simply total crap :). In addition, they claimed that it would be even better to not call lcta(U) at all for a single argument and just use U (since the least common type argument of a single argument U should always be U itself).