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

Tue, 09 Oct 2012 19:10:00 -0700

author
jjg
date
Tue, 09 Oct 2012 19:10:00 -0700
changeset 1357
c75be5bc5283
parent 1348
573ceb23beeb
child 1374
c002fdee76fd
permissions
-rw-r--r--

8000663: clean up langtools imports
Reviewed-by: darcy

     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.TypeTags.*;
    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     private 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.tag != 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.tag == 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.tag == NONE || resultInfo.checkContext.inferenceContext().free(resultInfo.pt)) {
   193             to = mtype.getReturnType().tag <= VOID ?
   194                     mtype.getReturnType() : syms.objectType;
   195         }
   196         Type qtype1 = inferenceContext.asFree(mtype.getReturnType(), types);
   197         if (!types.isSubtype(qtype1,
   198                 qtype1.tag == 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                                   Warner warn) throws InferenceException {
   275         //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG
   276         final InferenceContext inferenceContext = new InferenceContext(tvars, this, true);
   277         inferenceException.clear();
   279         try {
   280             rs.checkRawArgumentsAcceptable(env, msym, resolveContext.attrMode(), inferenceContext,
   281                     argtypes, mt.getParameterTypes(), allowBoxing, useVarargs, warn,
   282                     new InferenceCheckHandler(inferenceContext));
   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                     instantiateUninferred(env.tree.pos(), inferenceContext, mt, resultInfo, warn);
   298                     checkWithinBounds(inferenceContext, warn);
   299                     mt = (MethodType)inferenceContext.asInstType(mt, types);
   300                     if (rs.verboseResolutionMode.contains(VerboseResolutionMode.DEFERRED_INST)) {
   301                         log.note(env.tree.pos, "deferred.method.inst", msym, mt, resultInfo.pt);
   302                     }
   303                 }
   304             }
   306             // return instantiated version of method type
   307             return mt;
   308         } finally {
   309             inferenceContext.notifyChange(types);
   310         }
   311     }
   312     //where
   314         /** inference check handler **/
   315         class InferenceCheckHandler implements Resolve.MethodCheckHandler {
   317             InferenceContext inferenceContext;
   319             public InferenceCheckHandler(InferenceContext inferenceContext) {
   320                 this.inferenceContext = inferenceContext;
   321             }
   323             public InapplicableMethodException arityMismatch() {
   324                 return inferenceException.setMessage("infer.arg.length.mismatch", inferenceContext.inferenceVars());
   325             }
   326             public InapplicableMethodException argumentMismatch(boolean varargs, JCDiagnostic details) {
   327                 String key = varargs ?
   328                         "infer.varargs.argument.mismatch" :
   329                         "infer.no.conforming.assignment.exists";
   330                 return inferenceException.setMessage(key,
   331                         inferenceContext.inferenceVars(), details);
   332             }
   333             public InapplicableMethodException inaccessibleVarargs(Symbol location, Type expected) {
   334                 return inferenceException.setMessage("inaccessible.varargs.type",
   335                         expected, Kinds.kindName(location), location);
   336             }
   337         }
   339     /** check that type parameters are within their bounds.
   340      */
   341     void checkWithinBounds(InferenceContext inferenceContext,
   342                            Warner warn) throws InferenceException {
   343         //step 1 - check compatibility of instantiated type w.r.t. initial bounds
   344         for (Type t : inferenceContext.undetvars) {
   345             UndetVar uv = (UndetVar)t;
   346             uv.substBounds(inferenceContext.inferenceVars(), inferenceContext.instTypes(), types);
   347             checkCompatibleUpperBounds(uv, inferenceContext.inferenceVars());
   348             if (!inferenceContext.restvars().contains(uv.qtype)) {
   349                 Type inst = inferenceContext.asInstType(t, types);
   350                 for (Type u : uv.getBounds(InferenceBound.UPPER)) {
   351                     if (!types.isSubtypeUnchecked(inst, inferenceContext.asFree(u, types), warn)) {
   352                         reportBoundError(uv, BoundErrorKind.UPPER);
   353                     }
   354                 }
   355                 for (Type l : uv.getBounds(InferenceBound.LOWER)) {
   356                     Assert.check(!inferenceContext.free(l));
   357                     if (!types.isSubtypeUnchecked(l, inst, warn)) {
   358                         reportBoundError(uv, BoundErrorKind.LOWER);
   359                     }
   360                 }
   361                 for (Type e : uv.getBounds(InferenceBound.EQ)) {
   362                     Assert.check(!inferenceContext.free(e));
   363                     if (!types.isSameType(inst, e)) {
   364                         reportBoundError(uv, BoundErrorKind.EQ);
   365                     }
   366                 }
   367             }
   368         }
   370         //step 2 - check that eq bounds are consistent w.r.t. eq/lower bounds
   371         for (Type t : inferenceContext.undetvars) {
   372             UndetVar uv = (UndetVar)t;
   373             //check eq bounds consistency
   374             Type eq = null;
   375             for (Type e : uv.getBounds(InferenceBound.EQ)) {
   376                 Assert.check(!inferenceContext.free(e));
   377                 if (eq != null && !types.isSameType(e, eq)) {
   378                     reportBoundError(uv, BoundErrorKind.EQ);
   379                 }
   380                 eq = e;
   381                 for (Type l : uv.getBounds(InferenceBound.LOWER)) {
   382                     Assert.check(!inferenceContext.free(l));
   383                     if (!types.isSubtypeUnchecked(l, e, warn)) {
   384                         reportBoundError(uv, BoundErrorKind.BAD_EQ_LOWER);
   385                     }
   386                 }
   387                 for (Type u : uv.getBounds(InferenceBound.UPPER)) {
   388                     if (inferenceContext.free(u)) continue;
   389                     if (!types.isSubtypeUnchecked(e, u, warn)) {
   390                         reportBoundError(uv, BoundErrorKind.BAD_EQ_UPPER);
   391                     }
   392                 }
   393             }
   394         }
   395     }
   397     void checkCompatibleUpperBounds(UndetVar uv, List<Type> tvars) {
   398         // VGJ: sort of inlined maximizeInst() below.  Adding
   399         // bounds can cause lobounds that are above hibounds.
   400         ListBuffer<Type> hiboundsNoVars = ListBuffer.lb();
   401         for (Type t : Type.filter(uv.getBounds(InferenceBound.UPPER), boundFilter)) {
   402             if (!t.containsAny(tvars)) {
   403                 hiboundsNoVars.append(t);
   404             }
   405         }
   406         List<Type> hibounds = hiboundsNoVars.toList();
   407         Type hb = null;
   408         if (hibounds.isEmpty())
   409             hb = syms.objectType;
   410         else if (hibounds.tail.isEmpty())
   411             hb = hibounds.head;
   412         else
   413             hb = types.glb(hibounds);
   414         if (hb == null || hb.isErroneous())
   415             reportBoundError(uv, BoundErrorKind.BAD_UPPER);
   416     }
   418     enum BoundErrorKind {
   419         BAD_UPPER() {
   420             @Override
   421             InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
   422                 return ex.setMessage("incompatible.upper.bounds", uv.qtype,
   423                         uv.getBounds(InferenceBound.UPPER));
   424             }
   425         },
   426         BAD_EQ_UPPER() {
   427             @Override
   428             InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
   429                 return ex.setMessage("incompatible.eq.upper.bounds", uv.qtype,
   430                         uv.getBounds(InferenceBound.EQ), uv.getBounds(InferenceBound.UPPER));
   431             }
   432         },
   433         BAD_EQ_LOWER() {
   434             @Override
   435             InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
   436                 return ex.setMessage("incompatible.eq.lower.bounds", uv.qtype,
   437                         uv.getBounds(InferenceBound.EQ), uv.getBounds(InferenceBound.LOWER));
   438             }
   439         },
   440         UPPER() {
   441             @Override
   442             InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
   443                 return ex.setMessage("inferred.do.not.conform.to.upper.bounds", uv.inst,
   444                         uv.getBounds(InferenceBound.UPPER));
   445             }
   446         },
   447         LOWER() {
   448             @Override
   449             InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
   450                 return ex.setMessage("inferred.do.not.conform.to.lower.bounds", uv.inst,
   451                         uv.getBounds(InferenceBound.LOWER));
   452             }
   453         },
   454         EQ() {
   455             @Override
   456             InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
   457                 return ex.setMessage("inferred.do.not.conform.to.eq.bounds", uv.inst,
   458                         uv.getBounds(InferenceBound.EQ));
   459             }
   460         };
   462         abstract InapplicableMethodException setMessage(InferenceException ex, UndetVar uv);
   463     }
   464     //where
   465     void reportBoundError(UndetVar uv, BoundErrorKind bk) {
   466         throw bk.setMessage(inferenceException, uv);
   467     }
   469     // <editor-fold desc="functional interface instantiation">
   470     /**
   471      * This method is used to infer a suitable target functional interface in case
   472      * the original parameterized interface contains wildcards. An inference process
   473      * is applied so that wildcard bounds, as well as explicit lambda/method ref parameters
   474      * (where applicable) are used to constraint the solution.
   475      */
   476     public Type instantiateFunctionalInterface(DiagnosticPosition pos, Type funcInterface,
   477             List<Type> paramTypes, Check.CheckContext checkContext) {
   478         if (types.capture(funcInterface) == funcInterface) {
   479             //if capture doesn't change the type then return the target unchanged
   480             //(this means the target contains no wildcards!)
   481             return funcInterface;
   482         } else {
   483             Type formalInterface = funcInterface.tsym.type;
   484             InferenceContext funcInterfaceContext =
   485                     new InferenceContext(funcInterface.tsym.type.getTypeArguments(), this, false);
   486             if (paramTypes != null) {
   487                 //get constraints from explicit params (this is done by
   488                 //checking that explicit param types are equal to the ones
   489                 //in the functional interface descriptors)
   490                 List<Type> descParameterTypes = types.findDescriptorType(formalInterface).getParameterTypes();
   491                 if (descParameterTypes.size() != paramTypes.size()) {
   492                     checkContext.report(pos, diags.fragment("incompatible.arg.types.in.lambda"));
   493                     return types.createErrorType(funcInterface);
   494                 }
   495                 for (Type p : descParameterTypes) {
   496                     if (!types.isSameType(funcInterfaceContext.asFree(p, types), paramTypes.head)) {
   497                         checkContext.report(pos, diags.fragment("no.suitable.functional.intf.inst", funcInterface));
   498                         return types.createErrorType(funcInterface);
   499                     }
   500                     paramTypes = paramTypes.tail;
   501                 }
   502                 for (Type t : funcInterfaceContext.undetvars) {
   503                     UndetVar uv = (UndetVar)t;
   504                     minimizeInst(uv, Warner.noWarnings);
   505                     if (uv.inst == null &&
   506                             Type.filter(uv.getBounds(InferenceBound.UPPER), boundFilter).nonEmpty()) {
   507                         maximizeInst(uv, Warner.noWarnings);
   508                     }
   509                 }
   511                 formalInterface = funcInterfaceContext.asInstType(formalInterface, types);
   512             }
   513             ListBuffer<Type> typeargs = ListBuffer.lb();
   514             List<Type> actualTypeargs = funcInterface.getTypeArguments();
   515             //for remaining uninferred type-vars in the functional interface type,
   516             //simply replace the wildcards with its bound
   517             for (Type t : formalInterface.getTypeArguments()) {
   518                 if (actualTypeargs.head.tag == WILDCARD) {
   519                     WildcardType wt = (WildcardType)actualTypeargs.head;
   520                     typeargs.append(wt.type);
   521                 } else {
   522                     typeargs.append(actualTypeargs.head);
   523                 }
   524                 actualTypeargs = actualTypeargs.tail;
   525             }
   526             Type owntype = types.subst(formalInterface, funcInterfaceContext.inferenceVars(), typeargs.toList());
   527             if (!chk.checkValidGenericType(owntype)) {
   528                 //if the inferred functional interface type is not well-formed,
   529                 //or if it's not a subtype of the original target, issue an error
   530                 checkContext.report(pos, diags.fragment("no.suitable.functional.intf.inst", funcInterface));
   531                 return types.createErrorType(funcInterface);
   532             }
   533             return owntype;
   534         }
   535     }
   536     // </editor-fold>
   538     /**
   539      * Compute a synthetic method type corresponding to the requested polymorphic
   540      * method signature. The target return type is computed from the immediately
   541      * enclosing scope surrounding the polymorphic-signature call.
   542      */
   543     Type instantiatePolymorphicSignatureInstance(Env<AttrContext> env,
   544                                             MethodSymbol spMethod,  // sig. poly. method or null if none
   545                                             Resolve.MethodResolutionContext resolveContext,
   546                                             List<Type> argtypes) {
   547         final Type restype;
   549         //The return type for a polymorphic signature call is computed from
   550         //the enclosing tree E, as follows: if E is a cast, then use the
   551         //target type of the cast expression as a return type; if E is an
   552         //expression statement, the return type is 'void' - otherwise the
   553         //return type is simply 'Object'. A correctness check ensures that
   554         //env.next refers to the lexically enclosing environment in which
   555         //the polymorphic signature call environment is nested.
   557         switch (env.next.tree.getTag()) {
   558             case TYPECAST:
   559                 JCTypeCast castTree = (JCTypeCast)env.next.tree;
   560                 restype = (TreeInfo.skipParens(castTree.expr) == env.tree) ?
   561                     castTree.clazz.type :
   562                     syms.objectType;
   563                 break;
   564             case EXEC:
   565                 JCTree.JCExpressionStatement execTree =
   566                         (JCTree.JCExpressionStatement)env.next.tree;
   567                 restype = (TreeInfo.skipParens(execTree.expr) == env.tree) ?
   568                     syms.voidType :
   569                     syms.objectType;
   570                 break;
   571             default:
   572                 restype = syms.objectType;
   573         }
   575         List<Type> paramtypes = Type.map(argtypes, new ImplicitArgType(spMethod, resolveContext.step));
   576         List<Type> exType = spMethod != null ?
   577             spMethod.getThrownTypes() :
   578             List.of(syms.throwableType); // make it throw all exceptions
   580         MethodType mtype = new MethodType(paramtypes,
   581                                           restype,
   582                                           exType,
   583                                           syms.methodClass);
   584         return mtype;
   585     }
   586     //where
   587         class ImplicitArgType extends DeferredAttr.DeferredTypeMap {
   589             public ImplicitArgType(Symbol msym, Resolve.MethodResolutionPhase phase) {
   590                 deferredAttr.super(AttrMode.SPECULATIVE, msym, phase);
   591             }
   593             public Type apply(Type t) {
   594                 t = types.erasure(super.apply(t));
   595                 if (t.tag == BOT)
   596                     // nulls type as the marker type Null (which has no instances)
   597                     // infer as java.lang.Void for now
   598                     t = types.boxedClass(syms.voidType).type;
   599                 return t;
   600             }
   601         }
   603     /**
   604      * Mapping that turns inference variables into undet vars
   605      * (used by inference context)
   606      */
   607     class FromTypeVarFun extends Mapping {
   609         boolean includeBounds;
   611         FromTypeVarFun(boolean includeBounds) {
   612             super("fromTypeVarFunWithBounds");
   613             this.includeBounds = includeBounds;
   614         }
   616         public Type apply(Type t) {
   617             if (t.tag == TYPEVAR) return new UndetVar((TypeVar)t, types, includeBounds);
   618             else return t.map(this);
   619         }
   620     };
   622     /**
   623      * An inference context keeps track of the set of variables that are free
   624      * in the current context. It provides utility methods for opening/closing
   625      * types to their corresponding free/closed forms. It also provide hooks for
   626      * attaching deferred post-inference action (see PendingCheck). Finally,
   627      * it can be used as an entry point for performing upper/lower bound inference
   628      * (see InferenceKind).
   629      */
   630     static class InferenceContext {
   632         /**
   633         * Single-method-interface for defining inference callbacks. Certain actions
   634         * (i.e. subtyping checks) might need to be redone after all inference variables
   635         * have been fixed.
   636         */
   637         interface FreeTypeListener {
   638             void typesInferred(InferenceContext inferenceContext);
   639         }
   641         /** list of inference vars as undet vars */
   642         List<Type> undetvars;
   644         /** list of inference vars in this context */
   645         List<Type> inferencevars;
   647         java.util.Map<FreeTypeListener, List<Type>> freeTypeListeners =
   648                 new java.util.HashMap<FreeTypeListener, List<Type>>();
   650         List<FreeTypeListener> freetypeListeners = List.nil();
   652         public InferenceContext(List<Type> inferencevars, Infer infer, boolean includeBounds) {
   653             this.undetvars = Type.map(inferencevars, infer.new FromTypeVarFun(includeBounds));
   654             this.inferencevars = inferencevars;
   655         }
   657         /**
   658          * returns the list of free variables (as type-variables) in this
   659          * inference context
   660          */
   661         List<Type> inferenceVars() {
   662             return inferencevars;
   663         }
   665         /**
   666          * returns the list of uninstantiated variables (as type-variables) in this
   667          * inference context (usually called after instantiate())
   668          */
   669         List<Type> restvars() {
   670             List<Type> undetvars = this.undetvars;
   671             ListBuffer<Type> restvars = ListBuffer.lb();
   672             for (Type t : instTypes()) {
   673                 UndetVar uv = (UndetVar)undetvars.head;
   674                 if (uv.qtype == t) {
   675                     restvars.append(t);
   676                 }
   677                 undetvars = undetvars.tail;
   678             }
   679             return restvars.toList();
   680         }
   682         /**
   683          * is this type free?
   684          */
   685         final boolean free(Type t) {
   686             return t.containsAny(inferencevars);
   687         }
   689         final boolean free(List<Type> ts) {
   690             for (Type t : ts) {
   691                 if (free(t)) return true;
   692             }
   693             return false;
   694         }
   696         /**
   697          * Returns a list of free variables in a given type
   698          */
   699         final List<Type> freeVarsIn(Type t) {
   700             ListBuffer<Type> buf = ListBuffer.lb();
   701             for (Type iv : inferenceVars()) {
   702                 if (t.contains(iv)) {
   703                     buf.add(iv);
   704                 }
   705             }
   706             return buf.toList();
   707         }
   709         final List<Type> freeVarsIn(List<Type> ts) {
   710             ListBuffer<Type> buf = ListBuffer.lb();
   711             for (Type t : ts) {
   712                 buf.appendList(freeVarsIn(t));
   713             }
   714             ListBuffer<Type> buf2 = ListBuffer.lb();
   715             for (Type t : buf) {
   716                 if (!buf2.contains(t)) {
   717                     buf2.add(t);
   718                 }
   719             }
   720             return buf2.toList();
   721         }
   723         /**
   724          * Replace all free variables in a given type with corresponding
   725          * undet vars (used ahead of subtyping/compatibility checks to allow propagation
   726          * of inference constraints).
   727          */
   728         final Type asFree(Type t, Types types) {
   729             return types.subst(t, inferencevars, undetvars);
   730         }
   732         final List<Type> asFree(List<Type> ts, Types types) {
   733             ListBuffer<Type> buf = ListBuffer.lb();
   734             for (Type t : ts) {
   735                 buf.append(asFree(t, types));
   736             }
   737             return buf.toList();
   738         }
   740         List<Type> instTypes() {
   741             ListBuffer<Type> buf = ListBuffer.lb();
   742             for (Type t : undetvars) {
   743                 UndetVar uv = (UndetVar)t;
   744                 buf.append(uv.inst != null ? uv.inst : uv.qtype);
   745             }
   746             return buf.toList();
   747         }
   749         /**
   750          * Replace all free variables in a given type with corresponding
   751          * instantiated types - if one or more free variable has not been
   752          * fully instantiated, it will still be available in the resulting type.
   753          */
   754         Type asInstType(Type t, Types types) {
   755             return types.subst(t, inferencevars, instTypes());
   756         }
   758         List<Type> asInstTypes(List<Type> ts, Types types) {
   759             ListBuffer<Type> buf = ListBuffer.lb();
   760             for (Type t : ts) {
   761                 buf.append(asInstType(t, types));
   762             }
   763             return buf.toList();
   764         }
   766         /**
   767          * Add custom hook for performing post-inference action
   768          */
   769         void addFreeTypeListener(List<Type> types, FreeTypeListener ftl) {
   770             freeTypeListeners.put(ftl, freeVarsIn(types));
   771         }
   773         /**
   774          * Mark the inference context as complete and trigger evaluation
   775          * of all deferred checks.
   776          */
   777         void notifyChange(Types types) {
   778             InferenceException thrownEx = null;
   779             for (Map.Entry<FreeTypeListener, List<Type>> entry :
   780                     new HashMap<FreeTypeListener, List<Type>>(freeTypeListeners).entrySet()) {
   781                 if (!Type.containsAny(entry.getValue(), restvars())) {
   782                     try {
   783                         entry.getKey().typesInferred(this);
   784                         freeTypeListeners.remove(entry.getKey());
   785                     } catch (InferenceException ex) {
   786                         if (thrownEx == null) {
   787                             thrownEx = ex;
   788                         }
   789                     }
   790                 }
   791             }
   792             //inference exception multiplexing - present any inference exception
   793             //thrown when processing listeners as a single one
   794             if (thrownEx != null) {
   795                 throw thrownEx;
   796             }
   797         }
   799         void solveAny(List<Type> varsToSolve, Types types, Infer infer) {
   800             boolean progress = false;
   801             for (Type t : varsToSolve) {
   802                 UndetVar uv = (UndetVar)asFree(t, types);
   803                 if (uv.inst == null) {
   804                     infer.minimizeInst(uv, Warner.noWarnings);
   805                     if (uv.inst != null) {
   806                         progress = true;
   807                     }
   808                 }
   809             }
   810             if (!progress) {
   811                 throw infer.inferenceException.setMessage("cyclic.inference", varsToSolve);
   812             }
   813         }
   814     }
   816     final InferenceContext emptyContext = new InferenceContext(List.<Type>nil(), this, false);
   817 }

mercurial