Community
Participate
Working Groups
The test code: public class EclipseBug { private interface ReturnBase { // Empty } private interface ReturnDerived extends ReturnBase { // Empty } private interface Interface { ReturnBase bar(); } private static class Implementation { public final ReturnDerived bar() { return null; } } private static class Child extends Implementation implements Interface { // Empty } private static class Grandchild extends Child implements Interface { // Empty } public static void main(String[] args) { new Grandchild(); } } Trying to run this class results in Exception in thread "main" java.lang.VerifyError: class EclipseBug$Grandchild overrides final method bar.()LEclipseBug$ReturnBase; at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:620) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124) at java.net.URLClassLoader.defineClass(URLClassLoader.java:260) at java.net.URLClassLoader.access$000(URLClassLoader.java:56) at java.net.URLClassLoader$1.run(URLClassLoader.java:195) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:188) at java.lang.ClassLoader.loadClass(ClassLoader.java:306) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:276) at java.lang.ClassLoader.loadClass(ClassLoader.java:251) at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319) at EclipseBug.main(EclipseBug.java:30) I expected it to do nothing (which is also what happens when using the Sun javac). This happens in Eclipse 3.3M1 and 3.3M2. I have not tried it with earlier versions.
Bridge methods are added to override a final method leading to the VerifyError. compliance >= 1.5 is required to compile this code.
I can confirm it happens in 3.2.1, too.
The only difference between 3.2.0 and HEAD or 3.2.1 is that the bridge method is final. I'll check the diff between 3.2.0 and 3.2.1 to find out when this was introduced.
In this case javac doesn't create a bridge method at all.
The problem seems to come from the fix for bug 147690. I might have a fix for it that also passes the regression test for 147690, but we should investigate why we do have a bridge method in this case and javac doesn't.
Created attachment 51792 [details] Proposed fix
Please note that this is not for sure a regression bug, ie. I don't know whether it happens in 3.2.0 and Bas doesn't either, as far as I know. So to my knowledge this bug might always have been there.
From what I tried, it worked fine in 3.2.0, but failed in 3.2.1 due to the fix for bug 147690. Discussing with Kent, we should have a bridge method on Child, but not on Grandchild, since Child has one. I'll test a better fix and if it is good, I'll attach it to the PR. This would definitely be a candidate for 3.2.2. The previous fix was passing the VerifyError, but I end up with a bridge method for Child and Grandchild. All tests should be done by tomorrow.
+1 for 3.2.2. We have been having the extra bridge method on GrandChild before 3.2.0.
If we fix the extra bridge method, it is unclear we need to clear the final flag, other than for matching expectation. We would reject subsequent overrides anyway, e.g. public class X { private interface ReturnBase {} private interface ReturnDerived extends ReturnBase {} private interface ReturnLeaf extends ReturnDerived {} private interface Interface { ReturnBase bar(); } private static class Implementation { public final ReturnDerived bar() { return null; } } private static class Child extends Implementation implements Interface {} private static class Grandchild extends Child implements Interface { public ReturnLeaf bar() { return null; } } public static void main(String[] args) { new Grandchild(); } }
Pls make sure bridge fix is not order dependant: e.g. public class X { private interface ReturnBase {} private interface ReturnDerived extends ReturnBase {} private interface Interface { ReturnBase bar(); } private static class Implementation { public final ReturnDerived bar() { return null; } } private static class Grandchild extends Child implements Interface {} private static class Child extends Implementation implements Interface {} public static void main(String[] args) { new Grandchild(); } }
Created attachment 51822 [details] Proposed fix This patch removes the needs to clear the final bit since it generates only one bridge method.
Created attachment 51823 [details] Regression tests Several regression tests added to cover corner cases.
The interface only check tricked me, so I wrote the following test case, which we pass, since another pass is followed for abstract method situations: we still issue a bridge on Bar. public class X { interface A1 {} interface A2 extends A1 {} abstract static class AbstractBar { abstract A1 bar(); } static class Bar extends AbstractBar { @Override A2 bar() { return null; } } } Now the patch should be improved to check for interface first, since this is the less expensive check.
BTW, the fix doesn't work with generics. public class X { private interface ReturnBase {} private interface ReturnDerived extends ReturnBase {} private interface Interface<E> { ReturnBase bar(); } private static class Implementation<T> { public final ReturnDerived bar() { return null; } } private static class Child<U> extends Implementation<U> implements Interface<U> {} private static class Grandchild<V> extends Child<V> implements Interface<V> {} public static void main(String[] args) { new Grandchild(); } }
Also in the proposed patch, the check on concreteMethod.declaringClass is subsumed by the next check on superclass.
Created attachment 51836 [details] Better patch Also you should check javac behavior for final bit clearance. Though not mandated, might still be a good idea for easing compatibility.
Olivier - pls mirror all testcases with generics. We should issue this fix for the 3.2.1 patch feature. Please talk with Frederic, once all our testing has completed.
When javac adds a bridge method, it seems that the final bit is cleared.
Released for 3.3M3. Regression tests added in org.eclipse.jdt.core.tests.compiler.regression.MethodVerifyTest#test102-112
Reopen for releasing in 3.2.2
Released for 3.2.2. Same regression tests added.
*** Bug 160254 has been marked as a duplicate of this bug. ***
*** Bug 161442 has been marked as a duplicate of this bug. ***
Verified for 3.3 M3 using build I20061030-0010
Verified for 3.2.2 using build M20070112-1200.