langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java
changeset 1533 6a9a2f681d24
parent 1529 a076d4cd3048
child 1534 e923a41e84cc
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Fri Oct 24 12:45:47 2008 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Fri Oct 24 12:46:07 2008 +0100
@@ -30,6 +30,7 @@
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.jvm.*;
 import com.sun.tools.javac.tree.*;
+import static com.sun.tools.javac.comp.Resolve.MethodResolutionPhase.*;
 
 import com.sun.tools.javac.code.Type.*;
 import com.sun.tools.javac.code.Symbol.*;
@@ -40,6 +41,9 @@
 import static com.sun.tools.javac.code.TypeTags.*;
 import javax.lang.model.element.ElementVisitor;
 
+import java.util.Map;
+import java.util.HashMap;
+
 /** Helper class for name resolution, used mostly by the attribution phase.
  *
  *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
@@ -1192,15 +1196,23 @@
                          Name name,
                          List<Type> argtypes,
                          List<Type> typeargtypes) {
-        Symbol sym = findFun(env, name, argtypes, typeargtypes, false, env.info.varArgs=false);
-        if (varargsEnabled && sym.kind >= WRONG_MTHS) {
-            sym = findFun(env, name, argtypes, typeargtypes, true, false);
-            if (sym.kind >= WRONG_MTHS)
-                sym = findFun(env, name, argtypes, typeargtypes, true, env.info.varArgs=true);
+        Symbol sym = methodNotFound;
+        List<MethodResolutionPhase> steps = methodResolutionSteps;
+        while (steps.nonEmpty() &&
+               steps.head.isApplicable(boxingEnabled, varargsEnabled) &&
+               sym.kind >= ERRONEOUS) {
+            sym = findFun(env, name, argtypes, typeargtypes,
+                    steps.head.isBoxingRequired,
+                    env.info.varArgs = steps.head.isVarargsRequired);
+            methodResolutionCache.put(steps.head, sym);
+            steps = steps.tail;
         }
-        if (sym.kind >= AMBIGUOUS) {
-            sym = access(
-                sym, pos, env.enclClass.sym.type, name, false, argtypes, typeargtypes);
+        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;
         }
         return sym;
     }
@@ -1217,17 +1229,23 @@
     Symbol resolveQualifiedMethod(DiagnosticPosition pos, Env<AttrContext> env,
                                   Type site, Name name, List<Type> argtypes,
                                   List<Type> typeargtypes) {
-        Symbol sym = findMethod(env, site, name, argtypes, typeargtypes, false,
-                                env.info.varArgs=false, false);
-        if (varargsEnabled && sym.kind >= WRONG_MTHS) {
-            sym = findMethod(env, site, name, argtypes, typeargtypes, true,
-                             false, false);
-            if (sym.kind >= WRONG_MTHS)
-                sym = findMethod(env, site, name, argtypes, typeargtypes, true,
-                                 env.info.varArgs=true, false);
+        Symbol sym = methodNotFound;
+        List<MethodResolutionPhase> steps = methodResolutionSteps;
+        while (steps.nonEmpty() &&
+               steps.head.isApplicable(boxingEnabled, varargsEnabled) &&
+               sym.kind >= ERRONEOUS) {
+            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) {
-            sym = access(sym, pos, site, name, true, argtypes, typeargtypes);
+        if (sym.kind >= AMBIGUOUS) {//if nothing is found return the 'first' error
+            MethodResolutionPhase errPhase =
+                    firstErroneousResolutionPhase();
+            sym = access(methodResolutionCache.get(errPhase),
+                    pos, site, name, true, argtypes, typeargtypes);
+            env.info.varArgs = errPhase.isVarargsRequired;
         }
         return sym;
     }
@@ -1268,14 +1286,22 @@
                               Type site,
                               List<Type> argtypes,
                               List<Type> typeargtypes) {
-        Symbol sym = resolveConstructor(pos, env, site, argtypes, typeargtypes, false, env.info.varArgs=false);
-        if (varargsEnabled && sym.kind >= WRONG_MTHS) {
-            sym = resolveConstructor(pos, env, site, argtypes, typeargtypes, true, false);
-            if (sym.kind >= WRONG_MTHS)
-                sym = resolveConstructor(pos, env, site, argtypes, typeargtypes, true, env.info.varArgs=true);
+        Symbol sym = methodNotFound;
+        List<MethodResolutionPhase> steps = methodResolutionSteps;
+        while (steps.nonEmpty() &&
+               steps.head.isApplicable(boxingEnabled, varargsEnabled) &&
+               sym.kind >= ERRONEOUS) {
+            sym = resolveConstructor(pos, env, site, argtypes, typeargtypes,
+                    steps.head.isBoxingRequired(),
+                    env.info.varArgs = steps.head.isVarargsRequired());
+            methodResolutionCache.put(steps.head, sym);
+            steps = steps.tail;
         }
-        if (sym.kind >= AMBIGUOUS) {
-            sym = access(sym, pos, site, names.init, true, argtypes, typeargtypes);
+        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();
         }
         return sym;
     }
@@ -1733,4 +1759,50 @@
                       pair.sym2.location(site, types));
         }
     }
+
+    enum MethodResolutionPhase {
+        BASIC(false, false),
+        BOX(true, false),
+        VARARITY(true, true);
+
+        boolean isBoxingRequired;
+        boolean isVarargsRequired;
+
+        MethodResolutionPhase(boolean isBoxingRequired, boolean isVarargsRequired) {
+           this.isBoxingRequired = isBoxingRequired;
+           this.isVarargsRequired = isVarargsRequired;
+        }
+
+        public boolean isBoxingRequired() {
+            return isBoxingRequired;
+        }
+
+        public boolean isVarargsRequired() {
+            return isVarargsRequired;
+        }
+
+        public boolean isApplicable(boolean boxingEnabled, boolean varargsEnabled) {
+            return (varargsEnabled || !isVarargsRequired) &&
+                   (boxingEnabled || !isBoxingRequired);
+        }
+    }
+
+    private Map<MethodResolutionPhase, Symbol> methodResolutionCache =
+        new HashMap<MethodResolutionPhase, Symbol>(MethodResolutionPhase.values().length);
+
+    final List<MethodResolutionPhase> methodResolutionSteps = List.of(BASIC, BOX, VARARITY);
+
+    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;
+        }
+        return bestSoFar;
+    }
 }