langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java
changeset 12334 29e1bfdcba4e
parent 12082 32bdf6ef6388
child 12335 4725d88691dd
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Mon Mar 26 15:27:51 2012 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Mon Mar 26 15:28:22 2012 +0100
@@ -29,6 +29,8 @@
 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.Attr.ResultInfo;
+import com.sun.tools.javac.comp.Check.CheckContext;
 import com.sun.tools.javac.comp.Resolve.MethodResolutionContext.Candidate;
 import com.sun.tools.javac.jvm.*;
 import com.sun.tools.javac.tree.*;
@@ -70,6 +72,7 @@
     Names names;
     Log log;
     Symtab syms;
+    Attr attr;
     Check chk;
     Infer infer;
     ClassReader reader;
@@ -101,6 +104,7 @@
 
         names = Names.instance(context);
         log = Log.instance(context);
+        attr = Attr.instance(context);
         chk = Check.instance(context);
         infer = Infer.instance(context);
         reader = ClassReader.instance(context);
@@ -627,15 +631,8 @@
         }
 
         while (argtypes.nonEmpty() && formals.head != varargsFormal) {
-            Type undetFormal = infer.asUndetType(formals.head, undetvars);
-            Type capturedActual = types.capture(argtypes.head);
-            boolean works = allowBoxing ?
-                    types.isConvertible(capturedActual, undetFormal, warn) :
-                    types.isSubtypeUnchecked(capturedActual, undetFormal, warn);
-            if (!works) {
-                throw handler.argumentMismatch(false, argtypes.head, formals.head);
-            }
-            checkedArgs.append(capturedActual);
+            ResultInfo resultInfo = methodCheckResult(formals.head, allowBoxing, false, undetvars, handler, warn);
+            checkedArgs.append(resultInfo.check(env.tree.pos(), argtypes.head));
             argtypes = argtypes.tail;
             formals = formals.tail;
         }
@@ -648,13 +645,9 @@
             //note: if applicability check is triggered by most specific test,
             //the last argument of a varargs is _not_ an array type (see JLS 15.12.2.5)
             Type elt = types.elemtype(varargsFormal);
-            Type eltUndet = infer.asUndetType(elt, undetvars);
             while (argtypes.nonEmpty()) {
-                Type capturedActual = types.capture(argtypes.head);
-                if (!types.isConvertible(capturedActual, eltUndet, warn)) {
-                    throw handler.argumentMismatch(true, argtypes.head, elt);
-                }
-                checkedArgs.append(capturedActual);
+                ResultInfo resultInfo = methodCheckResult(elt, allowBoxing, true, undetvars, handler, warn);
+                checkedArgs.append(resultInfo.check(env.tree.pos(), argtypes.head));
                 argtypes = argtypes.tail;
             }
             //check varargs element type accessibility
@@ -665,39 +658,116 @@
         }
         return checkedArgs.toList();
     }
