Summary: | [compiler] [1.5] internal compiler reports a bug javac only a warning | ||||||||
---|---|---|---|---|---|---|---|---|---|
Product: | [Eclipse Project] JDT | Reporter: | Ralf Behle <ralf.be> | ||||||
Component: | Core | Assignee: | Kent Johnson <kent_johnson> | ||||||
Status: | RESOLVED WORKSFORME | QA Contact: | |||||||
Severity: | normal | ||||||||
Priority: | P3 | CC: | mlists, philippe_mulet | ||||||
Version: | 3.1 | ||||||||
Target Milestone: | 3.1 RC2 | ||||||||
Hardware: | PC | ||||||||
OS: | Linux | ||||||||
Whiteboard: | |||||||||
Attachments: |
|
Description
Ralf Behle
2005-04-18 08:30:58 EDT
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. |