Mon, 01 Jul 2013 14:57:03 +0100
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
1.1 --- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java Sat Jun 29 20:12:24 2013 +0100 1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java Mon Jul 01 14:57:03 2013 +0100 1.3 @@ -1573,7 +1573,6 @@ 1.4 allowBoxing, 1.5 useVarargs, 1.6 operator); 1.7 - reportVerboseResolutionDiagnostic(env.tree.pos(), name, site, argtypes, typeargtypes, bestSoFar); 1.8 return bestSoFar; 1.9 } 1.10 // where 1.11 @@ -2224,7 +2223,7 @@ 1.12 return lookupMethod(env, pos, env.enclClass.sym, resolveMethodCheck, 1.13 new BasicLookupHelper(name, env.enclClass.sym.type, argtypes, typeargtypes) { 1.14 @Override 1.15 - Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) { 1.16 + Symbol doLookup(Env<AttrContext> env, MethodResolutionPhase phase) { 1.17 return findFun(env, name, argtypes, typeargtypes, 1.18 phase.isBoxingRequired(), 1.19 phase.isVarargsRequired()); 1.20 @@ -2256,7 +2255,7 @@ 1.21 List<Type> typeargtypes) { 1.22 return lookupMethod(env, pos, location, resolveContext, new BasicLookupHelper(name, site, argtypes, typeargtypes) { 1.23 @Override 1.24 - Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) { 1.25 + Symbol doLookup(Env<AttrContext> env, MethodResolutionPhase phase) { 1.26 return findMethod(env, site, name, argtypes, typeargtypes, 1.27 phase.isBoxingRequired(), 1.28 phase.isVarargsRequired(), false); 1.29 @@ -2355,7 +2354,7 @@ 1.30 List<Type> typeargtypes) { 1.31 return lookupMethod(env, pos, site.tsym, resolveContext, new BasicLookupHelper(names.init, site, argtypes, typeargtypes) { 1.32 @Override 1.33 - Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) { 1.34 + Symbol doLookup(Env<AttrContext> env, MethodResolutionPhase phase) { 1.35 return findConstructor(pos, env, site, argtypes, typeargtypes, 1.36 phase.isBoxingRequired(), 1.37 phase.isVarargsRequired()); 1.38 @@ -2413,7 +2412,7 @@ 1.39 return lookupMethod(env, pos, site.tsym, resolveMethodCheck, 1.40 new BasicLookupHelper(names.init, site, argtypes, typeargtypes) { 1.41 @Override 1.42 - Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) { 1.43 + Symbol doLookup(Env<AttrContext> env, MethodResolutionPhase phase) { 1.44 return findDiamond(env, site, argtypes, typeargtypes, 1.45 phase.isBoxingRequired(), 1.46 phase.isVarargsRequired()); 1.47 @@ -2503,7 +2502,7 @@ 1.48 return lookupMethod(env, pos, syms.predefClass, currentResolutionContext, 1.49 new BasicLookupHelper(name, syms.predefClass.type, argtypes, null, BOX) { 1.50 @Override 1.51 - Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) { 1.52 + Symbol doLookup(Env<AttrContext> env, MethodResolutionPhase phase) { 1.53 return findMethod(env, site, name, argtypes, typeargtypes, 1.54 phase.isBoxingRequired(), 1.55 phase.isVarargsRequired(), true); 1.56 @@ -2669,6 +2668,13 @@ 1.57 abstract Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase); 1.58 1.59 /** 1.60 + * Dump overload resolution info 1.61 + */ 1.62 + void debug(DiagnosticPosition pos, Symbol sym) { 1.63 + //do nothing 1.64 + } 1.65 + 1.66 + /** 1.67 * Validate the result of the lookup 1.68 */ 1.69 abstract Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym); 1.70 @@ -2685,17 +2691,30 @@ 1.71 } 1.72 1.73 @Override 1.74 - Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) { 1.75 + final Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) { 1.76 + Symbol sym = doLookup(env, phase); 1.77 if (sym.kind == AMBIGUOUS) { 1.78 AmbiguityError a_err = (AmbiguityError)sym; 1.79 sym = a_err.mergeAbstracts(site); 1.80 } 1.81 + return sym; 1.82 + } 1.83 + 1.84 + abstract Symbol doLookup(Env<AttrContext> env, MethodResolutionPhase phase); 1.85 + 1.86 + @Override 1.87 + Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) { 1.88 if (sym.kind >= AMBIGUOUS) { 1.89 //if nothing is found return the 'first' error 1.90 sym = accessMethod(sym, pos, location, site, name, true, argtypes, typeargtypes); 1.91 } 1.92 return sym; 1.93 } 1.94 + 1.95 + @Override 1.96 + void debug(DiagnosticPosition pos, Symbol sym) { 1.97 + reportVerboseResolutionDiagnostic(pos, name, site, argtypes, typeargtypes, sym); 1.98 + } 1.99 } 1.100 1.101 /** 1.102 @@ -2924,7 +2943,9 @@ 1.103 MethodResolutionPhase prevPhase = currentResolutionContext.step; 1.104 Symbol prevBest = bestSoFar; 1.105 currentResolutionContext.step = phase; 1.106 - bestSoFar = phase.mergeResults(bestSoFar, lookupHelper.lookup(env, phase)); 1.107 + Symbol sym = lookupHelper.lookup(env, phase); 1.108 + lookupHelper.debug(pos, sym); 1.109 + bestSoFar = phase.mergeResults(bestSoFar, sym); 1.110 env.info.pendingResolutionPhase = (prevBest == bestSoFar) ? prevPhase : phase; 1.111 } 1.112 return lookupHelper.access(env, pos, location, bestSoFar); 1.113 @@ -3630,35 +3651,39 @@ 1.114 * is more specific than the others, attempt to merge their signatures. 1.115 */ 1.116 Symbol mergeAbstracts(Type site) { 1.117 - Symbol fst = ambiguousSyms.last(); 1.118 - Symbol res = fst; 1.119 - for (Symbol s : ambiguousSyms.reverse()) { 1.120 - Type mt1 = types.memberType(site, res); 1.121 - Type mt2 = types.memberType(site, s); 1.122 - if ((s.flags() & ABSTRACT) == 0 || 1.123 - !types.overrideEquivalent(mt1, mt2) || 1.124 - !types.isSameTypes(fst.erasure(types).getParameterTypes(), 1.125 - s.erasure(types).getParameterTypes())) { 1.126 - //ambiguity cannot be resolved 1.127 - return this; 1.128 - } else { 1.129 - Type mst = mostSpecificReturnType(mt1, mt2); 1.130 - if (mst == null) { 1.131 - // Theoretically, this can't happen, but it is possible 1.132 - // due to error recovery or mixing incompatible class files 1.133 + List<Symbol> ambiguousInOrder = ambiguousSyms.reverse(); 1.134 + for (Symbol s : ambiguousInOrder) { 1.135 + Type mt = types.memberType(site, s); 1.136 + boolean found = true; 1.137 + List<Type> allThrown = mt.getThrownTypes(); 1.138 + for (Symbol s2 : ambiguousInOrder) { 1.139 + Type mt2 = types.memberType(site, s2); 1.140 + if ((s2.flags() & ABSTRACT) == 0 || 1.141 + !types.overrideEquivalent(mt, mt2) || 1.142 + !types.isSameTypes(s.erasure(types).getParameterTypes(), 1.143 + s2.erasure(types).getParameterTypes())) { 1.144 + //ambiguity cannot be resolved 1.145 return this; 1.146 } 1.147 - Symbol mostSpecific = mst == mt1 ? res : s; 1.148 - List<Type> allThrown = chk.intersect(mt1.getThrownTypes(), mt2.getThrownTypes()); 1.149 - Type newSig = types.createMethodTypeWithThrown(mostSpecific.type, allThrown); 1.150 - res = new MethodSymbol( 1.151 - mostSpecific.flags(), 1.152 - mostSpecific.name, 1.153 - newSig, 1.154 - mostSpecific.owner); 1.155 + Type mst = mostSpecificReturnType(mt, mt2); 1.156 + if (mst == null || mst != mt) { 1.157 + found = false; 1.158 + break; 1.159 + } 1.160 + allThrown = chk.intersect(allThrown, mt2.getThrownTypes()); 1.161 + } 1.162 + if (found) { 1.163 + //all ambiguous methods were abstract and one method had 1.164 + //most specific return type then others 1.165 + return (allThrown == mt.getThrownTypes()) ? 1.166 + s : new MethodSymbol( 1.167 + s.flags(), 1.168 + s.name, 1.169 + types.createMethodTypeWithThrown(mt, allThrown), 1.170 + s.owner); 1.171 } 1.172 } 1.173 - return res; 1.174 + return this; 1.175 } 1.176 1.177 @Override
2.1 --- a/test/tools/javac/resolve/ResolveHarness.java Sat Jun 29 20:12:24 2013 +0100 2.2 +++ b/test/tools/javac/resolve/ResolveHarness.java Mon Jul 01 14:57:03 2013 +0100 2.3 @@ -32,6 +32,8 @@ 2.4 2.5 import com.sun.source.util.JavacTask; 2.6 import com.sun.tools.javac.api.ClientCodeWrapper.DiagnosticSourceUnwrapper; 2.7 +import com.sun.tools.javac.code.Flags; 2.8 +import com.sun.tools.javac.code.Symbol; 2.9 import com.sun.tools.javac.code.Type.MethodType; 2.10 import com.sun.tools.javac.util.JCDiagnostic; 2.11 2.12 @@ -154,7 +156,7 @@ 2.13 //check all candidates have been used up 2.14 for (Map.Entry<ElementKey, Candidate> entry : candidatesMap.entrySet()) { 2.15 if (!seenCandidates.contains(entry.getKey())) { 2.16 - error("Redundant @Candidate annotation on method " + entry.getKey().elem); 2.17 + error("Redundant @Candidate annotation on method " + entry.getKey().elem + " sig = " + entry.getKey().elem.asType()); 2.18 } 2.19 } 2.20 } 2.21 @@ -250,7 +252,7 @@ 2.22 void process(Diagnostic<? extends JavaFileObject> diagnostic) { 2.23 Element siteSym = getSiteSym(diagnostic); 2.24 if (siteSym.getSimpleName().length() != 0 && 2.25 - siteSym.getAnnotation(TraceResolve.class) == null) { 2.26 + ((Symbol)siteSym).outermostClass().getAnnotation(TraceResolve.class) == null) { 2.27 return; 2.28 } 2.29 int candidateIdx = 0; 2.30 @@ -308,7 +310,11 @@ 2.31 2.32 @Override 2.33 void process(Diagnostic<? extends JavaFileObject> diagnostic) { 2.34 - Element methodSym = methodSym(diagnostic); 2.35 + Symbol methodSym = (Symbol)methodSym(diagnostic); 2.36 + if ((methodSym.flags() & Flags.GENERATEDCONSTR) != 0) { 2.37 + //skip resolution of default constructor (put there by javac) 2.38 + return; 2.39 + } 2.40 Candidate c = getCandidateAtPos(methodSym, 2.41 asJCDiagnostic(diagnostic).getLineNumber(), 2.42 asJCDiagnostic(diagnostic).getColumnNumber()); 2.43 @@ -470,23 +476,10 @@ 2.44 } 2.45 2.46 String computeKey(Element e) { 2.47 - StringBuilder buf = new StringBuilder(); 2.48 - if (predefTranslationMap.containsKey(e.getSimpleName().toString())) { 2.49 - //predef element 2.50 - buf.append("<predef>."); 2.51 - String replacedName = predefTranslationMap.get(e.getSimpleName().toString()); 2.52 - buf.append(e.toString().replace(e.getSimpleName().toString(), replacedName)); 2.53 - } else if (e.getSimpleName().toString().startsWith("_")) { 2.54 - buf.append("<predef>."); 2.55 - buf.append(e.toString()); 2.56 - } else { 2.57 - while (e != null) { 2.58 - buf.append(e.toString()); 2.59 - e = e.getEnclosingElement(); 2.60 - } 2.61 - buf.append(jfo.getName()); 2.62 - } 2.63 - return buf.toString(); 2.64 + String simpleName = e.getSimpleName().toString(); 2.65 + String opName = predefTranslationMap.get(simpleName); 2.66 + String name = opName != null ? opName : simpleName; 2.67 + return name + e.asType(); 2.68 } 2.69 2.70 @Override
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/test/tools/javac/resolve/tests/AbstractMerge.java Mon Jul 01 14:57:03 2013 +0100 3.3 @@ -0,0 +1,107 @@ 3.4 +/* 3.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 3.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3.7 + * 3.8 + * This code is free software; you can redistribute it and/or modify it 3.9 + * under the terms of the GNU General Public License version 2 only, as 3.10 + * published by the Free Software Foundation. 3.11 + * 3.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 3.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 3.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 3.15 + * version 2 for more details (a copy is included in the LICENSE file that 3.16 + * accompanied this code). 3.17 + * 3.18 + * You should have received a copy of the GNU General Public License version 3.19 + * 2 along with this work; if not, write to the Free Software Foundation, 3.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 3.21 + * 3.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 3.23 + * or visit www.oracle.com if you need additional information or have any 3.24 + * questions. 3.25 + */ 3.26 +@TraceResolve 3.27 +class AbstractMerge { 3.28 + 3.29 + interface A { 3.30 + @Candidate(applicable=Phase.BASIC) 3.31 + java.io.Serializable m1(); 3.32 + @Candidate(applicable=Phase.BASIC) 3.33 + java.io.Serializable m2(); 3.34 + @Candidate(applicable=Phase.BASIC) 3.35 + java.io.Serializable m3(); 3.36 + @Candidate(applicable=Phase.BASIC) 3.37 + java.io.Serializable m4(); 3.38 + @Candidate(applicable=Phase.BASIC) 3.39 + java.io.Serializable m5(); 3.40 + @Candidate(applicable=Phase.BASIC) 3.41 + java.io.Serializable m6(); 3.42 + } 3.43 + 3.44 + interface B { 3.45 + @Candidate(applicable=Phase.BASIC) 3.46 + Cloneable m1(); 3.47 + @Candidate(applicable=Phase.BASIC) 3.48 + Cloneable m2(); 3.49 + @Candidate(applicable=Phase.BASIC) 3.50 + Cloneable m3(); 3.51 + @Candidate(applicable=Phase.BASIC) 3.52 + Cloneable m4(); 3.53 + @Candidate(applicable=Phase.BASIC) 3.54 + Cloneable m5(); 3.55 + @Candidate(applicable=Phase.BASIC) 3.56 + Cloneable m6(); 3.57 + } 3.58 + 3.59 + interface C { 3.60 + @Candidate(applicable=Phase.BASIC, mostSpecific=true) 3.61 + Object[] m1(); 3.62 + @Candidate(applicable=Phase.BASIC, mostSpecific=true) 3.63 + Object[] m2(); 3.64 + @Candidate(applicable=Phase.BASIC, mostSpecific=true) 3.65 + Object[] m3(); 3.66 + @Candidate(applicable=Phase.BASIC, mostSpecific=true) 3.67 + Object[] m4(); 3.68 + @Candidate(applicable=Phase.BASIC, mostSpecific=true) 3.69 + Object[] m5(); 3.70 + @Candidate(applicable=Phase.BASIC, mostSpecific=true) 3.71 + Object[] m6(); 3.72 + } 3.73 + 3.74 + interface ABC extends A, B, C { } 3.75 + interface ACB extends A, C, B { } 3.76 + interface BAC extends B, A, C { } 3.77 + interface BCA extends B, C, A { } 3.78 + interface CAB extends C, A, B { } 3.79 + interface CBA extends C, B, A { } 3.80 + 3.81 + { 3.82 + ABC abc = null; 3.83 + abc.m1(); 3.84 + } 3.85 + 3.86 + { 3.87 + ACB acb = null; 3.88 + acb.m2(); 3.89 + } 3.90 + 3.91 + { 3.92 + BAC bac = null; 3.93 + bac.m3(); 3.94 + } 3.95 + 3.96 + { 3.97 + BCA bca = null; 3.98 + bca.m4(); 3.99 + } 3.100 + 3.101 + { 3.102 + CAB cab = null; 3.103 + cab.m5(); 3.104 + } 3.105 + 3.106 + { 3.107 + CBA cba = null; 3.108 + cba.m6(); 3.109 + } 3.110 +}
4.1 --- a/test/tools/javac/resolve/tests/InnerOverOuter.java Sat Jun 29 20:12:24 2013 +0100 4.2 +++ b/test/tools/javac/resolve/tests/InnerOverOuter.java Mon Jul 01 14:57:03 2013 +0100 4.3 @@ -21,7 +21,7 @@ 4.4 * questions. 4.5 */ 4.6 4.7 -@TraceResolve 4.8 +@TraceResolve(keys={"compiler.err.cant.apply.symbol"}) 4.9 class Test { 4.10 4.11 //no annotation here - this should NOT even be considered! 4.12 @@ -30,7 +30,6 @@ 4.13 //no annotation here - this should NOT even be considered! 4.14 void m(Object... o) { } 4.15 4.16 - @TraceResolve(keys={"compiler.err.cant.apply.symbol"}) 4.17 class Inner { 4.18 @Candidate 4.19 void m(String s) {