Home » openjdk-7 » com.sun.tools » javac » comp » [javadoc | source]

    1   /*
    2    * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package com.sun.tools.javac.comp;
   27   
   28   import java.util;
   29   
   30   import javax.lang.model.element.ElementKind;
   31   
   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;
   39   
   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.*;
   43   
   44   /** This pass translates Generic Java to conventional Java.
   45    *
   46    *  <p><b>This is NOT part of any supported API.
   47    *  If 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>();
   55   
   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       }
   63   
   64       private Names names;
   65       private Log log;
   66       private Symtab syms;
   67       private TreeMaker make;
   68       private Enter enter;
   69       private boolean allowEnums;
   70       private Types types;
   71       private final Resolve resolve;
   72   
   73       /**
   74        * Flag to indicate whether or not to generate bridge methods.
   75        * For pre-Tiger source there is no need for bridge methods, so it
   76        * can be skipped to get better performance for -source 1.4 etc.
   77        */
   78       private final boolean addBridges;
   79   
   80       protected TransTypes(Context context) {
   81           context.put(transTypesKey, this);
   82           names = Names.instance(context);
   83           log = Log.instance(context);
   84           syms = Symtab.instance(context);
   85           enter = Enter.instance(context);
   86           overridden = new HashMap<MethodSymbol,MethodSymbol>();
   87           Source source = Source.instance(context);
   88           allowEnums = source.allowEnums();
   89           addBridges = source.addBridges();
   90           types = Types.instance(context);
   91           make = TreeMaker.instance(context);
   92           resolve = Resolve.instance(context);
   93       }
   94   
   95       /** A hashtable mapping bridge methods to the methods they override after
   96        *  type erasure.
   97        */
   98       Map<MethodSymbol,MethodSymbol> overridden;
   99   
  100       /** Construct an attributed tree for a cast of expression to target type,
  101        *  unless it already has precisely that type.
  102        *  @param tree    The expression tree.
  103        *  @param target  The target type.
  104        */
  105       JCExpression cast(JCExpression tree, Type target) {
  106           int oldpos = make.pos;
  107           make.at(tree.pos);
  108           if (!types.isSameType(tree.type, target)) {
  109               if (!resolve.isAccessible(env, target.tsym))
  110                   resolve.logAccessError(env, tree, target);
  111               tree = make.TypeCast(make.Type(target), tree).setType(target);
  112           }
  113           make.pos = oldpos;
  114           return tree;
  115       }
  116   
  117       /** Construct an attributed tree to coerce an expression to some erased
  118        *  target type, unless the expression is already assignable to that type.
  119        *  If target type is a constant type, use its base type instead.
  120        *  @param tree    The expression tree.
  121        *  @param target  The target type.
  122        */
  123       JCExpression coerce(JCExpression tree, Type target) {
  124           Type btarget = target.baseType();
  125           if (tree.type.isPrimitive() == target.isPrimitive()) {
  126               return types.isAssignable(tree.type, btarget, Warner.noWarnings)
  127                   ? tree
  128                   : cast(tree, btarget);
  129           }
  130           return tree;
  131       }
  132   
  133       /** Given an erased reference type, assume this type as the tree's type.
  134        *  Then, coerce to some given target type unless target type is null.
  135        *  This operation is used in situations like the following:
  136        *
  137        *  class Cell<A> { A value; }
  138        *  ...
  139        *  Cell<Integer> cell;
  140        *  Integer x = cell.value;
  141        *
  142        *  Since the erasure of Cell.value is Object, but the type
  143        *  of cell.value in the assignment is Integer, we need to
  144        *  adjust the original type of cell.value to Object, and insert
  145        *  a cast to Integer. That is, the last assignment becomes:
  146        *
  147        *  Integer x = (Integer)cell.value;
  148        *
  149        *  @param tree       The expression tree whose type might need adjustment.
  150        *  @param erasedType The expression's type after erasure.
  151        *  @param target     The target type, which is usually the erasure of the
  152        *                    expression's original type.
  153        */
  154       JCExpression retype(JCExpression tree, Type erasedType, Type target) {
  155   //      System.err.println("retype " + tree + " to " + erasedType);//DEBUG
  156           if (erasedType.tag > lastBaseTag) {
  157               if (target != null && target.isPrimitive())
  158                   target = erasure(tree.type);
  159               tree.type = erasedType;
  160               if (target != null) return coerce(tree, target);
  161           }
  162           return tree;
  163       }
  164   
  165       /** Translate method argument list, casting each argument
  166        *  to its corresponding type in a list of target types.
  167        *  @param _args            The method argument list.
  168        *  @param parameters       The list of target types.
  169        *  @param varargsElement   The erasure of the varargs element type,
  170        *  or null if translating a non-varargs invocation
  171        */
  172       <T extends JCTree> List<T> translateArgs(List<T> _args,
  173                                              List<Type> parameters,
  174                                              Type varargsElement) {
  175           if (parameters.isEmpty()) return _args;
  176           List<T> args = _args;
  177           while (parameters.tail.nonEmpty()) {
  178               args.head = translate(args.head, parameters.head);
  179               args = args.tail;
  180               parameters = parameters.tail;
  181           }
  182           Type parameter = parameters.head;
  183           Assert.check(varargsElement != null || args.length() == 1);
  184           if (varargsElement != null) {
  185               while (args.nonEmpty()) {
  186                   args.head = translate(args.head, varargsElement);
  187                   args = args.tail;
  188               }
  189           } else {
  190               args.head = translate(args.head, parameter);
  191           }
  192           return _args;
  193       }
  194   
  195       /** Add a bridge definition and enter corresponding method symbol in
  196        *  local scope of origin.
  197        *
  198        *  @param pos     The source code position to be used for the definition.
  199        *  @param meth    The method for which a bridge needs to be added
  200        *  @param impl    That method's implementation (possibly the method itself)
  201        *  @param origin  The class to which the bridge will be added
  202        *  @param hypothetical
  203        *                 True if the bridge method is not strictly necessary in the
  204        *                 binary, but is represented in the symbol table to detect
  205        *                 erasure clashes.
  206        *  @param bridges The list buffer to which the bridge will be added
  207        */
  208       void addBridge(DiagnosticPosition pos,
  209                      MethodSymbol meth,
  210                      MethodSymbol impl,
  211                      ClassSymbol origin,
  212                      boolean hypothetical,
  213                      ListBuffer<JCTree> bridges) {
  214           make.at(pos);
  215           Type origType = types.memberType(origin.type, meth);
  216           Type origErasure = erasure(origType);
  217   
  218           // Create a bridge method symbol and a bridge definition without a body.
  219           Type bridgeType = meth.erasure(types);
  220           long flags = impl.flags() & AccessFlags | SYNTHETIC | BRIDGE;
  221           if (hypothetical) flags |= HYPOTHETICAL;
  222           MethodSymbol bridge = new MethodSymbol(flags,
  223                                                  meth.name,
  224                                                  bridgeType,
  225                                                  origin);
  226           if (!hypothetical) {
  227               JCMethodDecl md = make.MethodDef(bridge, null);
  228   
  229               // The bridge calls this.impl(..), if we have an implementation
  230               // in the current class, super.impl(...) otherwise.
  231               JCExpression receiver = (impl.owner == origin)
  232                   ? make.This(origin.erasure(types))
  233                   : make.Super(types.supertype(origin.type).tsym.erasure(types), origin);
  234   
  235               // The type returned from the original method.
  236               Type calltype = erasure(impl.type.getReturnType());
  237   
  238               // Construct a call of  this.impl(params), or super.impl(params),
  239               // casting params and possibly results as needed.
  240               JCExpression call =
  241                   make.Apply(
  242                              null,
  243                              make.Select(receiver, impl).setType(calltype),
  244                              translateArgs(make.Idents(md.params), origErasure.getParameterTypes(), null))
  245                   .setType(calltype);
  246               JCStatement stat = (origErasure.getReturnType().tag == VOID)
  247                   ? make.Exec(call)
  248                   : make.Return(coerce(call, bridgeType.getReturnType()));
  249               md.body = make.Block(0, List.of(stat));
  250   
  251               // Add bridge to `bridges' buffer
  252               bridges.append(md);
  253           }
  254   
  255           // Add bridge to scope of enclosing class and `overridden' table.
  256           origin.members().enter(bridge);
  257           overridden.put(bridge, meth);
  258       }
  259   
  260       /** Add bridge if given symbol is a non-private, non-static member
  261        *  of the given class, which is either defined in the class or non-final
  262        *  inherited, and one of the two following conditions holds:
  263        *  1. The method's type changes in the given class, as compared to the
  264        *     class where the symbol was defined, (in this case
  265        *     we have extended a parameterized class with non-trivial parameters).
  266        *  2. The method has an implementation with a different erased return type.
  267        *     (in this case we have used co-variant returns).
  268        *  If a bridge already exists in some other class, no new bridge is added.
  269        *  Instead, it is checked that the bridge symbol overrides the method symbol.
  270        *  (Spec ???).
  271        *  todo: what about bridges for privates???
  272        *
  273        *  @param pos     The source code position to be used for the definition.
  274        *  @param sym     The symbol for which a bridge might have to be added.
  275        *  @param origin  The class in which the bridge would go.
  276        *  @param bridges The list buffer to which the bridge would be added.
  277        */
  278       void addBridgeIfNeeded(DiagnosticPosition pos,
  279                              Symbol sym,
  280                              ClassSymbol origin,
  281                              ListBuffer<JCTree> bridges) {
  282           if (sym.kind == MTH &&
  283               sym.name != names.init &&
  284               (sym.flags() & (PRIVATE | STATIC)) == 0 &&
  285               (sym.flags() & (SYNTHETIC | OVERRIDE_BRIDGE)) != SYNTHETIC &&
  286               sym.isMemberOf(origin, types))
  287           {
  288               MethodSymbol meth = (MethodSymbol)sym;
  289               MethodSymbol bridge = meth.binaryImplementation(origin, types);
  290               MethodSymbol impl = meth.implementation(origin, types, true, overrideBridgeFilter);
  291               if (bridge == null ||
  292                   bridge == meth ||
  293                   (impl != null && !bridge.owner.isSubClass(impl.owner, types))) {
  294                   // No bridge was added yet.
  295                   if (impl != null && isBridgeNeeded(meth, impl, origin.type)) {
  296                       addBridge(pos, meth, impl, origin, bridge==impl, bridges);
  297                   } else if (impl == meth
  298                              && impl.owner != origin
  299                              && (impl.flags() & FINAL) == 0
  300                              && (meth.flags() & (ABSTRACT|PUBLIC)) == PUBLIC
  301                              && (origin.flags() & PUBLIC) > (impl.owner.flags() & PUBLIC)) {
  302                       // this is to work around a horrible but permanent
  303                       // reflection design error.
  304                       addBridge(pos, meth, impl, origin, false, bridges);
  305                   }
  306               } else if ((bridge.flags() & (SYNTHETIC | OVERRIDE_BRIDGE)) == SYNTHETIC) {
  307                   MethodSymbol other = overridden.get(bridge);
  308                   if (other != null && other != meth) {
  309                       if (impl == null || !impl.overrides(other, origin, types, true)) {
  310                           // Bridge for other symbol pair was added
  311                           log.error(pos, "name.clash.same.erasure.no.override",
  312                                     other, other.location(origin.type, types),
  313                                     meth,  meth.location(origin.type, types));
  314                       }
  315                   }
  316               } else if (!bridge.overrides(meth, origin, types, true)) {
  317                   // Accidental binary override without source override.
  318                   if (bridge.owner == origin ||
  319                       types.asSuper(bridge.owner.type, meth.owner) == null)
  320                       // Don't diagnose the problem if it would already
  321                       // have been reported in the superclass
  322                       log.error(pos, "name.clash.same.erasure.no.override",
  323                                 bridge, bridge.location(origin.type, types),
  324                                 meth,  meth.location(origin.type, types));
  325               }
  326           }
  327       }
  328       // where
  329           Filter<Symbol> overrideBridgeFilter = new Filter<Symbol>() {
  330               public boolean accepts(Symbol s) {
  331                   return (s.flags() & (SYNTHETIC | OVERRIDE_BRIDGE)) != SYNTHETIC;
  332               }
  333           };
  334           /**
  335            * @param method The symbol for which a bridge might have to be added
  336            * @param impl The implementation of method
  337            * @param dest The type in which the bridge would go
  338            */
  339           private boolean isBridgeNeeded(MethodSymbol method,
  340                                          MethodSymbol impl,
  341                                          Type dest) {
  342               if (impl != method) {
  343                   // If either method or impl have different erasures as
  344                   // members of dest, a bridge is needed.
  345                   Type method_erasure = method.erasure(types);
  346                   if (!isSameMemberWhenErased(dest, method, method_erasure))
  347                       return true;
  348                   Type impl_erasure = impl.erasure(types);
  349                   if (!isSameMemberWhenErased(dest, impl, impl_erasure))
  350                       return true;
  351   
  352                   // If the erasure of the return type is different, a
  353                   // bridge is needed.
  354                   return !types.isSameType(impl_erasure.getReturnType(),
  355                                            method_erasure.getReturnType());
  356               } else {
  357                  // method and impl are the same...
  358                   if ((method.flags() & ABSTRACT) != 0) {
  359                       // ...and abstract so a bridge is not needed.
  360                       // Concrete subclasses will bridge as needed.
  361                       return false;
  362                   }
  363   
  364                   // The erasure of the return type is always the same
  365                   // for the same symbol.  Reducing the three tests in
  366                   // the other branch to just one:
  367                   return !isSameMemberWhenErased(dest, method, method.erasure(types));
  368               }
  369           }
  370           /**
  371            * Lookup the method as a member of the type.  Compare the
  372            * erasures.
  373            * @param type the class where to look for the method
  374            * @param method the method to look for in class
  375            * @param erasure the erasure of method
  376            */
  377           private boolean isSameMemberWhenErased(Type type,
  378                                                  MethodSymbol method,
  379                                                  Type erasure) {
  380               return types.isSameType(erasure(types.memberType(type, method)),
  381                                       erasure);
  382           }
  383   
  384       void addBridges(DiagnosticPosition pos,
  385                       TypeSymbol i,
  386                       ClassSymbol origin,
  387                       ListBuffer<JCTree> bridges) {
  388           for (Scope.Entry e = i.members().elems; e != null; e = e.sibling)
  389               addBridgeIfNeeded(pos, e.sym, origin, bridges);
  390           for (List<Type> l = types.interfaces(i.type); l.nonEmpty(); l = l.tail)
  391               addBridges(pos, l.head.tsym, origin, bridges);
  392       }
  393   
  394       /** Add all necessary bridges to some class appending them to list buffer.
  395        *  @param pos     The source code position to be used for the bridges.
  396        *  @param origin  The class in which the bridges go.
  397        *  @param bridges The list buffer to which the bridges are added.
  398        */
  399       void addBridges(DiagnosticPosition pos, ClassSymbol origin, ListBuffer<JCTree> bridges) {
  400           Type st = types.supertype(origin.type);
  401           while (st.tag == CLASS) {
  402   //          if (isSpecialization(st))
  403               addBridges(pos, st.tsym, origin, bridges);
  404               st = types.supertype(st);
  405           }
  406           for (List<Type> l = types.interfaces(origin.type); l.nonEmpty(); l = l.tail)
  407   //          if (isSpecialization(l.head))
  408               addBridges(pos, l.head.tsym, origin, bridges);
  409       }
  410   
  411   /* ************************************************************************
  412    * Visitor methods
  413    *************************************************************************/
  414   
  415       /** Visitor argument: proto-type.
  416        */
  417       private Type pt;
  418   
  419       /** Visitor method: perform a type translation on tree.
  420        */
  421       public <T extends JCTree> T translate(T tree, Type pt) {
  422           Type prevPt = this.pt;
  423           try {
  424               this.pt = pt;
  425               return translate(tree);
  426           } finally {
  427               this.pt = prevPt;
  428           }
  429       }
  430   
  431       /** Visitor method: perform a type translation on list of trees.
  432        */
  433       public <T extends JCTree> List<T> translate(List<T> trees, Type pt) {
  434           Type prevPt = this.pt;
  435           List<T> res;
  436           try {
  437               this.pt = pt;
  438               res = translate(trees);
  439           } finally {
  440               this.pt = prevPt;
  441           }
  442           return res;
  443       }
  444   
  445       public void visitClassDef(JCClassDecl tree) {
  446           translateClass(tree.sym);
  447           result = tree;
  448       }
  449   
  450       JCMethodDecl currentMethod = null;
  451       public void visitMethodDef(JCMethodDecl tree) {
  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           }
  465   
  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       }
  479   
  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       }
  486   
  487       public void visitDoLoop(JCDoWhileLoop tree) {
  488           tree.body = translate(tree.body);
  489           tree.cond = translate(tree.cond, syms.booleanType);
  490           result = tree;
  491       }
  492   
  493       public void visitWhileLoop(JCWhileLoop tree) {
  494           tree.cond = translate(tree.cond, syms.booleanType);
  495           tree.body = translate(tree.body);
  496           result = tree;
  497       }
  498   
  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       }
  507   
  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       }
  517   
  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       }
  527   
  528       public void visitCase(JCCase tree) {
  529           tree.pat = translate(tree.pat, null);
  530           tree.stats = translate(tree.stats);
  531           result = tree;
  532       }
  533   
  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       }
  539   
  540       public void visitTry(JCTry tree) {
  541           tree.resources = translate(tree.resources, syms.autoCloseableType);
  542           tree.body = translate(tree.body);
  543           tree.catchers = translateCatchers(tree.catchers);
  544           tree.finalizer = translate(tree.finalizer);
  545           result = tree;
  546       }
  547   
  548       public void visitConditional(JCConditional tree) {
  549           tree.cond = translate(tree.cond, syms.booleanType);
  550           tree.truepart = translate(tree.truepart, erasure(tree.type));
  551           tree.falsepart = translate(tree.falsepart, erasure(tree.type));
  552           tree.type = erasure(tree.type);
  553           result = retype(tree, tree.type, pt);
  554       }
  555   
  556      public void visitIf(JCIf tree) {
  557           tree.cond = translate(tree.cond, syms.booleanType);
  558           tree.thenpart = translate(tree.thenpart);
  559           tree.elsepart = translate(tree.elsepart);
  560           result = tree;
  561       }
  562   
  563       public void visitExec(JCExpressionStatement tree) {
  564           tree.expr = translate(tree.expr, null);
  565           result = tree;
  566       }
  567   
  568       public void visitReturn(JCReturn tree) {
  569           tree.expr = translate(tree.expr, currentMethod.sym.erasure(types).getReturnType());
  570           result = tree;
  571       }
  572   
  573       public void visitThrow(JCThrow tree) {
  574           tree.expr = translate(tree.expr, erasure(tree.expr.type));
  575           result = tree;
  576       }
  577   
  578       public void visitAssert(JCAssert tree) {
  579           tree.cond = translate(tree.cond, syms.booleanType);
  580           if (tree.detail != null)
  581               tree.detail = translate(tree.detail, erasure(tree.detail.type));
  582           result = tree;
  583       }
  584   
  585       public void visitApply(JCMethodInvocation tree) {
  586           tree.meth = translate(tree.meth, null);
  587           Symbol meth = TreeInfo.symbol(tree.meth);
  588           Type mt = meth.erasure(types);
  589           List<Type> argtypes = mt.getParameterTypes();
  590           if (allowEnums &&
  591               meth.name==names.init &&
  592               meth.owner == syms.enumSym)
  593               argtypes = argtypes.tail.tail;
  594           if (tree.varargsElement != null)
  595               tree.varargsElement = types.erasure(tree.varargsElement);
  596           else
  597               Assert.check(tree.args.length() == argtypes.length());
  598           tree.args = translateArgs(tree.args, argtypes, tree.varargsElement);
  599   
  600           // Insert casts of method invocation results as needed.
  601           result = retype(tree, mt.getReturnType(), pt);
  602       }
  603   
  604       public void visitNewClass(JCNewClass tree) {
  605           if (tree.encl != null)
  606               tree.encl = translate(tree.encl, erasure(tree.encl.type));
  607           tree.clazz = translate(tree.clazz, null);
  608           if (tree.varargsElement != null)
  609               tree.varargsElement = types.erasure(tree.varargsElement);
  610           tree.args = translateArgs(
  611               tree.args, tree.constructor.erasure(types).getParameterTypes(), tree.varargsElement);
  612           tree.def = translate(tree.def, null);
  613           tree.type = erasure(tree.type);
  614           result = tree;
  615       }
  616   
  617       public void visitNewArray(JCNewArray tree) {
  618           tree.elemtype = translate(tree.elemtype, null);
  619           translate(tree.dims, syms.intType);
  620           if (tree.type != null) {
  621               tree.elems = translate(tree.elems, erasure(types.elemtype(tree.type)));
  622               tree.type = erasure(tree.type);
  623           } else {
  624               tree.elems = translate(tree.elems, null);
  625           }
  626   
  627           result = tree;
  628       }
  629   
  630       public void visitParens(JCParens tree) {
  631           tree.expr = translate(tree.expr, pt);
  632           tree.type = erasure(tree.type);
  633           result = tree;
  634       }
  635   
  636       public void visitAssign(JCAssign tree) {
  637           tree.lhs = translate(tree.lhs, null);
  638           tree.rhs = translate(tree.rhs, erasure(tree.lhs.type));
  639           tree.type = erasure(tree.type);
  640           result = tree;
  641       }
  642   
  643       public void visitAssignop(JCAssignOp tree) {
  644           tree.lhs = translate(tree.lhs, null);
  645           tree.rhs = translate(tree.rhs, tree.operator.type.getParameterTypes().tail.head);
  646           tree.type = erasure(tree.type);
  647           result = tree;
  648       }
  649   
  650       public void visitUnary(JCUnary tree) {
  651           tree.arg = translate(tree.arg, tree.operator.type.getParameterTypes().head);
  652           result = tree;
  653       }
  654   
  655       public void visitBinary(JCBinary tree) {
  656           tree.lhs = translate(tree.lhs, tree.operator.type.getParameterTypes().head);
  657           tree.rhs = translate(tree.rhs, tree.operator.type.getParameterTypes().tail.head);
  658           result = tree;
  659       }
  660   
  661       public void visitTypeCast(JCTypeCast tree) {
  662           tree.clazz = translate(tree.clazz, null);
  663           tree.type = erasure(tree.type);
  664           tree.expr = translate(tree.expr, tree.type);
  665           result = tree;
  666       }
  667   
  668       public void visitTypeTest(JCInstanceOf tree) {
  669           tree.expr = translate(tree.expr, null);
  670           tree.clazz = translate(tree.clazz, null);
  671           result = tree;
  672       }
  673   
  674       public void visitIndexed(JCArrayAccess tree) {
  675           tree.indexed = translate(tree.indexed, erasure(tree.indexed.type));
  676           tree.index = translate(tree.index, syms.intType);
  677   
  678           // Insert casts of indexed expressions as needed.
  679           result = retype(tree, types.elemtype(tree.indexed.type), pt);
  680       }
  681   
  682       // There ought to be nothing to rewrite here;
  683       // we don't generate code.
  684       public void visitAnnotation(JCAnnotation tree) {
  685           result = tree;
  686       }
  687   
  688       public void visitIdent(JCIdent tree) {
  689           Type et = tree.sym.erasure(types);
  690   
  691           // Map type variables to their bounds.
  692           if (tree.sym.kind == TYP && tree.sym.type.tag == TYPEVAR) {
  693               result = make.at(tree.pos).Type(et);
  694           } else
  695           // Map constants expressions to themselves.
  696           if (tree.type.constValue() != null) {
  697               result = tree;
  698           }
  699           // Insert casts of variable uses as needed.
  700           else if (tree.sym.kind == VAR) {
  701               result = retype(tree, et, pt);
  702           }
  703           else {
  704               tree.type = erasure(tree.type);
  705               result = tree;
  706           }
  707       }
  708   
  709       public void visitSelect(JCFieldAccess tree) {
  710           Type t = tree.selected.type;
  711           while (t.tag == TYPEVAR)
  712               t = t.getUpperBound();
  713           if (t.isCompound()) {
  714               if ((tree.sym.flags() & IPROXY) != 0) {
  715                   tree.sym = ((MethodSymbol)tree.sym).
  716                       implemented((TypeSymbol)tree.sym.owner, types);
  717               }
  718               tree.selected = coerce(
  719                   translate(tree.selected, erasure(tree.selected.type)),
  720                   erasure(tree.sym.owner.type));
  721           } else
  722               tree.selected = translate(tree.selected, erasure(t));
  723   
  724           // Map constants expressions to themselves.
  725           if (tree.type.constValue() != null) {
  726               result = tree;
  727           }
  728           // Insert casts of variable uses as needed.
  729           else if (tree.sym.kind == VAR) {
  730               result = retype(tree, tree.sym.erasure(types), pt);
  731           }
  732           else {
  733               tree.type = erasure(tree.type);
  734               result = tree;
  735           }
  736       }
  737   
  738       public void visitTypeArray(JCArrayTypeTree tree) {
  739           tree.elemtype = translate(tree.elemtype, null);
  740           tree.type = erasure(tree.type);
  741           result = tree;
  742       }
  743   
  744       /** Visitor method for parameterized types.
  745        */
  746       public void visitTypeApply(JCTypeApply tree) {
  747           JCTree clazz = translate(tree.clazz, null);
  748           result = clazz;
  749       }
  750   
  751   /**************************************************************************
  752    * utility methods
  753    *************************************************************************/
  754   
  755       private Type erasure(Type t) {
  756           return types.erasure(t);
  757       }
  758   
  759       private boolean boundsRestricted(ClassSymbol c) {
  760           Type st = types.supertype(c.type);
  761           if (st.isParameterized()) {
  762               List<Type> actuals = st.allparams();
  763               List<Type> formals = st.tsym.type.allparams();
  764               while (!actuals.isEmpty() && !formals.isEmpty()) {
  765                   Type actual = actuals.head;
  766                   Type formal = formals.head;
  767   
  768                   if (!types.isSameType(types.erasure(actual),
  769                           types.erasure(formal)))
  770                       return true;
  771   
  772                   actuals = actuals.tail;
  773                   formals = formals.tail;
  774               }
  775           }
  776           return false;
  777       }
  778   
  779       private List<JCTree> addOverrideBridgesIfNeeded(DiagnosticPosition pos,
  780                                       final ClassSymbol c) {
  781           ListBuffer<JCTree> buf = ListBuffer.lb();
  782           if (c.isInterface() || !boundsRestricted(c))
  783               return buf.toList();
  784           Type t = types.supertype(c.type);
  785               Scope s = t.tsym.members();
  786               if (s.elems != null) {
  787                   for (Symbol sym : s.getElements(new NeedsOverridBridgeFilter(c))) {
  788   
  789                       MethodSymbol m = (MethodSymbol)sym;
  790                       MethodSymbol member = (MethodSymbol)m.asMemberOf(c.type, types);
  791                       MethodSymbol impl = m.implementation(c, types, false);
  792   
  793                       if ((impl == null || impl.owner != c) &&
  794                               !types.isSameType(member.erasure(types), m.erasure(types))) {
  795                           addOverrideBridges(pos, m, member, c, buf);
  796                       }
  797                   }
  798               }
  799           return buf.toList();
  800       }
  801       // where
  802           class NeedsOverridBridgeFilter implements Filter<Symbol> {
  803   
  804               ClassSymbol c;
  805   
  806               NeedsOverridBridgeFilter(ClassSymbol c) {
  807                   this.c = c;
  808               }
  809               public boolean accepts(Symbol s) {
  810                   return s.kind == MTH &&
  811                               !s.isConstructor() &&
  812                               s.isInheritedIn(c, types) &&
  813                               (s.flags() & FINAL) == 0 &&
  814                               (s.flags() & (SYNTHETIC | OVERRIDE_BRIDGE)) != SYNTHETIC;
  815               }
  816           }
  817   
  818       private void addOverrideBridges(DiagnosticPosition pos,
  819                                       MethodSymbol impl,
  820                                       MethodSymbol member,
  821                                       ClassSymbol c,
  822                                       ListBuffer<JCTree> bridges) {
  823           Type implErasure = impl.erasure(types);
  824           long flags = (impl.flags() & AccessFlags) | SYNTHETIC | BRIDGE | OVERRIDE_BRIDGE;
  825           member = new MethodSymbol(flags, member.name, member.type, c);
  826           JCMethodDecl md = make.MethodDef(member, null);
  827           JCExpression receiver = make.Super(types.supertype(c.type).tsym.erasure(types), c);
  828           Type calltype = erasure(impl.type.getReturnType());
  829           JCExpression call =
  830               make.Apply(null,
  831                          make.Select(receiver, impl).setType(calltype),
  832                          translateArgs(make.Idents(md.params),
  833                                        implErasure.getParameterTypes(), null))
  834               .setType(calltype);
  835           JCStatement stat = (member.getReturnType().tag == VOID)
  836               ? make.Exec(call)
  837               : make.Return(coerce(call, member.erasure(types).getReturnType()));
  838           md.body = make.Block(0, List.of(stat));
  839           c.members().enter(member);
  840           bridges.append(md);
  841       }
  842   
  843   /**************************************************************************
  844    * main method
  845    *************************************************************************/
  846   
  847       private Env<AttrContext> env;
  848   
  849       void translateClass(ClassSymbol c) {
  850           Type st = types.supertype(c.type);
  851   
  852           // process superclass before derived
  853           if (st.tag == CLASS)
  854               translateClass((ClassSymbol)st.tsym);
  855   
  856           Env<AttrContext> myEnv = enter.typeEnvs.remove(c);
  857           if (myEnv == null)
  858               return;
  859           Env<AttrContext> oldEnv = env;
  860           try {
  861               env = myEnv;
  862               // class has not been translated yet
  863   
  864               TreeMaker savedMake = make;
  865               Type savedPt = pt;
  866               make = make.forToplevel(env.toplevel);
  867               pt = null;
  868               try {
  869                   JCClassDecl tree = (JCClassDecl) env.tree;
  870                   tree.typarams = List.nil();
  871                   super.visitClassDef(tree);
  872                   make.at(tree.pos);
  873                   if (addBridges) {
  874                       ListBuffer<JCTree> bridges = new ListBuffer<JCTree>();
  875                       if (false) //see CR: 6996415
  876                           bridges.appendList(addOverrideBridgesIfNeeded(tree, c));
  877                       if ((tree.sym.flags() & INTERFACE) == 0)
  878                           addBridges(tree.pos(), tree.sym, bridges);
  879                       tree.defs = bridges.toList().prependList(tree.defs);
  880                   }
  881                   tree.type = erasure(tree.type);
  882               } finally {
  883                   make = savedMake;
  884                   pt = savedPt;
  885               }
  886           } finally {
  887               env = oldEnv;
  888           }
  889       }
  890   
  891       /** Translate a toplevel class definition.
  892        *  @param cdef    The definition to be translated.
  893        */
  894       public JCTree translateTopLevelClass(JCTree cdef, TreeMaker make) {
  895           // note that this method does NOT support recursion.
  896           this.make = make;
  897           pt = null;
  898           return translate(cdef, null);
  899       }
  900   }

Home » openjdk-7 » com.sun.tools » javac » comp » [javadoc | source]