8194932: no ambuguity error is emitted if classfile contains two identical methods with different return types
Summary: add recovery logic when classfile contains two signature-equivalent methods
Reviewed-by: jlahoda, vromero
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java Fri Jan 12 10:33:06 2018 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java Fri Jan 12 16:49:58 2018 +0000
@@ -3464,6 +3464,7 @@
types.hasSameArgs(sym.type, byName.type) ||
types.hasSameArgs(types.erasure(sym.type), types.erasure(byName.type)))) {
if ((sym.flags() & VARARGS) != (byName.flags() & VARARGS)) {
+ sym.flags_field |= CLASH;
varargsDuplicateError(pos, sym, byName);
return true;
} else if (sym.kind == MTH && !types.hasSameArgs(sym.type, byName.type, false)) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java Fri Jan 12 10:33:06 2018 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java Fri Jan 12 16:49:58 2018 +0000
@@ -1618,19 +1618,30 @@
if ((m1.flags() & BRIDGE) != (m2.flags() & BRIDGE))
return ((m1.flags() & BRIDGE) != 0) ? m2 : m1;
+ if (m1.baseSymbol() == m2.baseSymbol()) {
+ // this is the same imported symbol which has been cloned twice.
+ // Return the first one (either will do).
+ return m1;
+ }
+
// if one overrides or hides the other, use it
TypeSymbol m1Owner = (TypeSymbol)m1.owner;
TypeSymbol m2Owner = (TypeSymbol)m2.owner;
- if (types.asSuper(m1Owner.type, m2Owner) != null &&
- ((m1.owner.flags_field & INTERFACE) == 0 ||
- (m2.owner.flags_field & INTERFACE) != 0) &&
- m1.overrides(m2, m1Owner, types, false))
- return m1;
- if (types.asSuper(m2Owner.type, m1Owner) != null &&
- ((m2.owner.flags_field & INTERFACE) == 0 ||
- (m1.owner.flags_field & INTERFACE) != 0) &&
- m2.overrides(m1, m2Owner, types, false))
- return m2;
+ // the two owners can never be the same if the target methods are compiled from source,
+ // but we need to protect against cases where the methods are defined in some classfile
+ // and make sure we issue an ambiguity error accordingly (by skipping the logic below).
+ if (m1Owner != m2Owner) {
+ if (types.asSuper(m1Owner.type, m2Owner) != null &&
+ ((m1.owner.flags_field & INTERFACE) == 0 ||
+ (m2.owner.flags_field & INTERFACE) != 0) &&
+ m1.overrides(m2, m1Owner, types, false))
+ return m1;
+ if (types.asSuper(m2Owner.type, m1Owner) != null &&
+ ((m2.owner.flags_field & INTERFACE) == 0 ||
+ (m1.owner.flags_field & INTERFACE) != 0) &&
+ m2.overrides(m1, m2Owner, types, false))
+ return m2;
+ }
boolean m1Abstract = (m1.flags() & ABSTRACT) != 0;
boolean m2Abstract = (m2.flags() & ABSTRACT) != 0;
if (m1Abstract && !m2Abstract) return m2;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/8194932/Foo.jcod Fri Jan 12 16:49:58 2018 +0000
@@ -0,0 +1,115 @@
+class Foo {
+ 0xCAFEBABE;
+ 0; // minor version
+ 52; // version
+ [] { // Constant Pool
+ ; // first element is empty
+ Method #4 #14; // #1
+ String #15; // #2
+ class #16; // #3
+ class #17; // #4
+ Utf8 "<init>"; // #5
+ Utf8 "()V"; // #6
+ Utf8 "Code"; // #7
+ Utf8 "LineNumberTable"; // #8
+ Utf8 "m"; // #9
+ Utf8 "m2"; // #10
+ Utf8 "()Ljava/lang/String;"; // #11
+ Utf8 "SourceFile"; // #12
+ Utf8 "Foo.java"; // #13
+ NameAndType #5 #6; // #14
+ Utf8 "Hello"; // #15
+ Utf8 "Foo"; // #16
+ Utf8 "java/lang/Object"; // #17
+ } // Constant Pool
+
+ 0x0020; // access
+ #3;// this_cpx
+ #4;// super_cpx
+
+ [] { // Interfaces
+ } // Interfaces
+
+ [] { // fields
+ } // fields
+
+ [] { // methods
+ { // Member
+ 0x0000; // access
+ #5; // name_cpx
+ #6; // sig_cpx
+ [] { // Attributes
+ Attr(#7) { // Code
+ 1; // max_stack
+ 1; // max_locals
+ Bytes[]{
+ 0x2AB70001B1;
+ };
+ [] { // Traps
+ } // end Traps
+ [] { // Attributes
+ Attr(#8) { // LineNumberTable
+ [] { // LineNumberTable
+ 0 1;
+ }
+ } // end LineNumberTable
+ } // Attributes
+ } // end Code
+ } // Attributes
+ } // Member
+ ;
+ { // Member
+ 0x0000; // access
+ #9; // name_cpx
+ #6; // sig_cpx
+ [] { // Attributes
+ Attr(#7) { // Code
+ 0; // max_stack
+ 1; // max_locals
+ Bytes[]{
+ 0xB1;
+ };
+ [] { // Traps
+ } // end Traps
+ [] { // Attributes
+ Attr(#8) { // LineNumberTable
+ [] { // LineNumberTable
+ 0 2;
+ }
+ } // end LineNumberTable
+ } // Attributes
+ } // end Code
+ } // Attributes
+ } // Member
+ ;
+ { // Member
+ 0x0000; // access
+ #9; // name_cpx
+ #11; // sig_cpx
+ [] { // Attributes
+ Attr(#7) { // Code
+ 1; // max_stack
+ 1; // max_locals
+ Bytes[]{
+ 0x1202B0;
+ };
+ [] { // Traps
+ } // end Traps
+ [] { // Attributes
+ Attr(#8) { // LineNumberTable
+ [] { // LineNumberTable
+ 0 3;
+ }
+ } // end LineNumberTable
+ } // Attributes
+ } // end Code
+ } // Attributes
+ } // Member
+ } // methods
+
+ [] { // Attributes
+ Attr(#12) { // SourceFile
+ #13;
+ } // end SourceFile
+ } // Attributes
+} // end class Foo
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/8194932/T8194932.java Fri Jan 12 16:49:58 2018 +0000
@@ -0,0 +1,13 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8194932
+ * @summary no ambuguity error is emitted if classfile contains two identical methods with different return types
+ * @build Foo
+ * @compile/fail/ref=T8194932.out -XDrawDiagnostics T8194932.java
+ */
+
+class T8194932 {
+ void test(Foo foo) {
+ foo.m(); //should get an ambiguity here
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/8194932/T8194932.out Fri Jan 12 16:49:58 2018 +0000
@@ -0,0 +1,2 @@
+T8194932.java:11:12: compiler.err.ref.ambiguous: m, kindname.method, m(), Foo, kindname.method, m(), Foo
+1 error