src/share/classes/com/sun/tools/javac/comp/Infer.java

Thu, 02 Aug 2012 18:24:01 +0100

author
mcimadamore
date
Thu, 02 Aug 2012 18:24:01 +0100
changeset 1298
2d75e7c952b8
parent 1296
cddc2c894cc6
child 1337
2eca84194807
permissions
-rw-r--r--

7187104: Inference cleanup: remove redundant exception classes in Infer.java
Summary: Remove unused exception classes in Infer.java
Reviewed-by: jjg

     1 /*
     2  * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package com.sun.tools.javac.comp;
    28 import com.sun.tools.javac.tree.JCTree;
    29 import com.sun.tools.javac.tree.JCTree.JCTypeCast;
    30 import com.sun.tools.javac.tree.TreeInfo;
    31 import com.sun.tools.javac.util.*;
    32 import com.sun.tools.javac.util.List;
    33 import com.sun.tools.javac.code.*;
    34 import com.sun.tools.javac.code.Type.*;
    35 import com.sun.tools.javac.code.Symbol.*;
    36 import com.sun.tools.javac.comp.Resolve.InapplicableMethodException;
    37 import com.sun.tools.javac.comp.Resolve.VerboseResolutionMode;
    38 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    40 import static com.sun.tools.javac.code.TypeTags.*;
    42 /** Helper class for type parameter inference, used by the attribution phase.
    43  *
    44  *  <p><b>This is NOT part of any supported API.
    45  *  If you write code that depends on this, you do so at your own risk.
    46  *  This code and its internal interfaces are subject to change or
    47  *  deletion without notice.</b>
    48  */
    49 public class Infer {
    50     protected static final Context.Key<Infer> inferKey =
    51         new Context.Key<Infer>();
    53     /** A value for prototypes that admit any type, including polymorphic ones. */
    54     public static final Type anyPoly = new Type(NONE, null);
    56     Symtab syms;
    57     Types types;
    58     Check chk;
    59     Resolve rs;
    60     Log log;
    61     JCDiagnostic.Factory diags;
    63     public static Infer instance(Context context) {
    64         Infer instance = context.get(inferKey);
    65         if (instance == null)
    66             instance = new Infer(context);
    67         return instance;
    68     }
    70     protected Infer(Context context) {
    71         context.put(inferKey, this);
    72         syms = Symtab.instance(context);
    73         types = Types.instance(context);
    74         rs = Resolve.instance(context);
    75         log = Log.instance(context);
    76         chk = Check.instance(context);
    77         diags = JCDiagnostic.Factory.instance(context);
    78         inferenceException = new InferenceException(diags);
    80     }
    82     public static class InferenceException extends InapplicableMethodException {
    83         private static final long serialVersionUID = 0;
    85         InferenceException(JCDiagnostic.Factory diags) {
    86             super(diags);
    87         }
    88     }
    90     private final InferenceException inferenceException;
    92 /***************************************************************************
    93  * Auxiliary type values and classes
    94  ***************************************************************************/
    96     /** A mapping that turns type variables into undetermined type variables.
    97      */
    98     List<Type> makeUndetvars(List<Type> tvars) {
    99         List<Type> undetvars = Type.map(tvars, fromTypeVarFun);
   100         for (Type t : undetvars) {
   101             UndetVar uv = (UndetVar)t;
   102             uv.hibounds = types.getBounds((TypeVar)uv.qtype);
   103         }
   104         return undetvars;
   105     }
   106     //where
   107             Mapping fromTypeVarFun = new Mapping("fromTypeVarFun") {
   108                 public Type apply(Type t) {
   109                     if (t.tag == TYPEVAR) return new UndetVar(t);
   110                     else return t.map(this);
   111                 }
   112             };
   114 /***************************************************************************
   115  * Mini/Maximization of UndetVars
   116  ***************************************************************************/
   118     /** Instantiate undetermined type variable to its minimal upper bound.
   119      *  Throw a NoInstanceException if this not possible.
   120      */
   121     void maximizeInst(UndetVar that, Warner warn) throws InferenceException {
   122         List<Type> hibounds = Type.filter(that.hibounds, errorFilter);
   123         if (that.eq.isEmpty()) {
   124             if (hibounds.isEmpty())
   125                 that.inst = syms.objectType;
   126             else if (hibounds.tail.isEmpty())
   127                 that.inst = hibounds.head;
   128             else
   129                 that.inst = types.glb(hibounds);
   130         } else {
   131             that.inst = that.eq.head;
   132         }
   133         if (that.inst == null ||
   134             that.inst.isErroneous())
   135             throw inferenceException
   136                 .setMessage("no.unique.maximal.instance.exists",
   137                             that.qtype, hibounds);
   138     }
   140     private Filter<Type> errorFilter = new Filter<Type>() {
   141         @Override
   142         public boolean accepts(Type t) {
   143             return !t.isErroneous();
   144         }
   145     };
   147     /** Instantiate undetermined type variable to the lub of all its lower bounds.
   148      *  Throw a NoInstanceException if this not possible.
   149      */
   150     void minimizeInst(UndetVar that, Warner warn) throws InferenceException {
   151         List<Type> lobounds = Type.filter(that.lobounds, errorFilter);
   152         if (that.eq.isEmpty()) {
   153             if (lobounds.isEmpty())
   154                 that.inst = syms.botType;
   155             else if (lobounds.tail.isEmpty())
   156                 that.inst = lobounds.head.isPrimitive() ? syms.errType : lobounds.head;
   157             else {
   158                 that.inst = types.lub(lobounds);
   159             }
   160             if (that.inst == null || that.inst.tag == ERROR)
   161                     throw inferenceException
   162                         .setMessage("no.unique.minimal.instance.exists",
   163                                     that.qtype, lobounds);
   164         } else {
   165             that.inst = that.eq.head;
   166         }
   167     }
   169     Type asUndetType(Type t, List<Type> undetvars) {
   170         return types.subst(t, inferenceVars(undetvars), undetvars);
   171     }
   173     List<Type> inferenceVars(List<Type> undetvars) {
   174         ListBuffer<Type> tvars = ListBuffer.lb();
   175         for (Type uv : undetvars) {
   176             tvars.append(((UndetVar)uv).qtype);
   177         }
   178         return tvars.toList();
   179     }
   181 /***************************************************************************
   182  * Exported Methods
   183  ***************************************************************************/
   185     /** Try to instantiate expression type `that' to given type `to'.
   186      *  If a maximal instantiation exists which makes this type
   187      *  a subtype of type `to', return the instantiated type.
   188      *  If no instantiation exists, or if several incomparable
   189      *  best instantiations exist throw a NoInstanceException.
   190      */
   191     public List<Type> instantiateUninferred(DiagnosticPosition pos,
   192                                 List<Type> undetvars,
   193                                 List<Type> tvars,
   194                                 MethodType mtype,
   195                                 Attr.ResultInfo resultInfo,
   196                                 Warner warn) throws InferenceException {
   197         Type to = resultInfo.pt;
   198         if (to.tag == NONE) {
   199             to = mtype.getReturnType().tag <= VOID ?
   200                     mtype.getReturnType() : syms.objectType;
   201         }
   202         Type qtype1 = types.subst(mtype.getReturnType(), tvars, undetvars);
   203         if (!types.isSubtype(qtype1,
   204                 qtype1.tag == UNDETVAR ? types.boxedTypeOrType(to) : to)) {
   205             throw inferenceException
   206                 .setMessage("infer.no.conforming.instance.exists",
   207                             tvars, mtype.getReturnType(), to);
   208         }
   210         List<Type> insttypes;
   211         while (true) {
   212             boolean stuck = true;
   213             insttypes = List.nil();
   214             for (Type t : undetvars) {
   215                 UndetVar uv = (UndetVar)t;
   216                 if (uv.inst == null && (uv.eq.nonEmpty() || !Type.containsAny(uv.hibounds, tvars))) {
   217                     maximizeInst((UndetVar)t, warn);
   218                     stuck = false;
   219                 }
   220                 insttypes = insttypes.append(uv.inst == null ? uv.qtype : uv.inst);
   221             }
   222             if (!Type.containsAny(insttypes, tvars)) {
   223                 //all variables have been instantiated - exit
   224                 break;
   225             } else if (stuck) {
   226                 //some variables could not be instantiated because of cycles in
   227                 //upper bounds - provide a (possibly recursive) default instantiation
   228                 insttypes = types.subst(insttypes,
   229                     tvars,
   230                     instantiateAsUninferredVars(undetvars, tvars));
   231                 break;
   232             } else {
   233                 //some variables have been instantiated - replace newly instantiated
   234                 //variables in remaining upper bounds and continue
   235                 for (Type t : undetvars) {
   236                     UndetVar uv = (UndetVar)t;
   237                     uv.hibounds = types.subst(uv.hibounds, tvars, insttypes);
   238                 }
   239             }
   240         }
   241         return insttypes;
   242     }
   244     /**
   245      * Infer cyclic inference variables as described in 15.12.2.8.
   246      */
   247     private List<Type> instantiateAsUninferredVars(List<Type> undetvars, List<Type> tvars) {
   248         Assert.check(undetvars.length() == tvars.length());
   249         ListBuffer<Type> insttypes = ListBuffer.lb();
   250         ListBuffer<Type> todo = ListBuffer.lb();
   251         //step 1 - create fresh tvars
   252         for (Type t : undetvars) {
   253             UndetVar uv = (UndetVar)t;
   254             if (uv.inst == null) {
   255                 TypeSymbol fresh_tvar = new TypeSymbol(Flags.SYNTHETIC, uv.qtype.tsym.name, null, uv.qtype.tsym.owner);
   256                 fresh_tvar.type = new TypeVar(fresh_tvar, types.makeCompoundType(uv.hibounds), null);
   257                 todo.append(uv);
   258                 uv.inst = fresh_tvar.type;
   259             }
   260             insttypes.append(uv.inst);
   261         }
   262         //step 2 - replace fresh tvars in their bounds
   263         List<Type> formals = tvars;
   264         for (Type t : todo) {
   265             UndetVar uv = (UndetVar)t;
   266             TypeVar ct = (TypeVar)uv.inst;
   267             ct.bound = types.glb(types.subst(types.getBounds(ct), tvars, insttypes.toList()));
   268             if (ct.bound.isErroneous()) {
   269                 //report inference error if glb fails
   270                 reportBoundError(uv, BoundErrorKind.BAD_UPPER);
   271             }
   272             formals = formals.tail;
   273         }
   274         return insttypes.toList();
   275     }
   277     /** Instantiate method type `mt' by finding instantiations of
   278      *  `tvars' so that method can be applied to `argtypes'.
   279      */
   280     public Type instantiateMethod(Env<AttrContext> env,
   281                                   List<Type> tvars,
   282                                   MethodType mt,
   283                                   Attr.ResultInfo resultInfo,
   284                                   Symbol msym,
   285                                   List<Type> argtypes,
   286                                   boolean allowBoxing,
   287                                   boolean useVarargs,
   288                                   Warner warn) throws InferenceException {
   289         //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG
   290         List<Type> undetvars =  makeUndetvars(tvars);
   292         List<Type> capturedArgs =
   293                 rs.checkRawArgumentsAcceptable(env, undetvars, argtypes, mt.getParameterTypes(),
   294                     allowBoxing, useVarargs, warn, new InferenceCheckHandler(undetvars));
   296         // minimize as yet undetermined type variables
   297         for (Type t : undetvars)
   298             minimizeInst((UndetVar) t, warn);
   300         /** Type variables instantiated to bottom */
   301         ListBuffer<Type> restvars = new ListBuffer<Type>();
   303         /** Undet vars instantiated to bottom */
   304         final ListBuffer<Type> restundet = new ListBuffer<Type>();
   306         /** Instantiated types or TypeVars if under-constrained */
   307         ListBuffer<Type> insttypes = new ListBuffer<Type>();
   309         /** Instantiated types or UndetVars if under-constrained */
   310         ListBuffer<Type> undettypes = new ListBuffer<Type>();
   312         for (Type t : undetvars) {
   313             UndetVar uv = (UndetVar)t;
   314             if (uv.inst.tag == BOT) {
   315                 restvars.append(uv.qtype);
   316                 restundet.append(uv);
   317                 insttypes.append(uv.qtype);
   318                 undettypes.append(uv);
   319                 uv.inst = null;
   320             } else {
   321                 insttypes.append(uv.inst);
   322                 undettypes.append(uv.inst);
   323             }
   324         }
   325         checkWithinBounds(tvars, undetvars, insttypes.toList(), warn);
   327         mt = (MethodType)types.subst(mt, tvars, insttypes.toList());
   329         if (!restvars.isEmpty() && resultInfo != null) {
   330             List<Type> restInferred =
   331                     instantiateUninferred(env.tree.pos(), restundet.toList(), restvars.toList(), mt, resultInfo, warn);
   332             checkWithinBounds(tvars, undetvars,
   333                            types.subst(insttypes.toList(), restvars.toList(), restInferred), warn);
   334             mt = (MethodType)types.subst(mt, restvars.toList(), restInferred);
   335             if (rs.verboseResolutionMode.contains(VerboseResolutionMode.DEFERRED_INST)) {
   336                 log.note(env.tree.pos, "deferred.method.inst", msym, mt, resultInfo.pt);
   337             }
   338         }
   340         if (restvars.isEmpty() || resultInfo != null) {
   341             // check that actuals conform to inferred formals
   342             checkArgumentsAcceptable(env, capturedArgs, mt.getParameterTypes(), allowBoxing, useVarargs, warn);
   343         }
   344         // return instantiated version of method type
   345         return mt;
   346     }
   347     //where
   349         /** inference check handler **/
   350         class InferenceCheckHandler implements Resolve.MethodCheckHandler {
   352             List<Type> undetvars;
   354             public InferenceCheckHandler(List<Type> undetvars) {
   355                 this.undetvars = undetvars;
   356             }
   358             public InapplicableMethodException arityMismatch() {
   359                 return inferenceException.setMessage("infer.arg.length.mismatch", inferenceVars(undetvars));
   360             }
   361             public InapplicableMethodException argumentMismatch(boolean varargs, JCDiagnostic details) {
   362                 String key = varargs ?
   363                         "infer.varargs.argument.mismatch" :
   364                         "infer.no.conforming.assignment.exists";
   365                 return inferenceException.setMessage(key,
   366                         inferenceVars(undetvars), details);
   367             }
   368             public InapplicableMethodException inaccessibleVarargs(Symbol location, Type expected) {
   369                 return inferenceException.setMessage("inaccessible.varargs.type",
   370                         expected, Kinds.kindName(location), location);
   371             }
   372         }
   374         private void checkArgumentsAcceptable(Env<AttrContext> env, List<Type> actuals, List<Type> formals,
   375                 boolean allowBoxing, boolean useVarargs, Warner warn) {
   376             try {
   377                 rs.checkRawArgumentsAcceptable(env, actuals, formals,
   378                        allowBoxing, useVarargs, warn);
   379             }
   380             catch (InapplicableMethodException ex) {
   381                 // inferred method is not applicable
   382                 throw inferenceException.setMessage(ex.getDiagnostic());
   383             }
   384         }
   386     /** check that type parameters are within their bounds.
   387      */
   388     void checkWithinBounds(List<Type> tvars,
   389                            List<Type> undetvars,
   390                            List<Type> arguments,
   391                            Warner warn)
   392         throws InferenceException {
   393         List<Type> args = arguments;
   394         for (Type t : undetvars) {
   395             UndetVar uv = (UndetVar)t;
   396             uv.hibounds = types.subst(uv.hibounds, tvars, arguments);
   397             uv.lobounds = types.subst(uv.lobounds, tvars, arguments);
   398             uv.eq = types.subst(uv.eq, tvars, arguments);
   399             checkCompatibleUpperBounds(uv, tvars);
   400             if (args.head.tag != TYPEVAR || !args.head.containsAny(tvars)) {
   401                 Type inst = args.head;
   402                 for (Type u : uv.hibounds) {
   403                     if (!types.isSubtypeUnchecked(inst, types.subst(u, tvars, undetvars), warn)) {
   404                         reportBoundError(uv, BoundErrorKind.UPPER);
   405                     }
   406                 }
   407                 for (Type l : uv.lobounds) {
   408                     if (!types.isSubtypeUnchecked(types.subst(l, tvars, undetvars), inst, warn)) {
   409                         reportBoundError(uv, BoundErrorKind.LOWER);
   410                     }
   411                 }
   412                 for (Type e : uv.eq) {
   413                     if (!types.isSameType(inst, types.subst(e, tvars, undetvars))) {
   414                         reportBoundError(uv, BoundErrorKind.EQ);
   415                     }
   416                 }
   417             }
   418             args = args.tail;
   419         }
   420     }
   422     void checkCompatibleUpperBounds(UndetVar uv, List<Type> tvars) {
   423         // VGJ: sort of inlined maximizeInst() below.  Adding
   424         // bounds can cause lobounds that are above hibounds.
   425         ListBuffer<Type> hiboundsNoVars = ListBuffer.lb();
   426         for (Type t : Type.filter(uv.hibounds, errorFilter)) {
   427             if (!t.containsAny(tvars)) {
   428                 hiboundsNoVars.append(t);
   429             }
   430         }
   431         List<Type> hibounds = hiboundsNoVars.toList();
   432         Type hb = null;
   433         if (hibounds.isEmpty())
   434             hb = syms.objectType;
   435         else if (hibounds.tail.isEmpty())
   436             hb = hibounds.head;
   437         else
   438             hb = types.glb(hibounds);
   439         if (hb == null || hb.isErroneous())
   440             reportBoundError(uv, BoundErrorKind.BAD_UPPER);
   441     }
   443     enum BoundErrorKind {
   444         BAD_UPPER() {
   445             @Override
   446             InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
   447                 return ex.setMessage("incompatible.upper.bounds", uv.qtype, uv.hibounds);
   448             }
   449         },
   450         UPPER() {
   451             @Override
   452             InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
   453                 return ex.setMessage("inferred.do.not.conform.to.upper.bounds", uv.inst, uv.hibounds);
   454             }
   455         },
   456         LOWER() {
   457             @Override
   458             InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
   459                 return ex.setMessage("inferred.do.not.conform.to.lower.bounds", uv.inst, uv.lobounds);
   460             }
   461         },
   462         EQ() {
   463             @Override
   464             InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
   465                 return ex.setMessage("inferred.do.not.conform.to.eq.bounds", uv.inst, uv.eq);
   466             }
   467         };
   469         abstract InapplicableMethodException setMessage(InferenceException ex, UndetVar uv);
   470     }
   471     //where
   472     void reportBoundError(UndetVar uv, BoundErrorKind bk) {
   473         throw bk.setMessage(inferenceException, uv);
   474     }
   476     /**
   477      * Compute a synthetic method type corresponding to the requested polymorphic
   478      * method signature. The target return type is computed from the immediately
   479      * enclosing scope surrounding the polymorphic-signature call.
   480      */
   481     Type instantiatePolymorphicSignatureInstance(Env<AttrContext> env,
   482                                             MethodSymbol spMethod,  // sig. poly. method or null if none
   483                                             List<Type> argtypes) {
   484         final Type restype;
   486         //The return type for a polymorphic signature call is computed from
   487         //the enclosing tree E, as follows: if E is a cast, then use the
   488         //target type of the cast expression as a return type; if E is an
   489         //expression statement, the return type is 'void' - otherwise the
   490         //return type is simply 'Object'. A correctness check ensures that
   491         //env.next refers to the lexically enclosing environment in which
   492         //the polymorphic signature call environment is nested.
   494         switch (env.next.tree.getTag()) {
   495             case TYPECAST:
   496                 JCTypeCast castTree = (JCTypeCast)env.next.tree;
   497                 restype = (TreeInfo.skipParens(castTree.expr) == env.tree) ?
   498                     castTree.clazz.type :
   499                     syms.objectType;
   500                 break;
   501             case EXEC:
   502                 JCTree.JCExpressionStatement execTree =
   503                         (JCTree.JCExpressionStatement)env.next.tree;
   504                 restype = (TreeInfo.skipParens(execTree.expr) == env.tree) ?
   505                     syms.voidType :
   506                     syms.objectType;
   507                 break;
   508             default:
   509                 restype = syms.objectType;
   510         }
   512         List<Type> paramtypes = Type.map(argtypes, implicitArgType);
   513         List<Type> exType = spMethod != null ?
   514             spMethod.getThrownTypes() :
   515             List.of(syms.throwableType); // make it throw all exceptions
   517         MethodType mtype = new MethodType(paramtypes,
   518                                           restype,
   519                                           exType,
   520                                           syms.methodClass);
   521         return mtype;
   522     }
   523     //where
   524         Mapping implicitArgType = new Mapping ("implicitArgType") {
   525                 public Type apply(Type t) {
   526                     t = types.erasure(t);
   527                     if (t.tag == BOT)
   528                         // nulls type as the marker type Null (which has no instances)
   529                         // infer as java.lang.Void for now
   530                         t = types.boxedClass(syms.voidType).type;
   531                     return t;
   532                 }
   533         };
   534     }

mercurial