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

Wed, 23 Jan 2013 15:08:03 +0000

author
mcimadamore
date
Wed, 23 Jan 2013 15:08:03 +0000
changeset 1519
97bd5e7151bc
parent 1510
7873d37f5b37
child 1550
1df20330f6bd
permissions
-rw-r--r--

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

mercurial