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

Tue, 08 Jan 2013 10:15:30 +0100

author
mcimadamore
date
Tue, 08 Jan 2013 10:15:30 +0100
changeset 1479
38d3d1027f5a
parent 1415
01c9d4161882
child 1510
7873d37f5b37
permissions
-rw-r--r--

8005243: Restructure method check code to allow pluggable checkers
Summary: Add interface to perform a method check - to be implemented by helper classes
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.code.*;
    29 import com.sun.tools.javac.code.Symbol.*;
    30 import com.sun.tools.javac.code.Type.*;
    31 import com.sun.tools.javac.code.Type.UndetVar.InferenceBound;
    32 import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
    33 import com.sun.tools.javac.comp.Resolve.InapplicableMethodException;
    34 import com.sun.tools.javac.comp.Resolve.VerboseResolutionMode;
    35 import com.sun.tools.javac.tree.JCTree;
    36 import com.sun.tools.javac.tree.JCTree.JCTypeCast;
    37 import com.sun.tools.javac.tree.TreeInfo;
    38 import com.sun.tools.javac.util.*;
    39 import com.sun.tools.javac.util.List;
    40 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    42 import java.util.HashMap;
    43 import java.util.Map;
    45 import static com.sun.tools.javac.code.TypeTag.*;
    47 /** Helper class for type parameter inference, used by the attribution phase.
    48  *
    49  *  <p><b>This is NOT part of any supported API.
    50  *  If you write code that depends on this, you do so at your own risk.
    51  *  This code and its internal interfaces are subject to change or
    52  *  deletion without notice.</b>
    53  */
    54 public class Infer {
    55     protected static final Context.Key<Infer> inferKey =
    56         new Context.Key<Infer>();
    58     /** A value for prototypes that admit any type, including polymorphic ones. */
    59     public static final Type anyPoly = new Type(NONE, null);
    61     Symtab syms;
    62     Types types;
    63     Check chk;
    64     Resolve rs;
    65     DeferredAttr deferredAttr;
    66     Log log;
    67     JCDiagnostic.Factory diags;
    69     public static Infer instance(Context context) {
    70         Infer instance = context.get(inferKey);
    71         if (instance == null)
    72             instance = new Infer(context);
    73         return instance;
    74     }
    76     protected Infer(Context context) {
    77         context.put(inferKey, this);
    78         syms = Symtab.instance(context);
    79         types = Types.instance(context);
    80         rs = Resolve.instance(context);
    81         deferredAttr = DeferredAttr.instance(context);
    82         log = Log.instance(context);
    83         chk = Check.instance(context);
    84         diags = JCDiagnostic.Factory.instance(context);
    85         inferenceException = new InferenceException(diags);
    86     }
    88    /**
    89     * This exception class is design to store a list of diagnostics corresponding
    90     * to inference errors that can arise during a method applicability check.
    91     */
    92     public static class InferenceException extends InapplicableMethodException {
    93         private static final long serialVersionUID = 0;
    95         List<JCDiagnostic> messages = List.nil();
    97         InferenceException(JCDiagnostic.Factory diags) {
    98             super(diags);
    99         }
   101         @Override
   102         InapplicableMethodException setMessage(JCDiagnostic diag) {
   103             messages = messages.append(diag);
   104             return this;
   105         }
   107         @Override
   108         public JCDiagnostic getDiagnostic() {
   109             return messages.head;
   110         }
   112         void clear() {
   113             messages = List.nil();
   114         }
   115     }
   117     final InferenceException inferenceException;
   119 /***************************************************************************
   120  * Mini/Maximization of UndetVars
   121  ***************************************************************************/
   123     /** Instantiate undetermined type variable to its minimal upper bound.
   124      *  Throw a NoInstanceException if this not possible.
   125      */
   126    void maximizeInst(UndetVar that, Warner warn) throws InferenceException {
   127         List<Type> hibounds = Type.filter(that.getBounds(InferenceBound.UPPER), boundFilter);
   128         if (that.getBounds(InferenceBound.EQ).isEmpty()) {
   129             if (hibounds.isEmpty())
   130                 that.inst = syms.objectType;
   131             else if (hibounds.tail.isEmpty())
   132                 that.inst = hibounds.head;
   133             else
   134                 that.inst = types.glb(hibounds);
   135         } else {
   136             that.inst = that.getBounds(InferenceBound.EQ).head;
   137         }
   138         if (that.inst == null ||
   139             that.inst.isErroneous())
   140             throw inferenceException
   141                 .setMessage("no.unique.maximal.instance.exists",
   142                             that.qtype, hibounds);
   143     }
   145     private Filter<Type> boundFilter = new Filter<Type>() {
   146         @Override
   147         public boolean accepts(Type t) {
   148             return !t.isErroneous() && !t.hasTag(BOT);
   149         }
   150     };
   152     /** Instantiate undetermined type variable to the lub of all its lower bounds.
   153      *  Throw a NoInstanceException if this not possible.
   154      */
   155     void minimizeInst(UndetVar that, Warner warn) throws InferenceException {
   156         List<Type> lobounds = Type.filter(that.getBounds(InferenceBound.LOWER), boundFilter);
   157         if (that.getBounds(InferenceBound.EQ).isEmpty()) {
   158             if (lobounds.isEmpty()) {
   159                 //do nothing - the inference variable is under-constrained
   160                 return;
   161             } else if (lobounds.tail.isEmpty())
   162                 that.inst = lobounds.head.isPrimitive() ? syms.errType : lobounds.head;
   163             else {
   164                 that.inst = types.lub(lobounds);
   165             }
   166             if (that.inst == null || that.inst.hasTag(ERROR))
   167                     throw inferenceException
   168                         .setMessage("no.unique.minimal.instance.exists",
   169                                     that.qtype, lobounds);
   170         } else {
   171             that.inst = that.getBounds(InferenceBound.EQ).head;
   172         }
   173     }
   175 /***************************************************************************
   176  * Exported Methods
   177  ***************************************************************************/
   179     /**
   180      * Instantiate uninferred inference variables (JLS 15.12.2.8). First
   181      * if the method return type is non-void, we derive constraints from the
   182      * expected type - then we use declared bound well-formedness to derive additional
   183      * constraints. If no instantiation exists, or if several incomparable
   184      * best instantiations exist throw a NoInstanceException.
   185      */
   186     public void instantiateUninferred(DiagnosticPosition pos,
   187             InferenceContext inferenceContext,
   188             MethodType mtype,
   189             Attr.ResultInfo resultInfo,
   190             Warner warn) throws InferenceException {
   191         Type to = resultInfo.pt;
   192         if (to.hasTag(NONE) || resultInfo.checkContext.inferenceContext().free(resultInfo.pt)) {
   193             to = mtype.getReturnType().isPrimitiveOrVoid() ?
   194                     mtype.getReturnType() : syms.objectType;
   195         }
   196         Type qtype1 = inferenceContext.asFree(mtype.getReturnType(), types);
   197         if (!types.isSubtype(qtype1,
   198                 qtype1.hasTag(UNDETVAR) ? types.boxedTypeOrType(to) : to)) {
   199             throw inferenceException
   200                     .setMessage("infer.no.conforming.instance.exists",
   201                     inferenceContext.restvars(), mtype.getReturnType(), to);
   202         }
   204         while (true) {
   205             boolean stuck = true;
   206             for (Type t : inferenceContext.undetvars) {
   207                 UndetVar uv = (UndetVar)t;
   208                 if (uv.inst == null && (uv.getBounds(InferenceBound.EQ).nonEmpty() ||
   209                         !inferenceContext.free(uv.getBounds(InferenceBound.UPPER)))) {
   210                     maximizeInst((UndetVar)t, warn);
   211                     stuck = false;
   212                 }
   213             }
   214             if (inferenceContext.restvars().isEmpty()) {
   215                 //all variables have been instantiated - exit
   216                 break;
   217             } else if (stuck) {
   218                 //some variables could not be instantiated because of cycles in
   219                 //upper bounds - provide a (possibly recursive) default instantiation
   220                 instantiateAsUninferredVars(inferenceContext);
   221                 break;
   222             } else {
   223                 //some variables have been instantiated - replace newly instantiated
   224                 //variables in remaining upper bounds and continue
   225                 for (Type t : inferenceContext.undetvars) {
   226                     UndetVar uv = (UndetVar)t;
   227                     uv.substBounds(inferenceContext.inferenceVars(), inferenceContext.instTypes(), types);
   228                 }
   229             }
   230         }
   231     }
   233     /**
   234      * Infer cyclic inference variables as described in 15.12.2.8.
   235      */
   236     private void instantiateAsUninferredVars(InferenceContext inferenceContext) {
   237         ListBuffer<Type> todo = ListBuffer.lb();
   238         //step 1 - create fresh tvars
   239         for (Type t : inferenceContext.undetvars) {
   240             UndetVar uv = (UndetVar)t;
   241             if (uv.inst == null) {
   242                 TypeSymbol fresh_tvar = new TypeSymbol(Flags.SYNTHETIC, uv.qtype.tsym.name, null, uv.qtype.tsym.owner);
   243                 fresh_tvar.type = new TypeVar(fresh_tvar, types.makeCompoundType(uv.getBounds(InferenceBound.UPPER)), null);
   244                 todo.append(uv);
   245                 uv.inst = fresh_tvar.type;
   246             }
   247         }
   248         //step 2 - replace fresh tvars in their bounds
   249         List<Type> formals = inferenceContext.inferenceVars();
   250         for (Type t : todo) {
   251             UndetVar uv = (UndetVar)t;
   252             TypeVar ct = (TypeVar)uv.inst;
   253             ct.bound = types.glb(inferenceContext.asInstTypes(types.getBounds(ct), types));
   254             if (ct.bound.isErroneous()) {
   255                 //report inference error if glb fails
   256                 reportBoundError(uv, BoundErrorKind.BAD_UPPER);
   257             }
   258             formals = formals.tail;
   259         }
   260     }
   262     /** Instantiate a generic method type by finding instantiations for all its
   263      * inference variables so that it can be applied to a given argument type list.
   264      */
   265     public Type instantiateMethod(Env<AttrContext> env,
   266                                   List<Type> tvars,
   267                                   MethodType mt,
   268                                   Attr.ResultInfo resultInfo,
   269                                   Symbol msym,
   270                                   List<Type> argtypes,
   271                                   boolean allowBoxing,
   272                                   boolean useVarargs,
   273                                   Resolve.MethodResolutionContext resolveContext,
   274                                   Resolve.MethodCheck methodCheck,
   275                                   Warner warn) throws InferenceException {
   276         //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG
   277         final InferenceContext inferenceContext = new InferenceContext(tvars, this, true);
   278         inferenceException.clear();
   280         DeferredAttr.DeferredAttrContext deferredAttrContext =
   281                 resolveContext.deferredAttrContext(msym, inferenceContext);
   283         try {
   284             methodCheck.argumentsAcceptable(env, deferredAttrContext, argtypes, mt.getParameterTypes(), warn);
   286             deferredAttrContext.complete();
   288             // minimize as yet undetermined type variables
   289             for (Type t : inferenceContext.undetvars) {
   290                 minimizeInst((UndetVar)t, warn);
   291             }
   293             checkWithinBounds(inferenceContext, warn);
   295             mt = (MethodType)inferenceContext.asInstType(mt, types);
   297             List<Type> restvars = inferenceContext.restvars();
   299             if (!restvars.isEmpty()) {
   300                 if (resultInfo != null && !warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED)) {
   301                     instantiateUninferred(env.tree.pos(), inferenceContext, mt, resultInfo, warn);
   302                     checkWithinBounds(inferenceContext, warn);
   303                     mt = (MethodType)inferenceContext.asInstType(mt, types);
   304                     if (rs.verboseResolutionMode.contains(VerboseResolutionMode.DEFERRED_INST)) {
   305                         log.note(env.tree.pos, "deferred.method.inst", msym, mt, resultInfo.pt);
   306                     }
   307                 }
   308             }
   310             // return instantiated version of method type
   311             return mt;
   312         } finally {
   313             inferenceContext.notifyChange(types);
   314         }
   315     }
   317     /** check that type parameters are within their bounds.
   318      */
   319     void checkWithinBounds(InferenceContext inferenceContext,
   320                            Warner warn) throws InferenceException {
   321         //step 1 - check compatibility of instantiated type w.r.t. initial bounds
   322         for (Type t : inferenceContext.undetvars) {
   323             UndetVar uv = (UndetVar)t;
   324             uv.substBounds(inferenceContext.inferenceVars(), inferenceContext.instTypes(), types);
   325             checkCompatibleUpperBounds(uv, inferenceContext.inferenceVars());
   326             if (!inferenceContext.restvars().contains(uv.qtype)) {
   327                 Type inst = inferenceContext.asInstType(t, types);
   328                 for (Type u : uv.getBounds(InferenceBound.UPPER)) {
   329                     if (!types.isSubtypeUnchecked(inst, inferenceContext.asFree(u, types), warn)) {
   330                         reportBoundError(uv, BoundErrorKind.UPPER);
   331                     }
   332                 }
   333                 for (Type l : uv.getBounds(InferenceBound.LOWER)) {
   334                     Assert.check(!inferenceContext.free(l));
   335                     if (!types.isSubtypeUnchecked(l, inst, warn)) {
   336                         reportBoundError(uv, BoundErrorKind.LOWER);
   337                     }
   338                 }
   339                 for (Type e : uv.getBounds(InferenceBound.EQ)) {
   340                     Assert.check(!inferenceContext.free(e));
   341                     if (!types.isSameType(inst, e)) {
   342                         reportBoundError(uv, BoundErrorKind.EQ);
   343                     }
   344                 }
   345             }
   346         }
   348         //step 2 - check that eq bounds are consistent w.r.t. eq/lower bounds
   349         for (Type t : inferenceContext.undetvars) {
   350             UndetVar uv = (UndetVar)t;
   351             //check eq bounds consistency
   352             Type eq = null;
   353             for (Type e : uv.getBounds(InferenceBound.EQ)) {
   354                 Assert.check(!inferenceContext.free(e));
   355                 if (eq != null && !types.isSameType(e, eq)) {
   356                     reportBoundError(uv, BoundErrorKind.EQ);
   357                 }
   358                 eq = e;
   359                 for (Type l : uv.getBounds(InferenceBound.LOWER)) {
   360                     Assert.check(!inferenceContext.free(l));
   361                     if (!types.isSubtypeUnchecked(l, e, warn)) {
   362                         reportBoundError(uv, BoundErrorKind.BAD_EQ_LOWER);
   363                     }
   364                 }
   365                 for (Type u : uv.getBounds(InferenceBound.UPPER)) {
   366                     if (inferenceContext.free(u)) continue;
   367                     if (!types.isSubtypeUnchecked(e, u, warn)) {
   368                         reportBoundError(uv, BoundErrorKind.BAD_EQ_UPPER);
   369                     }
   370                 }
   371             }
   372         }
   373     }
   375     void checkCompatibleUpperBounds(UndetVar uv, List<Type> tvars) {
   376         // VGJ: sort of inlined maximizeInst() below.  Adding
   377         // bounds can cause lobounds that are above hibounds.
   378         ListBuffer<Type> hiboundsNoVars = ListBuffer.lb();
   379         for (Type t : Type.filter(uv.getBounds(InferenceBound.UPPER), boundFilter)) {
   380             if (!t.containsAny(tvars)) {
   381                 hiboundsNoVars.append(t);
   382             }
   383         }
   384         List<Type> hibounds = hiboundsNoVars.toList();
   385         Type hb = null;
   386         if (hibounds.isEmpty())
   387             hb = syms.objectType;
   388         else if (hibounds.tail.isEmpty())
   389             hb = hibounds.head;
   390         else
   391             hb = types.glb(hibounds);
   392         if (hb == null || hb.isErroneous())
   393             reportBoundError(uv, BoundErrorKind.BAD_UPPER);
   394     }
   396     enum BoundErrorKind {
   397         BAD_UPPER() {
   398             @Override
   399             InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
   400                 return ex.setMessage("incompatible.upper.bounds", uv.qtype,
   401                         uv.getBounds(InferenceBound.UPPER));
   402             }
   403         },
   404         BAD_EQ_UPPER() {
   405             @Override
   406             InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
   407                 return ex.setMessage("incompatible.eq.upper.bounds", uv.qtype,
   408                         uv.getBounds(InferenceBound.EQ), uv.getBounds(InferenceBound.UPPER));
   409             }
   410         },
   411         BAD_EQ_LOWER() {
   412             @Override
   413             InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
   414                 return ex.setMessage("incompatible.eq.lower.bounds", uv.qtype,
   415                         uv.getBounds(InferenceBound.EQ), uv.getBounds(InferenceBound.LOWER));
   416             }
   417         },
   418         UPPER() {
   419             @Override
   420             InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
   421                 return ex.setMessage("inferred.do.not.conform.to.upper.bounds", uv.inst,
   422                         uv.getBounds(InferenceBound.UPPER));
   423             }
   424         },
   425         LOWER() {
   426             @Override
   427             InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
   428                 return ex.setMessage("inferred.do.not.conform.to.lower.bounds", uv.inst,
   429                         uv.getBounds(InferenceBound.LOWER));
   430             }
   431         },
   432         EQ() {
   433             @Override
   434             InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
   435                 return ex.setMessage("inferred.do.not.conform.to.eq.bounds", uv.inst,
   436                         uv.getBounds(InferenceBound.EQ));
   437             }
   438         };
   440         abstract InapplicableMethodException setMessage(InferenceException ex, UndetVar uv);
   441     }
   442     //where
   443     void reportBoundError(UndetVar uv, BoundErrorKind bk) {
   444         throw bk.setMessage(inferenceException, uv);
   445     }
   447     // <editor-fold desc="functional interface instantiation">
   448     /**
   449      * This method is used to infer a suitable target functional interface in case
   450      * the original parameterized interface contains wildcards. An inference process
   451      * is applied so that wildcard bounds, as well as explicit lambda/method ref parameters
   452      * (where applicable) are used to constraint the solution.
   453      */
   454     public Type instantiateFunctionalInterface(DiagnosticPosition pos, Type funcInterface,
   455             List<Type> paramTypes, Check.CheckContext checkContext) {
   456         if (types.capture(funcInterface) == funcInterface) {
   457             //if capture doesn't change the type then return the target unchanged
   458             //(this means the target contains no wildcards!)
   459             return funcInterface;
   460         } else {
   461             Type formalInterface = funcInterface.tsym.type;
   462             InferenceContext funcInterfaceContext =
   463                     new InferenceContext(funcInterface.tsym.type.getTypeArguments(), this, false);
   464             if (paramTypes != null) {
   465                 //get constraints from explicit params (this is done by
   466                 //checking that explicit param types are equal to the ones
   467                 //in the functional interface descriptors)
   468                 List<Type> descParameterTypes = types.findDescriptorType(formalInterface).getParameterTypes();
   469                 if (descParameterTypes.size() != paramTypes.size()) {
   470                     checkContext.report(pos, diags.fragment("incompatible.arg.types.in.lambda"));
   471                     return types.createErrorType(funcInterface);
   472                 }
   473                 for (Type p : descParameterTypes) {
   474                     if (!types.isSameType(funcInterfaceContext.asFree(p, types), paramTypes.head)) {
   475                         checkContext.report(pos, diags.fragment("no.suitable.functional.intf.inst", funcInterface));
   476                         return types.createErrorType(funcInterface);
   477                     }
   478                     paramTypes = paramTypes.tail;
   479                 }
   480                 for (Type t : funcInterfaceContext.undetvars) {
   481                     UndetVar uv = (UndetVar)t;
   482                     minimizeInst(uv, types.noWarnings);
   483                     if (uv.inst == null &&
   484                             Type.filter(uv.getBounds(InferenceBound.UPPER), boundFilter).nonEmpty()) {
   485                         maximizeInst(uv, types.noWarnings);
   486                     }
   487                 }
   489                 formalInterface = funcInterfaceContext.asInstType(formalInterface, types);
   490             }
   491             ListBuffer<Type> typeargs = ListBuffer.lb();
   492             List<Type> actualTypeargs = funcInterface.getTypeArguments();
   493             //for remaining uninferred type-vars in the functional interface type,
   494             //simply replace the wildcards with its bound
   495             for (Type t : formalInterface.getTypeArguments()) {
   496                 if (actualTypeargs.head.hasTag(WILDCARD)) {
   497                     WildcardType wt = (WildcardType)actualTypeargs.head;
   498                     typeargs.append(wt.type);
   499                 } else {
   500                     typeargs.append(actualTypeargs.head);
   501                 }
   502                 actualTypeargs = actualTypeargs.tail;
   503             }
   504             Type owntype = types.subst(formalInterface, funcInterfaceContext.inferenceVars(), typeargs.toList());
   505             if (!chk.checkValidGenericType(owntype)) {
   506                 //if the inferred functional interface type is not well-formed,
   507                 //or if it's not a subtype of the original target, issue an error
   508                 checkContext.report(pos, diags.fragment("no.suitable.functional.intf.inst", funcInterface));
   509                 return types.createErrorType(funcInterface);
   510             }
   511             return owntype;
   512         }
   513     }
   514     // </editor-fold>
   516     /**
   517      * Compute a synthetic method type corresponding to the requested polymorphic
   518      * method signature. The target return type is computed from the immediately
   519      * enclosing scope surrounding the polymorphic-signature call.
   520      */
   521     Type instantiatePolymorphicSignatureInstance(Env<AttrContext> env,
   522                                             MethodSymbol spMethod,  // sig. poly. method or null if none
   523                                             Resolve.MethodResolutionContext resolveContext,
   524                                             List<Type> argtypes) {
   525         final Type restype;
   527         //The return type for a polymorphic signature call is computed from
   528         //the enclosing tree E, as follows: if E is a cast, then use the
   529         //target type of the cast expression as a return type; if E is an
   530         //expression statement, the return type is 'void' - otherwise the
   531         //return type is simply 'Object'. A correctness check ensures that
   532         //env.next refers to the lexically enclosing environment in which
   533         //the polymorphic signature call environment is nested.
   535         switch (env.next.tree.getTag()) {
   536             case TYPECAST:
   537                 JCTypeCast castTree = (JCTypeCast)env.next.tree;
   538                 restype = (TreeInfo.skipParens(castTree.expr) == env.tree) ?
   539                     castTree.clazz.type :
   540                     syms.objectType;
   541                 break;
   542             case EXEC:
   543                 JCTree.JCExpressionStatement execTree =
   544                         (JCTree.JCExpressionStatement)env.next.tree;
   545                 restype = (TreeInfo.skipParens(execTree.expr) == env.tree) ?
   546                     syms.voidType :
   547                     syms.objectType;
   548                 break;
   549             default:
   550                 restype = syms.objectType;
   551         }
   553         List<Type> paramtypes = Type.map(argtypes, new ImplicitArgType(spMethod, resolveContext.step));
   554         List<Type> exType = spMethod != null ?
   555             spMethod.getThrownTypes() :
   556             List.of(syms.throwableType); // make it throw all exceptions
   558         MethodType mtype = new MethodType(paramtypes,
   559                                           restype,
   560                                           exType,
   561                                           syms.methodClass);
   562         return mtype;
   563     }
   564     //where
   565         class ImplicitArgType extends DeferredAttr.DeferredTypeMap {
   567             public ImplicitArgType(Symbol msym, Resolve.MethodResolutionPhase phase) {
   568                 deferredAttr.super(AttrMode.SPECULATIVE, msym, phase);
   569             }
   571             public Type apply(Type t) {
   572                 t = types.erasure(super.apply(t));
   573                 if (t.hasTag(BOT))
   574                     // nulls type as the marker type Null (which has no instances)
   575                     // infer as java.lang.Void for now
   576                     t = types.boxedClass(syms.voidType).type;
   577                 return t;
   578             }
   579         }
   581     /**
   582      * Mapping that turns inference variables into undet vars
   583      * (used by inference context)
   584      */
   585     class FromTypeVarFun extends Mapping {
   587         boolean includeBounds;
   589         FromTypeVarFun(boolean includeBounds) {
   590             super("fromTypeVarFunWithBounds");
   591             this.includeBounds = includeBounds;
   592         }
   594         public Type apply(Type t) {
   595             if (t.hasTag(TYPEVAR)) return new UndetVar((TypeVar)t, types, includeBounds);
   596             else return t.map(this);
   597         }
   598     };
   600     /**
   601      * An inference context keeps track of the set of variables that are free
   602      * in the current context. It provides utility methods for opening/closing
   603      * types to their corresponding free/closed forms. It also provide hooks for
   604      * attaching deferred post-inference action (see PendingCheck). Finally,
   605      * it can be used as an entry point for performing upper/lower bound inference
   606      * (see InferenceKind).
   607      */
   608     static class InferenceContext {
   610         /**
   611         * Single-method-interface for defining inference callbacks. Certain actions
   612         * (i.e. subtyping checks) might need to be redone after all inference variables
   613         * have been fixed.
   614         */
   615         interface FreeTypeListener {
   616             void typesInferred(InferenceContext inferenceContext);
   617         }
   619         /** list of inference vars as undet vars */
   620         List<Type> undetvars;
   622         /** list of inference vars in this context */
   623         List<Type> inferencevars;
   625         java.util.Map<FreeTypeListener, List<Type>> freeTypeListeners =
   626                 new java.util.HashMap<FreeTypeListener, List<Type>>();
   628         List<FreeTypeListener> freetypeListeners = List.nil();
   630         public InferenceContext(List<Type> inferencevars, Infer infer, boolean includeBounds) {
   631             this.undetvars = Type.map(inferencevars, infer.new FromTypeVarFun(includeBounds));
   632             this.inferencevars = inferencevars;
   633         }
   635         /**
   636          * returns the list of free variables (as type-variables) in this
   637          * inference context
   638          */
   639         List<Type> inferenceVars() {
   640             return inferencevars;
   641         }
   643         /**
   644          * returns the list of uninstantiated variables (as type-variables) in this
   645          * inference context (usually called after instantiate())
   646          */
   647         List<Type> restvars() {
   648             List<Type> undetvars = this.undetvars;
   649             ListBuffer<Type> restvars = ListBuffer.lb();
   650             for (Type t : instTypes()) {
   651                 UndetVar uv = (UndetVar)undetvars.head;
   652                 if (uv.qtype == t) {
   653                     restvars.append(t);
   654                 }
   655                 undetvars = undetvars.tail;
   656             }
   657             return restvars.toList();
   658         }
   660         /**
   661          * is this type free?
   662          */
   663         final boolean free(Type t) {
   664             return t.containsAny(inferencevars);
   665         }
   667         final boolean free(List<Type> ts) {
   668             for (Type t : ts) {
   669                 if (free(t)) return true;
   670             }
   671             return false;
   672         }
   674         /**
   675          * Returns a list of free variables in a given type
   676          */
   677         final List<Type> freeVarsIn(Type t) {
   678             ListBuffer<Type> buf = ListBuffer.lb();
   679             for (Type iv : inferenceVars()) {
   680                 if (t.contains(iv)) {
   681                     buf.add(iv);
   682                 }
   683             }
   684             return buf.toList();
   685         }
   687         final List<Type> freeVarsIn(List<Type> ts) {
   688             ListBuffer<Type> buf = ListBuffer.lb();
   689             for (Type t : ts) {
   690                 buf.appendList(freeVarsIn(t));
   691             }
   692             ListBuffer<Type> buf2 = ListBuffer.lb();
   693             for (Type t : buf) {
   694                 if (!buf2.contains(t)) {
   695                     buf2.add(t);
   696                 }
   697             }
   698             return buf2.toList();
   699         }
   701         /**
   702          * Replace all free variables in a given type with corresponding
   703          * undet vars (used ahead of subtyping/compatibility checks to allow propagation
   704          * of inference constraints).
   705          */
   706         final Type asFree(Type t, Types types) {
   707             return types.subst(t, inferencevars, undetvars);
   708         }
   710         final List<Type> asFree(List<Type> ts, Types types) {
   711             ListBuffer<Type> buf = ListBuffer.lb();
   712             for (Type t : ts) {
   713                 buf.append(asFree(t, types));
   714             }
   715             return buf.toList();
   716         }
   718         List<Type> instTypes() {
   719             ListBuffer<Type> buf = ListBuffer.lb();
   720             for (Type t : undetvars) {
   721                 UndetVar uv = (UndetVar)t;
   722                 buf.append(uv.inst != null ? uv.inst : uv.qtype);
   723             }
   724             return buf.toList();
   725         }
   727         /**
   728          * Replace all free variables in a given type with corresponding
   729          * instantiated types - if one or more free variable has not been
   730          * fully instantiated, it will still be available in the resulting type.
   731          */
   732         Type asInstType(Type t, Types types) {
   733             return types.subst(t, inferencevars, instTypes());
   734         }
   736         List<Type> asInstTypes(List<Type> ts, Types types) {
   737             ListBuffer<Type> buf = ListBuffer.lb();
   738             for (Type t : ts) {
   739                 buf.append(asInstType(t, types));
   740             }
   741             return buf.toList();
   742         }
   744         /**
   745          * Add custom hook for performing post-inference action
   746          */
   747         void addFreeTypeListener(List<Type> types, FreeTypeListener ftl) {
   748             freeTypeListeners.put(ftl, freeVarsIn(types));
   749         }
   751         /**
   752          * Mark the inference context as complete and trigger evaluation
   753          * of all deferred checks.
   754          */
   755         void notifyChange(Types types) {
   756             InferenceException thrownEx = null;
   757             for (Map.Entry<FreeTypeListener, List<Type>> entry :
   758                     new HashMap<FreeTypeListener, List<Type>>(freeTypeListeners).entrySet()) {
   759                 if (!Type.containsAny(entry.getValue(), restvars())) {
   760                     try {
   761                         entry.getKey().typesInferred(this);
   762                         freeTypeListeners.remove(entry.getKey());
   763                     } catch (InferenceException ex) {
   764                         if (thrownEx == null) {
   765                             thrownEx = ex;
   766                         }
   767                     }
   768                 }
   769             }
   770             //inference exception multiplexing - present any inference exception
   771             //thrown when processing listeners as a single one
   772             if (thrownEx != null) {
   773                 throw thrownEx;
   774             }
   775         }
   777         void solveAny(List<Type> varsToSolve, Types types, Infer infer) {
   778             boolean progress = false;
   779             for (Type t : varsToSolve) {
   780                 UndetVar uv = (UndetVar)asFree(t, types);
   781                 if (uv.inst == null) {
   782                     infer.minimizeInst(uv, types.noWarnings);
   783                     if (uv.inst != null) {
   784                         progress = true;
   785                     }
   786                 }
   787             }
   788             if (!progress) {
   789                 throw infer.inferenceException.setMessage("cyclic.inference", varsToSolve);
   790             }
   791         }
   792     }
   794     final InferenceContext emptyContext = new InferenceContext(List.<Type>nil(), this, false);
   795 }

mercurial