<div dir="ltr"><div>I've got <a href="https://github.com/openjdk/jdk/pull/12503" target="_blank">a PR submitted</a> to fix JDK-5059679 but I'm having second thoughts and would appreciate some advice from the spec experts on the list.</div><div><p>The bug essentially asks whether a program like this should compile (currently, it does):<br></p><p style="margin-left:40px"><span style="font-family:monospace">public class NarrowingNameClash2 {<br><br> public abstract class Upper<T> {<br> abstract void method(T param);<br> }<br><br> public abstract class Lower<R> extends Upper<Class<R>> {<br> abstract void method(Class<?> param); // name clash here???<br> }<br>}</span><br></p><p dir="auto">§8.4.8.3 "Requirements in Overriding and Hiding" says:</p>
<p dir="auto">It is a compile-time error if a class or interface C has a
member method m1 and there exists a method m2 declared in C or a
superclass or superinterface of C, A, such that all of the following are
true:</p>
<ul dir="auto"><li>m1 and m2 have the same name.</li><li>m2 is accessible (§6.6) from C.</li><li>The signature of m1 is not a subsignature (§8.4.2) of the signature of m2 as a member of the supertype of C that names A.</li><li>The declared signature of m1 or some method m1 overrides (directly
or indirectly) has the same erasure as the declared signature of m2 or
some method m2 overrides (directly or indirectly).</li></ul><span style="font-family:arial,sans-serif"></span></div><div><span style="font-family:arial,sans-serif">OK so in this case let:</span></div><div><ul><li>C = A = <span style="font-family:monospace">Lower</span></li><li>m1 = <span style="font-family:monospace">Lower.method(Class<R>)</span><br></li><li>m2 = <span style="font-family:monospace">Lower.method(Class<?>)</span><br></li></ul></div><div><span style="font-family:arial,sans-serif">Note that m1 is a member of C by virtue of <a href="https://docs.oracle.com/javase/specs/jls/se19/html/jls-8.html#jls-8.2">§8.2</a> which states "</span>The members of a class are... members inherited from its direct superclass type (§8.1.4)".</div><div><br></div><div>Side note/question: Presumably when <span style="font-family:monospace">Upper.method(T)</span> is inherited by <span style="font-family:monospace">Lower</span>, its type changes from <span style="font-family:monospace">void method(T)</span> to void <span style="font-family:monospace">method(Class<R>)</span> - correct? Is this actually stated anywhere?<br></div><div><br></div><div><span style="font-family:arial,sans-serif">The first two criteria are easy:</span></div><div><ul><li>m1 and m2 have the same name ✅</li><li>m2 is accessible (§6.6) from C ✅</li></ul>Third criterion:</div><div><ul><li>The signature of m1 is not a subsignature (§8.4.2) of the signature of m2 as a member of the supertype of C that names A. <br></li></ul></div><div>For the signature of m1 to be a subsignature of the signature of m2, it would have to equal the erasure of the signature of m2 as a member of C, which would be <span style="font-family:monospace">void (Class)</span>. But the signature of m1 is void <span style="font-family:monospace">method(Class<R>)</span>. So criterion #3 is met. ✅</div><div><br></div><div>Fourth criterion:</div><div><ul><li>The declared signature of m1 or some method m1 overrides (directly
or indirectly) has the same erasure as the declared signature of m2 or
some method m2 overrides (directly or indirectly).</li></ul></div><div>Both methods erase to <span style="font-family:monospace">void</span><span style="font-family:monospace"> method(Class)</span>. ✅</div><div><br></div><div>OK so far so good (I think) and the above program should NOT compile and therefore there is a bug.<br></div><div><br></div><div>Now consider the same thing except using interfaces:</div><div><br></div><div style="margin-left:40px"><span style="font-family:monospace">public class NarrowingNameClash {<br><br> public interface Upper<T> {<br> void method(T param);<br> }<br><br> public interface Lower<R> extends Upper<Class<R>> {<br> void method(Class<?> param); // name clash here?<br> }<br>}</span><br></div><div><br></div><div>According to my reading, interfaces do NOT inherit methods from superinterfaces. So the above analysis fails, because the only candidates would be m1 = Lower.method(Class<?>) and m2 = Upper.method(T), and those don't erase to the same type.<br></div><div><div><br></div><div>So the second class using interfaces SHOULD compile successfully.<br></div><div><br></div><div>Does the above analysis sound correct?<br></div><div><br><div>Thanks,<br></div><div>-Archie<br></div><div><br></div><div>-- <br><div dir="ltr" data-smartmail="gmail_signature">Archie L. Cobbs<br></div></div></div></div></div>