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

Fri, 26 Jun 2009 18:51:39 -0700

author
jjg
date
Fri, 26 Jun 2009 18:51:39 -0700
changeset 308
03944ee4fac4
parent 133
c0372d1097c0
child 344
6d0add6ad778
permissions
-rw-r--r--

6843077: JSR 308: Annotations on types
Reviewed-by: jjg, mcimadamore, darcy
Contributed-by: mernst@cs.washington.edu, mali@csail.mit.edu, mpapi@csail.mit.edu

     1 /*
     2  * Copyright 1999-2008 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 java.util.*;
    30 import javax.lang.model.element.ElementKind;
    32 import com.sun.tools.javac.code.*;
    33 import com.sun.tools.javac.code.Symbol.*;
    34 import com.sun.tools.javac.tree.*;
    35 import com.sun.tools.javac.tree.JCTree.*;
    36 import com.sun.tools.javac.util.*;
    37 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    38 import com.sun.tools.javac.util.List;
    40 import static com.sun.tools.javac.code.Flags.*;
    41 import static com.sun.tools.javac.code.Kinds.*;
    42 import static com.sun.tools.javac.code.TypeTags.*;
    44 /** This pass translates Generic Java to conventional Java.
    45  *
    46  *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
    47  *  you write code that depends on this, you do so at your own risk.
    48  *  This code and its internal interfaces are subject to change or
    49  *  deletion without notice.</b>
    50  */
    51 public class TransTypes extends TreeTranslator {
    52     /** The context key for the TransTypes phase. */
    53     protected static final Context.Key<TransTypes> transTypesKey =
    54         new Context.Key<TransTypes>();
    56     /** Get the instance for this context. */
    57     public static TransTypes instance(Context context) {
    58         TransTypes instance = context.get(transTypesKey);
    59         if (instance == null)
    60             instance = new TransTypes(context);
    61         return instance;
    62     }
    64     private boolean debugJSR308;
    66     private Names names;
    67     private Log log;
    68     private Symtab syms;
    69     private TreeMaker make;
    70     private Enter enter;
    71     private boolean allowEnums;
    72     private Types types;
    73     private final Resolve resolve;
    75     /**
    76      * Flag to indicate whether or not to generate bridge methods.
    77      * For pre-Tiger source there is no need for bridge methods, so it
    78      * can be skipped to get better performance for -source 1.4 etc.
    79      */
    80     private final boolean addBridges;
    82     protected TransTypes(Context context) {
    83         context.put(transTypesKey, this);
    84         names = Names.instance(context);
    85         log = Log.instance(context);
    86         syms = Symtab.instance(context);
    87         enter = Enter.instance(context);
    88         overridden = new HashMap<MethodSymbol,MethodSymbol>();
    89         Source source = Source.instance(context);
    90         allowEnums = source.allowEnums();
    91         addBridges = source.addBridges();
    92         types = Types.instance(context);
    93         make = TreeMaker.instance(context);
    94         resolve = Resolve.instance(context);
    95         debugJSR308 = Options.instance(context).get("TA:trans") != null;
    96     }
    98     /** A hashtable mapping bridge methods to the methods they override after
    99      *  type erasure.
   100      */
   101     Map<MethodSymbol,MethodSymbol> overridden;
   103     /** Construct an attributed tree for a cast of expression to target type,
   104      *  unless it already has precisely that type.
   105      *  @param tree    The expression tree.
   106      *  @param target  The target type.
   107      */
   108     JCExpression cast(JCExpression tree, Type target) {
   109         int oldpos = make.pos;
   110         make.at(tree.pos);
   111         if (!types.isSameType(tree.type, target)) {
   112             if (!resolve.isAccessible(env, target.tsym))
   113                 resolve.logAccessError(env, tree, target);
   114             tree = make.TypeCast(make.Type(target), tree).setType(target);
   115         }
   116         make.pos = oldpos;
   117         return tree;
   118     }
   120     /** Construct an attributed tree to coerce an expression to some erased
   121      *  target type, unless the expression is already assignable to that type.
   122      *  If target type is a constant type, use its base type instead.
   123      *  @param tree    The expression tree.
   124      *  @param target  The target type.
   125      */
   126     JCExpression coerce(JCExpression tree, Type target) {
   127         Type btarget = target.baseType();
   128         if (tree.type.isPrimitive() == target.isPrimitive()) {
   129             return types.isAssignable(tree.type, btarget, Warner.noWarnings)
   130                 ? tree
   131                 : cast(tree, btarget);
   132         }
   133         return tree;
   134     }
   136     /** Given an erased reference type, assume this type as the tree's type.
   137      *  Then, coerce to some given target type unless target type is null.
   138      *  This operation is used in situations like the following:
   139      *
   140      *  class Cell<A> { A value; }
   141      *  ...
   142      *  Cell<Integer> cell;
   143      *  Integer x = cell.value;
   144      *
   145      *  Since the erasure of Cell.value is Object, but the type
   146      *  of cell.value in the assignment is Integer, we need to
   147      *  adjust the original type of cell.value to Object, and insert
   148      *  a cast to Integer. That is, the last assignment becomes:
   149      *
   150      *  Integer x = (Integer)cell.value;
   151      *
   152      *  @param tree       The expression tree whose type might need adjustment.
   153      *  @param erasedType The expression's type after erasure.
   154      *  @param target     The target type, which is usually the erasure of the
   155      *                    expression's original type.
   156      */
   157     JCExpression retype(JCExpression tree, Type erasedType, Type target) {
   158 //      System.err.println("retype " + tree + " to " + erasedType);//DEBUG
   159         if (erasedType.tag > lastBaseTag) {
   160             if (target != null && target.isPrimitive())
   161                 target = erasure(tree.type);
   162             tree.type = erasedType;
   163             if (target != null) return coerce(tree, target);
   164         }
   165         return tree;
   166     }
   168     /** Translate method argument list, casting each argument
   169      *  to its corresponding type in a list of target types.
   170      *  @param _args            The method argument list.
   171      *  @param parameters       The list of target types.
   172      *  @param varargsElement   The erasure of the varargs element type,
   173      *  or null if translating a non-varargs invocation
   174      */
   175     <T extends JCTree> List<T> translateArgs(List<T> _args,
   176                                            List<Type> parameters,
   177                                            Type varargsElement) {
   178         if (parameters.isEmpty()) return _args;
   179         List<T> args = _args;
   180         while (parameters.tail.nonEmpty()) {
   181             args.head = translate(args.head, parameters.head);
   182             args = args.tail;
   183             parameters = parameters.tail;
   184         }
   185         Type parameter = parameters.head;
   186         assert varargsElement != null || args.length() == 1;
   187         if (varargsElement != null) {
   188             while (args.nonEmpty()) {
   189                 args.head = translate(args.head, varargsElement);
   190                 args = args.tail;
   191             }
   192         } else {
   193             args.head = translate(args.head, parameter);
   194         }
   195         return _args;
   196     }
   198     /** Add a bridge definition and enter corresponding method symbol in
   199      *  local scope of origin.
   200      *
   201      *  @param pos     The source code position to be used for the definition.
   202      *  @param meth    The method for which a bridge needs to be added
   203      *  @param impl    That method's implementation (possibly the method itself)
   204      *  @param origin  The class to which the bridge will be added
   205      *  @param hypothetical
   206      *                 True if the bridge method is not strictly necessary in the
   207      *                 binary, but is represented in the symbol table to detect
   208      *                 erasure clashes.
   209      *  @param bridges The list buffer to which the bridge will be added
   210      */
   211     void addBridge(DiagnosticPosition pos,
   212                    MethodSymbol meth,
   213                    MethodSymbol impl,
   214                    ClassSymbol origin,
   215                    boolean hypothetical,
   216                    ListBuffer<JCTree> bridges) {
   217         make.at(pos);
   218         Type origType = types.memberType(origin.type, meth);
   219         Type origErasure = erasure(origType);
   221         // Create a bridge method symbol and a bridge definition without a body.
   222         Type bridgeType = meth.erasure(types);
   223         long flags = impl.flags() & AccessFlags | SYNTHETIC | BRIDGE;
   224         if (hypothetical) flags |= HYPOTHETICAL;
   225         MethodSymbol bridge = new MethodSymbol(flags,
   226                                                meth.name,
   227                                                bridgeType,
   228                                                origin);
   229         if (!hypothetical) {
   230             JCMethodDecl md = make.MethodDef(bridge, null);
   232             // The bridge calls this.impl(..), if we have an implementation
   233             // in the current class, super.impl(...) otherwise.
   234             JCExpression receiver = (impl.owner == origin)
   235                 ? make.This(origin.erasure(types))
   236                 : make.Super(types.supertype(origin.type).tsym.erasure(types), origin);
   238             // The type returned from the original method.
   239             Type calltype = erasure(impl.type.getReturnType());
   241             // Construct a call of  this.impl(params), or super.impl(params),
   242             // casting params and possibly results as needed.
   243             JCExpression call =
   244                 make.Apply(
   245                            null,
   246                            make.Select(receiver, impl).setType(calltype),
   247                            translateArgs(make.Idents(md.params), origErasure.getParameterTypes(), null))
   248                 .setType(calltype);
   249             JCStatement stat = (origErasure.getReturnType().tag == VOID)
   250                 ? make.Exec(call)
   251                 : make.Return(coerce(call, bridgeType.getReturnType()));
   252             md.body = make.Block(0, List.of(stat));
   254             // Add bridge to `bridges' buffer
   255             bridges.append(md);
   256         }
   258         // Add bridge to scope of enclosing class and `overridden' table.
   259         origin.members().enter(bridge);
   260         overridden.put(bridge, meth);
   261     }
   263     /** Add bridge if given symbol is a non-private, non-static member
   264      *  of the given class, which is either defined in the class or non-final
   265      *  inherited, and one of the two following conditions holds:
   266      *  1. The method's type changes in the given class, as compared to the
   267      *     class where the symbol was defined, (in this case
   268      *     we have extended a parameterized class with non-trivial parameters).
   269      *  2. The method has an implementation with a different erased return type.
   270      *     (in this case we have used co-variant returns).
   271      *  If a bridge already exists in some other class, no new bridge is added.
   272      *  Instead, it is checked that the bridge symbol overrides the method symbol.
   273      *  (Spec ???).
   274      *  todo: what about bridges for privates???
   275      *
   276      *  @param pos     The source code position to be used for the definition.
   277      *  @param sym     The symbol for which a bridge might have to be added.
   278      *  @param origin  The class in which the bridge would go.
   279      *  @param bridges The list buffer to which the bridge would be added.
   280      */
   281     void addBridgeIfNeeded(DiagnosticPosition pos,
   282                            Symbol sym,
   283                            ClassSymbol origin,
   284                            ListBuffer<JCTree> bridges) {
   285         if (sym.kind == MTH &&
   286             sym.name != names.init &&
   287             (sym.flags() & (PRIVATE | SYNTHETIC | STATIC)) == 0 &&
   288             sym.isMemberOf(origin, types))
   289         {
   290             MethodSymbol meth = (MethodSymbol)sym;
   291             MethodSymbol bridge = meth.binaryImplementation(origin, types);
   292             MethodSymbol impl = meth.implementation(origin, types, true);
   293             if (bridge == null ||
   294                 bridge == meth ||
   295                 (impl != null && !bridge.owner.isSubClass(impl.owner, types))) {
   296                 // No bridge was added yet.
   297                 if (impl != null && isBridgeNeeded(meth, impl, origin.type)) {
   298                     addBridge(pos, meth, impl, origin, bridge==impl, bridges);
   299                 } else if (impl == meth
   300                            && impl.owner != origin
   301                            && (impl.flags() & FINAL) == 0
   302                            && (meth.flags() & (ABSTRACT|PUBLIC)) == PUBLIC
   303                            && (origin.flags() & PUBLIC) > (impl.owner.flags() & PUBLIC)) {
   304                     // this is to work around a horrible but permanent
   305                     // reflection design error.
   306                     addBridge(pos, meth, impl, origin, false, bridges);
   307                 }
   308             } else if ((bridge.flags() & SYNTHETIC) != 0) {
   309                 MethodSymbol other = overridden.get(bridge);
   310                 if (other != null && other != meth) {
   311                     if (impl == null || !impl.overrides(other, origin, types, true)) {
   312                         // Bridge for other symbol pair was added
   313                         log.error(pos, "name.clash.same.erasure.no.override",
   314                                   other, other.location(origin.type, types),
   315                                   meth,  meth.location(origin.type, types));
   316                     }
   317                 }
   318             } else if (!bridge.overrides(meth, origin, types, true)) {
   319                 // Accidental binary override without source override.
   320                 if (bridge.owner == origin ||
   321                     types.asSuper(bridge.owner.type, meth.owner) == null)
   322                     // Don't diagnose the problem if it would already
   323                     // have been reported in the superclass
   324                     log.error(pos, "name.clash.same.erasure.no.override",
   325                               bridge, bridge.location(origin.type, types),
   326                               meth,  meth.location(origin.type, types));
   327             }
   328         }
   329     }
   330     // where
   331         /**
   332          * @param method The symbol for which a bridge might have to be added
   333          * @param impl The implementation of method
   334          * @param dest The type in which the bridge would go
   335          */
   336         private boolean isBridgeNeeded(MethodSymbol method,
   337                                        MethodSymbol impl,
   338                                        Type dest) {
   339             if (impl != method) {
   340                 // If either method or impl have different erasures as
   341                 // members of dest, a bridge is needed.
   342                 Type method_erasure = method.erasure(types);
   343                 if (!isSameMemberWhenErased(dest, method, method_erasure))
   344                     return true;
   345                 Type impl_erasure = impl.erasure(types);
   346                 if (!isSameMemberWhenErased(dest, impl, impl_erasure))
   347                     return true;
   349                 // If the erasure of the return type is different, a
   350                 // bridge is needed.
   351                 return !types.isSameType(impl_erasure.getReturnType(),
   352                                          method_erasure.getReturnType());
   353             } else {
   354                // method and impl are the same...
   355                 if ((method.flags() & ABSTRACT) != 0) {
   356                     // ...and abstract so a bridge is not needed.
   357                     // Concrete subclasses will bridge as needed.
   358                     return false;
   359                 }
   361                 // The erasure of the return type is always the same
   362                 // for the same symbol.  Reducing the three tests in
   363                 // the other branch to just one:
   364                 return !isSameMemberWhenErased(dest, method, method.erasure(types));
   365             }
   366         }
   367         /**
   368          * Lookup the method as a member of the type.  Compare the
   369          * erasures.
   370          * @param type the class where to look for the method
   371          * @param method the method to look for in class
   372          * @param erasure the erasure of method
   373          */
   374         private boolean isSameMemberWhenErased(Type type,
   375                                                MethodSymbol method,
   376                                                Type erasure) {
   377             return types.isSameType(erasure(types.memberType(type, method)),
   378                                     erasure);
   379         }
   381     void addBridges(DiagnosticPosition pos,
   382                     TypeSymbol i,
   383                     ClassSymbol origin,
   384                     ListBuffer<JCTree> bridges) {
   385         for (Scope.Entry e = i.members().elems; e != null; e = e.sibling)
   386             addBridgeIfNeeded(pos, e.sym, origin, bridges);
   387         for (List<Type> l = types.interfaces(i.type); l.nonEmpty(); l = l.tail)
   388             addBridges(pos, l.head.tsym, origin, bridges);
   389     }
   391     /** Add all necessary bridges to some class appending them to list buffer.
   392      *  @param pos     The source code position to be used for the bridges.
   393      *  @param origin  The class in which the bridges go.
   394      *  @param bridges The list buffer to which the bridges are added.
   395      */
   396     void addBridges(DiagnosticPosition pos, ClassSymbol origin, ListBuffer<JCTree> bridges) {
   397         Type st = types.supertype(origin.type);
   398         while (st.tag == CLASS) {
   399 //          if (isSpecialization(st))
   400             addBridges(pos, st.tsym, origin, bridges);
   401             st = types.supertype(st);
   402         }
   403         for (List<Type> l = types.interfaces(origin.type); l.nonEmpty(); l = l.tail)
   404 //          if (isSpecialization(l.head))
   405             addBridges(pos, l.head.tsym, origin, bridges);
   406     }
   408 /* ************************************************************************
   409  * Visitor methods
   410  *************************************************************************/
   412     /** Visitor argument: proto-type.
   413      */
   414     private Type pt;
   416     /** Visitor method: perform a type translation on tree.
   417      */
   418     public <T extends JCTree> T translate(T tree, Type pt) {
   419         Type prevPt = this.pt;
   420         try {
   421             this.pt = pt;
   422             return translate(tree);
   423         } finally {
   424             this.pt = prevPt;
   425         }
   426     }
   428     /** Visitor method: perform a type translation on list of trees.
   429      */
   430     public <T extends JCTree> List<T> translate(List<T> trees, Type pt) {
   431         Type prevPt = this.pt;
   432         List<T> res;
   433         try {
   434             this.pt = pt;
   435             res = translate(trees);
   436         } finally {
   437             this.pt = prevPt;
   438         }
   439         return res;
   440     }
   442     public void visitClassDef(JCClassDecl tree) {
   443         new TypeAnnotationPositions().scan(tree);
   444         new TypeAnnotationLift().scan(tree);
   445         translateClass(tree.sym);
   446         result = tree;
   447     }
   449     JCMethodDecl currentMethod = null;
   450     public void visitMethodDef(JCMethodDecl tree) {
   451         tree.sym.typeAnnotations = tree.sym.typeAnnotations;
   452         JCMethodDecl previousMethod = currentMethod;
   453         try {
   454             currentMethod = tree;
   455             tree.restype = translate(tree.restype, null);
   456             tree.typarams = List.nil();
   457             tree.params = translateVarDefs(tree.params);
   458             tree.thrown = translate(tree.thrown, null);
   459             tree.body = translate(tree.body, tree.sym.erasure(types).getReturnType());
   460             tree.type = erasure(tree.type);
   461             result = tree;
   462         } finally {
   463             currentMethod = previousMethod;
   464         }
   466         // Check that we do not introduce a name clash by erasing types.
   467         for (Scope.Entry e = tree.sym.owner.members().lookup(tree.name);
   468              e.sym != null;
   469              e = e.next()) {
   470             if (e.sym != tree.sym &&
   471                 types.isSameType(erasure(e.sym.type), tree.type)) {
   472                 log.error(tree.pos(),
   473                           "name.clash.same.erasure", tree.sym,
   474                           e.sym);
   475                 return;
   476             }
   477         }
   478     }
   480     public void visitVarDef(JCVariableDecl tree) {
   481         tree.vartype = translate(tree.vartype, null);
   482         tree.init = translate(tree.init, tree.sym.erasure(types));
   483         tree.type = erasure(tree.type);
   484         result = tree;
   485     }
   487     public void visitDoLoop(JCDoWhileLoop tree) {
   488         tree.body = translate(tree.body);
   489         tree.cond = translate(tree.cond, syms.booleanType);
   490         result = tree;
   491     }
   493     public void visitWhileLoop(JCWhileLoop tree) {
   494         tree.cond = translate(tree.cond, syms.booleanType);
   495         tree.body = translate(tree.body);
   496         result = tree;
   497     }
   499     public void visitForLoop(JCForLoop tree) {
   500         tree.init = translate(tree.init, null);
   501         if (tree.cond != null)
   502             tree.cond = translate(tree.cond, syms.booleanType);
   503         tree.step = translate(tree.step, null);
   504         tree.body = translate(tree.body);
   505         result = tree;
   506     }
   508     public void visitForeachLoop(JCEnhancedForLoop tree) {
   509         tree.var = translate(tree.var, null);
   510         Type iterableType = tree.expr.type;
   511         tree.expr = translate(tree.expr, erasure(tree.expr.type));
   512         if (types.elemtype(tree.expr.type) == null)
   513             tree.expr.type = iterableType; // preserve type for Lower
   514         tree.body = translate(tree.body);
   515         result = tree;
   516     }
   518     public void visitSwitch(JCSwitch tree) {
   519         Type selsuper = types.supertype(tree.selector.type);
   520         boolean enumSwitch = selsuper != null &&
   521             selsuper.tsym == syms.enumSym;
   522         Type target = enumSwitch ? erasure(tree.selector.type) : syms.intType;
   523         tree.selector = translate(tree.selector, target);
   524         tree.cases = translateCases(tree.cases);
   525         result = tree;
   526     }
   528     public void visitCase(JCCase tree) {
   529         tree.pat = translate(tree.pat, null);
   530         tree.stats = translate(tree.stats);
   531         result = tree;
   532     }
   534     public void visitSynchronized(JCSynchronized tree) {
   535         tree.lock = translate(tree.lock, erasure(tree.lock.type));
   536         tree.body = translate(tree.body);
   537         result = tree;
   538     }
   540     public void visitConditional(JCConditional tree) {
   541         tree.cond = translate(tree.cond, syms.booleanType);
   542         tree.truepart = translate(tree.truepart, erasure(tree.type));
   543         tree.falsepart = translate(tree.falsepart, erasure(tree.type));
   544         tree.type = erasure(tree.type);
   545         result = retype(tree, tree.type, pt);
   546     }
   548    public void visitIf(JCIf tree) {
   549         tree.cond = translate(tree.cond, syms.booleanType);
   550         tree.thenpart = translate(tree.thenpart);
   551         tree.elsepart = translate(tree.elsepart);
   552         result = tree;
   553     }
   555     public void visitExec(JCExpressionStatement tree) {
   556         tree.expr = translate(tree.expr, null);
   557         result = tree;
   558     }
   560     public void visitReturn(JCReturn tree) {
   561         tree.expr = translate(tree.expr, currentMethod.sym.erasure(types).getReturnType());
   562         result = tree;
   563     }
   565     public void visitThrow(JCThrow tree) {
   566         tree.expr = translate(tree.expr, erasure(tree.expr.type));
   567         result = tree;
   568     }
   570     public void visitAssert(JCAssert tree) {
   571         tree.cond = translate(tree.cond, syms.booleanType);
   572         if (tree.detail != null)
   573             tree.detail = translate(tree.detail, erasure(tree.detail.type));
   574         result = tree;
   575     }
   577     public void visitApply(JCMethodInvocation tree) {
   578         tree.meth = translate(tree.meth, null);
   579         Symbol meth = TreeInfo.symbol(tree.meth);
   580         Type mt = meth.erasure(types);
   581         List<Type> argtypes = mt.getParameterTypes();
   582         if (allowEnums &&
   583             meth.name==names.init &&
   584             meth.owner == syms.enumSym)
   585             argtypes = argtypes.tail.tail;
   586         if (tree.varargsElement != null)
   587             tree.varargsElement = types.erasure(tree.varargsElement);
   588         else
   589             assert tree.args.length() == argtypes.length();
   590         tree.args = translateArgs(tree.args, argtypes, tree.varargsElement);
   592         // Insert casts of method invocation results as needed.
   593         result = retype(tree, mt.getReturnType(), pt);
   594     }
   596     public void visitNewClass(JCNewClass tree) {
   597         if (tree.encl != null)
   598             tree.encl = translate(tree.encl, erasure(tree.encl.type));
   599         tree.clazz = translate(tree.clazz, null);
   600         if (tree.varargsElement != null)
   601             tree.varargsElement = types.erasure(tree.varargsElement);
   602         tree.args = translateArgs(
   603             tree.args, tree.constructor.erasure(types).getParameterTypes(), tree.varargsElement);
   604         tree.def = translate(tree.def, null);
   605         tree.type = erasure(tree.type);
   606         result = tree;
   607     }
   609     public void visitNewArray(JCNewArray tree) {
   610         tree.elemtype = translate(tree.elemtype, null);
   611         translate(tree.dims, syms.intType);
   612         tree.elems = translate(tree.elems,
   613                                (tree.type == null) ? null
   614                                : erasure(types.elemtype(tree.type)));
   615         tree.type = erasure(tree.type);
   617         result = tree;
   618     }
   620     public void visitParens(JCParens tree) {
   621         tree.expr = translate(tree.expr, pt);
   622         tree.type = erasure(tree.type);
   623         result = tree;
   624     }
   626     public void visitAssign(JCAssign tree) {
   627         tree.lhs = translate(tree.lhs, null);
   628         tree.rhs = translate(tree.rhs, erasure(tree.lhs.type));
   629         tree.type = erasure(tree.type);
   630         result = tree;
   631     }
   633     public void visitAssignop(JCAssignOp tree) {
   634         tree.lhs = translate(tree.lhs, tree.operator.type.getParameterTypes().head);
   635         tree.rhs = translate(tree.rhs, tree.operator.type.getParameterTypes().tail.head);
   636         tree.type = erasure(tree.type);
   637         result = tree;
   638     }
   640     public void visitUnary(JCUnary tree) {
   641         tree.arg = translate(tree.arg, tree.operator.type.getParameterTypes().head);
   642         result = tree;
   643     }
   645     public void visitBinary(JCBinary tree) {
   646         tree.lhs = translate(tree.lhs, tree.operator.type.getParameterTypes().head);
   647         tree.rhs = translate(tree.rhs, tree.operator.type.getParameterTypes().tail.head);
   648         result = tree;
   649     }
   651     public void visitTypeCast(JCTypeCast tree) {
   652         tree.clazz = translate(tree.clazz, null);
   653         tree.type = erasure(tree.type);
   654         tree.expr = translate(tree.expr, tree.type);
   655         result = tree;
   656     }
   658     public void visitTypeTest(JCInstanceOf tree) {
   659         tree.expr = translate(tree.expr, null);
   660         tree.clazz = translate(tree.clazz, null);
   661         result = tree;
   662     }
   664     public void visitIndexed(JCArrayAccess tree) {
   665         tree.indexed = translate(tree.indexed, erasure(tree.indexed.type));
   666         tree.index = translate(tree.index, syms.intType);
   668         // Insert casts of indexed expressions as needed.
   669         result = retype(tree, types.elemtype(tree.indexed.type), pt);
   670     }
   672     // There ought to be nothing to rewrite here;
   673     // we don't generate code.
   674     public void visitAnnotation(JCAnnotation tree) {
   675         result = tree;
   676     }
   678     public void visitIdent(JCIdent tree) {
   679         Type et = tree.sym.erasure(types);
   681         // Map type variables to their bounds.
   682         if (tree.sym.kind == TYP && tree.sym.type.tag == TYPEVAR) {
   683             result = make.at(tree.pos).Type(et);
   684         } else
   685         // Map constants expressions to themselves.
   686         if (tree.type.constValue() != null) {
   687             result = tree;
   688         }
   689         // Insert casts of variable uses as needed.
   690         else if (tree.sym.kind == VAR) {
   691             result = retype(tree, et, pt);
   692         }
   693         else {
   694             tree.type = erasure(tree.type);
   695             result = tree;
   696         }
   697     }
   699     public void visitSelect(JCFieldAccess tree) {
   700         Type t = tree.selected.type;
   701         while (t.tag == TYPEVAR)
   702             t = t.getUpperBound();
   703         if (t.isCompound()) {
   704             if ((tree.sym.flags() & IPROXY) != 0) {
   705                 tree.sym = ((MethodSymbol)tree.sym).
   706                     implemented((TypeSymbol)tree.sym.owner, types);
   707             }
   708             tree.selected = cast(
   709                 translate(tree.selected, erasure(tree.selected.type)),
   710                 erasure(tree.sym.owner.type));
   711         } else
   712             tree.selected = translate(tree.selected, erasure(t));
   714         // Map constants expressions to themselves.
   715         if (tree.type.constValue() != null) {
   716             result = tree;
   717         }
   718         // Insert casts of variable uses as needed.
   719         else if (tree.sym.kind == VAR) {
   720             result = retype(tree, tree.sym.erasure(types), pt);
   721         }
   722         else {
   723             tree.type = erasure(tree.type);
   724             result = tree;
   725         }
   726     }
   728     public void visitTypeArray(JCArrayTypeTree tree) {
   729         tree.elemtype = translate(tree.elemtype, null);
   730         tree.type = erasure(tree.type);
   731         result = tree;
   732     }
   734     /** Visitor method for parameterized types.
   735      */
   736     public void visitTypeApply(JCTypeApply tree) {
   737         JCTree clazz = translate(tree.clazz, null);
   738         result = clazz;
   739     }
   741 /**************************************************************************
   742  * utility methods
   743  *************************************************************************/
   745     private Type erasure(Type t) {
   746         return types.erasure(t);
   747     }
   749 /**************************************************************************
   750  * main method
   751  *************************************************************************/
   753     private Env<AttrContext> env;
   755     void translateClass(ClassSymbol c) {
   756         Type st = types.supertype(c.type);
   758         // process superclass before derived
   759         if (st.tag == CLASS)
   760             translateClass((ClassSymbol)st.tsym);
   762         Env<AttrContext> myEnv = enter.typeEnvs.remove(c);
   763         if (myEnv == null)
   764             return;
   765         Env<AttrContext> oldEnv = env;
   766         try {
   767             env = myEnv;
   768             // class has not been translated yet
   770             TreeMaker savedMake = make;
   771             Type savedPt = pt;
   772             make = make.forToplevel(env.toplevel);
   773             pt = null;
   774             try {
   775                 JCClassDecl tree = (JCClassDecl) env.tree;
   776                 tree.typarams = List.nil();
   777                 super.visitClassDef(tree);
   778                 make.at(tree.pos);
   779                 if (addBridges) {
   780                     ListBuffer<JCTree> bridges = new ListBuffer<JCTree>();
   781                     if ((tree.sym.flags() & INTERFACE) == 0)
   782                         addBridges(tree.pos(), tree.sym, bridges);
   783                     tree.defs = bridges.toList().prependList(tree.defs);
   784                 }
   785                 tree.type = erasure(tree.type);
   786             } finally {
   787                 make = savedMake;
   788                 pt = savedPt;
   789             }
   790         } finally {
   791             env = oldEnv;
   792         }
   793     }
   795     /** Translate a toplevel class definition.
   796      *  @param cdef    The definition to be translated.
   797      */
   798     public JCTree translateTopLevelClass(JCTree cdef, TreeMaker make) {
   799         // note that this method does NOT support recursion.
   800         this.make = make;
   801         pt = null;
   802         return translate(cdef, null);
   803     }
   805     private class TypeAnnotationPositions extends TreeScanner {
   807         private ListBuffer<JCTree> frames = ListBuffer.lb();
   808         private void push(JCTree t) { frames = frames.prepend(t); }
   809         private JCTree pop() { return frames.next(); }
   810         private JCTree peek() { return frames.first(); }
   811         private JCTree peek2() { return frames.toList().tail.head; }
   813         @Override
   814         public void scan(JCTree tree) {
   815             push(tree);
   816             super.scan(tree);
   817             pop();
   818         }
   820         private TypeAnnotationPosition resolveFrame(JCTree tree, JCTree frame,
   821                 List<JCTree> path, TypeAnnotationPosition p) {
   822             switch (frame.getKind()) {
   823                 case TYPE_CAST:
   824                     p.type = TargetType.TYPECAST;
   825                     p.pos = frame.pos;
   826                     return p;
   828                 case INSTANCE_OF:
   829                     p.type = TargetType.INSTANCEOF;
   830                     p.pos = frame.pos;
   831                     return p;
   833                 case NEW_CLASS:
   834                     p.type = TargetType.NEW;
   835                     p.pos = frame.pos;
   836                     return p;
   838                 case NEW_ARRAY:
   839                     p.type = TargetType.NEW;
   840                     p.pos = frame.pos;
   841                     return p;
   843                 case CLASS:
   844                     p.pos = frame.pos;
   845                     if (((JCClassDecl)frame).extending == tree) {
   846                         p.type = TargetType.CLASS_EXTENDS;
   847                         p.type_index = -1;
   848                     } else if (((JCClassDecl)frame).implementing.contains(tree)) {
   849                         p.type = TargetType.CLASS_EXTENDS;
   850                         p.type_index = ((JCClassDecl)frame).implementing.indexOf(tree);
   851                     } else if (((JCClassDecl)frame).typarams.contains(tree)) {
   852                         p.type = TargetType.CLASS_TYPE_PARAMETER;
   853                         p.parameter_index = ((JCClassDecl)frame).typarams.indexOf(tree);
   854                     } else
   855                         throw new AssertionError();
   856                     return p;
   858                 case METHOD: {
   859                     JCMethodDecl frameMethod = (JCMethodDecl)frame;
   860                     p.pos = frame.pos;
   861                     if (frameMethod.receiverAnnotations.contains(tree))
   862                         p.type = TargetType.METHOD_RECEIVER;
   863                     else if (frameMethod.thrown.contains(tree)) {
   864                         p.type = TargetType.THROWS;
   865                         p.type_index = frameMethod.thrown.indexOf(tree);
   866                     } else if (((JCMethodDecl)frame).restype == tree) {
   867                         p.type = TargetType.METHOD_RETURN_GENERIC_OR_ARRAY;
   868                     } else if (frameMethod.typarams.contains(tree)) {
   869                         p.type = TargetType.METHOD_TYPE_PARAMETER;
   870                         p.parameter_index = frameMethod.typarams.indexOf(tree);
   871                     } else
   872                         throw new AssertionError();
   873                     return p;
   874                 }
   875                 case MEMBER_SELECT: {
   876                     JCFieldAccess fieldFrame = (JCFieldAccess)frame;
   877                     if (fieldFrame.name == names._class) {
   878                         p.type = TargetType.CLASS_LITERAL;
   879                         if (fieldFrame.selected instanceof JCAnnotatedType) {
   880                             p.pos = TreeInfo.typeIn(fieldFrame).pos;
   881                         } else if (fieldFrame.selected instanceof JCArrayTypeTree) {
   882                             p.pos = fieldFrame.selected.pos;
   883                         }
   884                     } else
   885                         throw new AssertionError();
   886                     return p;
   887                 }
   888                 case PARAMETERIZED_TYPE: {
   889                     TypeAnnotationPosition nextP;
   890                     if (((JCTypeApply)frame).clazz == tree)
   891                         nextP = p; // generic: RAW; noop
   892                     else if (((JCTypeApply)frame).arguments.contains(tree))
   893                         p.location = p.location.prepend(
   894                                 ((JCTypeApply)frame).arguments.indexOf(tree));
   895                     else
   896                         throw new AssertionError();
   898                     List<JCTree> newPath = path.tail;
   899                     return resolveFrame(newPath.head, newPath.tail.head, newPath, p);
   900                 }
   902                 case ARRAY_TYPE: {
   903                     p.location = p.location.prepend(0);
   904                     List<JCTree> newPath = path.tail;
   905                     return resolveFrame(newPath.head, newPath.tail.head, newPath, p);
   906                 }
   908                 case TYPE_PARAMETER:
   909                     if (path.tail.tail.head.getTag() == JCTree.CLASSDEF) {
   910                         JCClassDecl clazz = (JCClassDecl)path.tail.tail.head;
   911                         p.type = TargetType.CLASS_TYPE_PARAMETER_BOUND;
   912                         p.parameter_index = clazz.typarams.indexOf(path.tail.head);
   913                         p.bound_index = ((JCTypeParameter)frame).bounds.indexOf(tree);
   914                     } else if (path.tail.tail.head.getTag() == JCTree.METHODDEF) {
   915                         JCMethodDecl method = (JCMethodDecl)path.tail.tail.head;
   916                         p.type = TargetType.METHOD_TYPE_PARAMETER_BOUND;
   917                         p.parameter_index = method.typarams.indexOf(path.tail.head);
   918                         p.bound_index = ((JCTypeParameter)frame).bounds.indexOf(tree);
   919                     } else
   920                         throw new AssertionError();
   921                     p.pos = frame.pos;
   922                     return p;
   924                 case VARIABLE:
   925                     VarSymbol v = ((JCVariableDecl)frame).sym;
   926                     p.pos = frame.pos;
   927                     switch (v.getKind()) {
   928                         case LOCAL_VARIABLE:
   929                             p.type = TargetType.LOCAL_VARIABLE; break;
   930                         case FIELD:
   931                             p.type = TargetType.FIELD_GENERIC_OR_ARRAY; break;
   932                         case PARAMETER:
   933                             p.type = TargetType.METHOD_PARAMETER_GENERIC_OR_ARRAY;
   934                             p.parameter_index = methodParamIndex(path, frame);
   935                             break;
   936                         default: throw new AssertionError();
   937                     }
   938                     return p;
   940                 case ANNOTATED_TYPE: {
   941                     List<JCTree> newPath = path.tail;
   942                     return resolveFrame(newPath.head, newPath.tail.head,
   943                             newPath, p);
   944                 }
   946                 case METHOD_INVOCATION: {
   947                     JCMethodInvocation invocation = (JCMethodInvocation)frame;
   948                     if (!invocation.typeargs.contains(tree))
   949                         throw new AssertionError("{" + tree + "} is not an argument in the invocation: " + invocation);
   950                     p.type = TargetType.METHOD_TYPE_ARGUMENT;
   951                     p.pos = invocation.pos;
   952                     p.type_index = invocation.typeargs.indexOf(tree);
   953                     return p;
   954                 }
   956                 case EXTENDS_WILDCARD:
   957                 case SUPER_WILDCARD: {
   958                     p.type = TargetType.WILDCARD_BOUND;
   959                     List<JCTree> newPath = path.tail;
   961                     TypeAnnotationPosition wildcard =
   962                         resolveFrame(newPath.head, newPath.tail.head, newPath,
   963                                 new TypeAnnotationPosition());
   964                     if (!wildcard.location.isEmpty())
   965                         wildcard.type = wildcard.type.getGenericComplement();
   966                     p.wildcard_position = wildcard;
   967                     p.pos = frame.pos;
   968                     return p;
   969                 }
   970             }
   971             return p;
   972         }
   974         @Override
   975         public void visitApply(JCMethodInvocation tree) {
   976             scan(tree.meth);
   977             scan(tree.typeargs);
   978             scan(tree.args);
   979         }
   981         private void setTypeAnnotationPos(List<JCTypeAnnotation> annotations, TypeAnnotationPosition position) {
   982             for (JCTypeAnnotation anno : annotations) {
   983                 anno.annotation_position = position;
   984                 anno.attribute_field.position = position;
   985             }
   986         }
   988         @Override
   989         public void visitNewArray(JCNewArray tree) {
   990             findPosition(tree, tree, tree.annotations);
   991             int dimAnnosCount = tree.dimAnnotations.size();
   993             // handle annotations associated with dimentions
   994             for (int i = 0; i < dimAnnosCount; ++i) {
   995                 TypeAnnotationPosition p = new TypeAnnotationPosition();
   996                 p.type = TargetType.NEW_GENERIC_OR_ARRAY;
   997                 p.pos = tree.pos;
   998                 p.location = p.location.append(i);
   999                 setTypeAnnotationPos(tree.dimAnnotations.get(i), p);
  1002             // handle "free" annotations
  1003             int i = dimAnnosCount == 0 ? 0 : dimAnnosCount - 1;
  1004             JCExpression elemType = tree.elemtype;
  1005             while (elemType != null) {
  1006                 if (elemType.getTag() == JCTree.ANNOTATED_TYPE) {
  1007                     JCAnnotatedType at = (JCAnnotatedType)elemType;
  1008                     TypeAnnotationPosition p = new TypeAnnotationPosition();
  1009                     p.type = TargetType.NEW_GENERIC_OR_ARRAY;
  1010                     p.pos = tree.pos;
  1011                     p.location = p.location.append(i);
  1012                     setTypeAnnotationPos(at.annotations, p);
  1013                     elemType = at.underlyingType;
  1014                 } else if (elemType.getTag() == JCTree.TYPEARRAY) {
  1015                     ++i;
  1016                     elemType = ((JCArrayTypeTree)elemType).elemtype;
  1017                 } else
  1018                     break;
  1021             // find annotations locations of initializer elements
  1022             scan(tree.elems);
  1025         @Override
  1026         public void visitAnnotatedType(JCAnnotatedType tree) {
  1027             findPosition(tree, peek2(), tree.annotations);
  1028             super.visitAnnotatedType(tree);
  1031         @Override
  1032         public void visitMethodDef(JCMethodDecl tree) {
  1033             TypeAnnotationPosition p = new TypeAnnotationPosition();
  1034             p.type = TargetType.METHOD_RECEIVER;
  1035             setTypeAnnotationPos(tree.receiverAnnotations, p);
  1036             super.visitMethodDef(tree);
  1038         @Override
  1039         public void visitTypeParameter(JCTypeParameter tree) {
  1040             findPosition(tree, peek2(), tree.annotations);
  1041             super.visitTypeParameter(tree);
  1044         void findPosition(JCTree tree, JCTree frame, List<JCTypeAnnotation> annotations) {
  1045             if (!annotations.isEmpty()) {
  1046                 TypeAnnotationPosition p =
  1047                         resolveFrame(tree, frame, frames.toList(),
  1048                                 new TypeAnnotationPosition());
  1049                 if (!p.location.isEmpty())
  1050                     p.type = p.type.getGenericComplement();
  1051                 setTypeAnnotationPos(annotations, p);
  1052                 if (debugJSR308) {
  1053                     System.out.println("trans: " + tree);
  1054                     System.out.println("  target: " + p);
  1059         private int methodParamIndex(List<JCTree> path, JCTree param) {
  1060             List<JCTree> curr = path;
  1061             if (curr.head != param)
  1062                 curr = path.tail;
  1063             JCMethodDecl method = (JCMethodDecl)curr.tail.head;
  1064             return method.params.indexOf(param);
  1068     private class TypeAnnotationLift extends TreeScanner {
  1069         List<Attribute.TypeCompound> recordedTypeAnnotations = List.nil();
  1071         boolean isInner = false;
  1072         @Override
  1073         public void visitClassDef(JCClassDecl tree) {
  1074             if (isInner) {
  1075                 // tree is an inner class tree.  stop now.
  1076                 // TransTypes.visitClassDef makes an invocation for each class
  1077                 // seperately.
  1078                 return;
  1080             isInner = true;
  1081             List<Attribute.TypeCompound> prevTAs = recordedTypeAnnotations;
  1082             recordedTypeAnnotations = List.nil();
  1083             try {
  1084                 super.visitClassDef(tree);
  1085             } finally {
  1086                 tree.sym.typeAnnotations = tree.sym.typeAnnotations.appendList(recordedTypeAnnotations);
  1087                 recordedTypeAnnotations = prevTAs;
  1091         @Override
  1092         public void visitMethodDef(JCMethodDecl tree) {
  1093             List<Attribute.TypeCompound> prevTAs = recordedTypeAnnotations;
  1094             recordedTypeAnnotations = List.nil();
  1095             try {
  1096                 super.visitMethodDef(tree);
  1097             } finally {
  1098                 tree.sym.typeAnnotations = tree.sym.typeAnnotations.appendList(recordedTypeAnnotations);
  1099                 recordedTypeAnnotations = prevTAs;
  1103         @Override
  1104         public void visitVarDef(JCVariableDecl tree) {
  1105             List<Attribute.TypeCompound> prevTAs = recordedTypeAnnotations;
  1106             recordedTypeAnnotations = List.nil();
  1107             ElementKind kind = tree.sym.getKind();
  1108             if (kind == ElementKind.LOCAL_VARIABLE && tree.mods.annotations.nonEmpty()) {
  1109                 // need to lift the annotations
  1110                 TypeAnnotationPosition position = new TypeAnnotationPosition();
  1111                 position.pos = tree.pos;
  1112                 position.type = TargetType.LOCAL_VARIABLE;
  1113                 for (Attribute.Compound attribute : tree.sym.attributes_field) {
  1114                     Attribute.TypeCompound tc =
  1115                         new Attribute.TypeCompound(attribute.type, attribute.values, position);
  1116                     recordedTypeAnnotations = recordedTypeAnnotations.append(tc);
  1119             try {
  1120                 super.visitVarDef(tree);
  1121             } finally {
  1122                 if (kind.isField() || kind == ElementKind.LOCAL_VARIABLE)
  1123                     tree.sym.typeAnnotations = tree.sym.typeAnnotations.appendList(recordedTypeAnnotations);
  1124                 recordedTypeAnnotations = kind.isField() ? prevTAs : prevTAs.appendList(recordedTypeAnnotations);
  1128         @Override
  1129         public void visitApply(JCMethodInvocation tree) {
  1130             scan(tree.meth);
  1131             scan(tree.typeargs);
  1132             scan(tree.args);
  1135         public void visitAnnotation(JCAnnotation tree) {
  1136             if (tree instanceof JCTypeAnnotation)
  1137                 recordedTypeAnnotations = recordedTypeAnnotations.append(((JCTypeAnnotation)tree).attribute_field);
  1138             super.visitAnnotation(tree);

mercurial