diff -r 0070e9c44020 -r c66c0a81c4ab langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java Mon Sep 24 14:04:34 2012 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java Tue Sep 25 11:52:37 2012 +0100 @@ -40,6 +40,7 @@ import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.EnumMap; @@ -57,6 +58,7 @@ import static com.sun.tools.javac.code.TypeTags.*; import static com.sun.tools.javac.comp.Resolve.MethodResolutionPhase.*; import static com.sun.tools.javac.tree.JCTree.Tag.*; +import java.util.Iterator; /** Helper class for name resolution, used mostly by the attribution phase. * @@ -1035,8 +1037,8 @@ return this; else return super.implementation(origin, types, checkResult); - } - }; + } + }; return result; } if (m1SignatureMoreSpecific) return m1; @@ -1160,12 +1162,10 @@ argtypes, typeargtypes, site.tsym.type, - true, bestSoFar, allowBoxing, useVarargs, - operator, - new HashSet()); + operator); reportVerboseResolutionDiagnostic(env.tree.pos(), name, site, argtypes, typeargtypes, bestSoFar); return bestSoFar; } @@ -1176,56 +1176,137 @@ List argtypes, List typeargtypes, Type intype, - boolean abstractok, Symbol bestSoFar, boolean allowBoxing, boolean useVarargs, - boolean operator, - Set seen) { - for (Type ct = intype; ct.tag == CLASS || ct.tag == TYPEVAR; ct = types.supertype(ct)) { - while (ct.tag == TYPEVAR) - ct = ct.getUpperBound(); - ClassSymbol c = (ClassSymbol)ct.tsym; - if (!seen.add(c)) return bestSoFar; - if ((c.flags() & (ABSTRACT | INTERFACE | ENUM)) == 0) - abstractok = false; - for (Scope.Entry e = c.members().lookup(name); - e.scope != null; - e = e.next()) { - //- System.out.println(" e " + e.sym); - if (e.sym.kind == MTH && - (e.sym.flags_field & SYNTHETIC) == 0) { - bestSoFar = selectBest(env, site, argtypes, typeargtypes, - e.sym, bestSoFar, - allowBoxing, - useVarargs, - operator); + boolean operator) { + boolean abstractOk = true; + List itypes = List.nil(); + for (TypeSymbol s : superclasses(intype)) { + bestSoFar = lookupMethod(env, site, name, argtypes, typeargtypes, + s.members(), bestSoFar, allowBoxing, useVarargs, operator, true); + abstractOk &= excludeAbstractsFilter.accepts(s); + if (abstractOk) { + for (Type itype : types.interfaces(s.type)) { + itypes = types.union(types.closure(itype), itypes); } } - if (name == names.init) - break; - //- System.out.println(" - " + bestSoFar); - if (abstractok) { - Symbol concrete = methodNotFound; - if ((bestSoFar.flags() & ABSTRACT) == 0) - concrete = bestSoFar; - for (List l = types.interfaces(c.type); - l.nonEmpty(); - l = l.tail) { - bestSoFar = findMethod(env, site, name, argtypes, - typeargtypes, - l.head, abstractok, bestSoFar, - allowBoxing, useVarargs, operator, seen); - } - if (concrete != bestSoFar && - concrete.kind < ERR && bestSoFar.kind < ERR && - types.isSubSignature(concrete.type, bestSoFar.type)) - bestSoFar = concrete; + if (name == names.init) break; + } + + Symbol concrete = bestSoFar.kind < ERR && + (bestSoFar.flags() & ABSTRACT) == 0 ? + bestSoFar : methodNotFound; + + if (name != names.init) { + //keep searching for abstract methods + for (Type itype : itypes) { + if (!itype.isInterface()) continue; //skip j.l.Object (included by Types.closure()) + bestSoFar = lookupMethod(env, site, name, argtypes, typeargtypes, + itype.tsym.members(), bestSoFar, allowBoxing, useVarargs, operator, true); + if (concrete != bestSoFar && + concrete.kind < ERR && bestSoFar.kind < ERR && + types.isSubSignature(concrete.type, bestSoFar.type)) { + //this is an hack - as javac does not do full membership checks + //most specific ends up comparing abstract methods that might have + //been implemented by some concrete method in a subclass and, + //because of raw override, it is possible for an abstract method + //to be more specific than the concrete method - so we need + //to explicitly call that out (see CR 6178365) + bestSoFar = concrete; + } } } return bestSoFar; } + /** + * Return an Iterable object to scan the superclasses of a given type. + * It's crucial that the scan is done lazily, as we don't want to accidentally + * access more supertypes than strictly needed (as this could trigger completion + * errors if some of the not-needed supertypes are missing/ill-formed). + */ + Iterable superclasses(final Type intype) { + return new Iterable() { + public Iterator iterator() { + return new Iterator() { + + List seen = List.nil(); + TypeSymbol currentSym = getSymbol(intype); + + public boolean hasNext() { + return currentSym != null; + } + + public TypeSymbol next() { + TypeSymbol prevSym = currentSym; + currentSym = getSymbol(types.supertype(currentSym.type)); + return prevSym; + } + + public void remove() { + throw new UnsupportedOperationException("Not supported yet."); + } + + TypeSymbol getSymbol(Type intype) { + if (intype.tag != CLASS && + intype.tag != TYPEVAR) { + return null; + } + while (intype.tag == TYPEVAR) + intype = intype.getUpperBound(); + if (seen.contains(intype.tsym)) { + //degenerate case in which we have a circular + //class hierarchy - because of ill-formed classfiles + return null; + } + seen = seen.prepend(intype.tsym); + return intype.tsym; + } + }; + } + }; + } + + /** + * We should not look for abstract methods if receiver is a concrete class + * (as concrete classes are expected to implement all abstracts coming + * from superinterfaces) + */ + Filter excludeAbstractsFilter = new Filter() { + public boolean accepts(Symbol s) { + return (s.flags() & (ABSTRACT | INTERFACE | ENUM)) != 0; + } + }; + + /** + * Lookup a method with given name and argument types in a given scope + */ + Symbol lookupMethod(Env env, + Type site, + Name name, + List argtypes, + List typeargtypes, + Scope sc, + Symbol bestSoFar, + boolean allowBoxing, + boolean useVarargs, + boolean operator, + boolean abstractok) { + for (Symbol s : sc.getElementsByName(name, lookupFilter)) { + bestSoFar = selectBest(env, site, argtypes, typeargtypes, s, + bestSoFar, allowBoxing, useVarargs, operator); + } + return bestSoFar; + } + //where + Filter lookupFilter = new Filter() { + public boolean accepts(Symbol s) { + return s.kind == MTH && + (s.flags() & SYNTHETIC) == 0; + } + }; + /** Find unqualified method matching given name, type and value arguments. * @param env The current environment. * @param name The method's name.