-
Bug
-
Resolution: Unresolved
-
P4
-
5.0, 7, 8
The erased-signature check is meant to prohibit method declarations that, due to the implementation strategy, can't be correctly implemented by compilation to bytecode -- specifically because of methods that appear to be related in bytecode but that are not related at the source level. The following falls into that category, but is not covered by the erased-signature check; the check should be expanded to include it.
public class A<T> {
public void m(T arg) { System.out.println("A.m"); }
}
public class B<U extends Number> extends A<U> {
public void m(Number arg) { System.out.println("B.m"); }
}
public class C<V extends Integer> extends B<V> {
public void m(Number arg) { System.out.println("C.m"); }
}
While C.m overrides B.m, it does _not_ override A.m, because it is not a subsignature of A.m (see JLS 8.4.8.1). Yet a bridge method generated in B will cause C.m(Number) to be run when A.m(Object) is invoked.
The adjusted 8.4.8.3 check could either add a separate condition for the case in which some method m1 overrides in turn overrides m2, or talk about the erased signatures of the methods overridden by a method overridden by m1.
Some alternative solutions to the example that we discussed but rejected:
- Define overriding to be transitive. Too invasive a change, and carries added complexity.
- Change javac bridges to use invokespecial. Risky change for an obscure corner case.
- Define "subsignature" such that the erased signature is that of the parent method _before_ substitution -- claim that B.m does not override A.m. More likely to break existing code.
public class A<T> {
public void m(T arg) { System.out.println("A.m"); }
}
public class B<U extends Number> extends A<U> {
public void m(Number arg) { System.out.println("B.m"); }
}
public class C<V extends Integer> extends B<V> {
public void m(Number arg) { System.out.println("C.m"); }
}
While C.m overrides B.m, it does _not_ override A.m, because it is not a subsignature of A.m (see JLS 8.4.8.1). Yet a bridge method generated in B will cause C.m(Number) to be run when A.m(Object) is invoked.
The adjusted 8.4.8.3 check could either add a separate condition for the case in which some method m1 overrides in turn overrides m2, or talk about the erased signatures of the methods overridden by a method overridden by m1.
Some alternative solutions to the example that we discussed but rejected:
- Define overriding to be transitive. Too invasive a change, and carries added complexity.
- Change javac bridges to use invokespecial. Risky change for an obscure corner case.
- Define "subsignature" such that the erased signature is that of the parent method _before_ substitution -- claim that B.m does not override A.m. More likely to break existing code.
- relates to
-
JDK-8010682 Enhance erased-signature clash check for subsignatures
- Open
-
JDK-8030143 8.4.8.4: Error for override-equivalent declared/inherited methods?
- Open
-
JDK-8009685 Bridge methods change overriding behavior
- Open