# HG changeset patch # User mcimadamore # Date 1372687023 -3600 # Node ID 1f99c1b43ab2d0bbbffb1249fe53dd3899dedb7e # Parent 7c871925691f56477e38dc6a138843a118ce7ae3 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 diff -r 7c871925691f -r 1f99c1b43ab2 langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.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 env, MethodResolutionPhase phase) { + Symbol doLookup(Env env, MethodResolutionPhase phase) { return findFun(env, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()); @@ -2256,7 +2255,7 @@ List typeargtypes) { return lookupMethod(env, pos, location, resolveContext, new BasicLookupHelper(name, site, argtypes, typeargtypes) { @Override - Symbol lookup(Env env, MethodResolutionPhase phase) { + Symbol doLookup(Env env, MethodResolutionPhase phase) { return findMethod(env, site, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired(), false); @@ -2355,7 +2354,7 @@ List typeargtypes) { return lookupMethod(env, pos, site.tsym, resolveContext, new BasicLookupHelper(names.init, site, argtypes, typeargtypes) { @Override - Symbol lookup(Env env, MethodResolutionPhase phase) { + Symbol doLookup(Env 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 env, MethodResolutionPhase phase) { + Symbol doLookup(Env 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 env, MethodResolutionPhase phase) { + Symbol doLookup(Env env, MethodResolutionPhase phase) { return findMethod(env, site, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired(), true); @@ -2669,6 +2668,13 @@ abstract Symbol lookup(Env 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 env, DiagnosticPosition pos, Symbol location, Symbol sym); @@ -2685,17 +2691,30 @@ } @Override - Symbol access(Env env, DiagnosticPosition pos, Symbol location, Symbol sym) { + final Symbol lookup(Env 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 env, MethodResolutionPhase phase); + + @Override + Symbol access(Env 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 ambiguousInOrder = ambiguousSyms.reverse(); + for (Symbol s : ambiguousInOrder) { + Type mt = types.memberType(site, s); + boolean found = true; + List 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 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 diff -r 7c871925691f -r 1f99c1b43ab2 langtools/test/tools/javac/resolve/ResolveHarness.java --- 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 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 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 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("."); - String replacedName = predefTranslationMap.get(e.getSimpleName().toString()); - buf.append(e.toString().replace(e.getSimpleName().toString(), replacedName)); - } else if (e.getSimpleName().toString().startsWith("_")) { - buf.append("."); - 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 diff -r 7c871925691f -r 1f99c1b43ab2 langtools/test/tools/javac/resolve/tests/AbstractMerge.java --- /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(); + } +} diff -r 7c871925691f -r 1f99c1b43ab2 langtools/test/tools/javac/resolve/tests/InnerOverOuter.java --- 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) {