7129801: Merge the two method applicability routines

Tue, 24 Jan 2012 17:52:02 +0000

author
mcimadamore
date
Tue, 24 Jan 2012 17:52:02 +0000
changeset 1186
51fb17abfc32
parent 1182
99261fc7d95d
child 1187
ac36176b7de0

7129801: Merge the two method applicability routines
Summary: Resolve.java and Infer.java should reuse the same method applicability check routine
Reviewed-by: dlsmith, jjg

src/share/classes/com/sun/tools/javac/comp/Infer.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/comp/Resolve.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/resources/compiler.properties file | annotate | diff | comparison | revisions
test/tools/javac/diags/examples/InferVarargsArgumentMismatch.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/classes/com/sun/tools/javac/comp/Infer.java	Wed Jan 18 18:26:36 2012 -0800
     1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Infer.java	Tue Jan 24 17:52:02 2012 +0000
     1.3 @@ -34,6 +34,7 @@
     1.4  import com.sun.tools.javac.code.Type.*;
     1.5  import com.sun.tools.javac.code.Type.ForAll.ConstraintKind;
     1.6  import com.sun.tools.javac.code.Symbol.*;
     1.7 +import com.sun.tools.javac.comp.Resolve.InapplicableMethodException;
     1.8  import com.sun.tools.javac.comp.Resolve.VerboseResolutionMode;
     1.9  import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    1.10  
    1.11 @@ -84,7 +85,7 @@
    1.12  
    1.13      }
    1.14  
    1.15 -    public static class InferenceException extends Resolve.InapplicableMethodException {
    1.16 +    public static class InferenceException extends InapplicableMethodException {
    1.17          private static final long serialVersionUID = 0;
    1.18  
    1.19          InferenceException(JCDiagnostic.Factory diags) {
    1.20 @@ -287,6 +288,18 @@
    1.21          }
    1.22      }
    1.23  
    1.24 +    Type asUndetType(Type t, List<Type> undetvars) {
    1.25 +        return types.subst(t, inferenceVars(undetvars), undetvars);
    1.26 +    }
    1.27 +
    1.28 +    List<Type> inferenceVars(List<Type> undetvars) {
    1.29 +        ListBuffer<Type> tvars = ListBuffer.lb();
    1.30 +        for (Type uv : undetvars) {
    1.31 +            tvars.append(((UndetVar)uv).qtype);
    1.32 +        }
    1.33 +        return tvars.toList();
    1.34 +    }
    1.35 +
    1.36  /***************************************************************************
    1.37   * Exported Methods
    1.38   ***************************************************************************/
    1.39 @@ -372,62 +385,11 @@
    1.40                                    final Warner warn) throws InferenceException {
    1.41          //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG
    1.42          List<Type> undetvars = Type.map(tvars, fromTypeVarFun);
    1.43 -        List<Type> formals = mt.argtypes;
    1.44 -        //need to capture exactly once - otherwise subsequent
    1.45 -        //applicability checks might fail
    1.46 -        final List<Type> capturedArgs = types.capture(argtypes);
    1.47 -        List<Type> actuals = capturedArgs;
    1.48 -        List<Type> actualsNoCapture = argtypes;
    1.49 -        // instantiate all polymorphic argument types and
    1.50 -        // set up lower bounds constraints for undetvars
    1.51 -        Type varargsFormal = useVarargs ? formals.last() : null;
    1.52 -        if (varargsFormal == null &&
    1.53 -                actuals.size() != formals.size()) {
    1.54 -            throw unambiguousNoInstanceException
    1.55 -                .setMessage("infer.arg.length.mismatch");
    1.56 -        }
    1.57 -        while (actuals.nonEmpty() && formals.head != varargsFormal) {
    1.58 -            Type formal = formals.head;
    1.59 -            Type actual = actuals.head.baseType();
    1.60 -            Type actualNoCapture = actualsNoCapture.head.baseType();
    1.61 -            if (actual.tag == FORALL)
    1.62 -                actual = instantiateArg((ForAll)actual, formal, tvars, warn);
    1.63 -            Type undetFormal = types.subst(formal, tvars, undetvars);
    1.64 -            boolean works = allowBoxing
    1.65 -                ? types.isConvertible(actual, undetFormal, warn)
    1.66 -                : types.isSubtypeUnchecked(actual, undetFormal, warn);
    1.67 -            if (!works) {
    1.68 -                throw unambiguousNoInstanceException
    1.69 -                    .setMessage("infer.no.conforming.assignment.exists",
    1.70 -                                tvars, actualNoCapture, formal);
    1.71 -            }
    1.72 -            formals = formals.tail;
    1.73 -            actuals = actuals.tail;
    1.74 -            actualsNoCapture = actualsNoCapture.tail;
    1.75 -        }
    1.76 +        //final List<Type> capturedArgs = types.capture(argtypes);
    1.77  
    1.78 -        if (formals.head != varargsFormal) // not enough args
    1.79 -            throw unambiguousNoInstanceException.setMessage("infer.arg.length.mismatch");
    1.80 -
    1.81 -        // for varargs arguments as well
    1.82 -        if (useVarargs) {
    1.83 -            Type elemType = types.elemtype(varargsFormal);
    1.84 -            Type elemUndet = types.subst(elemType, tvars, undetvars);
    1.85 -            while (actuals.nonEmpty()) {
    1.86 -                Type actual = actuals.head.baseType();
    1.87 -                Type actualNoCapture = actualsNoCapture.head.baseType();
    1.88 -                if (actual.tag == FORALL)
    1.89 -                    actual = instantiateArg((ForAll)actual, elemType, tvars, warn);
    1.90 -                boolean works = types.isConvertible(actual, elemUndet, warn);
    1.91 -                if (!works) {
    1.92 -                    throw unambiguousNoInstanceException
    1.93 -                        .setMessage("infer.no.conforming.assignment.exists",
    1.94 -                                    tvars, actualNoCapture, elemType);
    1.95 -                }
    1.96 -                actuals = actuals.tail;
    1.97 -                actualsNoCapture = actualsNoCapture.tail;
    1.98 -            }
    1.99 -        }
   1.100 +        final List<Type> capturedArgs =
   1.101 +                rs.checkRawArgumentsAcceptable(env, undetvars, argtypes, mt.getParameterTypes(),
   1.102 +                    allowBoxing, useVarargs, warn, new InferenceCheckHandler(undetvars));
   1.103  
   1.104          // minimize as yet undetermined type variables
   1.105          for (Type t : undetvars)
   1.106 @@ -503,6 +465,31 @@
   1.107      }
   1.108      //where
   1.109  
   1.110 +        /** inference check handler **/
   1.111 +        class InferenceCheckHandler implements Resolve.MethodCheckHandler {
   1.112 +
   1.113 +            List<Type> undetvars;
   1.114 +
   1.115 +            public InferenceCheckHandler(List<Type> undetvars) {
   1.116 +                this.undetvars = undetvars;
   1.117 +            }
   1.118 +
   1.119 +            public InapplicableMethodException arityMismatch() {
   1.120 +                return unambiguousNoInstanceException.setMessage("infer.arg.length.mismatch");
   1.121 +            }
   1.122 +            public InapplicableMethodException argumentMismatch(boolean varargs, Type found, Type expected) {
   1.123 +                String key = varargs ?
   1.124 +                    "infer.varargs.argument.mismatch" :
   1.125 +                    "infer.no.conforming.assignment.exists";
   1.126 +                return unambiguousNoInstanceException.setMessage(key,
   1.127 +                        inferenceVars(undetvars), found, expected);
   1.128 +            }
   1.129 +            public InapplicableMethodException inaccessibleVarargs(Symbol location, Type expected) {
   1.130 +                return unambiguousNoInstanceException.setMessage("inaccessible.varargs.type",
   1.131 +                        expected, Kinds.kindName(location), location);
   1.132 +            }
   1.133 +        }
   1.134 +
   1.135          /**
   1.136           * A delegated type representing a partially uninferred method type.
   1.137           * The return type of a partially uninferred method type is a ForAll
   1.138 @@ -572,7 +559,7 @@
   1.139                  rs.checkRawArgumentsAcceptable(env, actuals, formals,
   1.140                         allowBoxing, useVarargs, warn);
   1.141              }
   1.142 -            catch (Resolve.InapplicableMethodException ex) {
   1.143 +            catch (InapplicableMethodException ex) {
   1.144                  // inferred method is not applicable
   1.145                  throw invalidInstanceException.setMessage(ex.getDiagnostic());
   1.146              }
     2.1 --- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Wed Jan 18 18:26:36 2012 -0800
     2.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Tue Jan 24 17:52:02 2012 +0000
     2.3 @@ -1,5 +1,5 @@
     2.4  /*
     2.5 - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
     2.6 + * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
     2.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     2.8   *
     2.9   * This code is free software; you can redistribute it and/or modify it
    2.10 @@ -474,52 +474,126 @@
    2.11              return false;
    2.12          }
    2.13      }
    2.14 +    /**
    2.15 +     * A check handler is used by the main method applicability routine in order
    2.16 +     * to handle specific method applicability failures. It is assumed that a class
    2.17 +     * implementing this interface should throw exceptions that are a subtype of
    2.18 +     * InapplicableMethodException (see below). Such exception will terminate the
    2.19 +     * method applicability check and propagate important info outwards (for the
    2.20 +     * purpose of generating better diagnostics).
    2.21 +     */
    2.22 +    interface MethodCheckHandler {
    2.23 +        /* The number of actuals and formals differ */
    2.24 +        InapplicableMethodException arityMismatch();
    2.25 +        /* An actual argument type does not conform to the corresponding formal type */
    2.26 +        InapplicableMethodException argumentMismatch(boolean varargs, Type found, Type expected);
    2.27 +        /* The element type of a varargs is not accessible in the current context */
    2.28 +        InapplicableMethodException inaccessibleVarargs(Symbol location, Type expected);
    2.29 +    }
    2.30 +
    2.31 +    /**
    2.32 +     * Basic method check handler used within Resolve - all methods end up
    2.33 +     * throwing InapplicableMethodException; a diagnostic fragment that describes
    2.34 +     * the cause as to why the method is not applicable is set on the exception
    2.35 +     * before it is thrown.
    2.36 +     */
    2.37 +    MethodCheckHandler resolveHandler = new MethodCheckHandler() {
    2.38 +            public InapplicableMethodException arityMismatch() {
    2.39 +                return inapplicableMethodException.setMessage("arg.length.mismatch");
    2.40 +            }
    2.41 +            public InapplicableMethodException argumentMismatch(boolean varargs, Type found, Type expected) {
    2.42 +                String key = varargs ?
    2.43 +                        "varargs.argument.mismatch" :
    2.44 +                        "no.conforming.assignment.exists";
    2.45 +                return inapplicableMethodException.setMessage(key,
    2.46 +                        found, expected);
    2.47 +            }
    2.48 +            public InapplicableMethodException inaccessibleVarargs(Symbol location, Type expected) {
    2.49 +                return inapplicableMethodException.setMessage("inaccessible.varargs.type",
    2.50 +                        expected, Kinds.kindName(location), location);
    2.51 +            }
    2.52 +    };
    2.53 +
    2.54      void checkRawArgumentsAcceptable(Env<AttrContext> env,
    2.55                                  List<Type> argtypes,
    2.56                                  List<Type> formals,
    2.57                                  boolean allowBoxing,
    2.58                                  boolean useVarargs,
    2.59                                  Warner warn) {
    2.60 +        checkRawArgumentsAcceptable(env, List.<Type>nil(), argtypes, formals,
    2.61 +                allowBoxing, useVarargs, warn, resolveHandler);
    2.62 +    }
    2.63 +
    2.64 +    /**
    2.65 +     * Main method applicability routine. Given a list of actual types A,
    2.66 +     * a list of formal types F, determines whether the types in A are
    2.67 +     * compatible (by method invocation conversion) with the types in F.
    2.68 +     *
    2.69 +     * Since this routine is shared between overload resolution and method
    2.70 +     * type-inference, it is crucial that actual types are converted to the
    2.71 +     * corresponding 'undet' form (i.e. where inference variables are replaced
    2.72 +     * with undetvars) so that constraints can be propagated and collected.
    2.73 +     *
    2.74 +     * Moreover, if one or more types in A is a poly type, this routine calls
    2.75 +     * Infer.instantiateArg in order to complete the poly type (this might involve
    2.76 +     * deferred attribution).
    2.77 +     *
    2.78 +     * A method check handler (see above) is used in order to report errors.
    2.79 +     */
    2.80 +    List<Type> checkRawArgumentsAcceptable(Env<AttrContext> env,
    2.81 +                                List<Type> undetvars,
    2.82 +                                List<Type> argtypes,
    2.83 +                                List<Type> formals,
    2.84 +                                boolean allowBoxing,
    2.85 +                                boolean useVarargs,
    2.86 +                                Warner warn,
    2.87 +                                MethodCheckHandler handler) {
    2.88          Type varargsFormal = useVarargs ? formals.last() : null;
    2.89 +        ListBuffer<Type> checkedArgs = ListBuffer.lb();
    2.90 +
    2.91          if (varargsFormal == null &&
    2.92                  argtypes.size() != formals.size()) {
    2.93 -            throw inapplicableMethodException.setMessage("arg.length.mismatch"); // not enough args
    2.94 +            throw handler.arityMismatch(); // not enough args
    2.95          }
    2.96  
    2.97          while (argtypes.nonEmpty() && formals.head != varargsFormal) {
    2.98 -            boolean works = allowBoxing
    2.99 -                ? types.isConvertible(argtypes.head, formals.head, warn)
   2.100 -                : types.isSubtypeUnchecked(argtypes.head, formals.head, warn);
   2.101 -            if (!works)
   2.102 -                throw inapplicableMethodException.setMessage("no.conforming.assignment.exists",
   2.103 -                        argtypes.head,
   2.104 -                        formals.head);
   2.105 +            Type undetFormal = infer.asUndetType(formals.head, undetvars);
   2.106 +            Type capturedActual = types.capture(argtypes.head);
   2.107 +            boolean works = allowBoxing ?
   2.108 +                    types.isConvertible(capturedActual, undetFormal, warn) :
   2.109 +                    types.isSubtypeUnchecked(capturedActual, undetFormal, warn);
   2.110 +            if (!works) {
   2.111 +                throw handler.argumentMismatch(false, argtypes.head, formals.head);
   2.112 +            }
   2.113 +            checkedArgs.append(capturedActual);
   2.114              argtypes = argtypes.tail;
   2.115              formals = formals.tail;
   2.116          }
   2.117  
   2.118 -        if (formals.head != varargsFormal)
   2.119 -            throw inapplicableMethodException.setMessage("arg.length.mismatch"); // not enough args
   2.120 +        if (formals.head != varargsFormal) {
   2.121 +            throw handler.arityMismatch(); // not enough args
   2.122 +        }
   2.123  
   2.124          if (useVarargs) {
   2.125 +            //note: if applicability check is triggered by most specific test,
   2.126 +            //the last argument of a varargs is _not_ an array type (see JLS 15.12.2.5)
   2.127              Type elt = types.elemtype(varargsFormal);
   2.128 +            Type eltUndet = infer.asUndetType(elt, undetvars);
   2.129              while (argtypes.nonEmpty()) {
   2.130 -                if (!types.isConvertible(argtypes.head, elt, warn))
   2.131 -                    throw inapplicableMethodException.setMessage("varargs.argument.mismatch",
   2.132 -                            argtypes.head,
   2.133 -                            elt);
   2.134 +                Type capturedActual = types.capture(argtypes.head);
   2.135 +                if (!types.isConvertible(capturedActual, eltUndet, warn)) {
   2.136 +                    throw handler.argumentMismatch(true, argtypes.head, elt);
   2.137 +                }
   2.138 +                checkedArgs.append(capturedActual);
   2.139                  argtypes = argtypes.tail;
   2.140              }
   2.141              //check varargs element type accessibility
   2.142 -            if (!isAccessible(env, elt)) {
   2.143 +            if (undetvars.isEmpty() && !isAccessible(env, elt)) {
   2.144                  Symbol location = env.enclClass.sym;
   2.145 -                throw inapplicableMethodException.setMessage("inaccessible.varargs.type",
   2.146 -                            elt,
   2.147 -                            Kinds.kindName(location),
   2.148 -                            location);
   2.149 +                throw handler.inaccessibleVarargs(location, elt);
   2.150              }
   2.151          }
   2.152 -        return;
   2.153 +        return checkedArgs.toList();
   2.154      }
   2.155      // where
   2.156          public static class InapplicableMethodException extends RuntimeException {
     3.1 --- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Jan 18 18:26:36 2012 -0800
     3.2 +++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Tue Jan 24 17:52:02 2012 +0000
     3.3 @@ -1,5 +1,5 @@
     3.4  #
     3.5 -# Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
     3.6 +# Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
     3.7  # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3.8  #
     3.9  # This code is free software; you can redistribute it and/or modify it
    3.10 @@ -1620,6 +1620,10 @@
    3.11  compiler.misc.infer.arg.length.mismatch=\
    3.12      cannot instantiate from arguments because actual and formal argument lists differ in length
    3.13  
    3.14 +# 0: list of type, 1: type, 2: type
    3.15 +compiler.misc.infer.varargs.argument.mismatch=\
    3.16 +    no instance(s) of type variable(s) {0} exist so that argument type {1} conforms to vararg element type {2}
    3.17 +
    3.18  # 0: type, 1: list of type
    3.19  compiler.misc.inferred.do.not.conform.to.bounds=\
    3.20      inferred type does not conform to declared bound(s)\n\
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/test/tools/javac/diags/examples/InferVarargsArgumentMismatch.java	Tue Jan 24 17:52:02 2012 +0000
     4.3 @@ -0,0 +1,30 @@
     4.4 +/*
     4.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
     4.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4.7 + *
     4.8 + * This code is free software; you can redistribute it and/or modify it
     4.9 + * under the terms of the GNU General Public License version 2 only, as
    4.10 + * published by the Free Software Foundation.
    4.11 + *
    4.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    4.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    4.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    4.15 + * version 2 for more details (a copy is included in the LICENSE file that
    4.16 + * accompanied this code).
    4.17 + *
    4.18 + * You should have received a copy of the GNU General Public License version
    4.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    4.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    4.21 + *
    4.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    4.23 + * or visit www.oracle.com if you need additional information or have any
    4.24 + * questions.
    4.25 + */
    4.26 +
    4.27 +// key: compiler.err.cant.apply.symbol.1
    4.28 +// key: compiler.misc.infer.varargs.argument.mismatch
    4.29 +
    4.30 +class InferVarargsArgumentMismatch {
    4.31 +    <X> void m(X x1, String... xs) {}
    4.32 +    { this.m("", 1); }
    4.33 +}

mercurial