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

Fri, 05 Oct 2012 14:35:24 +0100

author
mcimadamore
date
Fri, 05 Oct 2012 14:35:24 +0100
changeset 1348
573ceb23beeb
parent 1347
1408af4cd8b0
child 1357
c75be5bc5283
permissions
-rw-r--r--

7177385: Add attribution support for lambda expressions
Summary: Add support for function descriptor lookup, functional interface inference and lambda expression type-checking
Reviewed-by: jjg, dlsmith

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

mercurial