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

Tue, 11 Aug 2009 01:13:14 +0100

author
mcimadamore
date
Tue, 11 Aug 2009 01:13:14 +0100
changeset 359
8227961c64d3
parent 299
22872b24d38c
child 396
dda7e13f09fb
permissions
-rw-r--r--

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

mercurial