langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java
changeset 12076 1b7560bd1760
parent 11707 532f41763bc9
child 12078 7470e05d486b
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Tue Feb 28 18:04:50 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Fri Mar 02 12:57:04 2012 +0000
@@ -29,6 +29,7 @@
 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.comp.Resolve.MethodResolutionContext.Candidate;
 import com.sun.tools.javac.jvm.*;
 import com.sun.tools.javac.tree.*;
 import com.sun.tools.javac.tree.JCTree.*;
@@ -39,10 +40,9 @@
 
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.EnumMap;
 import java.util.EnumSet;
-import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
 
@@ -84,6 +84,58 @@
 
     Scope polymorphicSignatureScope;
 
+    protected Resolve(Context context) {
+        context.put(resolveKey, this);
+        syms = Symtab.instance(context);
+
+        varNotFound = new
+            SymbolNotFoundError(ABSENT_VAR);
+        wrongMethod = new
+            InapplicableSymbolError();
+        wrongMethods = new
+            InapplicableSymbolsError();
+        methodNotFound = new
+            SymbolNotFoundError(ABSENT_MTH);
+        typeNotFound = new
+            SymbolNotFoundError(ABSENT_TYP);
+
+        names = Names.instance(context);
+        log = Log.instance(context);
+        chk = Check.instance(context);
+        infer = Infer.instance(context);
+        reader = ClassReader.instance(context);
+        treeinfo = TreeInfo.instance(context);
+        types = Types.instance(context);
+        diags = JCDiagnostic.Factory.instance(context);
+        Source source = Source.instance(context);
+        boxingEnabled = source.allowBoxing();
+        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);
+
+        inapplicableMethodException = new InapplicableMethodException(diags);
+    }
+
+    /** error symbols, which are returned when resolution fails
+     */
+    private final SymbolNotFoundError varNotFound;
+    private final InapplicableSymbolError wrongMethod;
+    private final InapplicableSymbolsError wrongMethods;
+    private final SymbolNotFoundError methodNotFound;
+    private final SymbolNotFoundError typeNotFound;
+
+    public static Resolve instance(Context context) {
+        Resolve instance = context.get(resolveKey);
+        if (instance == null)
+            instance = new Resolve(context);
+        return instance;
+    }
+
+    // <editor-fold defaultstate="collapsed" desc="Verbose resolution diagnostics support">
     enum VerboseResolutionMode {
         SUCCESS("success"),
         FAILURE("failure"),
@@ -119,56 +171,74 @@
         }
     }
 
-    public static Resolve instance(Context context) {
-        Resolve instance = context.get(resolveKey);
-        if (instance == null)
-            instance = new Resolve(context);
-        return instance;
+    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 (currentResolutionContext.internalResolution &&
+                !verboseResolutionMode.contains(VerboseResolutionMode.INTERNAL)) {
+            return;
+        }
+
+        int pos = 0;
+        int mostSpecificPos = -1;
+        ListBuffer<JCDiagnostic> subDiags = ListBuffer.lb();
+        for (Candidate c : currentResolutionContext.candidates) {
+            if (currentResolutionContext.step != c.step ||
+                    (c.isApplicable() && !verboseResolutionMode.contains(VerboseResolutionMode.APPLICABLE)) ||
+                    (!c.isApplicable() && !verboseResolutionMode.contains(VerboseResolutionMode.INAPPLICABLE))) {
+                continue;
+            } else {
+                subDiags.append(c.isApplicable() ?
+                        getVerboseApplicableCandidateDiag(pos, c.sym, c.mtype) :
+                        getVerboseInapplicableCandidateDiag(pos, c.sym, c.details));
+                if (c.sym == bestSoFar)
+                    mostSpecificPos = pos;
+                pos++;
+            }
+        }
+        String key = success ? "verbose.resolve.multi" : "verbose.resolve.multi.1";
+        JCDiagnostic main = diags.note(log.currentSource(), dpos, key, name,
+                site.tsym, mostSpecificPos, currentResolutionContext.step,
+                methodArguments(argtypes), methodArguments(typeargtypes));
+        JCDiagnostic d = new JCDiagnostic.MultilineDiagnostic(main, subDiags.toList());
+        log.report(d);
     }
 
