Bug 80028 - Ambiguous method error where javac succeeds
Summary: Ambiguous method error where javac succeeds
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.1   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 3.1 M4   Edit
Assignee: Kent Johnson CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2004-12-02 11:21 EST by Markus Keller CLA
Modified: 2004-12-15 20:29 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 Markus Keller CLA 2004-12-02 11:21:58 EST
Eclipse I20041201-1139 report the last call y.m(new Integer(2)) as ambiguous.
JDK 1.5.0-b64 compiles without error and prints this:
Y#m(Number): 1
Y#m(Number): 2

-----------------------------------------------------
class X<T> {
    public void m(Number num) {}
    public void m(T t) {}
}
class Y extends X<Number> {
    public void m(Number num) { System.out.println("Y#m(Number): " + num); }
}

class A {
    public static void main(String[] args) {
        Y y= new Y();
        Number n= new Integer(1);
        y.m(n);
        y.m(new Integer(2)); // The method m(Number) is ambiguous for the type Y
    }
}
Comment 1 Kent Johnson CLA 2004-12-13 11:11:30 EST
I suspect that this is a javac bug.

Once you define Y as class Y extends X<Number>, then it inherits 2 methods 
from X:

    public void m(Number num) {}
    public void m(<Number> t) {}

So how can you ever send the 2nd one? How is m(Number) not ambiguous?
Comment 2 Kent Johnson CLA 2004-12-13 11:47:15 EST
we should never accept this case:

class X<T> {
    public void m(Number num) {}
    public void m(T t) {}
}
class Y extends X<Number> {}

even javac complains that 2 methods are inherited with the same signature

*** This bug has been marked as a duplicate of 80739 ***
Comment 3 Markus Keller CLA 2004-12-13 11:55:32 EST
I agree that the example in comment 2 should be rejected by the compiler.
However, the original comment 0 was different.

Method m(Number) is ambiguous in X<Number>, but not in Y, where it is redefined.
Javac also flags references to X#m(Number) as ambiguous, such as when adding
this to main:

    X<Number> xn= new X<Number>();
    xn.m(n); //reference to m is ambiguous, both method
          // m(java.lang.Number) in xy.X<java.lang.Number> and method
          // m(T) in xy.X<java.lang.Number> match
    xn.m(new Integer(3)); //reference to m is ambiguous, both method
          // m(java.lang.Number) in xy.X<java.lang.Number> and method
          // m(T) in xy.X<java.lang.Number> match

When the redeclaration of m(Number) is removed from Y, Y inherits (JLS3:8.4.8)
two override-equivalent (JLS3:8.4.2) methods, which javac correctly flags as
compile error (JLS3: 8.4.8.4) - but eclipse doesn't.

In the original example, you indeed can never send a message to one of the two
overridden override-equivalent methods (i.e. you can't call super.m(..) in
Y#m(Number)), but this doesn't make up for a compile error by itself. Note that
the methods from X are not inherited by Y, since they are overridden (JLS3:8.4.8).
Comment 4 Kent Johnson CLA 2004-12-13 12:39:56 EST
"However, the original comment 0 was different."

No its not. The declaration of Y is the same in both cases. It subclasses X in 
a way that causes 2 methods m(Object) to exist. That is an error that the 
verifier will catch as described by bug 80739.

Whether Y reimplements m(Object) or not does not change that fact. The 
verifier will not skip over the fact that Y is incorrectly subclassing X just 
because it overrides the method.

What is supposed to happen when Y decides to do a super.m() call?
Comment 5 Markus Keller CLA 2004-12-13 13:20:57 EST
For me, comment 0:
    class Y extends X<Number> {
        public void m(Number num) { /*...*/ }
    }
looks different from comment 2:
    class Y extends X<Number> {}
;-)

> Whether Y reimplements m(Object) or not does not change that fact.
Oh yes, that's what I tried to "prove" with references to the not-yet-standard.
Can you give me a pointer that shows why the reimplementation shouldn't matter?

JLS3 8.4.8.4 'Inheriting Methods with Override-Equivalent Signatures' says:
"It is possible for a class to inherit multiple methods with override-equivalent
(ยง8.4.2) signatures. It is a compile time error if a class C inherits a concrete
method whose signatures is a subsignature of another concrete method inherited
by C."

My point is that this section perfectly makes comment 2 erroneous, but does not
affect the discussion of comment 0, since the methods are not inherited by Y.

> What is supposed to happen when Y decides to do a super.m() call?
That call is to be flagged as ambiguous at the invocation site, since there's no
single overridden method X#m(Number). See JLS3: 15.12.2.5 'Choosing the Most
Specific Method', last sentence.

It's just too bad that Java has gotten so complicated that we need to have
"language lawyers" as in the old C++ days :-(
Comment 6 Kent Johnson CLA 2004-12-13 13:37:22 EST
ok, you're right.

We handle this case differently.
Comment 7 Kent Johnson CLA 2004-12-13 15:35:40 EST
So much for my ability to write proper English...

Added GenericType test436
Comment 8 Kent Johnson CLA 2004-12-15 15:21:55 EST
fixed.
Comment 9 Olivier Thomann CLA 2004-12-15 20:29:07 EST
Verified in 200412160010