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 ?.
1 Answer 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>(); }.
javacis 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.javacis 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).