diff -r a719aa5f1631 -r ce8a7e9d8882 langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java Mon Oct 24 13:00:20 2011 +0100 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java Mon Oct 24 13:00:30 2011 +0100 @@ -25,29 +25,33 @@ package com.sun.tools.javac.comp; -import com.sun.tools.javac.util.*; -import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; +import com.sun.tools.javac.api.Formattable.LocalizedString; import com.sun.tools.javac.code.*; +import com.sun.tools.javac.code.Type.*; +import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.jvm.*; import com.sun.tools.javac.tree.*; -import com.sun.tools.javac.api.Formattable.LocalizedString; -import static com.sun.tools.javac.comp.Resolve.MethodResolutionPhase.*; +import com.sun.tools.javac.tree.JCTree.*; +import com.sun.tools.javac.util.*; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType; -import com.sun.tools.javac.code.Type.*; -import com.sun.tools.javac.code.Symbol.*; -import com.sun.tools.javac.tree.JCTree.*; +import java.util.Arrays; +import java.util.Collection; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import javax.lang.model.element.ElementVisitor; import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.Kinds.*; import static com.sun.tools.javac.code.TypeTags.*; -import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag; -import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType; -import javax.lang.model.element.ElementVisitor; - -import java.util.Map; -import java.util.Set; -import java.util.HashMap; -import java.util.HashSet; +import static com.sun.tools.javac.comp.Resolve.MethodResolutionPhase.*; /** Helper class for name resolution, used mostly by the attribution phase. * @@ -73,9 +77,45 @@ public final boolean varargsEnabled; // = source.allowVarargs(); public final boolean allowMethodHandles; private final boolean debugResolve; + final EnumSet<VerboseResolutionMode> verboseResolutionMode; Scope polymorphicSignatureScope; + enum VerboseResolutionMode { + SUCCESS("success"), + FAILURE("failure"), + APPLICABLE("applicable"), + INAPPLICABLE("inapplicable"), + DEFERRED_INST("deferred-inference"), + PREDEF("predef"), + OBJECT_INIT("object-init"), + INTERNAL("internal"); + + String opt; + + private VerboseResolutionMode(String opt) { + this.opt = opt; + } + + static EnumSet<VerboseResolutionMode> getVerboseResolutionMode(Options opts) { + String s = opts.get("verboseResolution"); + EnumSet<VerboseResolutionMode> res = EnumSet.noneOf(VerboseResolutionMode.class); + if (s == null) return res; + if (s.contains("all")) { + res = EnumSet.allOf(VerboseResolutionMode.class); + } + Collection<String> args = Arrays.asList(s.split(",")); + for (VerboseResolutionMode mode : values()) { + if (args.contains(mode.opt)) { + res.add(mode); + } else if (args.contains("-" + mode.opt)) { + res.remove(mode); + } + } + return res; + } + } + public static Resolve instance(Context context) { Resolve instance = context.get(resolveKey); if (instance == null) @@ -111,6 +151,7 @@ varargsEnabled = source.allowVarargs(); Options options = Options.instance(context); debugResolve = options.isSet("debugresolve"); + verboseResolutionMode = VerboseResolutionMode.getVerboseResolutionMode(options); Target target = Target.instance(context); allowMethodHandles = target.hasMethodHandles(); polymorphicSignatureScope = new Scope(syms.noSymbol); @@ -684,9 +725,11 @@ if (!sym.isInheritedIn(site.tsym, types)) return bestSoFar; Assert.check(sym.kind < AMBIGUOUS); try { - rawInstantiate(env, site, sym, argtypes, typeargtypes, + Type mt = rawInstantiate(env, site, sym, argtypes, typeargtypes, allowBoxing, useVarargs, Warner.noWarnings); + if (!operator) addVerboseApplicableCandidateDiag(sym ,mt); } catch (InapplicableMethodException ex) { + if (!operator) addVerboseInapplicableCandidateDiag(sym, ex.getDiagnostic()); switch (bestSoFar.kind) { case ABSENT_MTH: return wrongMethod.setWrongSym(sym, ex.getDiagnostic()); @@ -709,6 +752,34 @@ : mostSpecific(sym, bestSoFar, env, site, allowBoxing && operator, useVarargs); } + //where + void addVerboseApplicableCandidateDiag(Symbol sym, Type inst) { + if (!verboseResolutionMode.contains(VerboseResolutionMode.APPLICABLE)) + return; + + JCDiagnostic subDiag = null; + if (inst.getReturnType().tag == FORALL) { + Type diagType = types.createMethodTypeWithReturn(inst.asMethodType(), + ((ForAll)inst.getReturnType()).qtype); + subDiag = diags.fragment("partial.inst.sig", diagType); + } else if (sym.type.tag == FORALL) { + subDiag = diags.fragment("full.inst.sig", inst.asMethodType()); + } + + String key = subDiag == null ? + "applicable.method.found" : + "applicable.method.found.1"; + + verboseResolutionCandidateDiags.put(sym, + diags.fragment(key, verboseResolutionCandidateDiags.size(), sym, subDiag)); + } + + void addVerboseInapplicableCandidateDiag(Symbol sym, JCDiagnostic subDiag) { + if (!verboseResolutionMode.contains(VerboseResolutionMode.INAPPLICABLE)) + return; + verboseResolutionCandidateDiags.put(sym, + diags.fragment("not.applicable.method.found", verboseResolutionCandidateDiags.size(), sym, subDiag)); + } /* Return the most specific of the two methods for a call, * given that both are accessible and applicable. @@ -906,8 +977,9 @@ boolean allowBoxing, boolean useVarargs, boolean operator) { + verboseResolutionCandidateDiags.clear(); Symbol bestSoFar = methodNotFound; - return findMethod(env, + bestSoFar = findMethod(env, site, name, argtypes, @@ -919,6 +991,8 @@ useVarargs, operator, new HashSet<TypeSymbol>()); + reportVerboseResolutionDiagnostic(env.tree.pos(), name, site, argtypes, typeargtypes, bestSoFar); + return bestSoFar; } // where private Symbol findMethod(Env<AttrContext> env, @@ -976,6 +1050,37 @@ } return bestSoFar; } + //where + void reportVerboseResolutionDiagnostic(DiagnosticPosition dpos, Name name, Type site, List<Type> argtypes, List<Type> typeargtypes, Symbol bestSoFar) { + boolean success = bestSoFar.kind < ERRONEOUS; + + if (success && !verboseResolutionMode.contains(VerboseResolutionMode.SUCCESS)) { + return; + } else if (!success && !verboseResolutionMode.contains(VerboseResolutionMode.FAILURE)) { + return; + } + + if (bestSoFar.name == names.init && + bestSoFar.owner == syms.objectType.tsym && + !verboseResolutionMode.contains(VerboseResolutionMode.OBJECT_INIT)) { + return; //skip diags for Object constructor resolution + } else if (site == syms.predefClass.type && !verboseResolutionMode.contains(VerboseResolutionMode.PREDEF)) { + return; //skip spurious diags for predef symbols (i.e. operators) + } else if (internalResolution && !verboseResolutionMode.contains(VerboseResolutionMode.INTERNAL)) { + return; + } + + int pos = 0; + for (Symbol s : verboseResolutionCandidateDiags.keySet()) { + if (s == bestSoFar) break; + pos++; + } + String key = success ? "verbose.resolve.multi" : "verbose.resolve.multi.1"; + JCDiagnostic main = diags.note(log.currentSource(), dpos, key, name, site.tsym, pos, currentStep, + methodArguments(argtypes), methodArguments(typeargtypes)); + JCDiagnostic d = new JCDiagnostic.MultilineDiagnostic(main, List.from(verboseResolutionCandidateDiags.values().toArray(new JCDiagnostic[verboseResolutionCandidateDiags.size()]))); + log.report(d); + } /** Find unqualified method matching given name, type and value arguments. * @param env The current environment. @@ -1544,12 +1649,19 @@ Type site, Name name, List<Type> argtypes, List<Type> typeargtypes) { - Symbol sym = resolveQualifiedMethod( - pos, env, site.tsym, site, name, argtypes, typeargtypes); - if (sym.kind == MTH) return (MethodSymbol)sym; - else throw new FatalError( - diags.fragment("fatal.err.cant.locate.meth", - name)); + boolean prevInternal = internalResolution; + try { + internalResolution = true; + Symbol sym = resolveQualifiedMethod( + pos, env, site.tsym, site, name, argtypes, typeargtypes); + if (sym.kind == MTH) return (MethodSymbol)sym; + else throw new FatalError( + diags.fragment("fatal.err.cant.locate.meth", + name)); + } + finally { + internalResolution = prevInternal; + } } /** Resolve constructor. @@ -1830,7 +1942,7 @@ private final LocalizedString noArgs = new LocalizedString("compiler.misc.no.args"); public Object methodArguments(List<Type> argtypes) { - return argtypes.isEmpty() ? noArgs : argtypes; + return argtypes == null || argtypes.isEmpty() ? noArgs : argtypes; } /** @@ -2377,10 +2489,15 @@ private Map<MethodResolutionPhase, Symbol> methodResolutionCache = new HashMap<MethodResolutionPhase, Symbol>(MethodResolutionPhase.values().length); + private Map<Symbol, JCDiagnostic> verboseResolutionCandidateDiags = + new LinkedHashMap<Symbol, JCDiagnostic>(); + final List<MethodResolutionPhase> methodResolutionSteps = List.of(BASIC, BOX, VARARITY); private MethodResolutionPhase currentStep = null; + private boolean internalResolution = false; + private MethodResolutionPhase firstErroneousResolutionPhase() { MethodResolutionPhase bestSoFar = BASIC; Symbol sym = methodNotFound;