Community
Participate
Working Groups
For the given program eclipse reports an error. In the declaration of B.test. Javac only reports a reports due to an unchecked conversion. import java.util.*; public class A<S> { public static <U> A<U> test() { return null; } } class B extends A<Set> { public static B test() { return null; } }
Reproduced in M6.
So this case causes a return type compatibility error: class A<T> { A<Object> test() { return null; } } class B extends A<C> { // cannot override test() in A; attempting to use incompatible return type B test() { return null; } } class C {} but in this case its an unchecked conversion warning: class A<T> { <Unused> A<Object> test3() { return null; } } class B extends A<C> { // warning: test() in B overrides <Unused>test() in A; return type requires unchecked conversion B test3() { return null; } } class C {} Why?
I would suspect that comment#2 reveals a bug. I am guessing that our substitution mechanisms should be made smarter. Instead of stealing other variables, and missing ones (in this case) replaced with upper bounds (old code was incorrectly using #erasure()); it should use proper inference algorithm to compute based on arguments and expected types. See attached patch.
Created attachment 22507 [details] Patch for jdt/core Note1: that substitute computation will be more expensive (i.e. do we compute as little as we need?). Note2: if old code is left in place, it should still replace unbound variables with #upperBound() instead of erasure, and not bother when both method parameters counts are not identical.
Created attachment 22509 [details] Patch for compiler tests
My patch fails GenericTypeTest#test355 (no more name clash)
testcases already exist as 52 & 53 With the patch & this case: class X extends Y { <X1, X2> X2 foo(Class<X2> c) { return null; } } class Y { <Y1, Y2> Y1 foo(Class<Y1> c) { return null; } } I see the substitute method for Y.foo created as X2 foo(Class<X2>) instead of X1 foo(Class<X1>).
Actually, according to the spec, we should reject this program. Details from spec expert: "B.test() hides X.test(), because the signature of B.test() is a subsignature of that of X.test(): the signature of B.test() is (), which is the same as the erasure of <U>(), the signature of X.test(). Hence, we have the requirement that the return type of B.test() be return-type-substitutable for taht of X.test(), namely, we expect that: either B <: X<U>, or B can be converted to a subtype of X<U> by unchecked conversion, or B = |X<U>|. Unchecked conversion does not apply since B is not a parameterized type. B is equal to |X<U>| = X. So, is B <: X<U>? No. So this should be illegal."
Given the confirmation that the spec says this case is an error and not a conversion warning, we are going to close this PR. Expect this problem to be fixed in a new version of javac.
This case works 'properly' as it reports the unchecked warning: class Try { public static void main(String[] args) { new Ex().method2(new Integer(1)); } } class Top<TC> { <TM> void method2(TM mTop) { System.out.println("Top"); } } class Ex<C> extends Top<C> { @Override <M> void method2(M mEx) { System.out.println("Ex"); } }
Sorry wrong PR.