-    protected Resolve(Context context) {
-        context.put(resolveKey, this);
-        syms = Symtab.instance(context);
-
-        varNotFound = new
-            SymbolNotFoundError(ABSENT_VAR);
-        wrongMethod = new
-            InapplicableSymbolError(syms.errSymbol);
-        wrongMethods = new
-            InapplicableSymbolsError(syms.errSymbol);
-        methodNotFound = new
-            SymbolNotFoundError(ABSENT_MTH);
-        typeNotFound = new
-            SymbolNotFoundError(ABSENT_TYP);
+    JCDiagnostic getVerboseApplicableCandidateDiag(int pos, Symbol sym, Type inst) {
+        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());
+        }
 
-        names = Names.instance(context);
-        log = Log.instance(context);
-        chk = Check.instance(context);
-        infer = Infer.instance(context);
-        reader = ClassReader.instance(context);
-        treeinfo = TreeInfo.instance(context);
-        types = Types.instance(context);
-        diags = JCDiagnostic.Factory.instance(context);
-        Source source = Source.instance(context);
-        boxingEnabled = source.allowBoxing();
-        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);
+        String key = subDiag == null ?
+                "applicable.method.found" :
+                "applicable.method.found.1";
 
-        inapplicableMethodException = new InapplicableMethodException(diags);
+        return diags.fragment(key, pos, sym, subDiag);
     }
 