-    // where
-        public static class InapplicableMethodException extends RuntimeException {
-            private static final long serialVersionUID = 0;
+
+    /**
+     * Check context to be used during method applicability checks. A method check
+     * context might contain inference variables.
+     */
+    abstract class MethodCheckContext implements CheckContext {
+
+        MethodCheckHandler handler;
+        boolean useVarargs;
+        List<Type> undetvars;
+        Warner rsWarner;
 
-            JCDiagnostic diagnostic;
-            JCDiagnostic.Factory diags;
+        public MethodCheckContext(MethodCheckHandler handler, boolean useVarargs, List<Type> undetvars, Warner rsWarner) {
+            this.handler = handler;
+            this.useVarargs = useVarargs;
+            this.undetvars = undetvars;
+            this.rsWarner = rsWarner;
+        }
+
+        public void report(DiagnosticPosition pos, Type found, Type req, JCDiagnostic details) {
+            throw handler.argumentMismatch(useVarargs, found, req);
+        }
+
+        public Type rawInstantiatePoly(ForAll found, Type req, Warner warn) {
+            throw new AssertionError("ForAll in argument position");
+        }
+
+        public Warner checkWarner(DiagnosticPosition pos, Type found, Type req) {
+            return rsWarner;
+        }
+    }
 
-            InapplicableMethodException(JCDiagnostic.Factory diags) {
-                this.diagnostic = null;
-                this.diags = diags;
-            }
-            InapplicableMethodException setMessage() {
-                this.diagnostic = null;
-                return this;
+    /**
+     * Subclass of method check context class that implements strict method conversion.
+     * Strict method conversion checks compatibility between types using subtyping tests.
+     */
+    class StrictMethodContext extends MethodCheckContext {
+
+        public StrictMethodContext(MethodCheckHandler handler, boolean useVarargs, List<Type> undetvars, Warner rsWarner) {
+            super(handler, useVarargs, undetvars, rsWarner);
+        }
+
+        public boolean compatible(Type found, Type req, Warner warn) {
+            return types.isSubtypeUnchecked(found, infer.asUndetType(req, undetvars), warn);
+        }
+    }
+
+    /**
+     * Subclass of method check context class that implements loose method conversion.
+     * Loose method conversion checks compatibility between types using method conversion tests.
+     */
+    class LooseMethodContext extends MethodCheckContext {
+
+        public LooseMethodContext(MethodCheckHandler handler, boolean useVarargs, List<Type> undetvars, Warner rsWarner) {
+            super(handler, useVarargs, undetvars, rsWarner);
+        }
+
+        public boolean compatible(Type found, Type req, Warner warn) {
+            return types.isConvertible(found, infer.asUndetType(req, undetvars), warn);
+        }
+    }
+
+    /**
+     * Create a method check context to be used during method applicability check
+     */
+    ResultInfo methodCheckResult(Type to, boolean allowBoxing, boolean useVarargs,
+            List<Type> undetvars, MethodCheckHandler methodHandler, Warner rsWarner) {
+        MethodCheckContext checkContext = allowBoxing ?
+                new LooseMethodContext(methodHandler, useVarargs, undetvars, rsWarner) :
+                new StrictMethodContext(methodHandler, useVarargs, undetvars, rsWarner);
+        return attr.new ResultInfo(VAL, to, checkContext) {
+            @Override
+            protected Type check(DiagnosticPosition pos, Type found) {
+                return super.check(pos, chk.checkNonVoid(pos, types.capture(types.upperBound(found))));
             }
-            InapplicableMethodException setMessage(String key) {
-                this.diagnostic = key != null ? diags.fragment(key) : null;
-                return this;
-            }
-            InapplicableMethodException setMessage(String key, Object... args) {
-                this.diagnostic = key != null ? diags.fragment(key, args) : null;
-                return this;
-            }
-            InapplicableMethodException setMessage(JCDiagnostic diag) {
-                this.diagnostic = diag;
-                return this;
-            }
+        };
+    }
+
+    public static class InapplicableMethodException extends RuntimeException {
+        private static final long serialVersionUID = 0;
+
+        JCDiagnostic diagnostic;
+        JCDiagnostic.Factory diags;
 
-            public JCDiagnostic getDiagnostic() {
-                return diagnostic;
-            }
+        InapplicableMethodException(JCDiagnostic.Factory diags) {
+            this.diagnostic = null;
+            this.diags = diags;
+        }
+        InapplicableMethodException setMessage() {
+            this.diagnostic = null;
+            return this;
+        }
+        InapplicableMethodException setMessage(String key) {
+            this.diagnostic = key != null ? diags.fragment(key) : null;
+            return this;
         }
-        private final InapplicableMethodException inapplicableMethodException;
+        InapplicableMethodException setMessage(String key, Object... args) {
+            this.diagnostic = key != null ? diags.fragment(key, args) : null;
+            return this;
+        }
+        InapplicableMethodException setMessage(JCDiagnostic diag) {
+            this.diagnostic = diag;
+            return this;
+        }
+
+        public JCDiagnostic getDiagnostic() {
+            return diagnostic;
+        }
+    }
+    private final InapplicableMethodException inapplicableMethodException;
 
 /* ***************************************************************************
  *  Symbol lookup