2

I wonder if this is a bug in ECJ or a valid interpretation of the JLS.

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Supplier;
public class GenericsTest {
 public void testInference() {
 Set<Object> set1 = getCollection(HashSet::new);
 Set<Object> set2 = getCollection2(HashSet::new);
 }
 public static <E, C extends Collection<E>> C getCollection(Supplier<C> collectionSupplier) {
 return collectionSupplier.get();
 }
 public static <E, C extends Collection<E>> C getCollection2(CollectionSupplier<E, C> collectionSupplier) {
 return collectionSupplier.get();
 }
 public interface CollectionSupplier<E, C extends Collection<E>> {
 C get();
 }
}

Javac (11.0.11) compiles everything (correctly, I would say).

ECJ (4.20.0) fails to compile the getCollection2(HashSet::new) call with error "Type mismatch: cannot convert from Collection to Set".

The getCollection(HashSet::new) call is not a problem for any compiler.

If I apply the suggested quickfix and insert a cast to HashSet<Object>, I get a different error from ECJ: "Problem detected during type inference: Unknown error at invocation of getCollection2(GenericsTest.CollectionSupplier<Object,Collection>)"

There are lots of similar questions here and bugs at bugs.eclipse.org, but most examples seemed to involve ?.

asked Aug 4, 2021 at 12:49
7
  • 1
    There are pretty few people who know the spec well enough to know for sure. In the past I've known ECJ to often be more strict (and more correct) in their interpretation of the JSL so if there was a difference, then it tended to be a javac bug and ECJ was correct. I don't know if that's still true, especially when it comes to the "new" type inference rules. I'd file a bug with ECJ, as javac is effectively the reference implementation, so it's up to them to argue if/why they are correct in differing from what it does. Commented Aug 4, 2021 at 13:00
  • @JoachimSauer javac is not the reference implementation and is up to the bug reporter to argue why this is a bug according to JLS. Eclipse is open source so it's us, not them. Commented Aug 4, 2021 at 14:31
  • @howlger: both OpenJDK and Eclipse are open source and I (and I suspect OP as well) aren't actively working on either, so it is "them". And yes, javac is not the official reference implementation, but it is the de-facto reference by virtue of being the one that's developed "closest" to the standard. Any way: both the Eclipse and the javac people will be better able to judge which one is wrong here than I am and one has to pick one (or report to both and mention the other report in both). Commented Aug 4, 2021 at 15:18
  • @JoachimSauer I agree with your on the first part of your first comment. But it is not fair to misuse bug reports to ask whether a given code is valid Java code. It's up to the reporter to argue why a bug is a bug. I encourage everyone to contribute to the open source software they use, which can be done in many ways and which starts by realizing that it is us and not them. Commented Aug 5, 2021 at 8:22
  • @howlger: Of course it's up to the bug reporter to argue why they think it's wrong. I just think that "javac accepts it" is a reasonable argument. And it might still be a bug in javac instead of ECJ, but I'm saying I'm not qualified to judge that. And the guys at the ECJ project are. And I don't know why you latch onto the "them" so much: All I'm saying is that I'm not an active contributor to ECJ. I've filed bug reports with them before, but not enough to consider myself "part of the project". "Them" is not always about excluding others. Commented Aug 5, 2021 at 9:20

1 Answer 1

1

Please report the issue you get with the cast to Eclipse JDT.

As a workaround, you can give the Eclipse compiler a hint as follows:

Set<Object> set2 = getCollection2((CollectionSupplier<Object, Set<Object>>) HashSet::new);

The tricky part for the compiler is to check whether what getCollection2 returns is compatible to Set<Object>. But to be able to do that, the type parameter of the HashSet::new has to be known, and this is determined from Set<Object> (in this case, HashSet::new creates an instance of HashSet<Object>). So, the type parameter must be determined from the opposite direction than checking whether the return type is compatible with the declared type for which the type parameter is required.

It seems, Eclipse fails to compute the type parameter of HashSet::new. ObjectHashSet::new with static class ObjectHashSet extends HashSet<Object> {} works. GenericsTest::newObjectHashSet with static Set<Object> newObjectHashSet() { return new HashSet<Object>(); } works also, but fails with static <T> Set<T> newObjectHashSet() { return new HashSet<T>(); }.

answered Aug 4, 2021 at 14:56
Sign up to request clarification or add additional context in comments.

1 Comment

I wanted to report the bug, but I was not able to log into bugs.eclipse.org either with my old account or with a new one I created now (or at least I think I created, the reset password form says it doesn't exist and the create form says it does exist).

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.