-    /** error symbols, which are returned when resolution fails
-     */
-    final SymbolNotFoundError varNotFound;
-    final InapplicableSymbolError wrongMethod;
-    final InapplicableSymbolsError wrongMethods;
-    final SymbolNotFoundError methodNotFound;
-    final SymbolNotFoundError typeNotFound;
+    JCDiagnostic getVerboseInapplicableCandidateDiag(int pos, Symbol sym, JCDiagnostic subDiag) {
+        return diags.fragment("not.applicable.method.found", pos, sym, subDiag);
+    }
+    // </editor-fold>
 
 /* ************************************************************************
  * Identifier resolution
@@ -804,17 +874,18 @@
         try {
             Type mt = rawInstantiate(env, site, sym, argtypes, typeargtypes,
                                allowBoxing, useVarargs, Warner.noWarnings);
-            if (!operator) addVerboseApplicableCandidateDiag(sym ,mt);
+            if (!operator)
+                currentResolutionContext.addApplicableCandidate(sym, mt);
         } catch (InapplicableMethodException ex) {
-            if (!operator) addVerboseInapplicableCandidateDiag(sym, ex.getDiagnostic());
+            if (!operator)
+                currentResolutionContext.addInapplicableCandidate(sym, ex.getDiagnostic());
             switch (bestSoFar.kind) {
             case ABSENT_MTH:
-                return wrongMethod.setWrongSym(sym, ex.getDiagnostic());
+                return wrongMethod;
             case WRONG_MTH:
                 if (operator) return bestSoFar;
-                wrongMethods.addCandidate(currentStep, wrongMethod.sym, wrongMethod.explanation);
             case WRONG_MTHS:
-                return wrongMethods.addCandidate(currentStep, sym, ex.getDiagnostic());
+                return wrongMethods;
             default:
                 return bestSoFar;
             }
@@ -823,40 +894,12 @@
             return (bestSoFar.kind == ABSENT_MTH)
                 ? new AccessError(env, site, sym)
                 : bestSoFar;
-            }
+        }
         return (bestSoFar.kind > AMBIGUOUS)
             ? sym
             : 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.
@@ -1054,7 +1097,6 @@
                       boolean allowBoxing,
                       boolean useVarargs,
                       boolean operator) {
-        verboseResolutionCandidateDiags.clear();
         Symbol bestSoFar = methodNotFound;
         bestSoFar = findMethod(env,
                           site,
@@ -1127,37 +1169,6 @@
         }
         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.
@@ -1591,32 +1602,33 @@
                          Name name,
                          List<Type> argtypes,
                          List<Type> typeargtypes) {
-        Symbol sym = startResolution();
-        List<MethodResolutionPhase> steps = methodResolutionSteps;
-        while (steps.nonEmpty() &&
-               steps.head.isApplicable(boxingEnabled, varargsEnabled) &&
-               sym.kind >= ERRONEOUS) {
-            currentStep = steps.head;
-            sym = findFun(env, name, argtypes, typeargtypes,
-                    steps.head.isBoxingRequired,
-                    env.info.varArgs = steps.head.isVarargsRequired);
-            methodResolutionCache.put(steps.head, sym);
-            steps = steps.tail;
+        MethodResolutionContext prevResolutionContext = currentResolutionContext;
+        try {
+            currentResolutionContext = new MethodResolutionContext();
+            Symbol sym = methodNotFound;
+            List<MethodResolutionPhase> steps = methodResolutionSteps;
+            while (steps.nonEmpty() &&
+                   steps.head.isApplicable(boxingEnabled, varargsEnabled) &&
+                   sym.kind >= ERRONEOUS) {
+                currentResolutionContext.step = steps.head;
+                sym = findFun(env, name, argtypes, typeargtypes,
+                        steps.head.isBoxingRequired,
+                        env.info.varArgs = steps.head.isVarargsRequired);
+                currentResolutionContext.resolutionCache.put(steps.head, sym);
+                steps = steps.tail;
+            }
+            if (sym.kind >= AMBIGUOUS) {//if nothing is found return the 'first' error
+                MethodResolutionPhase errPhase =
+                        currentResolutionContext.firstErroneousResolutionPhase();
+                sym = access(currentResolutionContext.resolutionCache.get(errPhase),
+                        pos, env.enclClass.sym.type, name, false, argtypes, typeargtypes);
+                env.info.varArgs = errPhase.isVarargsRequired;
+            }
+            return sym;
         }
-        if (sym.kind >= AMBIGUOUS) {//if nothing is found return the 'first' error
-            MethodResolutionPhase errPhase =
-                    firstErroneousResolutionPhase();
-            sym = access(methodResolutionCache.get(errPhase),
-                    pos, env.enclClass.sym.type, name, false, argtypes, typeargtypes);
-            env.info.varArgs = errPhase.isVarargsRequired;
+        finally {
+            currentResolutionContext = prevResolutionContext;
         }
-        return sym;
-    }
-
-    private Symbol startResolution() {
-        wrongMethod.clear();
-        wrongMethods.clear();
-        return methodNotFound;
     }
 
     /** Resolve a qualified method identifier
@@ -1636,40 +1648,53 @@
     Symbol resolveQualifiedMethod(DiagnosticPosition pos, Env<AttrContext> env,
                                   Symbol location, Type site, Name name, List<Type> argtypes,
                                   List<Type> typeargtypes) {
-        Symbol sym = startResolution();
-        List<MethodResolutionPhase> steps = methodResolutionSteps;
-        while (steps.nonEmpty() &&
-               steps.head.isApplicable(boxingEnabled, varargsEnabled) &&
-               sym.kind >= ERRONEOUS) {
-            currentStep = steps.head;
-            sym = findMethod(env, site, name, argtypes, typeargtypes,
-                    steps.head.isBoxingRequired(),
-                    env.info.varArgs = steps.head.isVarargsRequired(), false);
-            methodResolutionCache.put(steps.head, sym);
-            steps = steps.tail;
-        }
-        if (sym.kind >= AMBIGUOUS) {
-            if (site.tsym.isPolymorphicSignatureGeneric()) {
-                //polymorphic receiver - synthesize new method symbol
+        return resolveQualifiedMethod(new MethodResolutionContext(), pos, env, location, site, name, argtypes, typeargtypes);
+    }
+    private Symbol resolveQualifiedMethod(MethodResolutionContext resolveContext,
+                                  DiagnosticPosition pos, Env<AttrContext> env,
+                                  Symbol location, Type site, Name name, List<Type> argtypes,
+                                  List<Type> typeargtypes) {
+        MethodResolutionContext prevResolutionContext = currentResolutionContext;
+        try {
+            currentResolutionContext = resolveContext;
+            Symbol sym = methodNotFound;
+            List<MethodResolutionPhase> steps = methodResolutionSteps;
+            while (steps.nonEmpty() &&
+                   steps.head.isApplicable(boxingEnabled, varargsEnabled) &&
+                   sym.kind >= ERRONEOUS) {
+                currentResolutionContext.step = steps.head;
+                sym = findMethod(env, site, name, argtypes, typeargtypes,
+                        steps.head.isBoxingRequired(),
+                        env.info.varArgs = steps.head.isVarargsRequired(), false);
+                currentResolutionContext.resolutionCache.put(steps.head, sym);
+                steps = steps.tail;
+            }
+            if (sym.kind >= AMBIGUOUS) {
+                if (site.tsym.isPolymorphicSignatureGeneric()) {
+                    //polymorphic receiver - synthesize new method symbol
+                    env.info.varArgs = false;
+                    sym = findPolymorphicSignatureInstance(env,
+                            site, name, null, argtypes);
+                }
+                else {
+                    //if nothing is found return the 'first' error
+                    MethodResolutionPhase errPhase =
+                            currentResolutionContext.firstErroneousResolutionPhase();
+                    sym = access(currentResolutionContext.resolutionCache.get(errPhase),
+                            pos, location, site, name, true, argtypes, typeargtypes);
+                    env.info.varArgs = errPhase.isVarargsRequired;
+                }
+            } else if (allowMethodHandles && sym.isPolymorphicSignatureGeneric()) {
+                //non-instantiated polymorphic signature - synthesize new method symbol
                 env.info.varArgs = false;
                 sym = findPolymorphicSignatureInstance(env,
-                        site, name, null, argtypes);
+                        site, name, (MethodSymbol)sym, argtypes);
             }
-            else {
-                //if nothing is found return the 'first' error
-                MethodResolutionPhase errPhase =
-                        firstErroneousResolutionPhase();
-                sym = access(methodResolutionCache.get(errPhase),
-                        pos, location, site, name, true, argtypes, typeargtypes);
-                env.info.varArgs = errPhase.isVarargsRequired;
-            }
-        } else if (allowMethodHandles && sym.isPolymorphicSignatureGeneric()) {
-            //non-instantiated polymorphic signature - synthesize new method symbol
-            env.info.varArgs = false;
-            sym = findPolymorphicSignatureInstance(env,
-                    site, name, (MethodSymbol)sym, argtypes);
+            return sym;
         }
-        return sym;
+        finally {
+            currentResolutionContext = prevResolutionContext;
+        }
     }
 
     /** Find or create an implicit method of exactly the given type (after erasure).
@@ -1726,19 +1751,14 @@
                                         Type site, Name name,
                                         List<Type> argtypes,
                                         List<Type> typeargtypes) {
-        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;
-        }
+        MethodResolutionContext resolveContext = new MethodResolutionContext();
+        resolveContext.internalResolution = true;
+        Symbol sym = resolveQualifiedMethod(resolveContext, 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));
     }
 
     /** Resolve constructor.
@@ -1755,25 +1775,40 @@
                               Type site,
                               List<Type> argtypes,
                               List<Type> typeargtypes) {
-        Symbol sym = startResolution();
-        List<MethodResolutionPhase> steps = methodResolutionSteps;
-        while (steps.nonEmpty() &&
-               steps.head.isApplicable(boxingEnabled, varargsEnabled) &&
-               sym.kind >= ERRONEOUS) {
-            currentStep = steps.head;
-            sym = resolveConstructor(pos, env, site, argtypes, typeargtypes,
-                    steps.head.isBoxingRequired(),
-                    env.info.varArgs = steps.head.isVarargsRequired());
-            methodResolutionCache.put(steps.head, sym);
-            steps = steps.tail;
+        return resolveConstructor(new MethodResolutionContext(), pos, env, site, argtypes, typeargtypes);
+    }
+    private Symbol resolveConstructor(MethodResolutionContext resolveContext,
+                              DiagnosticPosition pos,
+                              Env<AttrContext> env,
+                              Type site,
+                              List<Type> argtypes,
+                              List<Type> typeargtypes) {
+        MethodResolutionContext prevResolutionContext = currentResolutionContext;
+        try {
+            currentResolutionContext = resolveContext;
+            Symbol sym = methodNotFound;
+            List<MethodResolutionPhase> steps = methodResolutionSteps;
+            while (steps.nonEmpty() &&
+                   steps.head.isApplicable(boxingEnabled, varargsEnabled) &&
+                   sym.kind >= ERRONEOUS) {
+                currentResolutionContext.step = steps.head;
+                sym = findConstructor(pos, env, site, argtypes, typeargtypes,
+                        steps.head.isBoxingRequired(),
+                        env.info.varArgs = steps.head.isVarargsRequired());
+                currentResolutionContext.resolutionCache.put(steps.head, sym);
+                steps = steps.tail;
+            }
+            if (sym.kind >= AMBIGUOUS) {//if nothing is found return the 'first' error
+                MethodResolutionPhase errPhase = currentResolutionContext.firstErroneousResolutionPhase();
+                sym = access(currentResolutionContext.resolutionCache.get(errPhase),
+                        pos, site, names.init, true, argtypes, typeargtypes);
+                env.info.varArgs = errPhase.isVarargsRequired();
+            }
+            return sym;
         }
-        if (sym.kind >= AMBIGUOUS) {//if nothing is found return the 'first' error
-            MethodResolutionPhase errPhase = firstErroneousResolutionPhase();
-            sym = access(methodResolutionCache.get(errPhase),
-                    pos, site, names.init, true, argtypes, typeargtypes);
-            env.info.varArgs = errPhase.isVarargsRequired();
+        finally {
+            currentResolutionContext = prevResolutionContext;
         }
-        return sym;
     }
 
     /** Resolve constructor using diamond inference.
@@ -1791,38 +1826,45 @@
                               Type site,
                               List<Type> argtypes,
                               List<Type> typeargtypes) {
-        Symbol sym = startResolution();
-        List<MethodResolutionPhase> steps = methodResolutionSteps;
-        while (steps.nonEmpty() &&
-               steps.head.isApplicable(boxingEnabled, varargsEnabled) &&
-               sym.kind >= ERRONEOUS) {
-            currentStep = steps.head;
-            sym = resolveConstructor(pos, env, site, argtypes, typeargtypes,
-                    steps.head.isBoxingRequired(),
-                    env.info.varArgs = steps.head.isVarargsRequired());
-            methodResolutionCache.put(steps.head, sym);
-            steps = steps.tail;
+        MethodResolutionContext prevResolutionContext = currentResolutionContext;
+        try {
+            currentResolutionContext = new MethodResolutionContext();
+            Symbol sym = methodNotFound;
+            List<MethodResolutionPhase> steps = methodResolutionSteps;
+            while (steps.nonEmpty() &&
+                   steps.head.isApplicable(boxingEnabled, varargsEnabled) &&
+                   sym.kind >= ERRONEOUS) {
+                currentResolutionContext.step = steps.head;
+                sym = findConstructor(pos, env, site, argtypes, typeargtypes,
+                        steps.head.isBoxingRequired(),
+                        env.info.varArgs = steps.head.isVarargsRequired());
+                currentResolutionContext.resolutionCache.put(steps.head, sym);
+                steps = steps.tail;
+            }
+            if (sym.kind >= AMBIGUOUS) {
+                final JCDiagnostic details = sym.kind == WRONG_MTH ?
+                                currentResolutionContext.candidates.head.details :
+                                null;
+                Symbol errSym = new ResolveError(WRONG_MTH, "diamond error") {
+                    @Override
+                    JCDiagnostic getDiagnostic(DiagnosticType dkind, DiagnosticPosition pos,
+                            Symbol location, Type site, Name name, List<Type> argtypes, List<Type> typeargtypes) {
+                        String key = details == null ?
+                            "cant.apply.diamond" :
+                            "cant.apply.diamond.1";
+                        return diags.create(dkind, log.currentSource(), pos, key,
+                                diags.fragment("diamond", site.tsym), details);
+                    }
+                };
+                MethodResolutionPhase errPhase = currentResolutionContext.firstErroneousResolutionPhase();
+                sym = access(errSym, pos, site, names.init, true, argtypes, typeargtypes);
+                env.info.varArgs = errPhase.isVarargsRequired();
+            }
+            return sym;
         }
-        if (sym.kind >= AMBIGUOUS) {
-            final JCDiagnostic details = sym.kind == WRONG_MTH ?
-                ((InapplicableSymbolError)sym).explanation :
-                null;
-            Symbol errSym = new ResolveError(WRONG_MTH, "diamond error") {
-                @Override
-                JCDiagnostic getDiagnostic(DiagnosticType dkind, DiagnosticPosition pos,
-                        Symbol location, Type site, Name name, List<Type> argtypes, List<Type> typeargtypes) {
-                    String key = details == null ?
-                        "cant.apply.diamond" :
-                        "cant.apply.diamond.1";
-                    return diags.create(dkind, log.currentSource(), pos, key,
-                            diags.fragment("diamond", site.tsym), details);
-                }
-            };
-            MethodResolutionPhase errPhase = firstErroneousResolutionPhase();
-            sym = access(errSym, pos, site, names.init, true, argtypes, typeargtypes);
-            env.info.varArgs = errPhase.isVarargsRequired();
+        finally {
+            currentResolutionContext = prevResolutionContext;
         }
-        return sym;
     }
 
     /** Resolve constructor.
@@ -1841,10 +1883,25 @@
                               List<Type> typeargtypes,
                               boolean allowBoxing,
                               boolean useVarargs) {
+        MethodResolutionContext prevResolutionContext = currentResolutionContext;
+        try {
+            currentResolutionContext = new MethodResolutionContext();
+            return findConstructor(pos, env, site, argtypes, typeargtypes, allowBoxing, useVarargs);
+        }
+        finally {
+            currentResolutionContext = prevResolutionContext;
+        }
+    }
+
+    Symbol findConstructor(DiagnosticPosition pos, Env<AttrContext> env,
+                              Type site, List<Type> argtypes,
+                              List<Type> typeargtypes,
+                              boolean allowBoxing,
+                              boolean useVarargs) {
         Symbol sym = findMethod(env, site,
-                                names.init, argtypes,
-                                typeargtypes, allowBoxing,
-                                useVarargs, false);
+                                    names.init, argtypes,
+                                    typeargtypes, allowBoxing,
+                                    useVarargs, false);
         chk.checkDeprecated(pos, env.info.scope.owner, sym);
         return sym;
     }
@@ -1860,8 +1917,9 @@
                                         Type site,
                                         List<Type> argtypes,
                                         List<Type> typeargtypes) {
-        Symbol sym = resolveConstructor(
-            pos, env, site, argtypes, typeargtypes);
+        MethodResolutionContext resolveContext = new MethodResolutionContext();
+        resolveContext.internalResolution = true;
+        Symbol sym = resolveConstructor(resolveContext, pos, env, site, argtypes, typeargtypes);
         if (sym.kind == MTH) return (MethodSymbol)sym;
         else throw new FatalError(
                  diags.fragment("fatal.err.cant.locate.ctor", site));
@@ -1875,15 +1933,21 @@
      */
     Symbol resolveOperator(DiagnosticPosition pos, JCTree.Tag optag,
                            Env<AttrContext> env, List<Type> argtypes) {
-        startResolution();
-        Name name = treeinfo.operatorName(optag);
-        Symbol sym = findMethod(env, syms.predefClass.type, name, argtypes,
-                                null, false, false, true);
-        if (boxingEnabled && sym.kind >= WRONG_MTHS)
-            sym = findMethod(env, syms.predefClass.type, name, argtypes,
-                             null, true, false, true);
-        return access(sym, pos, env.enclClass.sym.type, name,
-                      false, argtypes, null);
+        MethodResolutionContext prevResolutionContext = currentResolutionContext;
+        try {
+            currentResolutionContext = new MethodResolutionContext();
+            Name name = treeinfo.operatorName(optag);
+            Symbol sym = findMethod(env, syms.predefClass.type, name, argtypes,
+                                    null, false, false, true);
+            if (boxingEnabled && sym.kind >= WRONG_MTHS)
+                sym = findMethod(env, syms.predefClass.type, name, argtypes,
+                                 null, true, false, true);
+            return access(sym, pos, env.enclClass.sym.type, name,
+                          false, argtypes, null);
+        }
+        finally {
+            currentResolutionContext = prevResolutionContext;
+        }
     }
 
     /** Resolve operator.
@@ -2227,34 +2291,24 @@
      * (either a method, a constructor or an operand) is not applicable
      * given an actual arguments/type argument list.
      */
