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

Wed, 19 May 2010 16:42:37 +0100

author
mcimadamore
date
Wed, 19 May 2010 16:42:37 +0100
changeset 562
2881b376a689
parent 547
04cf82179fa7
child 554
9d9f26857129
permissions
-rw-r--r--

6946618: sqe test fails: javac/generics/NewOnTypeParm in pit jdk7 b91 in all platforms.
Summary: Bad cast to ClassType in the new diamond implementation fails if the target type of the instance creation expression is a type-variable
Reviewed-by: jjg

     1 /*
     2  * Copyright 1999-2009 Sun Microsystems, Inc.  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.  Sun designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
    23  * have any questions.
    24  */
    26 package com.sun.tools.javac.comp;
    28 import com.sun.tools.javac.util.*;
    29 import com.sun.tools.javac.util.List;
    30 import com.sun.tools.javac.code.*;
    31 import com.sun.tools.javac.code.Type.*;
    32 import com.sun.tools.javac.code.Type.ForAll.ConstraintKind;
    33 import com.sun.tools.javac.code.Symbol.*;
    34 import com.sun.tools.javac.util.JCDiagnostic;
    36 import static com.sun.tools.javac.code.TypeTags.*;
    38 /** Helper class for type parameter inference, used by the attribution phase.
    39  *
    40  *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
    41  *  you write code that depends on this, you do so at your own risk.
    42  *  This code and its internal interfaces are subject to change or
    43  *  deletion without notice.</b>
    44  */
    45 public class Infer {
    46     protected static final Context.Key<Infer> inferKey =
    47         new Context.Key<Infer>();
    49     /** A value for prototypes that admit any type, including polymorphic ones. */
    50     public static final Type anyPoly = new Type(NONE, null);
    52     Symtab syms;
    53     Types types;
    54     Check chk;
    55     Resolve rs;
    56     JCDiagnostic.Factory diags;
    58     public static Infer instance(Context context) {
    59         Infer instance = context.get(inferKey);
    60         if (instance == null)
    61             instance = new Infer(context);
    62         return instance;
    63     }
    65     protected Infer(Context context) {
    66         context.put(inferKey, this);
    67         syms = Symtab.instance(context);
    68         types = Types.instance(context);
    69         rs = Resolve.instance(context);
    70         chk = Check.instance(context);
    71         diags = JCDiagnostic.Factory.instance(context);
    72         ambiguousNoInstanceException =
    73             new NoInstanceException(true, diags);
    74         unambiguousNoInstanceException =
    75             new NoInstanceException(false, diags);
    76         invalidInstanceException =
    77             new InvalidInstanceException(diags);
    79     }
    81     public static class InferenceException extends RuntimeException {
    82         private static final long serialVersionUID = 0;
    84         JCDiagnostic diagnostic;
    85         JCDiagnostic.Factory diags;
    87         InferenceException(JCDiagnostic.Factory diags) {
    88             this.diagnostic = null;
    89             this.diags = diags;
    90         }
    92         InferenceException setMessage(String key, Object... args) {
    93             this.diagnostic = diags.fragment(key, args);
    94             return this;
    95         }
    97         public JCDiagnostic getDiagnostic() {
    98              return diagnostic;
    99          }
   100     }
   102     public static class NoInstanceException extends InferenceException {
   103         private static final long serialVersionUID = 1;
   105         boolean isAmbiguous; // exist several incomparable best instances?
   107         NoInstanceException(boolean isAmbiguous, JCDiagnostic.Factory diags) {
   108             super(diags);
   109             this.isAmbiguous = isAmbiguous;
   110         }
   111     }
   113     public static class InvalidInstanceException extends InferenceException {
   114         private static final long serialVersionUID = 2;
   116         InvalidInstanceException(JCDiagnostic.Factory diags) {
   117             super(diags);
   118         }
   119     }
   121     private final NoInstanceException ambiguousNoInstanceException;
   122     private final NoInstanceException unambiguousNoInstanceException;
   123     private final InvalidInstanceException invalidInstanceException;
   125 /***************************************************************************
   126  * Auxiliary type values and classes
   127  ***************************************************************************/
   129     /** A mapping that turns type variables into undetermined type variables.
   130      */
   131     Mapping fromTypeVarFun = new Mapping("fromTypeVarFun") {
   132             public Type apply(Type t) {
   133                 if (t.tag == TYPEVAR) return new UndetVar(t);
   134                 else return t.map(this);
   135             }
   136         };
   138     /** A mapping that returns its type argument with every UndetVar replaced
   139      *  by its `inst' field. Throws a NoInstanceException
   140      *  if this not possible because an `inst' field is null.
   141      */
   142     Mapping getInstFun = new Mapping("getInstFun") {
   143             public Type apply(Type t) {
   144                 switch (t.tag) {
   145                 case UNKNOWN:
   146                     throw ambiguousNoInstanceException
   147                         .setMessage("undetermined.type");
   148                 case UNDETVAR:
   149                     UndetVar that = (UndetVar) t;
   150                     if (that.inst == null)
   151                         throw ambiguousNoInstanceException
   152                             .setMessage("type.variable.has.undetermined.type",
   153                                         that.qtype);
   154                     return apply(that.inst);
   155                 default:
   156                     return t.map(this);
   157                 }
   158             }
   159         };
   161 /***************************************************************************
   162  * Mini/Maximization of UndetVars
   163  ***************************************************************************/
   165     /** Instantiate undetermined type variable to its minimal upper bound.
   166      *  Throw a NoInstanceException if this not possible.
   167      */
   168     void maximizeInst(UndetVar that, Warner warn) throws NoInstanceException {
   169         if (that.inst == null) {
   170             if (that.hibounds.isEmpty())
   171                 that.inst = syms.objectType;
   172             else if (that.hibounds.tail.isEmpty())
   173                 that.inst = that.hibounds.head;
   174             else
   175                 that.inst = types.glb(that.hibounds);
   176         }
   177         if (that.inst == null ||
   178             that.inst.isErroneous())
   179             throw ambiguousNoInstanceException
   180                 .setMessage("no.unique.maximal.instance.exists",
   181                             that.qtype, that.hibounds);
   182     }
   183     //where
   184         private boolean isSubClass(Type t, final List<Type> ts) {
   185             t = t.baseType();
   186             if (t.tag == TYPEVAR) {
   187                 List<Type> bounds = types.getBounds((TypeVar)t);
   188                 for (Type s : ts) {
   189                     if (!types.isSameType(t, s.baseType())) {
   190                         for (Type bound : bounds) {
   191                             if (!isSubClass(bound, List.of(s.baseType())))
   192                                 return false;
   193                         }
   194                     }
   195                 }
   196             } else {
   197                 for (Type s : ts) {
   198                     if (!t.tsym.isSubClass(s.baseType().tsym, types))
   199                         return false;
   200                 }
   201             }
   202             return true;
   203         }
   205     /** Instantiate undetermined type variable to the lub of all its lower bounds.
   206      *  Throw a NoInstanceException if this not possible.
   207      */
   208     void minimizeInst(UndetVar that, Warner warn) throws NoInstanceException {
   209         if (that.inst == null) {
   210             if (that.lobounds.isEmpty())
   211                 that.inst = syms.botType;
   212             else if (that.lobounds.tail.isEmpty())
   213                 that.inst = that.lobounds.head.isPrimitive() ? syms.errType : that.lobounds.head;
   214             else {
   215                 that.inst = types.lub(that.lobounds);
   216             }
   217             if (that.inst == null || that.inst.tag == ERROR)
   218                     throw ambiguousNoInstanceException
   219                         .setMessage("no.unique.minimal.instance.exists",
   220                                     that.qtype, that.lobounds);
   221             // VGJ: sort of inlined maximizeInst() below.  Adding
   222             // bounds can cause lobounds that are above hibounds.
   223             if (that.hibounds.isEmpty())
   224                 return;
   225             Type hb = null;
   226             if (that.hibounds.tail.isEmpty())
   227                 hb = that.hibounds.head;
   228             else for (List<Type> bs = that.hibounds;
   229                       bs.nonEmpty() && hb == null;
   230                       bs = bs.tail) {
   231                 if (isSubClass(bs.head, that.hibounds))
   232                     hb = types.fromUnknownFun.apply(bs.head);
   233             }
   234             if (hb == null ||
   235                 !types.isSubtypeUnchecked(hb, that.hibounds, warn) ||
   236                 !types.isSubtypeUnchecked(that.inst, hb, warn))
   237                 throw ambiguousNoInstanceException;
   238         }
   239     }
   241 /***************************************************************************
   242  * Exported Methods
   243  ***************************************************************************/
   245     /** Try to instantiate expression type `that' to given type `to'.
   246      *  If a maximal instantiation exists which makes this type
   247      *  a subtype of type `to', return the instantiated type.
   248      *  If no instantiation exists, or if several incomparable
   249      *  best instantiations exist throw a NoInstanceException.
   250      */
   251     public Type instantiateExpr(ForAll that,
   252                                 Type to,
   253                                 Warner warn) throws InferenceException {
   254         List<Type> undetvars = Type.map(that.tvars, fromTypeVarFun);
   255         for (List<Type> l = undetvars; l.nonEmpty(); l = l.tail) {
   256             UndetVar uv = (UndetVar) l.head;
   257             TypeVar tv = (TypeVar)uv.qtype;
   258             ListBuffer<Type> hibounds = new ListBuffer<Type>();
   259             for (Type t : that.getConstraints(tv, ConstraintKind.EXTENDS).prependList(types.getBounds(tv))) {
   260                 if (!t.containsSome(that.tvars) && t.tag != BOT) {
   261                     hibounds.append(t);
   262                 }
   263             }
   264             List<Type> inst = that.getConstraints(tv, ConstraintKind.EQUAL);
   265             if (inst.nonEmpty() && inst.head.tag != BOT) {
   266                 uv.inst = inst.head;
   267             }
   268             uv.hibounds = hibounds.toList();
   269         }
   270         Type qtype1 = types.subst(that.qtype, that.tvars, undetvars);
   271         if (!types.isSubtype(qtype1, to)) {
   272             throw unambiguousNoInstanceException
   273                 .setMessage("no.conforming.instance.exists",
   274                             that.tvars, that.qtype, to);
   275         }
   276         for (List<Type> l = undetvars; l.nonEmpty(); l = l.tail)
   277             maximizeInst((UndetVar) l.head, warn);
   278         // System.out.println(" = " + qtype1.map(getInstFun));//DEBUG
   280         // check bounds
   281         List<Type> targs = Type.map(undetvars, getInstFun);
   282         targs = types.subst(targs, that.tvars, targs);
   283         checkWithinBounds(that.tvars, targs, warn);
   284         return chk.checkType(warn.pos(), that.inst(targs, types), to);
   285     }
   287     /** Instantiate method type `mt' by finding instantiations of
   288      *  `tvars' so that method can be applied to `argtypes'.
   289      */
   290     public Type instantiateMethod(final Env<AttrContext> env,
   291                                   List<Type> tvars,
   292                                   MethodType mt,
   293                                   final List<Type> argtypes,
   294                                   final boolean allowBoxing,
   295                                   final boolean useVarargs,
   296                                   final Warner warn) throws InferenceException {
   297         //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG
   298         List<Type> undetvars = Type.map(tvars, fromTypeVarFun);
   299         List<Type> formals = mt.argtypes;
   300         //need to capture exactly once - otherwise subsequent
   301         //applicability checks might fail
   302         final List<Type> capturedArgs = types.capture(argtypes);
   303         List<Type> actuals = capturedArgs;
   304         List<Type> actualsNoCapture = argtypes;
   305         // instantiate all polymorphic argument types and
   306         // set up lower bounds constraints for undetvars
   307         Type varargsFormal = useVarargs ? formals.last() : null;
   308         while (actuals.nonEmpty() && formals.head != varargsFormal) {
   309             Type formal = formals.head;
   310             Type actual = actuals.head.baseType();
   311             Type actualNoCapture = actualsNoCapture.head.baseType();
   312             if (actual.tag == FORALL)
   313                 actual = instantiateArg((ForAll)actual, formal, tvars, warn);
   314             Type undetFormal = types.subst(formal, tvars, undetvars);
   315             boolean works = allowBoxing
   316                 ? types.isConvertible(actual, undetFormal, warn)
   317                 : types.isSubtypeUnchecked(actual, undetFormal, warn);
   318             if (!works) {
   319                 throw unambiguousNoInstanceException
   320                     .setMessage("no.conforming.assignment.exists",
   321                                 tvars, actualNoCapture, formal);
   322             }
   323             formals = formals.tail;
   324             actuals = actuals.tail;
   325             actualsNoCapture = actualsNoCapture.tail;
   326         }
   327         if (formals.head != varargsFormal || // not enough args
   328             !useVarargs && actuals.nonEmpty()) { // too many args
   329             // argument lists differ in length
   330             throw unambiguousNoInstanceException
   331                 .setMessage("arg.length.mismatch");
   332         }
   334         // for varargs arguments as well
   335         if (useVarargs) {
   336             Type elemType = types.elemtype(varargsFormal);
   337             Type elemUndet = types.subst(elemType, tvars, undetvars);
   338             while (actuals.nonEmpty()) {
   339                 Type actual = actuals.head.baseType();
   340                 Type actualNoCapture = actualsNoCapture.head.baseType();
   341                 if (actual.tag == FORALL)
   342                     actual = instantiateArg((ForAll)actual, elemType, tvars, warn);
   343                 boolean works = types.isConvertible(actual, elemUndet, warn);
   344                 if (!works) {
   345                     throw unambiguousNoInstanceException
   346                         .setMessage("no.conforming.assignment.exists",
   347                                     tvars, actualNoCapture, elemType);
   348                 }
   349                 actuals = actuals.tail;
   350                 actualsNoCapture = actualsNoCapture.tail;
   351             }
   352         }
   354         // minimize as yet undetermined type variables
   355         for (Type t : undetvars)
   356             minimizeInst((UndetVar) t, warn);
   358         /** Type variables instantiated to bottom */
   359         ListBuffer<Type> restvars = new ListBuffer<Type>();
   361         /** Undet vars instantiated to bottom */
   362         final ListBuffer<Type> restundet = new ListBuffer<Type>();
   364         /** Instantiated types or TypeVars if under-constrained */
   365         ListBuffer<Type> insttypes = new ListBuffer<Type>();
   367         /** Instantiated types or UndetVars if under-constrained */
   368         ListBuffer<Type> undettypes = new ListBuffer<Type>();
   370         for (Type t : undetvars) {
   371             UndetVar uv = (UndetVar)t;
   372             if (uv.inst.tag == BOT) {
   373                 restvars.append(uv.qtype);
   374                 restundet.append(uv);
   375                 insttypes.append(uv.qtype);
   376                 undettypes.append(uv);
   377                 uv.inst = null;
   378             } else {
   379                 insttypes.append(uv.inst);
   380                 undettypes.append(uv.inst);
   381             }
   382         }
   383         checkWithinBounds(tvars, undettypes.toList(), warn);
   385         mt = (MethodType)types.subst(mt, tvars, insttypes.toList());
   387         if (!restvars.isEmpty()) {
   388             // if there are uninstantiated variables,
   389             // quantify result type with them
   390             final List<Type> inferredTypes = insttypes.toList();
   391             final List<Type> all_tvars = tvars; //this is the wrong tvars
   392             final MethodType mt2 = new MethodType(mt.argtypes, null, mt.thrown, syms.methodClass);
   393             mt2.restype = new ForAll(restvars.toList(), mt.restype) {
   394                 @Override
   395                 public List<Type> getConstraints(TypeVar tv, ConstraintKind ck) {
   396                     for (Type t : restundet.toList()) {
   397                         UndetVar uv = (UndetVar)t;
   398                         if (uv.qtype == tv) {
   399                             switch (ck) {
   400                                 case EXTENDS: return uv.hibounds;
   401                                 case SUPER: return uv.lobounds;
   402                                 case EQUAL: return uv.inst != null ? List.of(uv.inst) : List.<Type>nil();
   403                             }
   404                         }
   405                     }
   406                     return List.nil();
   407                 }
   409                 @Override
   410                 public Type inst(List<Type> inferred, Types types) throws NoInstanceException {
   411                     List<Type> formals = types.subst(mt2.argtypes, tvars, inferred);
   412                     if (!rs.argumentsAcceptable(capturedArgs, formals,
   413                            allowBoxing, useVarargs, warn)) {
   414                       // inferred method is not applicable
   415                       throw invalidInstanceException.setMessage("inferred.do.not.conform.to.params", formals, argtypes);
   416                     }
   417                     // check that inferred bounds conform to their bounds
   418                     checkWithinBounds(all_tvars,
   419                            types.subst(inferredTypes, tvars, inferred), warn);
   420                     if (useVarargs) {
   421                         chk.checkVararg(env.tree.pos(), formals);
   422                     }
   423                     return super.inst(inferred, types);
   424             }};
   425             return mt2;
   426         }
   427         else if (!rs.argumentsAcceptable(capturedArgs, mt.getParameterTypes(), allowBoxing, useVarargs, warn)) {
   428             // inferred method is not applicable
   429             throw invalidInstanceException.setMessage("inferred.do.not.conform.to.params", mt.getParameterTypes(), argtypes);
   430         }
   431         else {
   432             // return instantiated version of method type
   433             return mt;
   434         }
   435     }
   436     //where
   438         /** Try to instantiate argument type `that' to given type `to'.
   439          *  If this fails, try to insantiate `that' to `to' where
   440          *  every occurrence of a type variable in `tvars' is replaced
   441          *  by an unknown type.
   442          */
   443         private Type instantiateArg(ForAll that,
   444                                     Type to,
   445                                     List<Type> tvars,
   446                                     Warner warn) throws InferenceException {
   447             List<Type> targs;
   448             try {
   449                 return instantiateExpr(that, to, warn);
   450             } catch (NoInstanceException ex) {
   451                 Type to1 = to;
   452                 for (List<Type> l = tvars; l.nonEmpty(); l = l.tail)
   453                     to1 = types.subst(to1, List.of(l.head), List.of(syms.unknownType));
   454                 return instantiateExpr(that, to1, warn);
   455             }
   456         }
   458     /** check that type parameters are within their bounds.
   459      */
   460     private void checkWithinBounds(List<Type> tvars,
   461                                    List<Type> arguments,
   462                                    Warner warn)
   463         throws InvalidInstanceException {
   464         for (List<Type> tvs = tvars, args = arguments;
   465              tvs.nonEmpty();
   466              tvs = tvs.tail, args = args.tail) {
   467             if (args.head instanceof UndetVar) continue;
   468             List<Type> bounds = types.subst(types.getBounds((TypeVar)tvs.head), tvars, arguments);
   469             if (!types.isSubtypeUnchecked(args.head, bounds, warn))
   470                 throw invalidInstanceException
   471                     .setMessage("inferred.do.not.conform.to.bounds",
   472                                 args.head, bounds);
   473         }
   474     }
   475 }

mercurial