8194932: no ambuguity error is emitted if classfile contains two identical methods with different return types
authormcimadamore
Fri, 12 Jan 2018 16:49:58 +0000
changeset 48459 a5f815d1060b
parent 48458 7f57c5908c57
child 48460 bdbbf56c302e
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
src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java
test/langtools/tools/javac/8194932/Foo.jcod
test/langtools/tools/javac/8194932/T8194932.java
test/langtools/tools/javac/8194932/T8194932.out
--- 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