-    class InapplicableSymbolError extends InvalidSymbolError {
+    class InapplicableSymbolError extends ResolveError {
 
-        /** An auxiliary explanation set in case of instantiation errors. */
-        JCDiagnostic explanation;
-
-        InapplicableSymbolError(Symbol sym) {
-            super(WRONG_MTH, sym, "inapplicable symbol error");
+        InapplicableSymbolError() {
+            super(WRONG_MTH, "inapplicable symbol error");
         }
 
-        /** Update sym and explanation and return this.
-         */
-        InapplicableSymbolError setWrongSym(Symbol sym, JCDiagnostic explanation) {
-            this.sym = sym;
-            if (this.sym == sym && explanation != null)
-                this.explanation = explanation; //update the details
-            return this;
-        }
-
-        /** Update sym and return this.
-         */
-        InapplicableSymbolError setWrongSym(Symbol sym) {
-            this.sym = sym;
-            return this;
+        protected InapplicableSymbolError(int kind, String debugName) {
+            super(kind, debugName);
         }
 
         @Override
         public String toString() {
-            return super.toString() + " explanation=" + explanation;
+            return super.toString();
+        }
+
+        @Override
+        public boolean exists() {
+            return true;
         }
 
         @Override
@@ -2279,27 +2333,40 @@
                         key, name, first, second);
             }
             else {
-                Symbol ws = sym.asMemberOf(site, types);
+                Candidate c = errCandidate();
+                Symbol ws = c.sym.asMemberOf(site, types);
                 return diags.create(dkind, log.currentSource(), pos,
-                          "cant.apply.symbol" + (explanation != null ? ".1" : ""),
+                          "cant.apply.symbol" + (c.details != null ? ".1" : ""),
                           kindName(ws),
                           ws.name == names.init ? ws.owner.name : ws.name,
                           methodArguments(ws.type.getParameterTypes()),
                           methodArguments(argtypes),
                           kindName(ws.owner),
                           ws.owner.type,
-                          explanation);
+                          c.details);
             }
         }
 
