| Summary: | [1.5][compiler] regression - incorrect handling of generics | ||
|---|---|---|---|
| Product: | [Eclipse Project] JDT | Reporter: | Eric Goff <goffster> |
| Component: | Core | Assignee: | Philipe Mulet <philippe_mulet> |
| Status: | CLOSED FIXED | QA Contact: | |
| Severity: | blocker | ||
| Priority: | P3 | ||
| Version: | 3.1 | ||
| Target Milestone: | 3.1 RC2 | ||
| Hardware: | PC | ||
| OS: | Linux | ||
| Whiteboard: | |||
Reduced testcase:
package foo;
public class Test {
public static void main(String[] args) {
Controller<?> ctrl = null;
foobar(ctrl.getView().getContent());
}
static void foobar(Test t) {
}
}
interface Controller<T extends View<?>> {
public T getView() ;
}
interface View<U extends Test> {
public U getContent();
}
Reason for change is tightened capture conversion.
When 'ctrl' gets capture conversion applied, what is the fresh type variable
(say S) upper bound ?
Is it:
(1) strictly View<?>
(2) or rather View<capture-of ?> ? (which I am guessing)
If (1) is true, then the program should be rejected I think, as the type of
ctrl.getView() would yield 'capture-of ?', then next call for #getContent() will
issue '?' (from View<?>). Then this type hasn't been captured, and doesn't know
enough to be a proper 'Test' as mandated by #foobar(...) invocation.
If (2) is true, then it seems to indicate that capture conversion would have to
recurse when computing the bounds of the fresh type variables.
However, then I am wondering about infinite regressions when capturing some type
Y<?> where class Y<T extends Y<?>> {}; if capturing is allocating
a fresh variable each time it encounters Y<?>; could be closed by reusing same
capture; but then it would change semantics and handle
class Y<T extends Y<?>> {}; as if it had been defined: class Y<T extends Y<T>> {};
I can make this scenario work, by adding back type variable bounds in wildcard
direct supertypes. But as demonstrated by following program, it reveals non
substituted variables:
public class X<E> {
public static void main(String[] args) {
Controller<?> ctrl = null;
foobar(ctrl.getView().getContent());
}
static void foobar(X<String> x) {
}
}
interface Controller<T extends View<?>> {
public T getView() ;
}
interface View<U extends X<U>> {
public U getContent();
}
javac:
X.java:6: foobar(X<java.lang.String>) in X<E> cannot be applied to (X<U>)
foobar(ctrl.getView().getContent());
^
1 error
(U shouldn't appear outside its context !?)
Tuned wildcard supertypes to meet old behavior and javac. May reconsider this behavior in the light of spec revision. Added GenericTypeTest#test726-728. Fixed Verified in N20050609-0010 + JDT/Core HEAD. Verified for 3.1 RC2 using build I20050610-0010 |
This set of files compiled fine in M6 and M7 and the jdk 1.5.0 from Sun, but does not compile in RC1. Controller.java package foo; public interface Controller<T extends Model,U extends View<T,?>> { public U getView() ; public T getTarget() ; } Model.java package foo; public interface Model { } MouseEventReceiver.java package foo; import java.awt.Component ; public interface MouseEventReceiver { public interface Model extends foo.Model { } public interface View<T extends Model,U extends Component> extends foo.View<T,U> { } public interface Ctrl<T extends Model,U extends View<T,?>> extends Controller<T,U> { } } View.java package foo; public interface View<T extends Model, U> { public T getModel(); public U getContent(); } test.java package foo; import java.awt.Component; public class test { public static void main(String [] args) { MouseEventReceiver.Ctrl<?,?> ctrl = null ; foobar(ctrl.getView().getContent()) ; } public static void foobar(Component c) { } } I get: The method foobar(Component) in the type test is not applicable for the arguments (?) It is not correctly determining that ? is bound to Component.