推理变量具有不兼容的边界。 Java 8编译器回归? [英] Inference variable has incompatible bounds. Java 8 Compiler Regression?

查看:1197
本文介绍了推理变量具有不兼容的边界。 Java 8编译器回归?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下程序在Java 7和Eclipse Mars RC2 for Java 8中编译:

The following program compiles in Java 7 and in Eclipse Mars RC2 for Java 8:

import java.util.List;

public class Test {

    static final void a(Class<? extends List<?>> type) {
        b(newList(type));
    }

    static final <T> List<T> b(List<T> list) {
        return list;
    }

    static final <L extends List<?>> L newList(Class<L> type) {
        try {
            return type.newInstance();
        }
        catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

使用javac 1.8.0_45编译器,报告以下编译错误:

Using the javac 1.8.0_45 compiler, the following compilation error is reported:

Test.java:6: error: method b in class Test cannot be applied to given types;
        b(newList(type));
        ^
  required: List<T>
  found: CAP#1
  reason: inference variable L has incompatible bounds
    equality constraints: CAP#2
    upper bounds: List<CAP#3>,List<?>
  where T,L are type-variables:
    T extends Object declared in method <T>b(List<T>)
    L extends List<?> declared in method <L>newList(Class<L>)
  where CAP#1,CAP#2,CAP#3 are fresh type-variables:
    CAP#1 extends List<?> from capture of ? extends List<?>
    CAP#2 extends List<?> from capture of ? extends List<?>
    CAP#3 extends Object from capture of ?

解决方法是在本地分配变量:

A workaround is to locally assign a variable:

import java.util.List;

public class Test {

    static final void a(Class<? extends List<?>> type) {

        // Workaround here
        List<?> variable = newList(type);
        b(variable);
    }

    static final <T> List<T> b(List<T> list) {
        return list;
    }

    static final <L extends List<?>> L newList(Class<L> type) {
        try {
            return type.newInstance();
        }
        catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

我知道类型推断有在Java 8中发生了很大的变化(例如由于JEP 101广义目标类型推断)。那么,这是一个错误还是一个新的语言功能?

I know that type inference has changed a lot in Java 8 (e.g. due to JEP 101 "generalized target-type inference"). So, is this a bug or a new language "feature"?

编辑:我还向甲骨文报告了这个JI-9021550,但是为了防止这是Java 8中的功能,我也向Eclipse报告了这个问题:

EDIT: I have also reported this to Oracle as JI-9021550, but just in case this is a "feature" in Java 8, I've reported the issue also to Eclipse:

  • https://bugs.eclipse.org/bugs/show_bug.cgi?id=469297

推荐答案

感谢错误报告,感谢Holger,您的答案中的示例。这些和其他几个人最后让我质疑11年前在Eclipse编译器中做出的一个小改动。重点是:Eclipse非法扩展了捕获算法,以递归方式应用于通配符边界。

Thanks for the bug report, and thanks, Holger, for the example in your answer. These and several others finally made me question one small change made in the Eclipse compiler 11 years ago. The point was: Eclipse had illegally extended the capture algorithm to apply recursively to wildcard bounds.

有一个例子,这种非法更改完全符合Eclipse与javac的行为。与JLS中我们能够清楚看到的一样,Eclipse开发人员已经相信这个旧决定。今天我认为以前的偏差必然有不同的原因。

There was one example where this illegal change perfectly aligned Eclipse behavior with javac. Generations of Eclipse developers have trusted this old decision more than what we could clearly see in JLS. Today I believe that previous deviation must have had a different reason.

今天我鼓励人们将ecj与JLS在这方面保持一致,并认为5个错误看起来非常极端难以破解,基本上已经解决了这个问题(加上一点点调整以及补偿)。

Today I took the courage to align ecj with JLS in this regard and voila 5 bugs that appeared to be extremely hard to crack, have essentially been solved just like that (plus a little tweak here and there as compensation).

Ergo:是的,Eclipse有一个错误,但该错误已修复4.7里程碑2:)

Ergo: Yes, Eclipse had a bug, but that bug has been fixed as of 4.7 milestone 2 :)

以下是ecj今后将报告的内容:

Here's what ecj will report henceforth:

The method b(List<T>) in the type Test is not applicable for the arguments (capture#1-of ? extends List<?>)

捕获范围内的通配符没有找到检测兼容性的规则。更确切地说,在推理期间的某些时间(准确地并入)我们遇到以下约束(T#0表示推理变量):

It's the wildcard inside a capture bound that doesn't find a rule to detect compatibility. More precisely, some time during inference (incorporation to be precise) we encounter the following constraint (T#0 representing an inference variable):

⟨T#0 = ?⟩

天真地,我们可以将类型变量解析为通配符,但是 - 可能是因为通配符不被视为类型 - 减少规则将上述定义为减少为FALSE,从而使推理失败。

Naively, we could just resolve the type variable to the wildcard, but -- presumably because wildcards are not considered types -- the reduction rules define the above as reducing to FALSE, thus letting inference fail.

这篇关于推理变量具有不兼容的边界。 Java 8编译器回归?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