Community
Participate
Working Groups
Build ID: I20061102-1715 Steps To Reproduce: Try to compile the following source code, with compiler compliance level set to 5.0: import java.util.List; class Super<T> { public void accepts(final List<?> list) { } } class Sub extends Super { public void accepts(final List<?> list) { super.accepts(list); } } You will get the compiler error: Name clash: The method accepts(List<?>) of type Sub has the same erasure as accepts(List<?>) of type Super<T> but does not override it More information: The code compiles fine when you remove the generic type parameter T from the Super class.
javac agrees with us on this test case (1.5.10 and 6 b104, not tested b105 yet). Released GenericTypeTest#test1100 in HEAD and R3_2_maintenance.
Sorry for not trying with javac first... So are you saying that it is the correct behaviour according to the Java specification, or that it is a Sun bug that Eclipse emulates?
So far, I simply looked at javac and did not give much thought to the spec. I'll have a second look at it next week.
(In reply to comment #3) > So far, I simply looked at javac and did not give much thought to the spec. > I'll have a second look at it next week. > That's great, thanks!
Interesting indeed. Super#accepts and Sub#accepts clearly have the same erasure. Sub extending of Super#RAW makes it a raw type. Consequently, Sub#accepts signature is, per p 59, void accepts(List#RAW), which, per p. 213, is not the same as a void accepts(List<?>), but is a subsignature of it. Hence, per p. 224, Sub#accepts should override Super#accepts. Philippe, did I miss something?
Since Super is a generic class, when used as a raw supertype, a raw conversion is performed on all its non-static members. So the hierarchy of Sub looks like: Super +- accepts(List) Sub +- accepts(List<?>) which is expected to raise a nameclash. If you remove the type param from Super, then no raw conversion is performed any longer, and thus you end up comparing: Super +- accepts(List<?>) Sub +- accepts(List<?>) To confuse you even more, observe the following testcase: import java.util.List; class Super<T> { public void accepts(final List<Exception> list) { } } class Sub extends Super { public void accepts(final List<Thread> list) { super.accepts(list); } } Note that the nameclash is diagnosed as expected, but check out the line "super.accepts(list);". No error is flagged there, but a warning about using a raw method. The super method invoked is #accepts(List) not #accepts(List<Thread>) any longer. BTW, our error message about nameclash is quite misleading. It should surface the raw method instead of showing the generic methods. i.e. instead of telling: Name clash: The method accepts(List<?>) of type Sub has the same erasure as accepts(List<?>) of type Super<T> but does not override it it should tell: Name clash: The method accepts(List<?>) of type Sub has the same erasure as accepts(List) of type Super but does not override it
Kent - look at the error msg issue pls
(In reply to comment #5) > Philippe, did I miss something? What I missed was that Sub extending Super#RAW does not make it a raw type. Hence we're right to match accepts(List<?>) against accepts(List#RAW), and to complain.
The error message is produced by MethodVerifier15.detectNameClash(). We could change it to: boolean detectNameClash(MethodBinding current, MethodBinding inherited) { MethodBinding original = inherited.original(); // can be the same as inherited if (!current.areParameterErasuresEqual(original) || current.returnType.erasure() != original.returnType.erasure()) return false; problemReporter(current).methodNameClash(current, inherited); <<< was original return true; } 4 other tests besides 1100 are affected (298, 355, 397 & 435). Please take a look at those tests to make sure that this change makes sense.
Reopening to improve the message.
Tuning the severity as well, since we are right to complain.
Created attachment 57329 [details] Suggested fix Along the lines Kent suggested, but a bit more restrictive. In that patch, I hold on the original method unless the inherited one has a raw type as its declaring type. This should not change the situations where both types are raw, nor those where we do not rawify inherited (in which case the choice of the original method must have been deliberate, and seems better in that it refers to the method as it can be read in its declaring type). Bringing the raw types up in case we had to rawify should remove the oddity of this peculiar test case, and help the user understand that some magic happened that made the method signature change. Patch currently under test (other test cases may see parts of their messages change).
Fixed a few more test messages. Released for 3.3 M5.
Verified for 3.3 M5 using warm-up build I20070205-0009