-        void clear() {
-            explanation = null;
-        }
-
         @Override
         public Symbol access(Name name, TypeSymbol location) {
             return types.createErrorType(name, location, syms.errSymbol.type).tsym;
         }
+
+        protected boolean shouldReport(Candidate c) {
+            return !c.isApplicable() &&
+                    (((c.sym.flags() & VARARGS) != 0 && c.step == VARARITY) ||
+                      (c.sym.flags() & VARARGS) == 0 && c.step == (boxingEnabled ? BOX : BASIC));
+        }
+
+        private Candidate errCandidate() {
+            for (Candidate c : currentResolutionContext.candidates) {
+                if (shouldReport(c)) {
+                    return c;
+                }
+            }
+            Assert.error();
+            return null;
+        }
     }
 
     /**
@@ -2307,11 +2374,9 @@
      * (either methods, constructors or operands) is not applicable
      * given an actual arguments/type argument list.
      */
-    class InapplicableSymbolsError extends ResolveError {
+    class InapplicableSymbolsError extends InapplicableSymbolError {
 
-        private List<Candidate> candidates = List.nil();
-
-        InapplicableSymbolsError(Symbol sym) {
+        InapplicableSymbolsError() {
             super(WRONG_MTHS, "inapplicable symbols");
         }
 
@@ -2323,7 +2388,7 @@
                 Name name,
                 List<Type> argtypes,
                 List<Type> typeargtypes) {
-            if (candidates.nonEmpty()) {
+            if (currentResolutionContext.candidates.nonEmpty()) {
                 JCDiagnostic err = diags.create(dkind,
                         log.currentSource(),
                         pos,
@@ -2341,68 +2406,24 @@
         //where
         List<JCDiagnostic> candidateDetails(Type site) {
             List<JCDiagnostic> details = List.nil();
-            for (Candidate c : candidates)
-                details = details.prepend(c.getDiagnostic(site));
+            for (Candidate c : currentResolutionContext.candidates) {
+                if (!shouldReport(c)) continue;
+                JCDiagnostic detailDiag = diags.fragment("inapplicable.method",
+                        Kinds.kindName(c.sym),
+                        c.sym.location(site, types),
+                        c.sym.asMemberOf(site, types),
+                        c.details);
+                details = details.prepend(detailDiag);
+            }
             return details.reverse();
         }
 
-        Symbol addCandidate(MethodResolutionPhase currentStep, Symbol sym, JCDiagnostic details) {
-            Candidate c = new Candidate(currentStep, sym, details);
-            if (c.isValid() && !candidates.contains(c))
-                candidates = candidates.append(c);
-            return this;
-        }
-
-        void clear() {
-            candidates = List.nil();
-        }
-
         private Name getName() {
-            Symbol sym = candidates.head.sym;
+            Symbol sym = currentResolutionContext.candidates.head.sym;
             return sym.name == names.init ?
                 sym.owner.name :
                 sym.name;
         }
-
-        private class Candidate {
-
-            final MethodResolutionPhase step;
-            final Symbol sym;
-            final JCDiagnostic details;
-
-            private Candidate(MethodResolutionPhase step, Symbol sym, JCDiagnostic details) {
-                this.step = step;
-                this.sym = sym;
-                this.details = details;
-            }
-
-            JCDiagnostic getDiagnostic(Type site) {
-                return diags.fragment("inapplicable.method",
-                        Kinds.kindName(sym),
-                        sym.location(site, types),
-                        sym.asMemberOf(site, types),
-                        details);
-            }
-
-            @Override
-            public boolean equals(Object o) {
-                if (o instanceof Candidate) {
-                    Symbol s1 = this.sym;
-                    Symbol s2 = ((Candidate)o).sym;
-                    if  ((s1 != s2 &&
-                        (s1.overrides(s2, s1.owner.type.tsym, types, false) ||
-                        (s2.overrides(s1, s2.owner.type.tsym, types, false)))) ||
-                        ((s1.isConstructor() || s2.isConstructor()) && s1.owner != s2.owner))
-                        return true;
-                }
-                return false;
-            }
-
-            boolean isValid() {
-                return  (((sym.flags() & VARARGS) != 0 && step == VARARITY) ||
-                          (sym.flags() & VARARGS) == 0 && step == (boxingEnabled ? BOX : BASIC));
-            }
-        }
     }
 
     /**
@@ -2563,29 +2584,91 @@
         }
     }
 
-    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;
+    /**
+     * A resolution context is used to keep track of intermediate results of
+     * overload resolution, such as list of method that are not applicable
+     * (used to generate more precise diagnostics) and so on. Resolution contexts
+     * can be nested - this means that when each overload resolution routine should
+     * work within the resolution context it created.
+     */
+    class MethodResolutionContext {
+
+        private List<Candidate> candidates = List.nil();
+
+        private Map<MethodResolutionPhase, Symbol> resolutionCache =
+            new EnumMap<MethodResolutionPhase, Symbol>(MethodResolutionPhase.class);
+
+        private MethodResolutionPhase step = null;
+
+        private boolean internalResolution = false;
 
-    private boolean internalResolution = false;
+        private MethodResolutionPhase firstErroneousResolutionPhase() {
+            MethodResolutionPhase bestSoFar = BASIC;
+            Symbol sym = methodNotFound;
+            List<MethodResolutionPhase> steps = methodResolutionSteps;
+            while (steps.nonEmpty() &&
+                   steps.head.isApplicable(boxingEnabled, varargsEnabled) &&
+                   sym.kind >= WRONG_MTHS) {
+                sym = resolutionCache.get(steps.head);
+                bestSoFar = steps.head;
+                steps = steps.tail;
+            }
+            return bestSoFar;
+        }
+
+        void addInapplicableCandidate(Symbol sym, JCDiagnostic details) {
+            Candidate c = new Candidate(currentResolutionContext.step, sym, details, null);
+            if (!candidates.contains(c))
+                candidates = candidates.append(c);
+        }
+
+        void addApplicableCandidate(Symbol sym, Type mtype) {
+            Candidate c = new Candidate(currentResolutionContext.step, sym, null, mtype);
+            candidates = candidates.append(c);
+        }
 
-    private MethodResolutionPhase firstErroneousResolutionPhase() {
-        MethodResolutionPhase bestSoFar = BASIC;
-        Symbol sym = methodNotFound;
-        List<MethodResolutionPhase> steps = methodResolutionSteps;
-        while (steps.nonEmpty() &&
-               steps.head.isApplicable(boxingEnabled, varargsEnabled) &&
-               sym.kind >= WRONG_MTHS) {
-            sym = methodResolutionCache.get(steps.head);
-            bestSoFar = steps.head;
-            steps = steps.tail;
+        /**
+         * This class represents an overload resolution candidate. There are two
+         * kinds of candidates: applicable methods and inapplicable methods;
+         * applicable methods have a pointer to the instantiated method type,
+         * while inapplicable candidates contain further details about the
+         * reason why the method has been considered inapplicable.
+         */
+        class Candidate {
+
+            final MethodResolutionPhase step;
+            final Symbol sym;
+            final JCDiagnostic details;
+            final Type mtype;
+
+            private Candidate(MethodResolutionPhase step, Symbol sym, JCDiagnostic details, Type mtype) {
+                this.step = step;
+                this.sym = sym;
+                this.details = details;
+                this.mtype = mtype;
+            }
+
+            @Override
+            public boolean equals(Object o) {
+                if (o instanceof Candidate) {
+                    Symbol s1 = this.sym;
+                    Symbol s2 = ((Candidate)o).sym;
+                    if  ((s1 != s2 &&
+                        (s1.overrides(s2, s1.owner.type.tsym, types, false) ||
+                        (s2.overrides(s1, s2.owner.type.tsym, types, false)))) ||
+                        ((s1.isConstructor() || s2.isConstructor()) && s1.owner != s2.owner))
+                        return true;
+                }
+                return false;
+            }
+
+            boolean isApplicable() {
+                return mtype != null;
+            }
         }
-        return bestSoFar;
     }
+
+    MethodResolutionContext currentResolutionContext = null;
 }