Bug 83902 - [1.5] AbstractMethodError when using covariant returns
Summary: [1.5] AbstractMethodError when using covariant returns
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.1   Edit
Hardware: PC Windows XP
: P3 critical (vote)
Target Milestone: 3.1 M5   Edit
Assignee: Kent Johnson CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on: 83901
Blocks:
  Show dependency tree
 
Reported: 2005-01-27 21:39 EST by Matthew Hall CLA
Modified: 2005-02-16 09:21 EST (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Matthew Hall CLA 2005-01-27 21:39:13 EST
For an enum containing an abstract method with a non-primitive return type: if
any of the enum elements implements the method with a covariant return type, an
AbstractMethodError will be thrown when the method is invoked on that element.

The following test case succeeds when compiled with the Sun JDK compiler, but
fails when compiled in Eclipse.

Tested against Eclipse 3.1_I20050126-0800

---- EnumElementCovariantReturnTest.java ----

import junit.framework.TestCase;

public class EnumElementCovariantReturnTest extends TestCase {
  // this test passes
  public void testEnumElementNormalReturn() {
    E.ITEM_1.x();
  }

  // this test fails due to covariant return value in ITEM_2
  public void testEnumElementCovariantReturn() {
    E.ITEM_2.x();
  }

  static class X {}
  static class Y extends X {}

  enum E {
    ITEM_1() {
      // regular return value -- works as expected
      public X x() { return new Y(); }
    },
    ITEM_2() {
      // covariant return -- AbstractMethodError
      public Y x() { return new Y(); }
    };

    public abstract X x();
  }
}

---- End of EnumElementCovariantReturnTest.java ----

Now replace the abstract declaration of x() with the following:

public X x() {
  throw new UnsupportedOperationException();
}

Run the test case, and an UnsupportedOperationException will be thrown.  It
seems the compiler does not recognize that E.ITEM_2.x() is overriding E.x(). 
Therefore it would also seem in the original test case above that the compiler
does not recognize that ITEM_2.x() is implementing the abstract method E.x().
Comment 1 Matthew Hall CLA 2005-01-27 21:49:40 EST
We can't be sure this bug is really fixed until 83901 is fixed.
Comment 2 Trevor Robinson CLA 2005-02-04 17:39:00 EST
I'm encountering an AbstractMethodError involving a covariant return override as
well. Mine has nothing to do with enums, and is with build I20050202-0800. My
class hierarchy is very complex, and I don't have a small reproducer yet, but a
summary is:

interface Visibility {}
interface NamedObject {}
interface Function extends NamedObject {}
interface ClassMember { Visibility getVisibility(); }

class FooVisibility implements Visibility  {}
class FooFunction implements Function { FooVisibility getVisibility(); }
interface FooClassMember { FooVisibility getVisibility(); }
class FooMemberFunction extends FooFunction implements FooClassMember {}

void foo(NamedObject o)
{
  ClassMember member = (ClassMember) o;
  member.getVisibility(); // AbstractMethodError
}
Comment 3 Trevor Robinson CLA 2005-02-04 17:41:51 EST
Forgot to add: foo() is called with a FooMemberFunction object.
Comment 4 Trevor Robinson CLA 2005-02-04 17:59:57 EST
Here's a reproducer:

public final class Bug83902
{
    public interface Visibility
    {
    }

    public interface Function
    {
    }

    public interface ClassMember
    {
        Visibility getVisibility();
    }

    public interface MemberFunction
        extends Function, ClassMember
    {
    }

    public static class FooVisibility
        implements Visibility
    {
        public static final FooVisibility PUBLIC = new FooVisibility();
    }

    public static class FooFunction
        implements Function
    {
        public FooVisibility getVisibility()
        {
            return FooVisibility.PUBLIC;
        }
    }

    interface FooClassMember
        extends ClassMember
    {
        FooVisibility getVisibility();
    }

    public static class FooMemberFunction
        extends FooFunction
        implements MemberFunction, FooClassMember
    {
    }

    public static void main(String[] args)
    {
        FooMemberFunction fmf = new FooMemberFunction();
        fmf.getVisibility(); // OK
        FooClassMember fcm = fmf;
        fcm.getVisibility(); // OK
        ClassMember cm = fmf;
        cm.getVisibility(); // AbstractMethodError
    }
}

Exception in thread "main" java.lang.AbstractMethodError:
Bug83902$FooMemberFunction.getVisibility()LBug83902$Visibility;
	at Bug83902.main(Bug83902.java:55)
Comment 5 Philipe Mulet CLA 2005-02-08 06:01:01 EST
On second scenario, we are missing one bridge method on FooMemberFunction:
  public bridge synthetic X.IVisibility getVisibility();
Comment 6 Kent Johnson CLA 2005-02-09 17:57:20 EST
the problem in comment 0 is fixed.

the missing bridge method problem in comment 4 can be reproduced with:

public class X {
  interface I {}
  interface J { I getVisibility(); }

  static class A implements I {}
  static class B { public A getVisibility() { return null; } }
  static class C extends B implements J {}

  public static void main(String[] args) {
    C c = new C();
    c.getVisibility(); // OK
    J j = c;
    j.getVisibility(); // AbstractMethodError
  }
}

We are missing the bridge method on the class C because of the inherited 
methods from B & J
Comment 7 Kent Johnson CLA 2005-02-11 13:52:24 EST
Added EnumTest test076 for comment 0.

Added MethodVerifyTest test041 for comment 6
Comment 8 David Audel CLA 2005-02-16 09:21:01 EST
Verified in I20050215-2300