Bug 91728

Summary: [compiler] [1.5] internal compiler reports a bug javac only a warning
Product: [Eclipse Project] JDT Reporter: Ralf Behle <ralf.be>
Component: CoreAssignee: 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 Flags
Patch for jdt/core
none
Patch for compiler tests none

Description Ralf Behle CLA 2005-04-18 08:30:58 EDT
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;
	}
	
}
Comment 1 Philipe Mulet CLA 2005-04-18 11:04:39 EDT
Reproduced in M6.
Comment 2 Kent Johnson CLA 2005-05-27 12:10:24 EDT
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?
Comment 3 Philipe Mulet CLA 2005-06-07 09:37:03 EDT
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.
Comment 4 Philipe Mulet CLA 2005-06-07 09:39:30 EDT
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.
Comment 5 Philipe Mulet CLA 2005-06-07 09:40:20 EDT
Created attachment 22509 [details]
Patch for compiler tests
Comment 6 Philipe Mulet CLA 2005-06-07 09:49:02 EDT
My patch fails GenericTypeTest#test355 (no more name clash)
Comment 7 Kent Johnson CLA 2005-06-07 14:36:35 EDT
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>).
Comment 8 Philipe Mulet CLA 2005-06-07 15:06:58 EDT
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."
Comment 9 Kent Johnson CLA 2005-06-07 15:39:04 EDT
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.
Comment 10 Kent Johnson CLA 2005-06-09 10:34:22 EDT
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"); }
}
Comment 11 Kent Johnson CLA 2005-06-09 10:34:42 EDT
Sorry wrong PR.