I think this might be related to Why does a generic cast of a List<? extends Set..> to List<Set..> succeed on Sun JDK 6 but fail to compile on Oracle JDK 7?
If we take the following classes, they compile fine under JDK 6:
public final class Foo<V> {
private final V value;
private Foo(final V value) {
this.value = value;
}
public static <T, R extends T> Foo<T> of(final R value) {
return new Foo<T>(value);
}
}
final class Tester {
@Test(groups="unit")
public static void test() {
bar(Foo.of(BigDecimal.ZERO)); // This line fails in JDK 7 but not JDK 6
}
private static void bar(final Foo<? extends Number> target) {
assert target != null;
}
}
However, under JDK 7, I receive the following error:
[ERROR] \work\fsb-core\src\test\java\com\fsb\core\Foo.java:[42,8] error:
method bar in class Tester cannot be applied to given types;
I thought type inference was less restrictive (e.g., adding constructor inference) in JDK 7. However, here, the compiler is rejecting a type that is valid under JDK 6.
Is this a bug? Or were the rules on inference made more stringent for methods?
Strictly according to the spec, T
cannot be inferred (per 15.12.2.7), so it should be taken as Object
.
This can be viewed as a failure of the spec. This is how spec infers R
: first there is constraint R :> BigDecimal
, where :>
means is a supertype of. The inference rules then choose R=BigDecimal
since it's the most specific type satisfying the constraint.
Now, since T:>R
, T:>BigDecimal
, one would think this should yield T=BigDecimal
too.
Unfortunately the inference rules do not take T:>R
into account. There is no contraint on T
. T
is not inferred through the same principle.
While it sucks, spec is spec. Your code should not compile. Javac6 is wrong there.
In Java 8 there's an great improvement on inference rules to make lambda expression easier to use. Hopefully your code should compile in Java 8.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With