7034798: Ambiguity error for abstract method call is too eager
authormcimadamore
Mon, 01 Jul 2013 14:57:03 +0100
changeset 18668 1f99c1b43ab2
parent 18667 7c871925691f
child 18669 99572d59c916
7034798: Ambiguity error for abstract method call is too eager Summary: Javac should wait and see if ambiguous methods can be reconciled at the end of an overload resolution round Reviewed-by: jjg, vromero
langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java
langtools/test/tools/javac/resolve/ResolveHarness.java
langtools/test/tools/javac/resolve/tests/AbstractMerge.java
langtools/test/tools/javac/resolve/tests/InnerOverOuter.java
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Sat Jun 29 20:12:24 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Mon Jul 01 14:57:03 2013 +0100
@@ -1573,7 +1573,6 @@
                           allowBoxing,
                           useVarargs,
                           operator);
-        reportVerboseResolutionDiagnostic(env.tree.pos(), name, site, argtypes, typeargtypes, bestSoFar);
         return bestSoFar;
     }
     // where
@@ -2224,7 +2223,7 @@
         return lookupMethod(env, pos, env.enclClass.sym, resolveMethodCheck,
                 new BasicLookupHelper(name, env.enclClass.sym.type, argtypes, typeargtypes) {
                     @Override
-                    Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
+                    Symbol doLookup(Env<AttrContext> env, MethodResolutionPhase phase) {
                         return findFun(env, name, argtypes, typeargtypes,
                                 phase.isBoxingRequired(),
                                 phase.isVarargsRequired());
@@ -2256,7 +2255,7 @@
                                   List<Type> typeargtypes) {
         return lookupMethod(env, pos, location, resolveContext, new BasicLookupHelper(name, site, argtypes, typeargtypes) {
             @Override
-            Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
+            Symbol doLookup(Env<AttrContext> env, MethodResolutionPhase phase) {
                 return findMethod(env, site, name, argtypes, typeargtypes,
                         phase.isBoxingRequired(),
                         phase.isVarargsRequired(), false);
@@ -2355,7 +2354,7 @@
                               List<Type> typeargtypes) {
         return lookupMethod(env, pos, site.tsym, resolveContext, new BasicLookupHelper(names.init, site, argtypes, typeargtypes) {
             @Override
-            Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
+            Symbol doLookup(Env<AttrContext> env, MethodResolutionPhase phase) {
                 return findConstructor(pos, env, site, argtypes, typeargtypes,
                         phase.isBoxingRequired(),
                         phase.isVarargsRequired());
@@ -2413,7 +2412,7 @@
         return lookupMethod(env, pos, site.tsym, resolveMethodCheck,
                 new BasicLookupHelper(names.init, site, argtypes, typeargtypes) {
                     @Override
-                    Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
+                    Symbol doLookup(Env<AttrContext> env, MethodResolutionPhase phase) {
                         return findDiamond(env, site, argtypes, typeargtypes,
                                 phase.isBoxingRequired(),
                                 phase.isVarargsRequired());
@@ -2503,7 +2502,7 @@
             return lookupMethod(env, pos, syms.predefClass, currentResolutionContext,
                     new BasicLookupHelper(name, syms.predefClass.type, argtypes, null, BOX) {
                 @Override
-                Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
+                Symbol doLookup(Env<AttrContext> env, MethodResolutionPhase phase) {
                     return findMethod(env, site, name, argtypes, typeargtypes,
                             phase.isBoxingRequired(),
                             phase.isVarargsRequired(), true);
@@ -2669,6 +2668,13 @@
         abstract Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase);
 
         /**
+         * Dump overload resolution info
+         */
+        void debug(DiagnosticPosition pos, Symbol sym) {
+            //do nothing
+        }
+
+        /**
          * Validate the result of the lookup
          */
         abstract Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym);
@@ -2685,17 +2691,30 @@
         }
 
         @Override
-        Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
+        final Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
+            Symbol sym = doLookup(env, phase);
             if (sym.kind == AMBIGUOUS) {
                 AmbiguityError a_err = (AmbiguityError)sym;
                 sym = a_err.mergeAbstracts(site);
             }
+            return sym;
+        }
+
+        abstract Symbol doLookup(Env<AttrContext> env, MethodResolutionPhase phase);
+
+        @Override
+        Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
             if (sym.kind >= AMBIGUOUS) {
                 //if nothing is found return the 'first' error
                 sym = accessMethod(sym, pos, location, site, name, true, argtypes, typeargtypes);
             }
             return sym;
         }
+
+        @Override
+        void debug(DiagnosticPosition pos, Symbol sym) {
+            reportVerboseResolutionDiagnostic(pos, name, site, argtypes, typeargtypes, sym);
+        }
     }
 
     /**
@@ -2924,7 +2943,9 @@
                 MethodResolutionPhase prevPhase = currentResolutionContext.step;
                 Symbol prevBest = bestSoFar;
                 currentResolutionContext.step = phase;
-                bestSoFar = phase.mergeResults(bestSoFar, lookupHelper.lookup(env, phase));
+                Symbol sym = lookupHelper.lookup(env, phase);
+                lookupHelper.debug(pos, sym);
+                bestSoFar = phase.mergeResults(bestSoFar, sym);
                 env.info.pendingResolutionPhase = (prevBest == bestSoFar) ? prevPhase : phase;
             }
             return lookupHelper.access(env, pos, location, bestSoFar);
@@ -3630,35 +3651,39 @@
          * is more specific than the others, attempt to merge their signatures.
          */
         Symbol mergeAbstracts(Type site) {
-            Symbol fst = ambiguousSyms.last();
-            Symbol res = fst;
-            for (Symbol s : ambiguousSyms.reverse()) {
-                Type mt1 = types.memberType(site, res);
-                Type mt2 = types.memberType(site, s);
-                if ((s.flags() & ABSTRACT) == 0 ||
-                        !types.overrideEquivalent(mt1, mt2) ||
-                        !types.isSameTypes(fst.erasure(types).getParameterTypes(),
-                                       s.erasure(types).getParameterTypes())) {
-                    //ambiguity cannot be resolved
-                    return this;
-                } else {
-                    Type mst = mostSpecificReturnType(mt1, mt2);
-                    if (mst == null) {
-                        // Theoretically, this can't happen, but it is possible
-                        // due to error recovery or mixing incompatible class files
+            List<Symbol> ambiguousInOrder = ambiguousSyms.reverse();
+            for (Symbol s : ambiguousInOrder) {
+                Type mt = types.memberType(site, s);
+                boolean found = true;
+                List<Type> allThrown = mt.getThrownTypes();
+                for (Symbol s2 : ambiguousInOrder) {
+                    Type mt2 = types.memberType(site, s2);
+                    if ((s2.flags() & ABSTRACT) == 0 ||
+                        !types.overrideEquivalent(mt, mt2) ||
+                        !types.isSameTypes(s.erasure(types).getParameterTypes(),
+                                       s2.erasure(types).getParameterTypes())) {
+                        //ambiguity cannot be resolved
                         return this;
                     }
-                    Symbol mostSpecific = mst == mt1 ? res : s;
-                    List<Type> allThrown = chk.intersect(mt1.getThrownTypes(), mt2.getThrownTypes());
-                    Type newSig = types.createMethodTypeWithThrown(mostSpecific.type, allThrown);
-                    res = new MethodSymbol(
-                            mostSpecific.flags(),
-                            mostSpecific.name,
-                            newSig,
-                            mostSpecific.owner);
+                    Type mst = mostSpecificReturnType(mt, mt2);
+                    if (mst == null || mst != mt) {
+                        found = false;
+                        break;
+                    }
+                    allThrown = chk.intersect(allThrown, mt2.getThrownTypes());
+                }
+                if (found) {
+                    //all ambiguous methods were abstract and one method had
+                    //most specific return type then others
+                    return (allThrown == mt.getThrownTypes()) ?
+                            s : new MethodSymbol(
+                                s.flags(),
+                                s.name,
+                                types.createMethodTypeWithThrown(mt, allThrown),
+                                s.owner);
                 }
             }
-            return res;
+            return this;
         }
 
         @Override
--- a/langtools/test/tools/javac/resolve/ResolveHarness.java	Sat Jun 29 20:12:24 2013 +0100
+++ b/langtools/test/tools/javac/resolve/ResolveHarness.java	Mon Jul 01 14:57:03 2013 +0100
@@ -32,6 +32,8 @@
 
 import com.sun.source.util.JavacTask;
 import com.sun.tools.javac.api.ClientCodeWrapper.DiagnosticSourceUnwrapper;
+import com.sun.tools.javac.code.Flags;
+import com.sun.tools.javac.code.Symbol;
 import com.sun.tools.javac.code.Type.MethodType;
 import com.sun.tools.javac.util.JCDiagnostic;
 
@@ -154,7 +156,7 @@
         //check all candidates have been used up
         for (Map.Entry<ElementKey, Candidate> entry : candidatesMap.entrySet()) {
             if (!seenCandidates.contains(entry.getKey())) {
-                error("Redundant @Candidate annotation on method " + entry.getKey().elem);
+                error("Redundant @Candidate annotation on method " + entry.getKey().elem + " sig = " + entry.getKey().elem.asType());
             }
         }
     }
@@ -250,7 +252,7 @@
         void process(Diagnostic<? extends JavaFileObject> diagnostic) {
             Element siteSym = getSiteSym(diagnostic);
             if (siteSym.getSimpleName().length() != 0 &&
-                    siteSym.getAnnotation(TraceResolve.class) == null) {
+                    ((Symbol)siteSym).outermostClass().getAnnotation(TraceResolve.class) == null) {
                 return;
             }
             int candidateIdx = 0;
@@ -308,7 +310,11 @@
 
         @Override
         void process(Diagnostic<? extends JavaFileObject> diagnostic) {
-            Element methodSym = methodSym(diagnostic);
+            Symbol methodSym = (Symbol)methodSym(diagnostic);
+            if ((methodSym.flags() & Flags.GENERATEDCONSTR) != 0) {
+                //skip resolution of default constructor (put there by javac)
+                return;
+            }
             Candidate c = getCandidateAtPos(methodSym,
                     asJCDiagnostic(diagnostic).getLineNumber(),
                     asJCDiagnostic(diagnostic).getColumnNumber());
@@ -470,23 +476,10 @@
         }
 
         String computeKey(Element e) {
-            StringBuilder buf = new StringBuilder();
-            if (predefTranslationMap.containsKey(e.getSimpleName().toString())) {
-                //predef element
-                buf.append("<predef>.");
-                String replacedName = predefTranslationMap.get(e.getSimpleName().toString());
-                buf.append(e.toString().replace(e.getSimpleName().toString(), replacedName));
-            } else if (e.getSimpleName().toString().startsWith("_")) {
-                buf.append("<predef>.");
-                buf.append(e.toString());
-            } else {
-                while (e != null) {
-                    buf.append(e.toString());
-                    e = e.getEnclosingElement();
-                }
-                buf.append(jfo.getName());
-            }
-            return buf.toString();
+            String simpleName = e.getSimpleName().toString();
+            String opName = predefTranslationMap.get(simpleName);
+            String name = opName != null ? opName : simpleName;
+            return name + e.asType();
         }
 
         @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/resolve/tests/AbstractMerge.java	Mon Jul 01 14:57:03 2013 +0100
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+@TraceResolve
+class AbstractMerge {
+
+    interface A {
+        @Candidate(applicable=Phase.BASIC)
+        java.io.Serializable m1();
+        @Candidate(applicable=Phase.BASIC)
+        java.io.Serializable m2();
+        @Candidate(applicable=Phase.BASIC)
+        java.io.Serializable m3();
+        @Candidate(applicable=Phase.BASIC)
+        java.io.Serializable m4();
+        @Candidate(applicable=Phase.BASIC)
+        java.io.Serializable m5();
+        @Candidate(applicable=Phase.BASIC)
+        java.io.Serializable m6();
+    }
+
+    interface B {
+        @Candidate(applicable=Phase.BASIC)
+        Cloneable m1();
+        @Candidate(applicable=Phase.BASIC)
+        Cloneable m2();
+        @Candidate(applicable=Phase.BASIC)
+        Cloneable m3();
+        @Candidate(applicable=Phase.BASIC)
+        Cloneable m4();
+        @Candidate(applicable=Phase.BASIC)
+        Cloneable m5();
+        @Candidate(applicable=Phase.BASIC)
+        Cloneable m6();
+    }
+
+    interface C {
+        @Candidate(applicable=Phase.BASIC, mostSpecific=true)
+        Object[] m1();
+        @Candidate(applicable=Phase.BASIC, mostSpecific=true)
+        Object[] m2();
+        @Candidate(applicable=Phase.BASIC, mostSpecific=true)
+        Object[] m3();
+        @Candidate(applicable=Phase.BASIC, mostSpecific=true)
+        Object[] m4();
+        @Candidate(applicable=Phase.BASIC, mostSpecific=true)
+        Object[] m5();
+        @Candidate(applicable=Phase.BASIC, mostSpecific=true)
+        Object[] m6();
+    }
+
+    interface ABC extends A, B, C { }
+    interface ACB extends A, C, B { }
+    interface BAC extends B, A, C { }
+    interface BCA extends B, C, A { }
+    interface CAB extends C, A, B { }
+    interface CBA extends C, B, A { }
+
+    {
+        ABC abc = null;
+        abc.m1();
+    }
+
+    {
+        ACB acb = null;
+        acb.m2();
+    }
+
+    {
+        BAC bac = null;
+        bac.m3();
+    }
+
+    {
+        BCA bca = null;
+        bca.m4();
+    }
+
+    {
+        CAB cab = null;
+        cab.m5();
+    }
+
+    {
+        CBA cba = null;
+        cba.m6();
+    }
+}
--- a/langtools/test/tools/javac/resolve/tests/InnerOverOuter.java	Sat Jun 29 20:12:24 2013 +0100
+++ b/langtools/test/tools/javac/resolve/tests/InnerOverOuter.java	Mon Jul 01 14:57:03 2013 +0100
@@ -21,7 +21,7 @@
  * questions.
  */
 
-@TraceResolve
+@TraceResolve(keys={"compiler.err.cant.apply.symbol"})
 class Test {
 
     //no annotation here - this should NOT even be considered!
@@ -30,7 +30,6 @@
     //no annotation here - this should NOT even be considered!
     void m(Object... o) { }
 
-    @TraceResolve(keys={"compiler.err.cant.apply.symbol"})
     class Inner {
         @Candidate
         void m(String s) {