Eclipse Java 编译器推断出错误的泛型类型?

Eclipse Java compiler infers the wrong generic type?

我想知道这是 ECJ 中的错误还是 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) 编译一切(正确,我会说)。

ECJ (4.20.0) 无法编译 getCollection2(HashSet::new) 调用,出现错误“类型不匹配:无法从 Collection 转换为 Set”。

getCollection(HashSet::new) 调用对任何编译器来说都不是问题。

如果我应用建议的 quickfix 并向 HashSet<Object> 插入强制转换,我会收到来自 ECJ 的不同错误:“类型推断期间检测到问题:调用 getCollection2 时出现未知错误(GenericsTest.CollectionSupplier<对象,集合>)"

这里有很多类似的问题和 bugs.eclipse.org 处的错误,但大多数示例似乎都涉及 ?

请向 Eclipse JDT 报告您遇到的转换问题。

作为变通方法,您可以给 Eclipse 编译器一个提示,如下所示:

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

编译器的棘手部分是检查 getCollection2 return 是否与 Set<Object> 兼容。但要做到这一点,必须知道 HashSet::new 的类型参数,这是由 Set<Object> 确定的(在这种情况下,HashSet::new 创建了 HashSet<Object>).因此,必须从相反的方向确定类型参数,而不是检查 return 类型是否与需要类型参数的声明类型兼容。

看来,Eclipse 无法计算HashSet::new 的类型参数。 ObjectHashSet::newstatic class ObjectHashSet extends HashSet<Object> {} 有效。 GenericsTest::newObjectHashSetstatic Set<Object> newObjectHashSet() { return new HashSet<Object>(); } 也可以工作,但是静态 <T> Set<T> newObjectHashSet() { return new HashSet<T>(); }.

会失败