Community
Participate
Working Groups
Problem has been reported and discussed on Stackoverflow: http://stackoverflow.com/questions/23006777/eclipse-fails-to-compile-generic-code-but-mvn-compile-works In general ECJ reports and error where Javac does not and code runs succefully without any problems. {code} package testit; import java.util.Map; import java.util.Map.Entry; import com.google.common.base.Optional; public class Test { private static final Object NO_VALUE = new Object(); public void method(Map<String, ?> map) { for (Entry<String, ?> entry : map.entrySet()) { Optional.fromNullable(entry.getValue()).or(NO_VALUE); // ^^ error here } } } {code}
Created attachment 241877 [details] Maven project
Created attachment 241878 [details] Eclipse screenshot
Let's see which one is correct... My initial understanding is: - Type of entry.getValue() is "capture#2-of ?" - Type of fromNullable(..) is "Optional<capture#2-of ?>" - Parameter of or(..) is "capture#2-of ?" - Object is not compatible with any capture This would mean ecj is right, the bug is in javac. I'll try to find a matching bug in their system (or a corresponding discussion in our bugzilla). Note specifically, that the dot before "or" separates the inference for fromNullable(..) from the trailing method invocation, i.e., the type of NO_VALUE does not have any influence on the inferred type for fromNullable(..).
In my opinion a good point in the discussion have made Eugene on stackoverflow: "@JensSchauder a small search revealed this: 15.12.2.8 Any remaining type variables that have not yet been inferred are then inferred to have type Object – Eugene Apr 11 at 8:49" http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2.8 I've tested : jdk1.6.0_45 jdk1.7.0_51 jdk1.8.0 OpenJDK 1.7.0_51 all them succefully compile the code while ecj doesn't. As a Developer I would like ECJ does not correct the JDK.
> In my opinion a good point in the discussion have made Eugene on stackoverflow: The question is a bit more complex than that :) To get an idea about the status of javac in this field have a look at https://bugs.openjdk.java.net/browse/JDK-8016207 The bottom line is: if type checking involves captures (like in comment 0) then javac cannot be much relied on. That javac bug has been open for some time already. Note that this current bug is still targeted 4.4 so I'll try to find the time to clarify what exactly is going on before the Luna release.
(In reply to Jakub Gruszka from comment #4) > In my opinion a good point in the discussion have made Eugene on > stackoverflow: > > "@JensSchauder a small search revealed this: 15.12.2.8 Any remaining type > variables that have not yet been inferred are then inferred to have type > Object – Eugene Apr 11 at 8:49" > > http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2.8 This line doesn't apply for the following reason: Type inference starts by resolving this expression: Optional.fromNullable(entry.getValue()) In this expression all elements can be typed as stated above: entry : Entry<String, capture#2-of ?> entry.getValue: capture#2-of ? fromNullable(..) : (capture#2-of ?) -> Optional<capture#2-of ?> In short: T is inferred to be "capture#2-of ?". Inference succeeds. Only after all these have been decided, does resolution proceed to inspect the .or(..) method call. No reason to fill in un-inferred inference variables with "Object". With a receiver of type Optional<capture#2-of ?>, we have these three overloads of "or": Optional<capture#2-of ?> or(Optional<? extends capture#2-of ?>) capture#2-of ? or(Supplier<? extends capture#2-of ?> supplier) capture#2-of ? or(capture#2-of ? defaultValue) None of these methods is applicable for an argument of type Object. ecj arbitrarily picks the first method for error reporting: "The method or(Optional<? extends capture#2-of ?>) in the type Optional<capture#2-of ?> is not applicable for the arguments (Object)" The difference between ecj and javac is most certainly covered by the mentioned javac bug: https://bugs.openjdk.java.net/browse/JDK-8016207 As mentioned in that bug, a future update of the JLS may possibly adopt parts of the current javac behavior. Until such a spec update is released, the only reliable point of reference for ecj is the JLS. In this specification I see no reason for changing the behavior of ecj in this regard. BTW, the canonical fix (no cast needed) is: Optional.<Object>fromNullable(entry.getValue()).or(NO_VALUE);
I've released regression tests (negative and positive) via http://git.eclipse.org/c/jdt/eclipse.jdt.core.git/commit/?id=460d5bedc49ffdc3e78c2a4574461c7301168e97 That's all we can do here.
Thanks for the effort on the research as well for providing a constructive answer.
Verified for Luna 4.4 RC1.
Despite the related https://bugs.openjdk.java.net/browse/JDK-8039214 being fixed, javac9 still accepts the program. OTOH, https://bugs.openjdk.java.net/browse/JDK-8016207 is still unresolved ...