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

Tue, 12 Mar 2013 16:02:13 +0000

author
mcimadamore
date
Tue, 12 Mar 2013 16:02:13 +0000
changeset 1627
6db9a3b1a93f
parent 1623
c61add6bf8ac
child 1640
fa24eba012bd
permissions
-rw-r--r--

8008540: Constructor reference to non-reifiable array should be rejected
8008539: Spurious error when constructor reference mention an interface type
8008538: Constructor reference accepts wildcard parameterized types
Summary: Overhaul of Check.checkConstructorRefType
Reviewed-by: jjg

     1 /*
     2  * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package com.sun.tools.javac.comp;
    28 import java.util.*;
    30 import com.sun.tools.javac.code.*;
    31 import com.sun.tools.javac.jvm.*;
    32 import com.sun.tools.javac.main.Option.PkgInfo;
    33 import com.sun.tools.javac.tree.*;
    34 import com.sun.tools.javac.util.*;
    35 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    36 import com.sun.tools.javac.util.List;
    38 import com.sun.tools.javac.code.Symbol.*;
    39 import com.sun.tools.javac.tree.JCTree.*;
    40 import com.sun.tools.javac.code.Type.*;
    42 import com.sun.tools.javac.jvm.Target;
    43 import com.sun.tools.javac.tree.EndPosTable;
    45 import static com.sun.tools.javac.code.Flags.*;
    46 import static com.sun.tools.javac.code.Flags.BLOCK;
    47 import static com.sun.tools.javac.code.Kinds.*;
    48 import static com.sun.tools.javac.code.TypeTag.*;
    49 import static com.sun.tools.javac.jvm.ByteCodes.*;
    50 import static com.sun.tools.javac.tree.JCTree.Tag.*;
    52 /** This pass translates away some syntactic sugar: inner classes,
    53  *  class literals, assertions, foreach loops, etc.
    54  *
    55  *  <p><b>This is NOT part of any supported API.
    56  *  If you write code that depends on this, you do so at your own risk.
    57  *  This code and its internal interfaces are subject to change or
    58  *  deletion without notice.</b>
    59  */
    60 public class Lower extends TreeTranslator {
    61     protected static final Context.Key<Lower> lowerKey =
    62         new Context.Key<Lower>();
    64     public static Lower instance(Context context) {
    65         Lower instance = context.get(lowerKey);
    66         if (instance == null)
    67             instance = new Lower(context);
    68         return instance;
    69     }
    71     private Names names;
    72     private Log log;
    73     private Symtab syms;
    74     private Resolve rs;
    75     private Check chk;
    76     private Attr attr;
    77     private TreeMaker make;
    78     private DiagnosticPosition make_pos;
    79     private ClassWriter writer;
    80     private ClassReader reader;
    81     private ConstFold cfolder;
    82     private Target target;
    83     private Source source;
    84     private boolean allowEnums;
    85     private final Name dollarAssertionsDisabled;
    86     private final Name classDollar;
    87     private Types types;
    88     private boolean debugLower;
    89     private PkgInfo pkginfoOpt;
    91     protected Lower(Context context) {
    92         context.put(lowerKey, this);
    93         names = Names.instance(context);
    94         log = Log.instance(context);
    95         syms = Symtab.instance(context);
    96         rs = Resolve.instance(context);
    97         chk = Check.instance(context);
    98         attr = Attr.instance(context);
    99         make = TreeMaker.instance(context);
   100         writer = ClassWriter.instance(context);
   101         reader = ClassReader.instance(context);
   102         cfolder = ConstFold.instance(context);
   103         target = Target.instance(context);
   104         source = Source.instance(context);
   105         allowEnums = source.allowEnums();
   106         dollarAssertionsDisabled = names.
   107             fromString(target.syntheticNameChar() + "assertionsDisabled");
   108         classDollar = names.
   109             fromString("class" + target.syntheticNameChar());
   111         types = Types.instance(context);
   112         Options options = Options.instance(context);
   113         debugLower = options.isSet("debuglower");
   114         pkginfoOpt = PkgInfo.get(options);
   115     }
   117     /** The currently enclosing class.
   118      */
   119     ClassSymbol currentClass;
   121     /** A queue of all translated classes.
   122      */
   123     ListBuffer<JCTree> translated;
   125     /** Environment for symbol lookup, set by translateTopLevelClass.
   126      */
   127     Env<AttrContext> attrEnv;
   129     /** A hash table mapping syntax trees to their ending source positions.
   130      */
   131     EndPosTable endPosTable;
   133 /**************************************************************************
   134  * Global mappings
   135  *************************************************************************/
   137     /** A hash table mapping local classes to their definitions.
   138      */
   139     Map<ClassSymbol, JCClassDecl> classdefs;
   141     /** A hash table mapping local classes to a list of pruned trees.
   142      */
   143     public Map<ClassSymbol, List<JCTree>> prunedTree = new WeakHashMap<ClassSymbol, List<JCTree>>();
   145     /** A hash table mapping virtual accessed symbols in outer subclasses
   146      *  to the actually referred symbol in superclasses.
   147      */
   148     Map<Symbol,Symbol> actualSymbols;
   150     /** The current method definition.
   151      */
   152     JCMethodDecl currentMethodDef;
   154     /** The current method symbol.
   155      */
   156     MethodSymbol currentMethodSym;
   158     /** The currently enclosing outermost class definition.
   159      */
   160     JCClassDecl outermostClassDef;
   162     /** The currently enclosing outermost member definition.
   163      */
   164     JCTree outermostMemberDef;
   166     /** A map from local variable symbols to their translation (as per LambdaToMethod).
   167      * This is required when a capturing local class is created from a lambda (in which
   168      * case the captured symbols should be replaced with the translated lambda symbols).
   169      */
   170     Map<Symbol, Symbol> lambdaTranslationMap = null;
   172     /** A navigator class for assembling a mapping from local class symbols
   173      *  to class definition trees.
   174      *  There is only one case; all other cases simply traverse down the tree.
   175      */
   176     class ClassMap extends TreeScanner {
   178         /** All encountered class defs are entered into classdefs table.
   179          */
   180         public void visitClassDef(JCClassDecl tree) {
   181             classdefs.put(tree.sym, tree);
   182             super.visitClassDef(tree);
   183         }
   184     }
   185     ClassMap classMap = new ClassMap();
   187     /** Map a class symbol to its definition.
   188      *  @param c    The class symbol of which we want to determine the definition.
   189      */
   190     JCClassDecl classDef(ClassSymbol c) {
   191         // First lookup the class in the classdefs table.
   192         JCClassDecl def = classdefs.get(c);
   193         if (def == null && outermostMemberDef != null) {
   194             // If this fails, traverse outermost member definition, entering all
   195             // local classes into classdefs, and try again.
   196             classMap.scan(outermostMemberDef);
   197             def = classdefs.get(c);
   198         }
   199         if (def == null) {
   200             // If this fails, traverse outermost class definition, entering all
   201             // local classes into classdefs, and try again.
   202             classMap.scan(outermostClassDef);
   203             def = classdefs.get(c);
   204         }
   205         return def;
   206     }
   208     /** A hash table mapping class symbols to lists of free variables.
   209      *  accessed by them. Only free variables of the method immediately containing
   210      *  a class are associated with that class.
   211      */
   212     Map<ClassSymbol,List<VarSymbol>> freevarCache;
   214     /** A navigator class for collecting the free variables accessed
   215      *  from a local class. There is only one case; all other cases simply
   216      *  traverse down the tree. This class doesn't deal with the specific
   217      *  of Lower - it's an abstract visitor that is meant to be reused in
   218      *  order to share the local variable capture logic.
   219      */
   220     abstract class BasicFreeVarCollector extends TreeScanner {
   222         /** Add all free variables of class c to fvs list
   223          *  unless they are already there.
   224          */
   225         abstract void addFreeVars(ClassSymbol c);
   227         /** If tree refers to a variable in owner of local class, add it to
   228          *  free variables list.
   229          */
   230         public void visitIdent(JCIdent tree) {
   231             visitSymbol(tree.sym);
   232         }
   233         // where
   234         abstract void visitSymbol(Symbol _sym);
   236         /** If tree refers to a class instance creation expression
   237          *  add all free variables of the freshly created class.
   238          */
   239         public void visitNewClass(JCNewClass tree) {
   240             ClassSymbol c = (ClassSymbol)tree.constructor.owner;
   241             addFreeVars(c);
   242             super.visitNewClass(tree);
   243         }
   245         /** If tree refers to a superclass constructor call,
   246          *  add all free variables of the superclass.
   247          */
   248         public void visitApply(JCMethodInvocation tree) {
   249             if (TreeInfo.name(tree.meth) == names._super) {
   250                 addFreeVars((ClassSymbol) TreeInfo.symbol(tree.meth).owner);
   251             }
   252             super.visitApply(tree);
   253         }
   254     }
   256     /**
   257      * Lower-specific subclass of {@code BasicFreeVarCollector}.
   258      */
   259     class FreeVarCollector extends BasicFreeVarCollector {
   261         /** The owner of the local class.
   262          */
   263         Symbol owner;
   265         /** The local class.
   266          */
   267         ClassSymbol clazz;
   269         /** The list of owner's variables accessed from within the local class,
   270          *  without any duplicates.
   271          */
   272         List<VarSymbol> fvs;
   274         FreeVarCollector(ClassSymbol clazz) {
   275             this.clazz = clazz;
   276             this.owner = clazz.owner;
   277             this.fvs = List.nil();
   278         }
   280         /** Add free variable to fvs list unless it is already there.
   281          */
   282         private void addFreeVar(VarSymbol v) {
   283             for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail)
   284                 if (l.head == v) return;
   285             fvs = fvs.prepend(v);
   286         }
   288         @Override
   289         void addFreeVars(ClassSymbol c) {
   290             List<VarSymbol> fvs = freevarCache.get(c);
   291             if (fvs != null) {
   292                 for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail) {
   293                     addFreeVar(l.head);
   294                 }
   295             }
   296         }
   298         @Override
   299         void visitSymbol(Symbol _sym) {
   300             Symbol sym = _sym;
   301             if (sym.kind == VAR || sym.kind == MTH) {
   302                 while (sym != null && sym.owner != owner)
   303                     sym = proxies.lookup(proxyName(sym.name)).sym;
   304                 if (sym != null && sym.owner == owner) {
   305                     VarSymbol v = (VarSymbol)sym;
   306                     if (v.getConstValue() == null) {
   307                         addFreeVar(v);
   308                     }
   309                 } else {
   310                     if (outerThisStack.head != null &&
   311                         outerThisStack.head != _sym)
   312                         visitSymbol(outerThisStack.head);
   313                 }
   314             }
   315         }
   317         /** If tree refers to a class instance creation expression
   318          *  add all free variables of the freshly created class.
   319          */
   320         public void visitNewClass(JCNewClass tree) {
   321             ClassSymbol c = (ClassSymbol)tree.constructor.owner;
   322             if (tree.encl == null &&
   323                 c.hasOuterInstance() &&
   324                 outerThisStack.head != null)
   325                 visitSymbol(outerThisStack.head);
   326             super.visitNewClass(tree);
   327         }
   329         /** If tree refers to a qualified this or super expression
   330          *  for anything but the current class, add the outer this
   331          *  stack as a free variable.
   332          */
   333         public void visitSelect(JCFieldAccess tree) {
   334             if ((tree.name == names._this || tree.name == names._super) &&
   335                 tree.selected.type.tsym != clazz &&
   336                 outerThisStack.head != null)
   337                 visitSymbol(outerThisStack.head);
   338             super.visitSelect(tree);
   339         }
   341         /** If tree refers to a superclass constructor call,
   342          *  add all free variables of the superclass.
   343          */
   344         public void visitApply(JCMethodInvocation tree) {
   345             if (TreeInfo.name(tree.meth) == names._super) {
   346                 Symbol constructor = TreeInfo.symbol(tree.meth);
   347                 ClassSymbol c = (ClassSymbol)constructor.owner;
   348                 if (c.hasOuterInstance() &&
   349                     !tree.meth.hasTag(SELECT) &&
   350                     outerThisStack.head != null)
   351                     visitSymbol(outerThisStack.head);
   352             }
   353             super.visitApply(tree);
   354         }
   355     }
   357     /** Return the variables accessed from within a local class, which
   358      *  are declared in the local class' owner.
   359      *  (in reverse order of first access).
   360      */
   361     List<VarSymbol> freevars(ClassSymbol c)  {
   362         if ((c.owner.kind & (VAR | MTH)) != 0) {
   363             List<VarSymbol> fvs = freevarCache.get(c);
   364             if (fvs == null) {
   365                 FreeVarCollector collector = new FreeVarCollector(c);
   366                 collector.scan(classDef(c));
   367                 fvs = collector.fvs;
   368                 freevarCache.put(c, fvs);
   369             }
   370             return fvs;
   371         } else {
   372             return List.nil();
   373         }
   374     }
   376     Map<TypeSymbol,EnumMapping> enumSwitchMap = new LinkedHashMap<TypeSymbol,EnumMapping>();
   378     EnumMapping mapForEnum(DiagnosticPosition pos, TypeSymbol enumClass) {
   379         EnumMapping map = enumSwitchMap.get(enumClass);
   380         if (map == null)
   381             enumSwitchMap.put(enumClass, map = new EnumMapping(pos, enumClass));
   382         return map;
   383     }
   385     /** This map gives a translation table to be used for enum
   386      *  switches.
   387      *
   388      *  <p>For each enum that appears as the type of a switch
   389      *  expression, we maintain an EnumMapping to assist in the
   390      *  translation, as exemplified by the following example:
   391      *
   392      *  <p>we translate
   393      *  <pre>
   394      *          switch(colorExpression) {
   395      *          case red: stmt1;
   396      *          case green: stmt2;
   397      *          }
   398      *  </pre>
   399      *  into
   400      *  <pre>
   401      *          switch(Outer$0.$EnumMap$Color[colorExpression.ordinal()]) {
   402      *          case 1: stmt1;
   403      *          case 2: stmt2
   404      *          }
   405      *  </pre>
   406      *  with the auxiliary table initialized as follows:
   407      *  <pre>
   408      *          class Outer$0 {
   409      *              synthetic final int[] $EnumMap$Color = new int[Color.values().length];
   410      *              static {
   411      *                  try { $EnumMap$Color[red.ordinal()] = 1; } catch (NoSuchFieldError ex) {}
   412      *                  try { $EnumMap$Color[green.ordinal()] = 2; } catch (NoSuchFieldError ex) {}
   413      *              }
   414      *          }
   415      *  </pre>
   416      *  class EnumMapping provides mapping data and support methods for this translation.
   417      */
   418     class EnumMapping {
   419         EnumMapping(DiagnosticPosition pos, TypeSymbol forEnum) {
   420             this.forEnum = forEnum;
   421             this.values = new LinkedHashMap<VarSymbol,Integer>();
   422             this.pos = pos;
   423             Name varName = names
   424                 .fromString(target.syntheticNameChar() +
   425                             "SwitchMap" +
   426                             target.syntheticNameChar() +
   427                             writer.xClassName(forEnum.type).toString()
   428                             .replace('/', '.')
   429                             .replace('.', target.syntheticNameChar()));
   430             ClassSymbol outerCacheClass = outerCacheClass();
   431             this.mapVar = new VarSymbol(STATIC | SYNTHETIC | FINAL,
   432                                         varName,
   433                                         new ArrayType(syms.intType, syms.arrayClass),
   434                                         outerCacheClass);
   435             enterSynthetic(pos, mapVar, outerCacheClass.members());
   436         }
   438         DiagnosticPosition pos = null;
   440         // the next value to use
   441         int next = 1; // 0 (unused map elements) go to the default label
   443         // the enum for which this is a map
   444         final TypeSymbol forEnum;
   446         // the field containing the map
   447         final VarSymbol mapVar;
   449         // the mapped values
   450         final Map<VarSymbol,Integer> values;
   452         JCLiteral forConstant(VarSymbol v) {
   453             Integer result = values.get(v);
   454             if (result == null)
   455                 values.put(v, result = next++);
   456             return make.Literal(result);
   457         }
   459         // generate the field initializer for the map
   460         void translate() {
   461             make.at(pos.getStartPosition());
   462             JCClassDecl owner = classDef((ClassSymbol)mapVar.owner);
   464             // synthetic static final int[] $SwitchMap$Color = new int[Color.values().length];
   465             MethodSymbol valuesMethod = lookupMethod(pos,
   466                                                      names.values,
   467                                                      forEnum.type,
   468                                                      List.<Type>nil());
   469             JCExpression size = make // Color.values().length
   470                 .Select(make.App(make.QualIdent(valuesMethod)),
   471                         syms.lengthVar);
   472             JCExpression mapVarInit = make
   473                 .NewArray(make.Type(syms.intType), List.of(size), null)
   474                 .setType(new ArrayType(syms.intType, syms.arrayClass));
   476             // try { $SwitchMap$Color[red.ordinal()] = 1; } catch (java.lang.NoSuchFieldError ex) {}
   477             ListBuffer<JCStatement> stmts = new ListBuffer<JCStatement>();
   478             Symbol ordinalMethod = lookupMethod(pos,
   479                                                 names.ordinal,
   480                                                 forEnum.type,
   481                                                 List.<Type>nil());
   482             List<JCCatch> catcher = List.<JCCatch>nil()
   483                 .prepend(make.Catch(make.VarDef(new VarSymbol(PARAMETER, names.ex,
   484                                                               syms.noSuchFieldErrorType,
   485                                                               syms.noSymbol),
   486                                                 null),
   487                                     make.Block(0, List.<JCStatement>nil())));
   488             for (Map.Entry<VarSymbol,Integer> e : values.entrySet()) {
   489                 VarSymbol enumerator = e.getKey();
   490                 Integer mappedValue = e.getValue();
   491                 JCExpression assign = make
   492                     .Assign(make.Indexed(mapVar,
   493                                          make.App(make.Select(make.QualIdent(enumerator),
   494                                                               ordinalMethod))),
   495                             make.Literal(mappedValue))
   496                     .setType(syms.intType);
   497                 JCStatement exec = make.Exec(assign);
   498                 JCStatement _try = make.Try(make.Block(0, List.of(exec)), catcher, null);
   499                 stmts.append(_try);
   500             }
   502             owner.defs = owner.defs
   503                 .prepend(make.Block(STATIC, stmts.toList()))
   504                 .prepend(make.VarDef(mapVar, mapVarInit));
   505         }
   506     }
   509 /**************************************************************************
   510  * Tree building blocks
   511  *************************************************************************/
   513     /** Equivalent to make.at(pos.getStartPosition()) with side effect of caching
   514      *  pos as make_pos, for use in diagnostics.
   515      **/
   516     TreeMaker make_at(DiagnosticPosition pos) {
   517         make_pos = pos;
   518         return make.at(pos);
   519     }
   521     /** Make an attributed tree representing a literal. This will be an
   522      *  Ident node in the case of boolean literals, a Literal node in all
   523      *  other cases.
   524      *  @param type       The literal's type.
   525      *  @param value      The literal's value.
   526      */
   527     JCExpression makeLit(Type type, Object value) {
   528         return make.Literal(type.getTag(), value).setType(type.constType(value));
   529     }
   531     /** Make an attributed tree representing null.
   532      */
   533     JCExpression makeNull() {
   534         return makeLit(syms.botType, null);
   535     }
   537     /** Make an attributed class instance creation expression.
   538      *  @param ctype    The class type.
   539      *  @param args     The constructor arguments.
   540      */
   541     JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
   542         JCNewClass tree = make.NewClass(null,
   543             null, make.QualIdent(ctype.tsym), args, null);
   544         tree.constructor = rs.resolveConstructor(
   545             make_pos, attrEnv, ctype, TreeInfo.types(args), List.<Type>nil());
   546         tree.type = ctype;
   547         return tree;
   548     }
   550     /** Make an attributed unary expression.
   551      *  @param optag    The operators tree tag.
   552      *  @param arg      The operator's argument.
   553      */
   554     JCUnary makeUnary(JCTree.Tag optag, JCExpression arg) {
   555         JCUnary tree = make.Unary(optag, arg);
   556         tree.operator = rs.resolveUnaryOperator(
   557             make_pos, optag, attrEnv, arg.type);
   558         tree.type = tree.operator.type.getReturnType();
   559         return tree;
   560     }
   562     /** Make an attributed binary expression.
   563      *  @param optag    The operators tree tag.
   564      *  @param lhs      The operator's left argument.
   565      *  @param rhs      The operator's right argument.
   566      */
   567     JCBinary makeBinary(JCTree.Tag optag, JCExpression lhs, JCExpression rhs) {
   568         JCBinary tree = make.Binary(optag, lhs, rhs);
   569         tree.operator = rs.resolveBinaryOperator(
   570             make_pos, optag, attrEnv, lhs.type, rhs.type);
   571         tree.type = tree.operator.type.getReturnType();
   572         return tree;
   573     }
   575     /** Make an attributed assignop expression.
   576      *  @param optag    The operators tree tag.
   577      *  @param lhs      The operator's left argument.
   578      *  @param rhs      The operator's right argument.
   579      */
   580     JCAssignOp makeAssignop(JCTree.Tag optag, JCTree lhs, JCTree rhs) {
   581         JCAssignOp tree = make.Assignop(optag, lhs, rhs);
   582         tree.operator = rs.resolveBinaryOperator(
   583             make_pos, tree.getTag().noAssignOp(), attrEnv, lhs.type, rhs.type);
   584         tree.type = lhs.type;
   585         return tree;
   586     }
   588     /** Convert tree into string object, unless it has already a
   589      *  reference type..
   590      */
   591     JCExpression makeString(JCExpression tree) {
   592         if (!tree.type.isPrimitiveOrVoid()) {
   593             return tree;
   594         } else {
   595             Symbol valueOfSym = lookupMethod(tree.pos(),
   596                                              names.valueOf,
   597                                              syms.stringType,
   598                                              List.of(tree.type));
   599             return make.App(make.QualIdent(valueOfSym), List.of(tree));
   600         }
   601     }
   603     /** Create an empty anonymous class definition and enter and complete
   604      *  its symbol. Return the class definition's symbol.
   605      *  and create
   606      *  @param flags    The class symbol's flags
   607      *  @param owner    The class symbol's owner
   608      */
   609     JCClassDecl makeEmptyClass(long flags, ClassSymbol owner) {
   610         return makeEmptyClass(flags, owner, null, true);
   611     }
   613     JCClassDecl makeEmptyClass(long flags, ClassSymbol owner, Name flatname,
   614             boolean addToDefs) {
   615         // Create class symbol.
   616         ClassSymbol c = reader.defineClass(names.empty, owner);
   617         if (flatname != null) {
   618             c.flatname = flatname;
   619         } else {
   620             c.flatname = chk.localClassName(c);
   621         }
   622         c.sourcefile = owner.sourcefile;
   623         c.completer = null;
   624         c.members_field = new Scope(c);
   625         c.flags_field = flags;
   626         ClassType ctype = (ClassType) c.type;
   627         ctype.supertype_field = syms.objectType;
   628         ctype.interfaces_field = List.nil();
   630         JCClassDecl odef = classDef(owner);
   632         // Enter class symbol in owner scope and compiled table.
   633         enterSynthetic(odef.pos(), c, owner.members());
   634         chk.compiled.put(c.flatname, c);
   636         // Create class definition tree.
   637         JCClassDecl cdef = make.ClassDef(
   638             make.Modifiers(flags), names.empty,
   639             List.<JCTypeParameter>nil(),
   640             null, List.<JCExpression>nil(), List.<JCTree>nil());
   641         cdef.sym = c;
   642         cdef.type = c.type;
   644         // Append class definition tree to owner's definitions.
   645         if (addToDefs) odef.defs = odef.defs.prepend(cdef);
   646         return cdef;
   647     }
   649 /**************************************************************************
   650  * Symbol manipulation utilities
   651  *************************************************************************/
   653     /** Enter a synthetic symbol in a given scope, but complain if there was already one there.
   654      *  @param pos           Position for error reporting.
   655      *  @param sym           The symbol.
   656      *  @param s             The scope.
   657      */
   658     private void enterSynthetic(DiagnosticPosition pos, Symbol sym, Scope s) {
   659         s.enter(sym);
   660     }
   662     /** Create a fresh synthetic name within a given scope - the unique name is
   663      *  obtained by appending '$' chars at the end of the name until no match
   664      *  is found.
   665      *
   666      * @param name base name
   667      * @param s scope in which the name has to be unique
   668      * @return fresh synthetic name
   669      */
   670     private Name makeSyntheticName(Name name, Scope s) {
   671         do {
   672             name = name.append(
   673                     target.syntheticNameChar(),
   674                     names.empty);
   675         } while (lookupSynthetic(name, s) != null);
   676         return name;
   677     }
   679     /** Check whether synthetic symbols generated during lowering conflict
   680      *  with user-defined symbols.
   681      *
   682      *  @param translatedTrees lowered class trees
   683      */
   684     void checkConflicts(List<JCTree> translatedTrees) {
   685         for (JCTree t : translatedTrees) {
   686             t.accept(conflictsChecker);
   687         }
   688     }
   690     JCTree.Visitor conflictsChecker = new TreeScanner() {
   692         TypeSymbol currentClass;
   694         @Override
   695         public void visitMethodDef(JCMethodDecl that) {
   696             chk.checkConflicts(that.pos(), that.sym, currentClass);
   697             super.visitMethodDef(that);
   698         }
   700         @Override
   701         public void visitVarDef(JCVariableDecl that) {
   702             if (that.sym.owner.kind == TYP) {
   703                 chk.checkConflicts(that.pos(), that.sym, currentClass);
   704             }
   705             super.visitVarDef(that);
   706         }
   708         @Override
   709         public void visitClassDef(JCClassDecl that) {
   710             TypeSymbol prevCurrentClass = currentClass;
   711             currentClass = that.sym;
   712             try {
   713                 super.visitClassDef(that);
   714             }
   715             finally {
   716                 currentClass = prevCurrentClass;
   717             }
   718         }
   719     };
   721     /** Look up a synthetic name in a given scope.
   722      *  @param s            The scope.
   723      *  @param name         The name.
   724      */
   725     private Symbol lookupSynthetic(Name name, Scope s) {
   726         Symbol sym = s.lookup(name).sym;
   727         return (sym==null || (sym.flags()&SYNTHETIC)==0) ? null : sym;
   728     }
   730     /** Look up a method in a given scope.
   731      */
   732     private MethodSymbol lookupMethod(DiagnosticPosition pos, Name name, Type qual, List<Type> args) {
   733         return rs.resolveInternalMethod(pos, attrEnv, qual, name, args, List.<Type>nil());
   734     }
   736     /** Look up a constructor.
   737      */
   738     private MethodSymbol lookupConstructor(DiagnosticPosition pos, Type qual, List<Type> args) {
   739         return rs.resolveInternalConstructor(pos, attrEnv, qual, args, null);
   740     }
   742     /** Look up a field.
   743      */
   744     private VarSymbol lookupField(DiagnosticPosition pos, Type qual, Name name) {
   745         return rs.resolveInternalField(pos, attrEnv, qual, name);
   746     }
   748     /** Anon inner classes are used as access constructor tags.
   749      * accessConstructorTag will use an existing anon class if one is available,
   750      * and synthethise a class (with makeEmptyClass) if one is not available.
   751      * However, there is a small possibility that an existing class will not
   752      * be generated as expected if it is inside a conditional with a constant
   753      * expression. If that is found to be the case, create an empty class tree here.
   754      */
   755     private void checkAccessConstructorTags() {
   756         for (List<ClassSymbol> l = accessConstrTags; l.nonEmpty(); l = l.tail) {
   757             ClassSymbol c = l.head;
   758             if (isTranslatedClassAvailable(c))
   759                 continue;
   760             // Create class definition tree.
   761             JCClassDecl cdec = makeEmptyClass(STATIC | SYNTHETIC,
   762                     c.outermostClass(), c.flatname, false);
   763             swapAccessConstructorTag(c, cdec.sym);
   764             translated.append(cdec);
   765         }
   766     }
   767     // where
   768     private boolean isTranslatedClassAvailable(ClassSymbol c) {
   769         for (JCTree tree: translated) {
   770             if (tree.hasTag(CLASSDEF)
   771                     && ((JCClassDecl) tree).sym == c) {
   772                 return true;
   773             }
   774         }
   775         return false;
   776     }
   778     void swapAccessConstructorTag(ClassSymbol oldCTag, ClassSymbol newCTag) {
   779         for (MethodSymbol methodSymbol : accessConstrs.values()) {
   780             Assert.check(methodSymbol.type.hasTag(METHOD));
   781             MethodType oldMethodType =
   782                     (MethodType)methodSymbol.type;
   783             if (oldMethodType.argtypes.head.tsym == oldCTag)
   784                 methodSymbol.type =
   785                     types.createMethodTypeWithParameters(oldMethodType,
   786                         oldMethodType.getParameterTypes().tail
   787                             .prepend(newCTag.erasure(types)));
   788         }
   789     }
   791 /**************************************************************************
   792  * Access methods
   793  *************************************************************************/
   795     /** Access codes for dereferencing, assignment,
   796      *  and pre/post increment/decrement.
   797      *  Access codes for assignment operations are determined by method accessCode
   798      *  below.
   799      *
   800      *  All access codes for accesses to the current class are even.
   801      *  If a member of the superclass should be accessed instead (because
   802      *  access was via a qualified super), add one to the corresponding code
   803      *  for the current class, making the number odd.
   804      *  This numbering scheme is used by the backend to decide whether
   805      *  to issue an invokevirtual or invokespecial call.
   806      *
   807      *  @see Gen#visitSelect(JCFieldAccess tree)
   808      */
   809     private static final int
   810         DEREFcode = 0,
   811         ASSIGNcode = 2,
   812         PREINCcode = 4,
   813         PREDECcode = 6,
   814         POSTINCcode = 8,
   815         POSTDECcode = 10,
   816         FIRSTASGOPcode = 12;
   818     /** Number of access codes
   819      */
   820     private static final int NCODES = accessCode(ByteCodes.lushrl) + 2;
   822     /** A mapping from symbols to their access numbers.
   823      */
   824     private Map<Symbol,Integer> accessNums;
   826     /** A mapping from symbols to an array of access symbols, indexed by
   827      *  access code.
   828      */
   829     private Map<Symbol,MethodSymbol[]> accessSyms;
   831     /** A mapping from (constructor) symbols to access constructor symbols.
   832      */
   833     private Map<Symbol,MethodSymbol> accessConstrs;
   835     /** A list of all class symbols used for access constructor tags.
   836      */
   837     private List<ClassSymbol> accessConstrTags;
   839     /** A queue for all accessed symbols.
   840      */
   841     private ListBuffer<Symbol> accessed;
   843     /** Map bytecode of binary operation to access code of corresponding
   844      *  assignment operation. This is always an even number.
   845      */
   846     private static int accessCode(int bytecode) {
   847         if (ByteCodes.iadd <= bytecode && bytecode <= ByteCodes.lxor)
   848             return (bytecode - iadd) * 2 + FIRSTASGOPcode;
   849         else if (bytecode == ByteCodes.string_add)
   850             return (ByteCodes.lxor + 1 - iadd) * 2 + FIRSTASGOPcode;
   851         else if (ByteCodes.ishll <= bytecode && bytecode <= ByteCodes.lushrl)
   852             return (bytecode - ishll + ByteCodes.lxor + 2 - iadd) * 2 + FIRSTASGOPcode;
   853         else
   854             return -1;
   855     }
   857     /** return access code for identifier,
   858      *  @param tree     The tree representing the identifier use.
   859      *  @param enclOp   The closest enclosing operation node of tree,
   860      *                  null if tree is not a subtree of an operation.
   861      */
   862     private static int accessCode(JCTree tree, JCTree enclOp) {
   863         if (enclOp == null)
   864             return DEREFcode;
   865         else if (enclOp.hasTag(ASSIGN) &&
   866                  tree == TreeInfo.skipParens(((JCAssign) enclOp).lhs))
   867             return ASSIGNcode;
   868         else if (enclOp.getTag().isIncOrDecUnaryOp() &&
   869                  tree == TreeInfo.skipParens(((JCUnary) enclOp).arg))
   870             return mapTagToUnaryOpCode(enclOp.getTag());
   871         else if (enclOp.getTag().isAssignop() &&
   872                  tree == TreeInfo.skipParens(((JCAssignOp) enclOp).lhs))
   873             return accessCode(((OperatorSymbol) ((JCAssignOp) enclOp).operator).opcode);
   874         else
   875             return DEREFcode;
   876     }
   878     /** Return binary operator that corresponds to given access code.
   879      */
   880     private OperatorSymbol binaryAccessOperator(int acode) {
   881         for (Scope.Entry e = syms.predefClass.members().elems;
   882              e != null;
   883              e = e.sibling) {
   884             if (e.sym instanceof OperatorSymbol) {
   885                 OperatorSymbol op = (OperatorSymbol)e.sym;
   886                 if (accessCode(op.opcode) == acode) return op;
   887             }
   888         }
   889         return null;
   890     }
   892     /** Return tree tag for assignment operation corresponding
   893      *  to given binary operator.
   894      */
   895     private static JCTree.Tag treeTag(OperatorSymbol operator) {
   896         switch (operator.opcode) {
   897         case ByteCodes.ior: case ByteCodes.lor:
   898             return BITOR_ASG;
   899         case ByteCodes.ixor: case ByteCodes.lxor:
   900             return BITXOR_ASG;
   901         case ByteCodes.iand: case ByteCodes.land:
   902             return BITAND_ASG;
   903         case ByteCodes.ishl: case ByteCodes.lshl:
   904         case ByteCodes.ishll: case ByteCodes.lshll:
   905             return SL_ASG;
   906         case ByteCodes.ishr: case ByteCodes.lshr:
   907         case ByteCodes.ishrl: case ByteCodes.lshrl:
   908             return SR_ASG;
   909         case ByteCodes.iushr: case ByteCodes.lushr:
   910         case ByteCodes.iushrl: case ByteCodes.lushrl:
   911             return USR_ASG;
   912         case ByteCodes.iadd: case ByteCodes.ladd:
   913         case ByteCodes.fadd: case ByteCodes.dadd:
   914         case ByteCodes.string_add:
   915             return PLUS_ASG;
   916         case ByteCodes.isub: case ByteCodes.lsub:
   917         case ByteCodes.fsub: case ByteCodes.dsub:
   918             return MINUS_ASG;
   919         case ByteCodes.imul: case ByteCodes.lmul:
   920         case ByteCodes.fmul: case ByteCodes.dmul:
   921             return MUL_ASG;
   922         case ByteCodes.idiv: case ByteCodes.ldiv:
   923         case ByteCodes.fdiv: case ByteCodes.ddiv:
   924             return DIV_ASG;
   925         case ByteCodes.imod: case ByteCodes.lmod:
   926         case ByteCodes.fmod: case ByteCodes.dmod:
   927             return MOD_ASG;
   928         default:
   929             throw new AssertionError();
   930         }
   931     }
   933     /** The name of the access method with number `anum' and access code `acode'.
   934      */
   935     Name accessName(int anum, int acode) {
   936         return names.fromString(
   937             "access" + target.syntheticNameChar() + anum + acode / 10 + acode % 10);
   938     }
   940     /** Return access symbol for a private or protected symbol from an inner class.
   941      *  @param sym        The accessed private symbol.
   942      *  @param tree       The accessing tree.
   943      *  @param enclOp     The closest enclosing operation node of tree,
   944      *                    null if tree is not a subtree of an operation.
   945      *  @param protAccess Is access to a protected symbol in another
   946      *                    package?
   947      *  @param refSuper   Is access via a (qualified) C.super?
   948      */
   949     MethodSymbol accessSymbol(Symbol sym, JCTree tree, JCTree enclOp,
   950                               boolean protAccess, boolean refSuper) {
   951         ClassSymbol accOwner = refSuper && protAccess
   952             // For access via qualified super (T.super.x), place the
   953             // access symbol on T.
   954             ? (ClassSymbol)((JCFieldAccess) tree).selected.type.tsym
   955             // Otherwise pretend that the owner of an accessed
   956             // protected symbol is the enclosing class of the current
   957             // class which is a subclass of the symbol's owner.
   958             : accessClass(sym, protAccess, tree);
   960         Symbol vsym = sym;
   961         if (sym.owner != accOwner) {
   962             vsym = sym.clone(accOwner);
   963             actualSymbols.put(vsym, sym);
   964         }
   966         Integer anum              // The access number of the access method.
   967             = accessNums.get(vsym);
   968         if (anum == null) {
   969             anum = accessed.length();
   970             accessNums.put(vsym, anum);
   971             accessSyms.put(vsym, new MethodSymbol[NCODES]);
   972             accessed.append(vsym);
   973             // System.out.println("accessing " + vsym + " in " + vsym.location());
   974         }
   976         int acode;                // The access code of the access method.
   977         List<Type> argtypes;      // The argument types of the access method.
   978         Type restype;             // The result type of the access method.
   979         List<Type> thrown;        // The thrown exceptions of the access method.
   980         switch (vsym.kind) {
   981         case VAR:
   982             acode = accessCode(tree, enclOp);
   983             if (acode >= FIRSTASGOPcode) {
   984                 OperatorSymbol operator = binaryAccessOperator(acode);
   985                 if (operator.opcode == string_add)
   986                     argtypes = List.of(syms.objectType);
   987                 else
   988                     argtypes = operator.type.getParameterTypes().tail;
   989             } else if (acode == ASSIGNcode)
   990                 argtypes = List.of(vsym.erasure(types));
   991             else
   992                 argtypes = List.nil();
   993             restype = vsym.erasure(types);
   994             thrown = List.nil();
   995             break;
   996         case MTH:
   997             acode = DEREFcode;
   998             argtypes = vsym.erasure(types).getParameterTypes();
   999             restype = vsym.erasure(types).getReturnType();
  1000             thrown = vsym.type.getThrownTypes();
  1001             break;
  1002         default:
  1003             throw new AssertionError();
  1006         // For references via qualified super, increment acode by one,
  1007         // making it odd.
  1008         if (protAccess && refSuper) acode++;
  1010         // Instance access methods get instance as first parameter.
  1011         // For protected symbols this needs to be the instance as a member
  1012         // of the type containing the accessed symbol, not the class
  1013         // containing the access method.
  1014         if ((vsym.flags() & STATIC) == 0) {
  1015             argtypes = argtypes.prepend(vsym.owner.erasure(types));
  1017         MethodSymbol[] accessors = accessSyms.get(vsym);
  1018         MethodSymbol accessor = accessors[acode];
  1019         if (accessor == null) {
  1020             accessor = new MethodSymbol(
  1021                 STATIC | SYNTHETIC,
  1022                 accessName(anum.intValue(), acode),
  1023                 new MethodType(argtypes, restype, thrown, syms.methodClass),
  1024                 accOwner);
  1025             enterSynthetic(tree.pos(), accessor, accOwner.members());
  1026             accessors[acode] = accessor;
  1028         return accessor;
  1031     /** The qualifier to be used for accessing a symbol in an outer class.
  1032      *  This is either C.sym or C.this.sym, depending on whether or not
  1033      *  sym is static.
  1034      *  @param sym   The accessed symbol.
  1035      */
  1036     JCExpression accessBase(DiagnosticPosition pos, Symbol sym) {
  1037         return (sym.flags() & STATIC) != 0
  1038             ? access(make.at(pos.getStartPosition()).QualIdent(sym.owner))
  1039             : makeOwnerThis(pos, sym, true);
  1042     /** Do we need an access method to reference private symbol?
  1043      */
  1044     boolean needsPrivateAccess(Symbol sym) {
  1045         if ((sym.flags() & PRIVATE) == 0 || sym.owner == currentClass) {
  1046             return false;
  1047         } else if (sym.name == names.init && (sym.owner.owner.kind & (VAR | MTH)) != 0) {
  1048             // private constructor in local class: relax protection
  1049             sym.flags_field &= ~PRIVATE;
  1050             return false;
  1051         } else {
  1052             return true;
  1056     /** Do we need an access method to reference symbol in other package?
  1057      */
  1058     boolean needsProtectedAccess(Symbol sym, JCTree tree) {
  1059         if ((sym.flags() & PROTECTED) == 0 ||
  1060             sym.owner.owner == currentClass.owner || // fast special case
  1061             sym.packge() == currentClass.packge())
  1062             return false;
  1063         if (!currentClass.isSubClass(sym.owner, types))
  1064             return true;
  1065         if ((sym.flags() & STATIC) != 0 ||
  1066             !tree.hasTag(SELECT) ||
  1067             TreeInfo.name(((JCFieldAccess) tree).selected) == names._super)
  1068             return false;
  1069         return !((JCFieldAccess) tree).selected.type.tsym.isSubClass(currentClass, types);
  1072     /** The class in which an access method for given symbol goes.
  1073      *  @param sym        The access symbol
  1074      *  @param protAccess Is access to a protected symbol in another
  1075      *                    package?
  1076      */
  1077     ClassSymbol accessClass(Symbol sym, boolean protAccess, JCTree tree) {
  1078         if (protAccess) {
  1079             Symbol qualifier = null;
  1080             ClassSymbol c = currentClass;
  1081             if (tree.hasTag(SELECT) && (sym.flags() & STATIC) == 0) {
  1082                 qualifier = ((JCFieldAccess) tree).selected.type.tsym;
  1083                 while (!qualifier.isSubClass(c, types)) {
  1084                     c = c.owner.enclClass();
  1086                 return c;
  1087             } else {
  1088                 while (!c.isSubClass(sym.owner, types)) {
  1089                     c = c.owner.enclClass();
  1092             return c;
  1093         } else {
  1094             // the symbol is private
  1095             return sym.owner.enclClass();
  1099     private void addPrunedInfo(JCTree tree) {
  1100         List<JCTree> infoList = prunedTree.get(currentClass);
  1101         infoList = (infoList == null) ? List.of(tree) : infoList.prepend(tree);
  1102         prunedTree.put(currentClass, infoList);
  1105     /** Ensure that identifier is accessible, return tree accessing the identifier.
  1106      *  @param sym      The accessed symbol.
  1107      *  @param tree     The tree referring to the symbol.
  1108      *  @param enclOp   The closest enclosing operation node of tree,
  1109      *                  null if tree is not a subtree of an operation.
  1110      *  @param refSuper Is access via a (qualified) C.super?
  1111      */
  1112     JCExpression access(Symbol sym, JCExpression tree, JCExpression enclOp, boolean refSuper) {
  1113         // Access a free variable via its proxy, or its proxy's proxy
  1114         while (sym.kind == VAR && sym.owner.kind == MTH &&
  1115             sym.owner.enclClass() != currentClass) {
  1116             // A constant is replaced by its constant value.
  1117             Object cv = ((VarSymbol)sym).getConstValue();
  1118             if (cv != null) {
  1119                 make.at(tree.pos);
  1120                 return makeLit(sym.type, cv);
  1122             // Otherwise replace the variable by its proxy.
  1123             sym = proxies.lookup(proxyName(sym.name)).sym;
  1124             Assert.check(sym != null && (sym.flags_field & FINAL) != 0);
  1125             tree = make.at(tree.pos).Ident(sym);
  1127         JCExpression base = (tree.hasTag(SELECT)) ? ((JCFieldAccess) tree).selected : null;
  1128         switch (sym.kind) {
  1129         case TYP:
  1130             if (sym.owner.kind != PCK) {
  1131                 // Convert type idents to
  1132                 // <flat name> or <package name> . <flat name>
  1133                 Name flatname = Convert.shortName(sym.flatName());
  1134                 while (base != null &&
  1135                        TreeInfo.symbol(base) != null &&
  1136                        TreeInfo.symbol(base).kind != PCK) {
  1137                     base = (base.hasTag(SELECT))
  1138                         ? ((JCFieldAccess) base).selected
  1139                         : null;
  1141                 if (tree.hasTag(IDENT)) {
  1142                     ((JCIdent) tree).name = flatname;
  1143                 } else if (base == null) {
  1144                     tree = make.at(tree.pos).Ident(sym);
  1145                     ((JCIdent) tree).name = flatname;
  1146                 } else {
  1147                     ((JCFieldAccess) tree).selected = base;
  1148                     ((JCFieldAccess) tree).name = flatname;
  1151             break;
  1152         case MTH: case VAR:
  1153             if (sym.owner.kind == TYP) {
  1155                 // Access methods are required for
  1156                 //  - private members,
  1157                 //  - protected members in a superclass of an
  1158                 //    enclosing class contained in another package.
  1159                 //  - all non-private members accessed via a qualified super.
  1160                 boolean protAccess = refSuper && !needsPrivateAccess(sym)
  1161                     || needsProtectedAccess(sym, tree);
  1162                 boolean accReq = protAccess || needsPrivateAccess(sym);
  1164                 // A base has to be supplied for
  1165                 //  - simple identifiers accessing variables in outer classes.
  1166                 boolean baseReq =
  1167                     base == null &&
  1168                     sym.owner != syms.predefClass &&
  1169                     !sym.isMemberOf(currentClass, types);
  1171                 if (accReq || baseReq) {
  1172                     make.at(tree.pos);
  1174                     // Constants are replaced by their constant value.
  1175                     if (sym.kind == VAR) {
  1176                         Object cv = ((VarSymbol)sym).getConstValue();
  1177                         if (cv != null) {
  1178                             addPrunedInfo(tree);
  1179                             return makeLit(sym.type, cv);
  1183                     // Private variables and methods are replaced by calls
  1184                     // to their access methods.
  1185                     if (accReq) {
  1186                         List<JCExpression> args = List.nil();
  1187                         if ((sym.flags() & STATIC) == 0) {
  1188                             // Instance access methods get instance
  1189                             // as first parameter.
  1190                             if (base == null)
  1191                                 base = makeOwnerThis(tree.pos(), sym, true);
  1192                             args = args.prepend(base);
  1193                             base = null;   // so we don't duplicate code
  1195                         Symbol access = accessSymbol(sym, tree,
  1196                                                      enclOp, protAccess,
  1197                                                      refSuper);
  1198                         JCExpression receiver = make.Select(
  1199                             base != null ? base : make.QualIdent(access.owner),
  1200                             access);
  1201                         return make.App(receiver, args);
  1203                     // Other accesses to members of outer classes get a
  1204                     // qualifier.
  1205                     } else if (baseReq) {
  1206                         return make.at(tree.pos).Select(
  1207                             accessBase(tree.pos(), sym), sym).setType(tree.type);
  1210             } else if (sym.owner.kind == MTH && lambdaTranslationMap != null) {
  1211                 //sym is a local variable - check the lambda translation map to
  1212                 //see if sym has been translated to something else in the current
  1213                 //scope (by LambdaToMethod)
  1214                 Symbol translatedSym = lambdaTranslationMap.get(sym);
  1215                 if (translatedSym != null) {
  1216                     tree = make.at(tree.pos).Ident(translatedSym);
  1220         return tree;
  1223     /** Ensure that identifier is accessible, return tree accessing the identifier.
  1224      *  @param tree     The identifier tree.
  1225      */
  1226     JCExpression access(JCExpression tree) {
  1227         Symbol sym = TreeInfo.symbol(tree);
  1228         return sym == null ? tree : access(sym, tree, null, false);
  1231     /** Return access constructor for a private constructor,
  1232      *  or the constructor itself, if no access constructor is needed.
  1233      *  @param pos       The position to report diagnostics, if any.
  1234      *  @param constr    The private constructor.
  1235      */
  1236     Symbol accessConstructor(DiagnosticPosition pos, Symbol constr) {
  1237         if (needsPrivateAccess(constr)) {
  1238             ClassSymbol accOwner = constr.owner.enclClass();
  1239             MethodSymbol aconstr = accessConstrs.get(constr);
  1240             if (aconstr == null) {
  1241                 List<Type> argtypes = constr.type.getParameterTypes();
  1242                 if ((accOwner.flags_field & ENUM) != 0)
  1243                     argtypes = argtypes
  1244                         .prepend(syms.intType)
  1245                         .prepend(syms.stringType);
  1246                 aconstr = new MethodSymbol(
  1247                     SYNTHETIC,
  1248                     names.init,
  1249                     new MethodType(
  1250                         argtypes.append(
  1251                             accessConstructorTag().erasure(types)),
  1252                         constr.type.getReturnType(),
  1253                         constr.type.getThrownTypes(),
  1254                         syms.methodClass),
  1255                     accOwner);
  1256                 enterSynthetic(pos, aconstr, accOwner.members());
  1257                 accessConstrs.put(constr, aconstr);
  1258                 accessed.append(constr);
  1260             return aconstr;
  1261         } else {
  1262             return constr;
  1266     /** Return an anonymous class nested in this toplevel class.
  1267      */
  1268     ClassSymbol accessConstructorTag() {
  1269         ClassSymbol topClass = currentClass.outermostClass();
  1270         Name flatname = names.fromString("" + topClass.getQualifiedName() +
  1271                                          target.syntheticNameChar() +
  1272                                          "1");
  1273         ClassSymbol ctag = chk.compiled.get(flatname);
  1274         if (ctag == null)
  1275             ctag = makeEmptyClass(STATIC | SYNTHETIC, topClass).sym;
  1276         // keep a record of all tags, to verify that all are generated as required
  1277         accessConstrTags = accessConstrTags.prepend(ctag);
  1278         return ctag;
  1281     /** Add all required access methods for a private symbol to enclosing class.
  1282      *  @param sym       The symbol.
  1283      */
  1284     void makeAccessible(Symbol sym) {
  1285         JCClassDecl cdef = classDef(sym.owner.enclClass());
  1286         if (cdef == null) Assert.error("class def not found: " + sym + " in " + sym.owner);
  1287         if (sym.name == names.init) {
  1288             cdef.defs = cdef.defs.prepend(
  1289                 accessConstructorDef(cdef.pos, sym, accessConstrs.get(sym)));
  1290         } else {
  1291             MethodSymbol[] accessors = accessSyms.get(sym);
  1292             for (int i = 0; i < NCODES; i++) {
  1293                 if (accessors[i] != null)
  1294                     cdef.defs = cdef.defs.prepend(
  1295                         accessDef(cdef.pos, sym, accessors[i], i));
  1300     /** Maps unary operator integer codes to JCTree.Tag objects
  1301      *  @param unaryOpCode the unary operator code
  1302      */
  1303     private static Tag mapUnaryOpCodeToTag(int unaryOpCode){
  1304         switch (unaryOpCode){
  1305             case PREINCcode:
  1306                 return PREINC;
  1307             case PREDECcode:
  1308                 return PREDEC;
  1309             case POSTINCcode:
  1310                 return POSTINC;
  1311             case POSTDECcode:
  1312                 return POSTDEC;
  1313             default:
  1314                 return NO_TAG;
  1318     /** Maps JCTree.Tag objects to unary operator integer codes
  1319      *  @param tag the JCTree.Tag
  1320      */
  1321     private static int mapTagToUnaryOpCode(Tag tag){
  1322         switch (tag){
  1323             case PREINC:
  1324                 return PREINCcode;
  1325             case PREDEC:
  1326                 return PREDECcode;
  1327             case POSTINC:
  1328                 return POSTINCcode;
  1329             case POSTDEC:
  1330                 return POSTDECcode;
  1331             default:
  1332                 return -1;
  1336     /** Construct definition of an access method.
  1337      *  @param pos        The source code position of the definition.
  1338      *  @param vsym       The private or protected symbol.
  1339      *  @param accessor   The access method for the symbol.
  1340      *  @param acode      The access code.
  1341      */
  1342     JCTree accessDef(int pos, Symbol vsym, MethodSymbol accessor, int acode) {
  1343 //      System.err.println("access " + vsym + " with " + accessor);//DEBUG
  1344         currentClass = vsym.owner.enclClass();
  1345         make.at(pos);
  1346         JCMethodDecl md = make.MethodDef(accessor, null);
  1348         // Find actual symbol
  1349         Symbol sym = actualSymbols.get(vsym);
  1350         if (sym == null) sym = vsym;
  1352         JCExpression ref;           // The tree referencing the private symbol.
  1353         List<JCExpression> args;    // Any additional arguments to be passed along.
  1354         if ((sym.flags() & STATIC) != 0) {
  1355             ref = make.Ident(sym);
  1356             args = make.Idents(md.params);
  1357         } else {
  1358             ref = make.Select(make.Ident(md.params.head), sym);
  1359             args = make.Idents(md.params.tail);
  1361         JCStatement stat;          // The statement accessing the private symbol.
  1362         if (sym.kind == VAR) {
  1363             // Normalize out all odd access codes by taking floor modulo 2:
  1364             int acode1 = acode - (acode & 1);
  1366             JCExpression expr;      // The access method's return value.
  1367             switch (acode1) {
  1368             case DEREFcode:
  1369                 expr = ref;
  1370                 break;
  1371             case ASSIGNcode:
  1372                 expr = make.Assign(ref, args.head);
  1373                 break;
  1374             case PREINCcode: case POSTINCcode: case PREDECcode: case POSTDECcode:
  1375                 expr = makeUnary(mapUnaryOpCodeToTag(acode1), ref);
  1376                 break;
  1377             default:
  1378                 expr = make.Assignop(
  1379                     treeTag(binaryAccessOperator(acode1)), ref, args.head);
  1380                 ((JCAssignOp) expr).operator = binaryAccessOperator(acode1);
  1382             stat = make.Return(expr.setType(sym.type));
  1383         } else {
  1384             stat = make.Call(make.App(ref, args));
  1386         md.body = make.Block(0, List.of(stat));
  1388         // Make sure all parameters, result types and thrown exceptions
  1389         // are accessible.
  1390         for (List<JCVariableDecl> l = md.params; l.nonEmpty(); l = l.tail)
  1391             l.head.vartype = access(l.head.vartype);
  1392         md.restype = access(md.restype);
  1393         for (List<JCExpression> l = md.thrown; l.nonEmpty(); l = l.tail)
  1394             l.head = access(l.head);
  1396         return md;
  1399     /** Construct definition of an access constructor.
  1400      *  @param pos        The source code position of the definition.
  1401      *  @param constr     The private constructor.
  1402      *  @param accessor   The access method for the constructor.
  1403      */
  1404     JCTree accessConstructorDef(int pos, Symbol constr, MethodSymbol accessor) {
  1405         make.at(pos);
  1406         JCMethodDecl md = make.MethodDef(accessor,
  1407                                       accessor.externalType(types),
  1408                                       null);
  1409         JCIdent callee = make.Ident(names._this);
  1410         callee.sym = constr;
  1411         callee.type = constr.type;
  1412         md.body =
  1413             make.Block(0, List.<JCStatement>of(
  1414                 make.Call(
  1415                     make.App(
  1416                         callee,
  1417                         make.Idents(md.params.reverse().tail.reverse())))));
  1418         return md;
  1421 /**************************************************************************
  1422  * Free variables proxies and this$n
  1423  *************************************************************************/
  1425     /** A scope containing all free variable proxies for currently translated
  1426      *  class, as well as its this$n symbol (if needed).
  1427      *  Proxy scopes are nested in the same way classes are.
  1428      *  Inside a constructor, proxies and any this$n symbol are duplicated
  1429      *  in an additional innermost scope, where they represent the constructor
  1430      *  parameters.
  1431      */
  1432     Scope proxies;
  1434     /** A scope containing all unnamed resource variables/saved
  1435      *  exception variables for translated TWR blocks
  1436      */
  1437     Scope twrVars;
  1439     /** A stack containing the this$n field of the currently translated
  1440      *  classes (if needed) in innermost first order.
  1441      *  Inside a constructor, proxies and any this$n symbol are duplicated
  1442      *  in an additional innermost scope, where they represent the constructor
  1443      *  parameters.
  1444      */
  1445     List<VarSymbol> outerThisStack;
  1447     /** The name of a free variable proxy.
  1448      */
  1449     Name proxyName(Name name) {
  1450         return names.fromString("val" + target.syntheticNameChar() + name);
  1453     /** Proxy definitions for all free variables in given list, in reverse order.
  1454      *  @param pos        The source code position of the definition.
  1455      *  @param freevars   The free variables.
  1456      *  @param owner      The class in which the definitions go.
  1457      */
  1458     List<JCVariableDecl> freevarDefs(int pos, List<VarSymbol> freevars, Symbol owner) {
  1459         long flags = FINAL | SYNTHETIC;
  1460         if (owner.kind == TYP &&
  1461             target.usePrivateSyntheticFields())
  1462             flags |= PRIVATE;
  1463         List<JCVariableDecl> defs = List.nil();
  1464         for (List<VarSymbol> l = freevars; l.nonEmpty(); l = l.tail) {
  1465             VarSymbol v = l.head;
  1466             VarSymbol proxy = new VarSymbol(
  1467                 flags, proxyName(v.name), v.erasure(types), owner);
  1468             proxies.enter(proxy);
  1469             JCVariableDecl vd = make.at(pos).VarDef(proxy, null);
  1470             vd.vartype = access(vd.vartype);
  1471             defs = defs.prepend(vd);
  1473         return defs;
  1476     /** The name of a this$n field
  1477      *  @param type   The class referenced by the this$n field
  1478      */
  1479     Name outerThisName(Type type, Symbol owner) {
  1480         Type t = type.getEnclosingType();
  1481         int nestingLevel = 0;
  1482         while (t.hasTag(CLASS)) {
  1483             t = t.getEnclosingType();
  1484             nestingLevel++;
  1486         Name result = names.fromString("this" + target.syntheticNameChar() + nestingLevel);
  1487         while (owner.kind == TYP && ((ClassSymbol)owner).members().lookup(result).scope != null)
  1488             result = names.fromString(result.toString() + target.syntheticNameChar());
  1489         return result;
  1492     private VarSymbol makeOuterThisVarSymbol(Symbol owner, long flags) {
  1493         if (owner.kind == TYP &&
  1494             target.usePrivateSyntheticFields())
  1495             flags |= PRIVATE;
  1496         Type target = types.erasure(owner.enclClass().type.getEnclosingType());
  1497         VarSymbol outerThis =
  1498             new VarSymbol(flags, outerThisName(target, owner), target, owner);
  1499         outerThisStack = outerThisStack.prepend(outerThis);
  1500         return outerThis;
  1503     private JCVariableDecl makeOuterThisVarDecl(int pos, VarSymbol sym) {
  1504         JCVariableDecl vd = make.at(pos).VarDef(sym, null);
  1505         vd.vartype = access(vd.vartype);
  1506         return vd;
  1509     /** Definition for this$n field.
  1510      *  @param pos        The source code position of the definition.
  1511      *  @param owner      The method in which the definition goes.
  1512      */
  1513     JCVariableDecl outerThisDef(int pos, MethodSymbol owner) {
  1514         ClassSymbol c = owner.enclClass();
  1515         boolean isMandated =
  1516             // Anonymous constructors
  1517             (owner.isConstructor() && owner.isAnonymous()) ||
  1518             // Constructors of non-private inner member classes
  1519             (owner.isConstructor() && c.isInner() &&
  1520              !c.isPrivate() && !c.isStatic());
  1521         long flags =
  1522             FINAL | (isMandated ? MANDATED : SYNTHETIC);
  1523         VarSymbol outerThis = makeOuterThisVarSymbol(owner, flags);
  1524         owner.extraParams = owner.extraParams.prepend(outerThis);
  1525         return makeOuterThisVarDecl(pos, outerThis);
  1528     /** Definition for this$n field.
  1529      *  @param pos        The source code position of the definition.
  1530      *  @param owner      The class in which the definition goes.
  1531      */
  1532     JCVariableDecl outerThisDef(int pos, ClassSymbol owner) {
  1533         VarSymbol outerThis = makeOuterThisVarSymbol(owner, FINAL | SYNTHETIC);
  1534         return makeOuterThisVarDecl(pos, outerThis);
  1537     /** Return a list of trees that load the free variables in given list,
  1538      *  in reverse order.
  1539      *  @param pos          The source code position to be used for the trees.
  1540      *  @param freevars     The list of free variables.
  1541      */
  1542     List<JCExpression> loadFreevars(DiagnosticPosition pos, List<VarSymbol> freevars) {
  1543         List<JCExpression> args = List.nil();
  1544         for (List<VarSymbol> l = freevars; l.nonEmpty(); l = l.tail)
  1545             args = args.prepend(loadFreevar(pos, l.head));
  1546         return args;
  1548 //where
  1549         JCExpression loadFreevar(DiagnosticPosition pos, VarSymbol v) {
  1550             return access(v, make.at(pos).Ident(v), null, false);
  1553     /** Construct a tree simulating the expression {@code C.this}.
  1554      *  @param pos           The source code position to be used for the tree.
  1555      *  @param c             The qualifier class.
  1556      */
  1557     JCExpression makeThis(DiagnosticPosition pos, TypeSymbol c) {
  1558         if (currentClass == c) {
  1559             // in this case, `this' works fine
  1560             return make.at(pos).This(c.erasure(types));
  1561         } else {
  1562             // need to go via this$n
  1563             return makeOuterThis(pos, c);
  1567     /**
  1568      * Optionally replace a try statement with the desugaring of a
  1569      * try-with-resources statement.  The canonical desugaring of
  1571      * try ResourceSpecification
  1572      *   Block
  1574      * is
  1576      * {
  1577      *   final VariableModifiers_minus_final R #resource = Expression;
  1578      *   Throwable #primaryException = null;
  1580      *   try ResourceSpecificationtail
  1581      *     Block
  1582      *   catch (Throwable #t) {
  1583      *     #primaryException = t;
  1584      *     throw #t;
  1585      *   } finally {
  1586      *     if (#resource != null) {
  1587      *       if (#primaryException != null) {
  1588      *         try {
  1589      *           #resource.close();
  1590      *         } catch(Throwable #suppressedException) {
  1591      *           #primaryException.addSuppressed(#suppressedException);
  1592      *         }
  1593      *       } else {
  1594      *         #resource.close();
  1595      *       }
  1596      *     }
  1597      *   }
  1599      * @param tree  The try statement to inspect.
  1600      * @return A a desugared try-with-resources tree, or the original
  1601      * try block if there are no resources to manage.
  1602      */
  1603     JCTree makeTwrTry(JCTry tree) {
  1604         make_at(tree.pos());
  1605         twrVars = twrVars.dup();
  1606         JCBlock twrBlock = makeTwrBlock(tree.resources, tree.body, 0);
  1607         if (tree.catchers.isEmpty() && tree.finalizer == null)
  1608             result = translate(twrBlock);
  1609         else
  1610             result = translate(make.Try(twrBlock, tree.catchers, tree.finalizer));
  1611         twrVars = twrVars.leave();
  1612         return result;
  1615     private JCBlock makeTwrBlock(List<JCTree> resources, JCBlock block, int depth) {
  1616         if (resources.isEmpty())
  1617             return block;
  1619         // Add resource declaration or expression to block statements
  1620         ListBuffer<JCStatement> stats = new ListBuffer<JCStatement>();
  1621         JCTree resource = resources.head;
  1622         JCExpression expr = null;
  1623         if (resource instanceof JCVariableDecl) {
  1624             JCVariableDecl var = (JCVariableDecl) resource;
  1625             expr = make.Ident(var.sym).setType(resource.type);
  1626             stats.add(var);
  1627         } else {
  1628             Assert.check(resource instanceof JCExpression);
  1629             VarSymbol syntheticTwrVar =
  1630             new VarSymbol(SYNTHETIC | FINAL,
  1631                           makeSyntheticName(names.fromString("twrVar" +
  1632                                            depth), twrVars),
  1633                           (resource.type.hasTag(BOT)) ?
  1634                           syms.autoCloseableType : resource.type,
  1635                           currentMethodSym);
  1636             twrVars.enter(syntheticTwrVar);
  1637             JCVariableDecl syntheticTwrVarDecl =
  1638                 make.VarDef(syntheticTwrVar, (JCExpression)resource);
  1639             expr = (JCExpression)make.Ident(syntheticTwrVar);
  1640             stats.add(syntheticTwrVarDecl);
  1643         // Add primaryException declaration
  1644         VarSymbol primaryException =
  1645             new VarSymbol(SYNTHETIC,
  1646                           makeSyntheticName(names.fromString("primaryException" +
  1647                           depth), twrVars),
  1648                           syms.throwableType,
  1649                           currentMethodSym);
  1650         twrVars.enter(primaryException);
  1651         JCVariableDecl primaryExceptionTreeDecl = make.VarDef(primaryException, makeNull());
  1652         stats.add(primaryExceptionTreeDecl);
  1654         // Create catch clause that saves exception and then rethrows it
  1655         VarSymbol param =
  1656             new VarSymbol(FINAL|SYNTHETIC,
  1657                           names.fromString("t" +
  1658                                            target.syntheticNameChar()),
  1659                           syms.throwableType,
  1660                           currentMethodSym);
  1661         JCVariableDecl paramTree = make.VarDef(param, null);
  1662         JCStatement assign = make.Assignment(primaryException, make.Ident(param));
  1663         JCStatement rethrowStat = make.Throw(make.Ident(param));
  1664         JCBlock catchBlock = make.Block(0L, List.<JCStatement>of(assign, rethrowStat));
  1665         JCCatch catchClause = make.Catch(paramTree, catchBlock);
  1667         int oldPos = make.pos;
  1668         make.at(TreeInfo.endPos(block));
  1669         JCBlock finallyClause = makeTwrFinallyClause(primaryException, expr);
  1670         make.at(oldPos);
  1671         JCTry outerTry = make.Try(makeTwrBlock(resources.tail, block, depth + 1),
  1672                                   List.<JCCatch>of(catchClause),
  1673                                   finallyClause);
  1674         stats.add(outerTry);
  1675         return make.Block(0L, stats.toList());
  1678     private JCBlock makeTwrFinallyClause(Symbol primaryException, JCExpression resource) {
  1679         // primaryException.addSuppressed(catchException);
  1680         VarSymbol catchException =
  1681             new VarSymbol(0, make.paramName(2),
  1682                           syms.throwableType,
  1683                           currentMethodSym);
  1684         JCStatement addSuppressionStatement =
  1685             make.Exec(makeCall(make.Ident(primaryException),
  1686                                names.addSuppressed,
  1687                                List.<JCExpression>of(make.Ident(catchException))));
  1689         // try { resource.close(); } catch (e) { primaryException.addSuppressed(e); }
  1690         JCBlock tryBlock =
  1691             make.Block(0L, List.<JCStatement>of(makeResourceCloseInvocation(resource)));
  1692         JCVariableDecl catchExceptionDecl = make.VarDef(catchException, null);
  1693         JCBlock catchBlock = make.Block(0L, List.<JCStatement>of(addSuppressionStatement));
  1694         List<JCCatch> catchClauses = List.<JCCatch>of(make.Catch(catchExceptionDecl, catchBlock));
  1695         JCTry tryTree = make.Try(tryBlock, catchClauses, null);
  1697         // if (primaryException != null) {try...} else resourceClose;
  1698         JCIf closeIfStatement = make.If(makeNonNullCheck(make.Ident(primaryException)),
  1699                                         tryTree,
  1700                                         makeResourceCloseInvocation(resource));
  1702         // if (#resource != null) { if (primaryException ...  }
  1703         return make.Block(0L,
  1704                           List.<JCStatement>of(make.If(makeNonNullCheck(resource),
  1705                                                        closeIfStatement,
  1706                                                        null)));
  1709     private JCStatement makeResourceCloseInvocation(JCExpression resource) {
  1710         // convert to AutoCloseable if needed
  1711         if (types.asSuper(resource.type, syms.autoCloseableType.tsym) == null) {
  1712             resource = (JCExpression) convert(resource, syms.autoCloseableType);
  1715         // create resource.close() method invocation
  1716         JCExpression resourceClose = makeCall(resource,
  1717                                               names.close,
  1718                                               List.<JCExpression>nil());
  1719         return make.Exec(resourceClose);
  1722     private JCExpression makeNonNullCheck(JCExpression expression) {
  1723         return makeBinary(NE, expression, makeNull());
  1726     /** Construct a tree that represents the outer instance
  1727      *  {@code C.this}. Never pick the current `this'.
  1728      *  @param pos           The source code position to be used for the tree.
  1729      *  @param c             The qualifier class.
  1730      */
  1731     JCExpression makeOuterThis(DiagnosticPosition pos, TypeSymbol c) {
  1732         List<VarSymbol> ots = outerThisStack;
  1733         if (ots.isEmpty()) {
  1734             log.error(pos, "no.encl.instance.of.type.in.scope", c);
  1735             Assert.error();
  1736             return makeNull();
  1738         VarSymbol ot = ots.head;
  1739         JCExpression tree = access(make.at(pos).Ident(ot));
  1740         TypeSymbol otc = ot.type.tsym;
  1741         while (otc != c) {
  1742             do {
  1743                 ots = ots.tail;
  1744                 if (ots.isEmpty()) {
  1745                     log.error(pos,
  1746                               "no.encl.instance.of.type.in.scope",
  1747                               c);
  1748                     Assert.error(); // should have been caught in Attr
  1749                     return tree;
  1751                 ot = ots.head;
  1752             } while (ot.owner != otc);
  1753             if (otc.owner.kind != PCK && !otc.hasOuterInstance()) {
  1754                 chk.earlyRefError(pos, c);
  1755                 Assert.error(); // should have been caught in Attr
  1756                 return makeNull();
  1758             tree = access(make.at(pos).Select(tree, ot));
  1759             otc = ot.type.tsym;
  1761         return tree;
  1764     /** Construct a tree that represents the closest outer instance
  1765      *  {@code C.this} such that the given symbol is a member of C.
  1766      *  @param pos           The source code position to be used for the tree.
  1767      *  @param sym           The accessed symbol.
  1768      *  @param preciseMatch  should we accept a type that is a subtype of
  1769      *                       sym's owner, even if it doesn't contain sym
  1770      *                       due to hiding, overriding, or non-inheritance
  1771      *                       due to protection?
  1772      */
  1773     JCExpression makeOwnerThis(DiagnosticPosition pos, Symbol sym, boolean preciseMatch) {
  1774         Symbol c = sym.owner;
  1775         if (preciseMatch ? sym.isMemberOf(currentClass, types)
  1776                          : currentClass.isSubClass(sym.owner, types)) {
  1777             // in this case, `this' works fine
  1778             return make.at(pos).This(c.erasure(types));
  1779         } else {
  1780             // need to go via this$n
  1781             return makeOwnerThisN(pos, sym, preciseMatch);
  1785     /**
  1786      * Similar to makeOwnerThis but will never pick "this".
  1787      */
  1788     JCExpression makeOwnerThisN(DiagnosticPosition pos, Symbol sym, boolean preciseMatch) {
  1789         Symbol c = sym.owner;
  1790         List<VarSymbol> ots = outerThisStack;
  1791         if (ots.isEmpty()) {
  1792             log.error(pos, "no.encl.instance.of.type.in.scope", c);
  1793             Assert.error();
  1794             return makeNull();
  1796         VarSymbol ot = ots.head;
  1797         JCExpression tree = access(make.at(pos).Ident(ot));
  1798         TypeSymbol otc = ot.type.tsym;
  1799         while (!(preciseMatch ? sym.isMemberOf(otc, types) : otc.isSubClass(sym.owner, types))) {
  1800             do {
  1801                 ots = ots.tail;
  1802                 if (ots.isEmpty()) {
  1803                     log.error(pos,
  1804                         "no.encl.instance.of.type.in.scope",
  1805                         c);
  1806                     Assert.error();
  1807                     return tree;
  1809                 ot = ots.head;
  1810             } while (ot.owner != otc);
  1811             tree = access(make.at(pos).Select(tree, ot));
  1812             otc = ot.type.tsym;
  1814         return tree;
  1817     /** Return tree simulating the assignment {@code this.name = name}, where
  1818      *  name is the name of a free variable.
  1819      */
  1820     JCStatement initField(int pos, Name name) {
  1821         Scope.Entry e = proxies.lookup(name);
  1822         Symbol rhs = e.sym;
  1823         Assert.check(rhs.owner.kind == MTH);
  1824         Symbol lhs = e.next().sym;
  1825         Assert.check(rhs.owner.owner == lhs.owner);
  1826         make.at(pos);
  1827         return
  1828             make.Exec(
  1829                 make.Assign(
  1830                     make.Select(make.This(lhs.owner.erasure(types)), lhs),
  1831                     make.Ident(rhs)).setType(lhs.erasure(types)));
  1834     /** Return tree simulating the assignment {@code this.this$n = this$n}.
  1835      */
  1836     JCStatement initOuterThis(int pos) {
  1837         VarSymbol rhs = outerThisStack.head;
  1838         Assert.check(rhs.owner.kind == MTH);
  1839         VarSymbol lhs = outerThisStack.tail.head;
  1840         Assert.check(rhs.owner.owner == lhs.owner);
  1841         make.at(pos);
  1842         return
  1843             make.Exec(
  1844                 make.Assign(
  1845                     make.Select(make.This(lhs.owner.erasure(types)), lhs),
  1846                     make.Ident(rhs)).setType(lhs.erasure(types)));
  1849 /**************************************************************************
  1850  * Code for .class
  1851  *************************************************************************/
  1853     /** Return the symbol of a class to contain a cache of
  1854      *  compiler-generated statics such as class$ and the
  1855      *  $assertionsDisabled flag.  We create an anonymous nested class
  1856      *  (unless one already exists) and return its symbol.  However,
  1857      *  for backward compatibility in 1.4 and earlier we use the
  1858      *  top-level class itself.
  1859      */
  1860     private ClassSymbol outerCacheClass() {
  1861         ClassSymbol clazz = outermostClassDef.sym;
  1862         if ((clazz.flags() & INTERFACE) == 0 &&
  1863             !target.useInnerCacheClass()) return clazz;
  1864         Scope s = clazz.members();
  1865         for (Scope.Entry e = s.elems; e != null; e = e.sibling)
  1866             if (e.sym.kind == TYP &&
  1867                 e.sym.name == names.empty &&
  1868                 (e.sym.flags() & INTERFACE) == 0) return (ClassSymbol) e.sym;
  1869         return makeEmptyClass(STATIC | SYNTHETIC, clazz).sym;
  1872     /** Return symbol for "class$" method. If there is no method definition
  1873      *  for class$, construct one as follows:
  1875      *    class class$(String x0) {
  1876      *      try {
  1877      *        return Class.forName(x0);
  1878      *      } catch (ClassNotFoundException x1) {
  1879      *        throw new NoClassDefFoundError(x1.getMessage());
  1880      *      }
  1881      *    }
  1882      */
  1883     private MethodSymbol classDollarSym(DiagnosticPosition pos) {
  1884         ClassSymbol outerCacheClass = outerCacheClass();
  1885         MethodSymbol classDollarSym =
  1886             (MethodSymbol)lookupSynthetic(classDollar,
  1887                                           outerCacheClass.members());
  1888         if (classDollarSym == null) {
  1889             classDollarSym = new MethodSymbol(
  1890                 STATIC | SYNTHETIC,
  1891                 classDollar,
  1892                 new MethodType(
  1893                     List.of(syms.stringType),
  1894                     types.erasure(syms.classType),
  1895                     List.<Type>nil(),
  1896                     syms.methodClass),
  1897                 outerCacheClass);
  1898             enterSynthetic(pos, classDollarSym, outerCacheClass.members());
  1900             JCMethodDecl md = make.MethodDef(classDollarSym, null);
  1901             try {
  1902                 md.body = classDollarSymBody(pos, md);
  1903             } catch (CompletionFailure ex) {
  1904                 md.body = make.Block(0, List.<JCStatement>nil());
  1905                 chk.completionError(pos, ex);
  1907             JCClassDecl outerCacheClassDef = classDef(outerCacheClass);
  1908             outerCacheClassDef.defs = outerCacheClassDef.defs.prepend(md);
  1910         return classDollarSym;
  1913     /** Generate code for class$(String name). */
  1914     JCBlock classDollarSymBody(DiagnosticPosition pos, JCMethodDecl md) {
  1915         MethodSymbol classDollarSym = md.sym;
  1916         ClassSymbol outerCacheClass = (ClassSymbol)classDollarSym.owner;
  1918         JCBlock returnResult;
  1920         // in 1.4.2 and above, we use
  1921         // Class.forName(String name, boolean init, ClassLoader loader);
  1922         // which requires we cache the current loader in cl$
  1923         if (target.classLiteralsNoInit()) {
  1924             // clsym = "private static ClassLoader cl$"
  1925             VarSymbol clsym = new VarSymbol(STATIC|SYNTHETIC,
  1926                                             names.fromString("cl" + target.syntheticNameChar()),
  1927                                             syms.classLoaderType,
  1928                                             outerCacheClass);
  1929             enterSynthetic(pos, clsym, outerCacheClass.members());
  1931             // emit "private static ClassLoader cl$;"
  1932             JCVariableDecl cldef = make.VarDef(clsym, null);
  1933             JCClassDecl outerCacheClassDef = classDef(outerCacheClass);
  1934             outerCacheClassDef.defs = outerCacheClassDef.defs.prepend(cldef);
  1936             // newcache := "new cache$1[0]"
  1937             JCNewArray newcache = make.
  1938                 NewArray(make.Type(outerCacheClass.type),
  1939                          List.<JCExpression>of(make.Literal(INT, 0).setType(syms.intType)),
  1940                          null);
  1941             newcache.type = new ArrayType(types.erasure(outerCacheClass.type),
  1942                                           syms.arrayClass);
  1944             // forNameSym := java.lang.Class.forName(
  1945             //     String s,boolean init,ClassLoader loader)
  1946             Symbol forNameSym = lookupMethod(make_pos, names.forName,
  1947                                              types.erasure(syms.classType),
  1948                                              List.of(syms.stringType,
  1949                                                      syms.booleanType,
  1950                                                      syms.classLoaderType));
  1951             // clvalue := "(cl$ == null) ?
  1952             // $newcache.getClass().getComponentType().getClassLoader() : cl$"
  1953             JCExpression clvalue =
  1954                 make.Conditional(
  1955                     makeBinary(EQ, make.Ident(clsym), makeNull()),
  1956                     make.Assign(
  1957                         make.Ident(clsym),
  1958                         makeCall(
  1959                             makeCall(makeCall(newcache,
  1960                                               names.getClass,
  1961                                               List.<JCExpression>nil()),
  1962                                      names.getComponentType,
  1963                                      List.<JCExpression>nil()),
  1964                             names.getClassLoader,
  1965                             List.<JCExpression>nil())).setType(syms.classLoaderType),
  1966                     make.Ident(clsym)).setType(syms.classLoaderType);
  1968             // returnResult := "{ return Class.forName(param1, false, cl$); }"
  1969             List<JCExpression> args = List.of(make.Ident(md.params.head.sym),
  1970                                               makeLit(syms.booleanType, 0),
  1971                                               clvalue);
  1972             returnResult = make.
  1973                 Block(0, List.<JCStatement>of(make.
  1974                               Call(make. // return
  1975                                    App(make.
  1976                                        Ident(forNameSym), args))));
  1977         } else {
  1978             // forNameSym := java.lang.Class.forName(String s)
  1979             Symbol forNameSym = lookupMethod(make_pos,
  1980                                              names.forName,
  1981                                              types.erasure(syms.classType),
  1982                                              List.of(syms.stringType));
  1983             // returnResult := "{ return Class.forName(param1); }"
  1984             returnResult = make.
  1985                 Block(0, List.of(make.
  1986                           Call(make. // return
  1987                               App(make.
  1988                                   QualIdent(forNameSym),
  1989                                   List.<JCExpression>of(make.
  1990                                                         Ident(md.params.
  1991                                                               head.sym))))));
  1994         // catchParam := ClassNotFoundException e1
  1995         VarSymbol catchParam =
  1996             new VarSymbol(0, make.paramName(1),
  1997                           syms.classNotFoundExceptionType,
  1998                           classDollarSym);
  2000         JCStatement rethrow;
  2001         if (target.hasInitCause()) {
  2002             // rethrow = "throw new NoClassDefFoundError().initCause(e);
  2003             JCTree throwExpr =
  2004                 makeCall(makeNewClass(syms.noClassDefFoundErrorType,
  2005                                       List.<JCExpression>nil()),
  2006                          names.initCause,
  2007                          List.<JCExpression>of(make.Ident(catchParam)));
  2008             rethrow = make.Throw(throwExpr);
  2009         } else {
  2010             // getMessageSym := ClassNotFoundException.getMessage()
  2011             Symbol getMessageSym = lookupMethod(make_pos,
  2012                                                 names.getMessage,
  2013                                                 syms.classNotFoundExceptionType,
  2014                                                 List.<Type>nil());
  2015             // rethrow = "throw new NoClassDefFoundError(e.getMessage());"
  2016             rethrow = make.
  2017                 Throw(makeNewClass(syms.noClassDefFoundErrorType,
  2018                           List.<JCExpression>of(make.App(make.Select(make.Ident(catchParam),
  2019                                                                      getMessageSym),
  2020                                                          List.<JCExpression>nil()))));
  2023         // rethrowStmt := "( $rethrow )"
  2024         JCBlock rethrowStmt = make.Block(0, List.of(rethrow));
  2026         // catchBlock := "catch ($catchParam) $rethrowStmt"
  2027         JCCatch catchBlock = make.Catch(make.VarDef(catchParam, null),
  2028                                       rethrowStmt);
  2030         // tryCatch := "try $returnResult $catchBlock"
  2031         JCStatement tryCatch = make.Try(returnResult,
  2032                                         List.of(catchBlock), null);
  2034         return make.Block(0, List.of(tryCatch));
  2036     // where
  2037         /** Create an attributed tree of the form left.name(). */
  2038         private JCMethodInvocation makeCall(JCExpression left, Name name, List<JCExpression> args) {
  2039             Assert.checkNonNull(left.type);
  2040             Symbol funcsym = lookupMethod(make_pos, name, left.type,
  2041                                           TreeInfo.types(args));
  2042             return make.App(make.Select(left, funcsym), args);
  2045     /** The Name Of The variable to cache T.class values.
  2046      *  @param sig      The signature of type T.
  2047      */
  2048     private Name cacheName(String sig) {
  2049         StringBuilder buf = new StringBuilder();
  2050         if (sig.startsWith("[")) {
  2051             buf = buf.append("array");
  2052             while (sig.startsWith("[")) {
  2053                 buf = buf.append(target.syntheticNameChar());
  2054                 sig = sig.substring(1);
  2056             if (sig.startsWith("L")) {
  2057                 sig = sig.substring(0, sig.length() - 1);
  2059         } else {
  2060             buf = buf.append("class" + target.syntheticNameChar());
  2062         buf = buf.append(sig.replace('.', target.syntheticNameChar()));
  2063         return names.fromString(buf.toString());
  2066     /** The variable symbol that caches T.class values.
  2067      *  If none exists yet, create a definition.
  2068      *  @param sig      The signature of type T.
  2069      *  @param pos      The position to report diagnostics, if any.
  2070      */
  2071     private VarSymbol cacheSym(DiagnosticPosition pos, String sig) {
  2072         ClassSymbol outerCacheClass = outerCacheClass();
  2073         Name cname = cacheName(sig);
  2074         VarSymbol cacheSym =
  2075             (VarSymbol)lookupSynthetic(cname, outerCacheClass.members());
  2076         if (cacheSym == null) {
  2077             cacheSym = new VarSymbol(
  2078                 STATIC | SYNTHETIC, cname, types.erasure(syms.classType), outerCacheClass);
  2079             enterSynthetic(pos, cacheSym, outerCacheClass.members());
  2081             JCVariableDecl cacheDef = make.VarDef(cacheSym, null);
  2082             JCClassDecl outerCacheClassDef = classDef(outerCacheClass);
  2083             outerCacheClassDef.defs = outerCacheClassDef.defs.prepend(cacheDef);
  2085         return cacheSym;
  2088     /** The tree simulating a T.class expression.
  2089      *  @param clazz      The tree identifying type T.
  2090      */
  2091     private JCExpression classOf(JCTree clazz) {
  2092         return classOfType(clazz.type, clazz.pos());
  2095     private JCExpression classOfType(Type type, DiagnosticPosition pos) {
  2096         switch (type.getTag()) {
  2097         case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT:
  2098         case DOUBLE: case BOOLEAN: case VOID:
  2099             // replace with <BoxedClass>.TYPE
  2100             ClassSymbol c = types.boxedClass(type);
  2101             Symbol typeSym =
  2102                 rs.accessBase(
  2103                     rs.findIdentInType(attrEnv, c.type, names.TYPE, VAR),
  2104                     pos, c.type, names.TYPE, true);
  2105             if (typeSym.kind == VAR)
  2106                 ((VarSymbol)typeSym).getConstValue(); // ensure initializer is evaluated
  2107             return make.QualIdent(typeSym);
  2108         case CLASS: case ARRAY:
  2109             if (target.hasClassLiterals()) {
  2110                 VarSymbol sym = new VarSymbol(
  2111                         STATIC | PUBLIC | FINAL, names._class,
  2112                         syms.classType, type.tsym);
  2113                 return make_at(pos).Select(make.Type(type), sym);
  2115             // replace with <cache == null ? cache = class$(tsig) : cache>
  2116             // where
  2117             //  - <tsig>  is the type signature of T,
  2118             //  - <cache> is the cache variable for tsig.
  2119             String sig =
  2120                 writer.xClassName(type).toString().replace('/', '.');
  2121             Symbol cs = cacheSym(pos, sig);
  2122             return make_at(pos).Conditional(
  2123                 makeBinary(EQ, make.Ident(cs), makeNull()),
  2124                 make.Assign(
  2125                     make.Ident(cs),
  2126                     make.App(
  2127                         make.Ident(classDollarSym(pos)),
  2128                         List.<JCExpression>of(make.Literal(CLASS, sig)
  2129                                               .setType(syms.stringType))))
  2130                 .setType(types.erasure(syms.classType)),
  2131                 make.Ident(cs)).setType(types.erasure(syms.classType));
  2132         default:
  2133             throw new AssertionError();
  2137 /**************************************************************************
  2138  * Code for enabling/disabling assertions.
  2139  *************************************************************************/
  2141     // This code is not particularly robust if the user has
  2142     // previously declared a member named '$assertionsDisabled'.
  2143     // The same faulty idiom also appears in the translation of
  2144     // class literals above.  We should report an error if a
  2145     // previous declaration is not synthetic.
  2147     private JCExpression assertFlagTest(DiagnosticPosition pos) {
  2148         // Outermost class may be either true class or an interface.
  2149         ClassSymbol outermostClass = outermostClassDef.sym;
  2151         // note that this is a class, as an interface can't contain a statement.
  2152         ClassSymbol container = currentClass;
  2154         VarSymbol assertDisabledSym =
  2155             (VarSymbol)lookupSynthetic(dollarAssertionsDisabled,
  2156                                        container.members());
  2157         if (assertDisabledSym == null) {
  2158             assertDisabledSym =
  2159                 new VarSymbol(STATIC | FINAL | SYNTHETIC,
  2160                               dollarAssertionsDisabled,
  2161                               syms.booleanType,
  2162                               container);
  2163             enterSynthetic(pos, assertDisabledSym, container.members());
  2164             Symbol desiredAssertionStatusSym = lookupMethod(pos,
  2165                                                             names.desiredAssertionStatus,
  2166                                                             types.erasure(syms.classType),
  2167                                                             List.<Type>nil());
  2168             JCClassDecl containerDef = classDef(container);
  2169             make_at(containerDef.pos());
  2170             JCExpression notStatus = makeUnary(NOT, make.App(make.Select(
  2171                     classOfType(types.erasure(outermostClass.type),
  2172                                 containerDef.pos()),
  2173                     desiredAssertionStatusSym)));
  2174             JCVariableDecl assertDisabledDef = make.VarDef(assertDisabledSym,
  2175                                                    notStatus);
  2176             containerDef.defs = containerDef.defs.prepend(assertDisabledDef);
  2178         make_at(pos);
  2179         return makeUnary(NOT, make.Ident(assertDisabledSym));
  2183 /**************************************************************************
  2184  * Building blocks for let expressions
  2185  *************************************************************************/
  2187     interface TreeBuilder {
  2188         JCTree build(JCTree arg);
  2191     /** Construct an expression using the builder, with the given rval
  2192      *  expression as an argument to the builder.  However, the rval
  2193      *  expression must be computed only once, even if used multiple
  2194      *  times in the result of the builder.  We do that by
  2195      *  constructing a "let" expression that saves the rvalue into a
  2196      *  temporary variable and then uses the temporary variable in
  2197      *  place of the expression built by the builder.  The complete
  2198      *  resulting expression is of the form
  2199      *  <pre>
  2200      *    (let <b>TYPE</b> <b>TEMP</b> = <b>RVAL</b>;
  2201      *     in (<b>BUILDER</b>(<b>TEMP</b>)))
  2202      *  </pre>
  2203      *  where <code><b>TEMP</b></code> is a newly declared variable
  2204      *  in the let expression.
  2205      */
  2206     JCTree abstractRval(JCTree rval, Type type, TreeBuilder builder) {
  2207         rval = TreeInfo.skipParens(rval);
  2208         switch (rval.getTag()) {
  2209         case LITERAL:
  2210             return builder.build(rval);
  2211         case IDENT:
  2212             JCIdent id = (JCIdent) rval;
  2213             if ((id.sym.flags() & FINAL) != 0 && id.sym.owner.kind == MTH)
  2214                 return builder.build(rval);
  2216         VarSymbol var =
  2217             new VarSymbol(FINAL|SYNTHETIC,
  2218                           names.fromString(
  2219                                           target.syntheticNameChar()
  2220                                           + "" + rval.hashCode()),
  2221                                       type,
  2222                                       currentMethodSym);
  2223         rval = convert(rval,type);
  2224         JCVariableDecl def = make.VarDef(var, (JCExpression)rval); // XXX cast
  2225         JCTree built = builder.build(make.Ident(var));
  2226         JCTree res = make.LetExpr(def, built);
  2227         res.type = built.type;
  2228         return res;
  2231     // same as above, with the type of the temporary variable computed
  2232     JCTree abstractRval(JCTree rval, TreeBuilder builder) {
  2233         return abstractRval(rval, rval.type, builder);
  2236     // same as above, but for an expression that may be used as either
  2237     // an rvalue or an lvalue.  This requires special handling for
  2238     // Select expressions, where we place the left-hand-side of the
  2239     // select in a temporary, and for Indexed expressions, where we
  2240     // place both the indexed expression and the index value in temps.
  2241     JCTree abstractLval(JCTree lval, final TreeBuilder builder) {
  2242         lval = TreeInfo.skipParens(lval);
  2243         switch (lval.getTag()) {
  2244         case IDENT:
  2245             return builder.build(lval);
  2246         case SELECT: {
  2247             final JCFieldAccess s = (JCFieldAccess)lval;
  2248             JCTree selected = TreeInfo.skipParens(s.selected);
  2249             Symbol lid = TreeInfo.symbol(s.selected);
  2250             if (lid != null && lid.kind == TYP) return builder.build(lval);
  2251             return abstractRval(s.selected, new TreeBuilder() {
  2252                     public JCTree build(final JCTree selected) {
  2253                         return builder.build(make.Select((JCExpression)selected, s.sym));
  2255                 });
  2257         case INDEXED: {
  2258             final JCArrayAccess i = (JCArrayAccess)lval;
  2259             return abstractRval(i.indexed, new TreeBuilder() {
  2260                     public JCTree build(final JCTree indexed) {
  2261                         return abstractRval(i.index, syms.intType, new TreeBuilder() {
  2262                                 public JCTree build(final JCTree index) {
  2263                                     JCTree newLval = make.Indexed((JCExpression)indexed,
  2264                                                                 (JCExpression)index);
  2265                                     newLval.setType(i.type);
  2266                                     return builder.build(newLval);
  2268                             });
  2270                 });
  2272         case TYPECAST: {
  2273             return abstractLval(((JCTypeCast)lval).expr, builder);
  2276         throw new AssertionError(lval);
  2279     // evaluate and discard the first expression, then evaluate the second.
  2280     JCTree makeComma(final JCTree expr1, final JCTree expr2) {
  2281         return abstractRval(expr1, new TreeBuilder() {
  2282                 public JCTree build(final JCTree discarded) {
  2283                     return expr2;
  2285             });
  2288 /**************************************************************************
  2289  * Translation methods
  2290  *************************************************************************/
  2292     /** Visitor argument: enclosing operator node.
  2293      */
  2294     private JCExpression enclOp;
  2296     /** Visitor method: Translate a single node.
  2297      *  Attach the source position from the old tree to its replacement tree.
  2298      */
  2299     public <T extends JCTree> T translate(T tree) {
  2300         if (tree == null) {
  2301             return null;
  2302         } else {
  2303             make_at(tree.pos());
  2304             T result = super.translate(tree);
  2305             if (endPosTable != null && result != tree) {
  2306                 endPosTable.replaceTree(tree, result);
  2308             return result;
  2312     /** Visitor method: Translate a single node, boxing or unboxing if needed.
  2313      */
  2314     public <T extends JCTree> T translate(T tree, Type type) {
  2315         return (tree == null) ? null : boxIfNeeded(translate(tree), type);
  2318     /** Visitor method: Translate tree.
  2319      */
  2320     public <T extends JCTree> T translate(T tree, JCExpression enclOp) {
  2321         JCExpression prevEnclOp = this.enclOp;
  2322         this.enclOp = enclOp;
  2323         T res = translate(tree);
  2324         this.enclOp = prevEnclOp;
  2325         return res;
  2328     /** Visitor method: Translate list of trees.
  2329      */
  2330     public <T extends JCTree> List<T> translate(List<T> trees, JCExpression enclOp) {
  2331         JCExpression prevEnclOp = this.enclOp;
  2332         this.enclOp = enclOp;
  2333         List<T> res = translate(trees);
  2334         this.enclOp = prevEnclOp;
  2335         return res;
  2338     /** Visitor method: Translate list of trees.
  2339      */
  2340     public <T extends JCTree> List<T> translate(List<T> trees, Type type) {
  2341         if (trees == null) return null;
  2342         for (List<T> l = trees; l.nonEmpty(); l = l.tail)
  2343             l.head = translate(l.head, type);
  2344         return trees;
  2347     public void visitTopLevel(JCCompilationUnit tree) {
  2348         if (needPackageInfoClass(tree)) {
  2349             Name name = names.package_info;
  2350             long flags = Flags.ABSTRACT | Flags.INTERFACE;
  2351             if (target.isPackageInfoSynthetic())
  2352                 // package-info is marked SYNTHETIC in JDK 1.6 and later releases
  2353                 flags = flags | Flags.SYNTHETIC;
  2354             JCClassDecl packageAnnotationsClass
  2355                 = make.ClassDef(make.Modifiers(flags,
  2356                                                tree.packageAnnotations),
  2357                                 name, List.<JCTypeParameter>nil(),
  2358                                 null, List.<JCExpression>nil(), List.<JCTree>nil());
  2359             ClassSymbol c = tree.packge.package_info;
  2360             c.flags_field |= flags;
  2361             c.annotations.setAttributes(tree.packge.annotations);
  2362             ClassType ctype = (ClassType) c.type;
  2363             ctype.supertype_field = syms.objectType;
  2364             ctype.interfaces_field = List.nil();
  2365             packageAnnotationsClass.sym = c;
  2367             translated.append(packageAnnotationsClass);
  2370     // where
  2371     private boolean needPackageInfoClass(JCCompilationUnit tree) {
  2372         switch (pkginfoOpt) {
  2373             case ALWAYS:
  2374                 return true;
  2375             case LEGACY:
  2376                 return tree.packageAnnotations.nonEmpty();
  2377             case NONEMPTY:
  2378                 for (Attribute.Compound a :
  2379                          tree.packge.annotations.getDeclarationAttributes()) {
  2380                     Attribute.RetentionPolicy p = types.getRetention(a);
  2381                     if (p != Attribute.RetentionPolicy.SOURCE)
  2382                         return true;
  2384                 return false;
  2386         throw new AssertionError();
  2389     public void visitClassDef(JCClassDecl tree) {
  2390         ClassSymbol currentClassPrev = currentClass;
  2391         MethodSymbol currentMethodSymPrev = currentMethodSym;
  2392         currentClass = tree.sym;
  2393         currentMethodSym = null;
  2394         classdefs.put(currentClass, tree);
  2396         proxies = proxies.dup(currentClass);
  2397         List<VarSymbol> prevOuterThisStack = outerThisStack;
  2399         // If this is an enum definition
  2400         if ((tree.mods.flags & ENUM) != 0 &&
  2401             (types.supertype(currentClass.type).tsym.flags() & ENUM) == 0)
  2402             visitEnumDef(tree);
  2404         // If this is a nested class, define a this$n field for
  2405         // it and add to proxies.
  2406         JCVariableDecl otdef = null;
  2407         if (currentClass.hasOuterInstance())
  2408             otdef = outerThisDef(tree.pos, currentClass);
  2410         // If this is a local class, define proxies for all its free variables.
  2411         List<JCVariableDecl> fvdefs = freevarDefs(
  2412             tree.pos, freevars(currentClass), currentClass);
  2414         // Recursively translate superclass, interfaces.
  2415         tree.extending = translate(tree.extending);
  2416         tree.implementing = translate(tree.implementing);
  2418         if (currentClass.isLocal()) {
  2419             ClassSymbol encl = currentClass.owner.enclClass();
  2420             if (encl.trans_local == null) {
  2421                 encl.trans_local = List.nil();
  2423             encl.trans_local = encl.trans_local.prepend(currentClass);
  2426         // Recursively translate members, taking into account that new members
  2427         // might be created during the translation and prepended to the member
  2428         // list `tree.defs'.
  2429         List<JCTree> seen = List.nil();
  2430         while (tree.defs != seen) {
  2431             List<JCTree> unseen = tree.defs;
  2432             for (List<JCTree> l = unseen; l.nonEmpty() && l != seen; l = l.tail) {
  2433                 JCTree outermostMemberDefPrev = outermostMemberDef;
  2434                 if (outermostMemberDefPrev == null) outermostMemberDef = l.head;
  2435                 l.head = translate(l.head);
  2436                 outermostMemberDef = outermostMemberDefPrev;
  2438             seen = unseen;
  2441         // Convert a protected modifier to public, mask static modifier.
  2442         if ((tree.mods.flags & PROTECTED) != 0) tree.mods.flags |= PUBLIC;
  2443         tree.mods.flags &= ClassFlags;
  2445         // Convert name to flat representation, replacing '.' by '$'.
  2446         tree.name = Convert.shortName(currentClass.flatName());
  2448         // Add this$n and free variables proxy definitions to class.
  2449         for (List<JCVariableDecl> l = fvdefs; l.nonEmpty(); l = l.tail) {
  2450             tree.defs = tree.defs.prepend(l.head);
  2451             enterSynthetic(tree.pos(), l.head.sym, currentClass.members());
  2453         if (currentClass.hasOuterInstance()) {
  2454             tree.defs = tree.defs.prepend(otdef);
  2455             enterSynthetic(tree.pos(), otdef.sym, currentClass.members());
  2458         proxies = proxies.leave();
  2459         outerThisStack = prevOuterThisStack;
  2461         // Append translated tree to `translated' queue.
  2462         translated.append(tree);
  2464         currentClass = currentClassPrev;
  2465         currentMethodSym = currentMethodSymPrev;
  2467         // Return empty block {} as a placeholder for an inner class.
  2468         result = make_at(tree.pos()).Block(0, List.<JCStatement>nil());
  2471     /** Translate an enum class. */
  2472     private void visitEnumDef(JCClassDecl tree) {
  2473         make_at(tree.pos());
  2475         // add the supertype, if needed
  2476         if (tree.extending == null)
  2477             tree.extending = make.Type(types.supertype(tree.type));
  2479         // classOfType adds a cache field to tree.defs unless
  2480         // target.hasClassLiterals().
  2481         JCExpression e_class = classOfType(tree.sym.type, tree.pos()).
  2482             setType(types.erasure(syms.classType));
  2484         // process each enumeration constant, adding implicit constructor parameters
  2485         int nextOrdinal = 0;
  2486         ListBuffer<JCExpression> values = new ListBuffer<JCExpression>();
  2487         ListBuffer<JCTree> enumDefs = new ListBuffer<JCTree>();
  2488         ListBuffer<JCTree> otherDefs = new ListBuffer<JCTree>();
  2489         for (List<JCTree> defs = tree.defs;
  2490              defs.nonEmpty();
  2491              defs=defs.tail) {
  2492             if (defs.head.hasTag(VARDEF) && (((JCVariableDecl) defs.head).mods.flags & ENUM) != 0) {
  2493                 JCVariableDecl var = (JCVariableDecl)defs.head;
  2494                 visitEnumConstantDef(var, nextOrdinal++);
  2495                 values.append(make.QualIdent(var.sym));
  2496                 enumDefs.append(var);
  2497             } else {
  2498                 otherDefs.append(defs.head);
  2502         // private static final T[] #VALUES = { a, b, c };
  2503         Name valuesName = names.fromString(target.syntheticNameChar() + "VALUES");
  2504         while (tree.sym.members().lookup(valuesName).scope != null) // avoid name clash
  2505             valuesName = names.fromString(valuesName + "" + target.syntheticNameChar());
  2506         Type arrayType = new ArrayType(types.erasure(tree.type), syms.arrayClass);
  2507         VarSymbol valuesVar = new VarSymbol(PRIVATE|FINAL|STATIC|SYNTHETIC,
  2508                                             valuesName,
  2509                                             arrayType,
  2510                                             tree.type.tsym);
  2511         JCNewArray newArray = make.NewArray(make.Type(types.erasure(tree.type)),
  2512                                           List.<JCExpression>nil(),
  2513                                           values.toList());
  2514         newArray.type = arrayType;
  2515         enumDefs.append(make.VarDef(valuesVar, newArray));
  2516         tree.sym.members().enter(valuesVar);
  2518         Symbol valuesSym = lookupMethod(tree.pos(), names.values,
  2519                                         tree.type, List.<Type>nil());
  2520         List<JCStatement> valuesBody;
  2521         if (useClone()) {
  2522             // return (T[]) $VALUES.clone();
  2523             JCTypeCast valuesResult =
  2524                 make.TypeCast(valuesSym.type.getReturnType(),
  2525                               make.App(make.Select(make.Ident(valuesVar),
  2526                                                    syms.arrayCloneMethod)));
  2527             valuesBody = List.<JCStatement>of(make.Return(valuesResult));
  2528         } else {
  2529             // template: T[] $result = new T[$values.length];
  2530             Name resultName = names.fromString(target.syntheticNameChar() + "result");
  2531             while (tree.sym.members().lookup(resultName).scope != null) // avoid name clash
  2532                 resultName = names.fromString(resultName + "" + target.syntheticNameChar());
  2533             VarSymbol resultVar = new VarSymbol(FINAL|SYNTHETIC,
  2534                                                 resultName,
  2535                                                 arrayType,
  2536                                                 valuesSym);
  2537             JCNewArray resultArray = make.NewArray(make.Type(types.erasure(tree.type)),
  2538                                   List.of(make.Select(make.Ident(valuesVar), syms.lengthVar)),
  2539                                   null);
  2540             resultArray.type = arrayType;
  2541             JCVariableDecl decl = make.VarDef(resultVar, resultArray);
  2543             // template: System.arraycopy($VALUES, 0, $result, 0, $VALUES.length);
  2544             if (systemArraycopyMethod == null) {
  2545                 systemArraycopyMethod =
  2546                     new MethodSymbol(PUBLIC | STATIC,
  2547                                      names.fromString("arraycopy"),
  2548                                      new MethodType(List.<Type>of(syms.objectType,
  2549                                                             syms.intType,
  2550                                                             syms.objectType,
  2551                                                             syms.intType,
  2552                                                             syms.intType),
  2553                                                     syms.voidType,
  2554                                                     List.<Type>nil(),
  2555                                                     syms.methodClass),
  2556                                      syms.systemType.tsym);
  2558             JCStatement copy =
  2559                 make.Exec(make.App(make.Select(make.Ident(syms.systemType.tsym),
  2560                                                systemArraycopyMethod),
  2561                           List.of(make.Ident(valuesVar), make.Literal(0),
  2562                                   make.Ident(resultVar), make.Literal(0),
  2563                                   make.Select(make.Ident(valuesVar), syms.lengthVar))));
  2565             // template: return $result;
  2566             JCStatement ret = make.Return(make.Ident(resultVar));
  2567             valuesBody = List.<JCStatement>of(decl, copy, ret);
  2570         JCMethodDecl valuesDef =
  2571              make.MethodDef((MethodSymbol)valuesSym, make.Block(0, valuesBody));
  2573         enumDefs.append(valuesDef);
  2575         if (debugLower)
  2576             System.err.println(tree.sym + ".valuesDef = " + valuesDef);
  2578         /** The template for the following code is:
  2580          *     public static E valueOf(String name) {
  2581          *         return (E)Enum.valueOf(E.class, name);
  2582          *     }
  2584          *  where E is tree.sym
  2585          */
  2586         MethodSymbol valueOfSym = lookupMethod(tree.pos(),
  2587                          names.valueOf,
  2588                          tree.sym.type,
  2589                          List.of(syms.stringType));
  2590         Assert.check((valueOfSym.flags() & STATIC) != 0);
  2591         VarSymbol nameArgSym = valueOfSym.params.head;
  2592         JCIdent nameVal = make.Ident(nameArgSym);
  2593         JCStatement enum_ValueOf =
  2594             make.Return(make.TypeCast(tree.sym.type,
  2595                                       makeCall(make.Ident(syms.enumSym),
  2596                                                names.valueOf,
  2597                                                List.of(e_class, nameVal))));
  2598         JCMethodDecl valueOf = make.MethodDef(valueOfSym,
  2599                                            make.Block(0, List.of(enum_ValueOf)));
  2600         nameVal.sym = valueOf.params.head.sym;
  2601         if (debugLower)
  2602             System.err.println(tree.sym + ".valueOf = " + valueOf);
  2603         enumDefs.append(valueOf);
  2605         enumDefs.appendList(otherDefs.toList());
  2606         tree.defs = enumDefs.toList();
  2608         // Add the necessary members for the EnumCompatibleMode
  2609         if (target.compilerBootstrap(tree.sym)) {
  2610             addEnumCompatibleMembers(tree);
  2613         // where
  2614         private MethodSymbol systemArraycopyMethod;
  2615         private boolean useClone() {
  2616             try {
  2617                 Scope.Entry e = syms.objectType.tsym.members().lookup(names.clone);
  2618                 return (e.sym != null);
  2620             catch (CompletionFailure e) {
  2621                 return false;
  2625     /** Translate an enumeration constant and its initializer. */
  2626     private void visitEnumConstantDef(JCVariableDecl var, int ordinal) {
  2627         JCNewClass varDef = (JCNewClass)var.init;
  2628         varDef.args = varDef.args.
  2629             prepend(makeLit(syms.intType, ordinal)).
  2630             prepend(makeLit(syms.stringType, var.name.toString()));
  2633     public void visitMethodDef(JCMethodDecl tree) {
  2634         if (tree.name == names.init && (currentClass.flags_field&ENUM) != 0) {
  2635             // Add "String $enum$name, int $enum$ordinal" to the beginning of the
  2636             // argument list for each constructor of an enum.
  2637             JCVariableDecl nameParam = make_at(tree.pos()).
  2638                 Param(names.fromString(target.syntheticNameChar() +
  2639                                        "enum" + target.syntheticNameChar() + "name"),
  2640                       syms.stringType, tree.sym);
  2641             nameParam.mods.flags |= SYNTHETIC; nameParam.sym.flags_field |= SYNTHETIC;
  2642             JCVariableDecl ordParam = make.
  2643                 Param(names.fromString(target.syntheticNameChar() +
  2644                                        "enum" + target.syntheticNameChar() +
  2645                                        "ordinal"),
  2646                       syms.intType, tree.sym);
  2647             ordParam.mods.flags |= SYNTHETIC; ordParam.sym.flags_field |= SYNTHETIC;
  2649             tree.params = tree.params.prepend(ordParam).prepend(nameParam);
  2651             MethodSymbol m = tree.sym;
  2652             m.extraParams = m.extraParams.prepend(ordParam.sym);
  2653             m.extraParams = m.extraParams.prepend(nameParam.sym);
  2654             Type olderasure = m.erasure(types);
  2655             m.erasure_field = new MethodType(
  2656                 olderasure.getParameterTypes().prepend(syms.intType).prepend(syms.stringType),
  2657                 olderasure.getReturnType(),
  2658                 olderasure.getThrownTypes(),
  2659                 syms.methodClass);
  2661             if (target.compilerBootstrap(m.owner)) {
  2662                 // Initialize synthetic name field
  2663                 Symbol nameVarSym = lookupSynthetic(names.fromString("$name"),
  2664                                                     tree.sym.owner.members());
  2665                 JCIdent nameIdent = make.Ident(nameParam.sym);
  2666                 JCIdent id1 = make.Ident(nameVarSym);
  2667                 JCAssign newAssign = make.Assign(id1, nameIdent);
  2668                 newAssign.type = id1.type;
  2669                 JCExpressionStatement nameAssign = make.Exec(newAssign);
  2670                 nameAssign.type = id1.type;
  2671                 tree.body.stats = tree.body.stats.prepend(nameAssign);
  2673                 // Initialize synthetic ordinal field
  2674                 Symbol ordinalVarSym = lookupSynthetic(names.fromString("$ordinal"),
  2675                                                        tree.sym.owner.members());
  2676                 JCIdent ordIdent = make.Ident(ordParam.sym);
  2677                 id1 = make.Ident(ordinalVarSym);
  2678                 newAssign = make.Assign(id1, ordIdent);
  2679                 newAssign.type = id1.type;
  2680                 JCExpressionStatement ordinalAssign = make.Exec(newAssign);
  2681                 ordinalAssign.type = id1.type;
  2682                 tree.body.stats = tree.body.stats.prepend(ordinalAssign);
  2686         JCMethodDecl prevMethodDef = currentMethodDef;
  2687         MethodSymbol prevMethodSym = currentMethodSym;
  2688         try {
  2689             currentMethodDef = tree;
  2690             currentMethodSym = tree.sym;
  2691             visitMethodDefInternal(tree);
  2692         } finally {
  2693             currentMethodDef = prevMethodDef;
  2694             currentMethodSym = prevMethodSym;
  2697     //where
  2698     private void visitMethodDefInternal(JCMethodDecl tree) {
  2699         if (tree.name == names.init &&
  2700             (currentClass.isInner() ||
  2701              (currentClass.owner.kind & (VAR | MTH)) != 0)) {
  2702             // We are seeing a constructor of an inner class.
  2703             MethodSymbol m = tree.sym;
  2705             // Push a new proxy scope for constructor parameters.
  2706             // and create definitions for any this$n and proxy parameters.
  2707             proxies = proxies.dup(m);
  2708             List<VarSymbol> prevOuterThisStack = outerThisStack;
  2709             List<VarSymbol> fvs = freevars(currentClass);
  2710             JCVariableDecl otdef = null;
  2711             if (currentClass.hasOuterInstance())
  2712                 otdef = outerThisDef(tree.pos, m);
  2713             List<JCVariableDecl> fvdefs = freevarDefs(tree.pos, fvs, m);
  2715             // Recursively translate result type, parameters and thrown list.
  2716             tree.restype = translate(tree.restype);
  2717             tree.params = translateVarDefs(tree.params);
  2718             tree.thrown = translate(tree.thrown);
  2720             // when compiling stubs, don't process body
  2721             if (tree.body == null) {
  2722                 result = tree;
  2723                 return;
  2726             // Add this$n (if needed) in front of and free variables behind
  2727             // constructor parameter list.
  2728             tree.params = tree.params.appendList(fvdefs);
  2729             if (currentClass.hasOuterInstance())
  2730                 tree.params = tree.params.prepend(otdef);
  2732             // If this is an initial constructor, i.e., it does not start with
  2733             // this(...), insert initializers for this$n and proxies
  2734             // before (pre-1.4, after) the call to superclass constructor.
  2735             JCStatement selfCall = translate(tree.body.stats.head);
  2737             List<JCStatement> added = List.nil();
  2738             if (fvs.nonEmpty()) {
  2739                 List<Type> addedargtypes = List.nil();
  2740                 for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail) {
  2741                     if (TreeInfo.isInitialConstructor(tree))
  2742                         added = added.prepend(
  2743                             initField(tree.body.pos, proxyName(l.head.name)));
  2744                     addedargtypes = addedargtypes.prepend(l.head.erasure(types));
  2746                 Type olderasure = m.erasure(types);
  2747                 m.erasure_field = new MethodType(
  2748                     olderasure.getParameterTypes().appendList(addedargtypes),
  2749                     olderasure.getReturnType(),
  2750                     olderasure.getThrownTypes(),
  2751                     syms.methodClass);
  2753             if (currentClass.hasOuterInstance() &&
  2754                 TreeInfo.isInitialConstructor(tree))
  2756                 added = added.prepend(initOuterThis(tree.body.pos));
  2759             // pop local variables from proxy stack
  2760             proxies = proxies.leave();
  2762             // recursively translate following local statements and
  2763             // combine with this- or super-call
  2764             List<JCStatement> stats = translate(tree.body.stats.tail);
  2765             if (target.initializeFieldsBeforeSuper())
  2766                 tree.body.stats = stats.prepend(selfCall).prependList(added);
  2767             else
  2768                 tree.body.stats = stats.prependList(added).prepend(selfCall);
  2770             outerThisStack = prevOuterThisStack;
  2771         } else {
  2772             Map<Symbol, Symbol> prevLambdaTranslationMap =
  2773                     lambdaTranslationMap;
  2774             try {
  2775                 lambdaTranslationMap = (tree.sym.flags() & SYNTHETIC) != 0 &&
  2776                         tree.sym.name.startsWith(names.lambda) ?
  2777                         makeTranslationMap(tree) : null;
  2778                 super.visitMethodDef(tree);
  2779             } finally {
  2780                 lambdaTranslationMap = prevLambdaTranslationMap;
  2783         result = tree;
  2785     //where
  2786         private Map<Symbol, Symbol> makeTranslationMap(JCMethodDecl tree) {
  2787             Map<Symbol, Symbol> translationMap = new HashMap<Symbol,Symbol>();
  2788             for (JCVariableDecl vd : tree.params) {
  2789                 Symbol p = vd.sym;
  2790                 if (p != p.baseSymbol()) {
  2791                     translationMap.put(p.baseSymbol(), p);
  2794             return translationMap;
  2797     public void visitAnnotatedType(JCAnnotatedType tree) {
  2798         // No need to retain type annotations any longer.
  2799         // tree.annotations = translate(tree.annotations);
  2800         tree.underlyingType = translate(tree.underlyingType);
  2801         result = tree.underlyingType;
  2804     public void visitTypeCast(JCTypeCast tree) {
  2805         tree.clazz = translate(tree.clazz);
  2806         if (tree.type.isPrimitive() != tree.expr.type.isPrimitive())
  2807             tree.expr = translate(tree.expr, tree.type);
  2808         else
  2809             tree.expr = translate(tree.expr);
  2810         result = tree;
  2813     public void visitNewClass(JCNewClass tree) {
  2814         ClassSymbol c = (ClassSymbol)tree.constructor.owner;
  2816         // Box arguments, if necessary
  2817         boolean isEnum = (tree.constructor.owner.flags() & ENUM) != 0;
  2818         List<Type> argTypes = tree.constructor.type.getParameterTypes();
  2819         if (isEnum) argTypes = argTypes.prepend(syms.intType).prepend(syms.stringType);
  2820         tree.args = boxArgs(argTypes, tree.args, tree.varargsElement);
  2821         tree.varargsElement = null;
  2823         // If created class is local, add free variables after
  2824         // explicit constructor arguments.
  2825         if ((c.owner.kind & (VAR | MTH)) != 0) {
  2826             tree.args = tree.args.appendList(loadFreevars(tree.pos(), freevars(c)));
  2829         // If an access constructor is used, append null as a last argument.
  2830         Symbol constructor = accessConstructor(tree.pos(), tree.constructor);
  2831         if (constructor != tree.constructor) {
  2832             tree.args = tree.args.append(makeNull());
  2833             tree.constructor = constructor;
  2836         // If created class has an outer instance, and new is qualified, pass
  2837         // qualifier as first argument. If new is not qualified, pass the
  2838         // correct outer instance as first argument.
  2839         if (c.hasOuterInstance()) {
  2840             JCExpression thisArg;
  2841             if (tree.encl != null) {
  2842                 thisArg = attr.makeNullCheck(translate(tree.encl));
  2843                 thisArg.type = tree.encl.type;
  2844             } else if ((c.owner.kind & (MTH | VAR)) != 0) {
  2845                 // local class
  2846                 thisArg = makeThis(tree.pos(), c.type.getEnclosingType().tsym);
  2847             } else {
  2848                 // nested class
  2849                 thisArg = makeOwnerThis(tree.pos(), c, false);
  2851             tree.args = tree.args.prepend(thisArg);
  2853         tree.encl = null;
  2855         // If we have an anonymous class, create its flat version, rather
  2856         // than the class or interface following new.
  2857         if (tree.def != null) {
  2858             translate(tree.def);
  2859             tree.clazz = access(make_at(tree.clazz.pos()).Ident(tree.def.sym));
  2860             tree.def = null;
  2861         } else {
  2862             tree.clazz = access(c, tree.clazz, enclOp, false);
  2864         result = tree;
  2867     // Simplify conditionals with known constant controlling expressions.
  2868     // This allows us to avoid generating supporting declarations for
  2869     // the dead code, which will not be eliminated during code generation.
  2870     // Note that Flow.isFalse and Flow.isTrue only return true
  2871     // for constant expressions in the sense of JLS 15.27, which
  2872     // are guaranteed to have no side-effects.  More aggressive
  2873     // constant propagation would require that we take care to
  2874     // preserve possible side-effects in the condition expression.
  2876     /** Visitor method for conditional expressions.
  2877      */
  2878     @Override
  2879     public void visitConditional(JCConditional tree) {
  2880         JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
  2881         if (cond.type.isTrue()) {
  2882             result = convert(translate(tree.truepart, tree.type), tree.type);
  2883             addPrunedInfo(cond);
  2884         } else if (cond.type.isFalse()) {
  2885             result = convert(translate(tree.falsepart, tree.type), tree.type);
  2886             addPrunedInfo(cond);
  2887         } else {
  2888             // Condition is not a compile-time constant.
  2889             tree.truepart = translate(tree.truepart, tree.type);
  2890             tree.falsepart = translate(tree.falsepart, tree.type);
  2891             result = tree;
  2894 //where
  2895     private JCTree convert(JCTree tree, Type pt) {
  2896         if (tree.type == pt || tree.type.hasTag(BOT))
  2897             return tree;
  2898         JCTree result = make_at(tree.pos()).TypeCast(make.Type(pt), (JCExpression)tree);
  2899         result.type = (tree.type.constValue() != null) ? cfolder.coerce(tree.type, pt)
  2900                                                        : pt;
  2901         return result;
  2904     /** Visitor method for if statements.
  2905      */
  2906     public void visitIf(JCIf tree) {
  2907         JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
  2908         if (cond.type.isTrue()) {
  2909             result = translate(tree.thenpart);
  2910             addPrunedInfo(cond);
  2911         } else if (cond.type.isFalse()) {
  2912             if (tree.elsepart != null) {
  2913                 result = translate(tree.elsepart);
  2914             } else {
  2915                 result = make.Skip();
  2917             addPrunedInfo(cond);
  2918         } else {
  2919             // Condition is not a compile-time constant.
  2920             tree.thenpart = translate(tree.thenpart);
  2921             tree.elsepart = translate(tree.elsepart);
  2922             result = tree;
  2926     /** Visitor method for assert statements. Translate them away.
  2927      */
  2928     public void visitAssert(JCAssert tree) {
  2929         DiagnosticPosition detailPos = (tree.detail == null) ? tree.pos() : tree.detail.pos();
  2930         tree.cond = translate(tree.cond, syms.booleanType);
  2931         if (!tree.cond.type.isTrue()) {
  2932             JCExpression cond = assertFlagTest(tree.pos());
  2933             List<JCExpression> exnArgs = (tree.detail == null) ?
  2934                 List.<JCExpression>nil() : List.of(translate(tree.detail));
  2935             if (!tree.cond.type.isFalse()) {
  2936                 cond = makeBinary
  2937                     (AND,
  2938                      cond,
  2939                      makeUnary(NOT, tree.cond));
  2941             result =
  2942                 make.If(cond,
  2943                         make_at(detailPos).
  2944                            Throw(makeNewClass(syms.assertionErrorType, exnArgs)),
  2945                         null);
  2946         } else {
  2947             result = make.Skip();
  2951     public void visitApply(JCMethodInvocation tree) {
  2952         Symbol meth = TreeInfo.symbol(tree.meth);
  2953         List<Type> argtypes = meth.type.getParameterTypes();
  2954         if (allowEnums &&
  2955             meth.name==names.init &&
  2956             meth.owner == syms.enumSym)
  2957             argtypes = argtypes.tail.tail;
  2958         tree.args = boxArgs(argtypes, tree.args, tree.varargsElement);
  2959         tree.varargsElement = null;
  2960         Name methName = TreeInfo.name(tree.meth);
  2961         if (meth.name==names.init) {
  2962             // We are seeing a this(...) or super(...) constructor call.
  2963             // If an access constructor is used, append null as a last argument.
  2964             Symbol constructor = accessConstructor(tree.pos(), meth);
  2965             if (constructor != meth) {
  2966                 tree.args = tree.args.append(makeNull());
  2967                 TreeInfo.setSymbol(tree.meth, constructor);
  2970             // If we are calling a constructor of a local class, add
  2971             // free variables after explicit constructor arguments.
  2972             ClassSymbol c = (ClassSymbol)constructor.owner;
  2973             if ((c.owner.kind & (VAR | MTH)) != 0) {
  2974                 tree.args = tree.args.appendList(loadFreevars(tree.pos(), freevars(c)));
  2977             // If we are calling a constructor of an enum class, pass
  2978             // along the name and ordinal arguments
  2979             if ((c.flags_field&ENUM) != 0 || c.getQualifiedName() == names.java_lang_Enum) {
  2980                 List<JCVariableDecl> params = currentMethodDef.params;
  2981                 if (currentMethodSym.owner.hasOuterInstance())
  2982                     params = params.tail; // drop this$n
  2983                 tree.args = tree.args
  2984                     .prepend(make_at(tree.pos()).Ident(params.tail.head.sym)) // ordinal
  2985                     .prepend(make.Ident(params.head.sym)); // name
  2988             // If we are calling a constructor of a class with an outer
  2989             // instance, and the call
  2990             // is qualified, pass qualifier as first argument in front of
  2991             // the explicit constructor arguments. If the call
  2992             // is not qualified, pass the correct outer instance as
  2993             // first argument.
  2994             if (c.hasOuterInstance()) {
  2995                 JCExpression thisArg;
  2996                 if (tree.meth.hasTag(SELECT)) {
  2997                     thisArg = attr.
  2998                         makeNullCheck(translate(((JCFieldAccess) tree.meth).selected));
  2999                     tree.meth = make.Ident(constructor);
  3000                     ((JCIdent) tree.meth).name = methName;
  3001                 } else if ((c.owner.kind & (MTH | VAR)) != 0 || methName == names._this){
  3002                     // local class or this() call
  3003                     thisArg = makeThis(tree.meth.pos(), c.type.getEnclosingType().tsym);
  3004                 } else {
  3005                     // super() call of nested class - never pick 'this'
  3006                     thisArg = makeOwnerThisN(tree.meth.pos(), c, false);
  3008                 tree.args = tree.args.prepend(thisArg);
  3010         } else {
  3011             // We are seeing a normal method invocation; translate this as usual.
  3012             tree.meth = translate(tree.meth);
  3014             // If the translated method itself is an Apply tree, we are
  3015             // seeing an access method invocation. In this case, append
  3016             // the method arguments to the arguments of the access method.
  3017             if (tree.meth.hasTag(APPLY)) {
  3018                 JCMethodInvocation app = (JCMethodInvocation)tree.meth;
  3019                 app.args = tree.args.prependList(app.args);
  3020                 result = app;
  3021                 return;
  3024         result = tree;
  3027     List<JCExpression> boxArgs(List<Type> parameters, List<JCExpression> _args, Type varargsElement) {
  3028         List<JCExpression> args = _args;
  3029         if (parameters.isEmpty()) return args;
  3030         boolean anyChanges = false;
  3031         ListBuffer<JCExpression> result = new ListBuffer<JCExpression>();
  3032         while (parameters.tail.nonEmpty()) {
  3033             JCExpression arg = translate(args.head, parameters.head);
  3034             anyChanges |= (arg != args.head);
  3035             result.append(arg);
  3036             args = args.tail;
  3037             parameters = parameters.tail;
  3039         Type parameter = parameters.head;
  3040         if (varargsElement != null) {
  3041             anyChanges = true;
  3042             ListBuffer<JCExpression> elems = new ListBuffer<JCExpression>();
  3043             while (args.nonEmpty()) {
  3044                 JCExpression arg = translate(args.head, varargsElement);
  3045                 elems.append(arg);
  3046                 args = args.tail;
  3048             JCNewArray boxedArgs = make.NewArray(make.Type(varargsElement),
  3049                                                List.<JCExpression>nil(),
  3050                                                elems.toList());
  3051             boxedArgs.type = new ArrayType(varargsElement, syms.arrayClass);
  3052             result.append(boxedArgs);
  3053         } else {
  3054             if (args.length() != 1) throw new AssertionError(args);
  3055             JCExpression arg = translate(args.head, parameter);
  3056             anyChanges |= (arg != args.head);
  3057             result.append(arg);
  3058             if (!anyChanges) return _args;
  3060         return result.toList();
  3063     /** Expand a boxing or unboxing conversion if needed. */
  3064     @SuppressWarnings("unchecked") // XXX unchecked
  3065     <T extends JCTree> T boxIfNeeded(T tree, Type type) {
  3066         boolean havePrimitive = tree.type.isPrimitive();
  3067         if (havePrimitive == type.isPrimitive())
  3068             return tree;
  3069         if (havePrimitive) {
  3070             Type unboxedTarget = types.unboxedType(type);
  3071             if (!unboxedTarget.hasTag(NONE)) {
  3072                 if (!types.isSubtype(tree.type, unboxedTarget)) //e.g. Character c = 89;
  3073                     tree.type = unboxedTarget.constType(tree.type.constValue());
  3074                 return (T)boxPrimitive((JCExpression)tree, type);
  3075             } else {
  3076                 tree = (T)boxPrimitive((JCExpression)tree);
  3078         } else {
  3079             tree = (T)unbox((JCExpression)tree, type);
  3081         return tree;
  3084     /** Box up a single primitive expression. */
  3085     JCExpression boxPrimitive(JCExpression tree) {
  3086         return boxPrimitive(tree, types.boxedClass(tree.type).type);
  3089     /** Box up a single primitive expression. */
  3090     JCExpression boxPrimitive(JCExpression tree, Type box) {
  3091         make_at(tree.pos());
  3092         if (target.boxWithConstructors()) {
  3093             Symbol ctor = lookupConstructor(tree.pos(),
  3094                                             box,
  3095                                             List.<Type>nil()
  3096                                             .prepend(tree.type));
  3097             return make.Create(ctor, List.of(tree));
  3098         } else {
  3099             Symbol valueOfSym = lookupMethod(tree.pos(),
  3100                                              names.valueOf,
  3101                                              box,
  3102                                              List.<Type>nil()
  3103                                              .prepend(tree.type));
  3104             return make.App(make.QualIdent(valueOfSym), List.of(tree));
  3108     /** Unbox an object to a primitive value. */
  3109     JCExpression unbox(JCExpression tree, Type primitive) {
  3110         Type unboxedType = types.unboxedType(tree.type);
  3111         if (unboxedType.hasTag(NONE)) {
  3112             unboxedType = primitive;
  3113             if (!unboxedType.isPrimitive())
  3114                 throw new AssertionError(unboxedType);
  3115             make_at(tree.pos());
  3116             tree = make.TypeCast(types.boxedClass(unboxedType).type, tree);
  3117         } else {
  3118             // There must be a conversion from unboxedType to primitive.
  3119             if (!types.isSubtype(unboxedType, primitive))
  3120                 throw new AssertionError(tree);
  3122         make_at(tree.pos());
  3123         Symbol valueSym = lookupMethod(tree.pos(),
  3124                                        unboxedType.tsym.name.append(names.Value), // x.intValue()
  3125                                        tree.type,
  3126                                        List.<Type>nil());
  3127         return make.App(make.Select(tree, valueSym));
  3130     /** Visitor method for parenthesized expressions.
  3131      *  If the subexpression has changed, omit the parens.
  3132      */
  3133     public void visitParens(JCParens tree) {
  3134         JCTree expr = translate(tree.expr);
  3135         result = ((expr == tree.expr) ? tree : expr);
  3138     public void visitIndexed(JCArrayAccess tree) {
  3139         tree.indexed = translate(tree.indexed);
  3140         tree.index = translate(tree.index, syms.intType);
  3141         result = tree;
  3144     public void visitAssign(JCAssign tree) {
  3145         tree.lhs = translate(tree.lhs, tree);
  3146         tree.rhs = translate(tree.rhs, tree.lhs.type);
  3148         // If translated left hand side is an Apply, we are
  3149         // seeing an access method invocation. In this case, append
  3150         // right hand side as last argument of the access method.
  3151         if (tree.lhs.hasTag(APPLY)) {
  3152             JCMethodInvocation app = (JCMethodInvocation)tree.lhs;
  3153             app.args = List.of(tree.rhs).prependList(app.args);
  3154             result = app;
  3155         } else {
  3156             result = tree;
  3160     public void visitAssignop(final JCAssignOp tree) {
  3161         JCTree lhsAccess = access(TreeInfo.skipParens(tree.lhs));
  3162         final boolean boxingReq = !tree.lhs.type.isPrimitive() &&
  3163             tree.operator.type.getReturnType().isPrimitive();
  3165         if (boxingReq || lhsAccess.hasTag(APPLY)) {
  3166             // boxing required; need to rewrite as x = (unbox typeof x)(x op y);
  3167             // or if x == (typeof x)z then z = (unbox typeof x)((typeof x)z op y)
  3168             // (but without recomputing x)
  3169             JCTree newTree = abstractLval(tree.lhs, new TreeBuilder() {
  3170                     public JCTree build(final JCTree lhs) {
  3171                         JCTree.Tag newTag = tree.getTag().noAssignOp();
  3172                         // Erasure (TransTypes) can change the type of
  3173                         // tree.lhs.  However, we can still get the
  3174                         // unerased type of tree.lhs as it is stored
  3175                         // in tree.type in Attr.
  3176                         Symbol newOperator = rs.resolveBinaryOperator(tree.pos(),
  3177                                                                       newTag,
  3178                                                                       attrEnv,
  3179                                                                       tree.type,
  3180                                                                       tree.rhs.type);
  3181                         JCExpression expr = (JCExpression)lhs;
  3182                         if (expr.type != tree.type)
  3183                             expr = make.TypeCast(tree.type, expr);
  3184                         JCBinary opResult = make.Binary(newTag, expr, tree.rhs);
  3185                         opResult.operator = newOperator;
  3186                         opResult.type = newOperator.type.getReturnType();
  3187                         JCExpression newRhs = boxingReq ?
  3188                             make.TypeCast(types.unboxedType(tree.type), opResult) :
  3189                             opResult;
  3190                         return make.Assign((JCExpression)lhs, newRhs).setType(tree.type);
  3192                 });
  3193             result = translate(newTree);
  3194             return;
  3196         tree.lhs = translate(tree.lhs, tree);
  3197         tree.rhs = translate(tree.rhs, tree.operator.type.getParameterTypes().tail.head);
  3199         // If translated left hand side is an Apply, we are
  3200         // seeing an access method invocation. In this case, append
  3201         // right hand side as last argument of the access method.
  3202         if (tree.lhs.hasTag(APPLY)) {
  3203             JCMethodInvocation app = (JCMethodInvocation)tree.lhs;
  3204             // if operation is a += on strings,
  3205             // make sure to convert argument to string
  3206             JCExpression rhs = (((OperatorSymbol)tree.operator).opcode == string_add)
  3207               ? makeString(tree.rhs)
  3208               : tree.rhs;
  3209             app.args = List.of(rhs).prependList(app.args);
  3210             result = app;
  3211         } else {
  3212             result = tree;
  3216     /** Lower a tree of the form e++ or e-- where e is an object type */
  3217     JCTree lowerBoxedPostop(final JCUnary tree) {
  3218         // translate to tmp1=lval(e); tmp2=tmp1; tmp1 OP 1; tmp2
  3219         // or
  3220         // translate to tmp1=lval(e); tmp2=tmp1; (typeof tree)tmp1 OP 1; tmp2
  3221         // where OP is += or -=
  3222         final boolean cast = TreeInfo.skipParens(tree.arg).hasTag(TYPECAST);
  3223         return abstractLval(tree.arg, new TreeBuilder() {
  3224                 public JCTree build(final JCTree tmp1) {
  3225                     return abstractRval(tmp1, tree.arg.type, new TreeBuilder() {
  3226                             public JCTree build(final JCTree tmp2) {
  3227                                 JCTree.Tag opcode = (tree.hasTag(POSTINC))
  3228                                     ? PLUS_ASG : MINUS_ASG;
  3229                                 JCTree lhs = cast
  3230                                     ? make.TypeCast(tree.arg.type, (JCExpression)tmp1)
  3231                                     : tmp1;
  3232                                 JCTree update = makeAssignop(opcode,
  3233                                                              lhs,
  3234                                                              make.Literal(1));
  3235                                 return makeComma(update, tmp2);
  3237                         });
  3239             });
  3242     public void visitUnary(JCUnary tree) {
  3243         boolean isUpdateOperator = tree.getTag().isIncOrDecUnaryOp();
  3244         if (isUpdateOperator && !tree.arg.type.isPrimitive()) {
  3245             switch(tree.getTag()) {
  3246             case PREINC:            // ++ e
  3247                     // translate to e += 1
  3248             case PREDEC:            // -- e
  3249                     // translate to e -= 1
  3251                     JCTree.Tag opcode = (tree.hasTag(PREINC))
  3252                         ? PLUS_ASG : MINUS_ASG;
  3253                     JCAssignOp newTree = makeAssignop(opcode,
  3254                                                     tree.arg,
  3255                                                     make.Literal(1));
  3256                     result = translate(newTree, tree.type);
  3257                     return;
  3259             case POSTINC:           // e ++
  3260             case POSTDEC:           // e --
  3262                     result = translate(lowerBoxedPostop(tree), tree.type);
  3263                     return;
  3266             throw new AssertionError(tree);
  3269         tree.arg = boxIfNeeded(translate(tree.arg, tree), tree.type);
  3271         if (tree.hasTag(NOT) && tree.arg.type.constValue() != null) {
  3272             tree.type = cfolder.fold1(bool_not, tree.arg.type);
  3275         // If translated left hand side is an Apply, we are
  3276         // seeing an access method invocation. In this case, return
  3277         // that access method invocation as result.
  3278         if (isUpdateOperator && tree.arg.hasTag(APPLY)) {
  3279             result = tree.arg;
  3280         } else {
  3281             result = tree;
  3285     public void visitBinary(JCBinary tree) {
  3286         List<Type> formals = tree.operator.type.getParameterTypes();
  3287         JCTree lhs = tree.lhs = translate(tree.lhs, formals.head);
  3288         switch (tree.getTag()) {
  3289         case OR:
  3290             if (lhs.type.isTrue()) {
  3291                 result = lhs;
  3292                 return;
  3294             if (lhs.type.isFalse()) {
  3295                 result = translate(tree.rhs, formals.tail.head);
  3296                 return;
  3298             break;
  3299         case AND:
  3300             if (lhs.type.isFalse()) {
  3301                 result = lhs;
  3302                 return;
  3304             if (lhs.type.isTrue()) {
  3305                 result = translate(tree.rhs, formals.tail.head);
  3306                 return;
  3308             break;
  3310         tree.rhs = translate(tree.rhs, formals.tail.head);
  3311         result = tree;
  3314     public void visitIdent(JCIdent tree) {
  3315         result = access(tree.sym, tree, enclOp, false);
  3318     /** Translate away the foreach loop.  */
  3319     public void visitForeachLoop(JCEnhancedForLoop tree) {
  3320         if (types.elemtype(tree.expr.type) == null)
  3321             visitIterableForeachLoop(tree);
  3322         else
  3323             visitArrayForeachLoop(tree);
  3325         // where
  3326         /**
  3327          * A statement of the form
  3329          * <pre>
  3330          *     for ( T v : arrayexpr ) stmt;
  3331          * </pre>
  3333          * (where arrayexpr is of an array type) gets translated to
  3335          * <pre>{@code
  3336          *     for ( { arraytype #arr = arrayexpr;
  3337          *             int #len = array.length;
  3338          *             int #i = 0; };
  3339          *           #i < #len; i$++ ) {
  3340          *         T v = arr$[#i];
  3341          *         stmt;
  3342          *     }
  3343          * }</pre>
  3345          * where #arr, #len, and #i are freshly named synthetic local variables.
  3346          */
  3347         private void visitArrayForeachLoop(JCEnhancedForLoop tree) {
  3348             make_at(tree.expr.pos());
  3349             VarSymbol arraycache = new VarSymbol(0,
  3350                                                  names.fromString("arr" + target.syntheticNameChar()),
  3351                                                  tree.expr.type,
  3352                                                  currentMethodSym);
  3353             JCStatement arraycachedef = make.VarDef(arraycache, tree.expr);
  3354             VarSymbol lencache = new VarSymbol(0,
  3355                                                names.fromString("len" + target.syntheticNameChar()),
  3356                                                syms.intType,
  3357                                                currentMethodSym);
  3358             JCStatement lencachedef = make.
  3359                 VarDef(lencache, make.Select(make.Ident(arraycache), syms.lengthVar));
  3360             VarSymbol index = new VarSymbol(0,
  3361                                             names.fromString("i" + target.syntheticNameChar()),
  3362                                             syms.intType,
  3363                                             currentMethodSym);
  3365             JCVariableDecl indexdef = make.VarDef(index, make.Literal(INT, 0));
  3366             indexdef.init.type = indexdef.type = syms.intType.constType(0);
  3368             List<JCStatement> loopinit = List.of(arraycachedef, lencachedef, indexdef);
  3369             JCBinary cond = makeBinary(LT, make.Ident(index), make.Ident(lencache));
  3371             JCExpressionStatement step = make.Exec(makeUnary(PREINC, make.Ident(index)));
  3373             Type elemtype = types.elemtype(tree.expr.type);
  3374             JCExpression loopvarinit = make.Indexed(make.Ident(arraycache),
  3375                                                     make.Ident(index)).setType(elemtype);
  3376             JCVariableDecl loopvardef = (JCVariableDecl)make.VarDef(tree.var.mods,
  3377                                                   tree.var.name,
  3378                                                   tree.var.vartype,
  3379                                                   loopvarinit).setType(tree.var.type);
  3380             loopvardef.sym = tree.var.sym;
  3381             JCBlock body = make.
  3382                 Block(0, List.of(loopvardef, tree.body));
  3384             result = translate(make.
  3385                                ForLoop(loopinit,
  3386                                        cond,
  3387                                        List.of(step),
  3388                                        body));
  3389             patchTargets(body, tree, result);
  3391         /** Patch up break and continue targets. */
  3392         private void patchTargets(JCTree body, final JCTree src, final JCTree dest) {
  3393             class Patcher extends TreeScanner {
  3394                 public void visitBreak(JCBreak tree) {
  3395                     if (tree.target == src)
  3396                         tree.target = dest;
  3398                 public void visitContinue(JCContinue tree) {
  3399                     if (tree.target == src)
  3400                         tree.target = dest;
  3402                 public void visitClassDef(JCClassDecl tree) {}
  3404             new Patcher().scan(body);
  3406         /**
  3407          * A statement of the form
  3409          * <pre>
  3410          *     for ( T v : coll ) stmt ;
  3411          * </pre>
  3413          * (where coll implements {@code Iterable<? extends T>}) gets translated to
  3415          * <pre>{@code
  3416          *     for ( Iterator<? extends T> #i = coll.iterator(); #i.hasNext(); ) {
  3417          *         T v = (T) #i.next();
  3418          *         stmt;
  3419          *     }
  3420          * }</pre>
  3422          * where #i is a freshly named synthetic local variable.
  3423          */
  3424         private void visitIterableForeachLoop(JCEnhancedForLoop tree) {
  3425             make_at(tree.expr.pos());
  3426             Type iteratorTarget = syms.objectType;
  3427             Type iterableType = types.asSuper(types.upperBound(tree.expr.type),
  3428                                               syms.iterableType.tsym);
  3429             if (iterableType.getTypeArguments().nonEmpty())
  3430                 iteratorTarget = types.erasure(iterableType.getTypeArguments().head);
  3431             Type eType = tree.expr.type;
  3432             tree.expr.type = types.erasure(eType);
  3433             if (eType.hasTag(TYPEVAR) && eType.getUpperBound().isCompound())
  3434                 tree.expr = make.TypeCast(types.erasure(iterableType), tree.expr);
  3435             Symbol iterator = lookupMethod(tree.expr.pos(),
  3436                                            names.iterator,
  3437                                            types.erasure(syms.iterableType),
  3438                                            List.<Type>nil());
  3439             VarSymbol itvar = new VarSymbol(0, names.fromString("i" + target.syntheticNameChar()),
  3440                                             types.erasure(iterator.type.getReturnType()),
  3441                                             currentMethodSym);
  3442             JCStatement init = make.
  3443                 VarDef(itvar,
  3444                        make.App(make.Select(tree.expr, iterator)));
  3445             Symbol hasNext = lookupMethod(tree.expr.pos(),
  3446                                           names.hasNext,
  3447                                           itvar.type,
  3448                                           List.<Type>nil());
  3449             JCMethodInvocation cond = make.App(make.Select(make.Ident(itvar), hasNext));
  3450             Symbol next = lookupMethod(tree.expr.pos(),
  3451                                        names.next,
  3452                                        itvar.type,
  3453                                        List.<Type>nil());
  3454             JCExpression vardefinit = make.App(make.Select(make.Ident(itvar), next));
  3455             if (tree.var.type.isPrimitive())
  3456                 vardefinit = make.TypeCast(types.upperBound(iteratorTarget), vardefinit);
  3457             else
  3458                 vardefinit = make.TypeCast(tree.var.type, vardefinit);
  3459             JCVariableDecl indexDef = (JCVariableDecl)make.VarDef(tree.var.mods,
  3460                                                   tree.var.name,
  3461                                                   tree.var.vartype,
  3462                                                   vardefinit).setType(tree.var.type);
  3463             indexDef.sym = tree.var.sym;
  3464             JCBlock body = make.Block(0, List.of(indexDef, tree.body));
  3465             body.endpos = TreeInfo.endPos(tree.body);
  3466             result = translate(make.
  3467                 ForLoop(List.of(init),
  3468                         cond,
  3469                         List.<JCExpressionStatement>nil(),
  3470                         body));
  3471             patchTargets(body, tree, result);
  3474     public void visitVarDef(JCVariableDecl tree) {
  3475         MethodSymbol oldMethodSym = currentMethodSym;
  3476         tree.mods = translate(tree.mods);
  3477         tree.vartype = translate(tree.vartype);
  3478         if (currentMethodSym == null) {
  3479             // A class or instance field initializer.
  3480             currentMethodSym =
  3481                 new MethodSymbol((tree.mods.flags&STATIC) | BLOCK,
  3482                                  names.empty, null,
  3483                                  currentClass);
  3485         if (tree.init != null) tree.init = translate(tree.init, tree.type);
  3486         result = tree;
  3487         currentMethodSym = oldMethodSym;
  3490     public void visitBlock(JCBlock tree) {
  3491         MethodSymbol oldMethodSym = currentMethodSym;
  3492         if (currentMethodSym == null) {
  3493             // Block is a static or instance initializer.
  3494             currentMethodSym =
  3495                 new MethodSymbol(tree.flags | BLOCK,
  3496                                  names.empty, null,
  3497                                  currentClass);
  3499         super.visitBlock(tree);
  3500         currentMethodSym = oldMethodSym;
  3503     public void visitDoLoop(JCDoWhileLoop tree) {
  3504         tree.body = translate(tree.body);
  3505         tree.cond = translate(tree.cond, syms.booleanType);
  3506         result = tree;
  3509     public void visitWhileLoop(JCWhileLoop tree) {
  3510         tree.cond = translate(tree.cond, syms.booleanType);
  3511         tree.body = translate(tree.body);
  3512         result = tree;
  3515     public void visitForLoop(JCForLoop tree) {
  3516         tree.init = translate(tree.init);
  3517         if (tree.cond != null)
  3518             tree.cond = translate(tree.cond, syms.booleanType);
  3519         tree.step = translate(tree.step);
  3520         tree.body = translate(tree.body);
  3521         result = tree;
  3524     public void visitReturn(JCReturn tree) {
  3525         if (tree.expr != null)
  3526             tree.expr = translate(tree.expr,
  3527                                   types.erasure(currentMethodDef
  3528                                                 .restype.type));
  3529         result = tree;
  3532     public void visitSwitch(JCSwitch tree) {
  3533         Type selsuper = types.supertype(tree.selector.type);
  3534         boolean enumSwitch = selsuper != null &&
  3535             (tree.selector.type.tsym.flags() & ENUM) != 0;
  3536         boolean stringSwitch = selsuper != null &&
  3537             types.isSameType(tree.selector.type, syms.stringType);
  3538         Type target = enumSwitch ? tree.selector.type :
  3539             (stringSwitch? syms.stringType : syms.intType);
  3540         tree.selector = translate(tree.selector, target);
  3541         tree.cases = translateCases(tree.cases);
  3542         if (enumSwitch) {
  3543             result = visitEnumSwitch(tree);
  3544         } else if (stringSwitch) {
  3545             result = visitStringSwitch(tree);
  3546         } else {
  3547             result = tree;
  3551     public JCTree visitEnumSwitch(JCSwitch tree) {
  3552         TypeSymbol enumSym = tree.selector.type.tsym;
  3553         EnumMapping map = mapForEnum(tree.pos(), enumSym);
  3554         make_at(tree.pos());
  3555         Symbol ordinalMethod = lookupMethod(tree.pos(),
  3556                                             names.ordinal,
  3557                                             tree.selector.type,
  3558                                             List.<Type>nil());
  3559         JCArrayAccess selector = make.Indexed(map.mapVar,
  3560                                         make.App(make.Select(tree.selector,
  3561                                                              ordinalMethod)));
  3562         ListBuffer<JCCase> cases = new ListBuffer<JCCase>();
  3563         for (JCCase c : tree.cases) {
  3564             if (c.pat != null) {
  3565                 VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pat);
  3566                 JCLiteral pat = map.forConstant(label);
  3567                 cases.append(make.Case(pat, c.stats));
  3568             } else {
  3569                 cases.append(c);
  3572         JCSwitch enumSwitch = make.Switch(selector, cases.toList());
  3573         patchTargets(enumSwitch, tree, enumSwitch);
  3574         return enumSwitch;
  3577     public JCTree visitStringSwitch(JCSwitch tree) {
  3578         List<JCCase> caseList = tree.getCases();
  3579         int alternatives = caseList.size();
  3581         if (alternatives == 0) { // Strange but legal possibility
  3582             return make.at(tree.pos()).Exec(attr.makeNullCheck(tree.getExpression()));
  3583         } else {
  3584             /*
  3585              * The general approach used is to translate a single
  3586              * string switch statement into a series of two chained
  3587              * switch statements: the first a synthesized statement
  3588              * switching on the argument string's hash value and
  3589              * computing a string's position in the list of original
  3590              * case labels, if any, followed by a second switch on the
  3591              * computed integer value.  The second switch has the same
  3592              * code structure as the original string switch statement
  3593              * except that the string case labels are replaced with
  3594              * positional integer constants starting at 0.
  3596              * The first switch statement can be thought of as an
  3597              * inlined map from strings to their position in the case
  3598              * label list.  An alternate implementation would use an
  3599              * actual Map for this purpose, as done for enum switches.
  3601              * With some additional effort, it would be possible to
  3602              * use a single switch statement on the hash code of the
  3603              * argument, but care would need to be taken to preserve
  3604              * the proper control flow in the presence of hash
  3605              * collisions and other complications, such as
  3606              * fallthroughs.  Switch statements with one or two
  3607              * alternatives could also be specially translated into
  3608              * if-then statements to omit the computation of the hash
  3609              * code.
  3611              * The generated code assumes that the hashing algorithm
  3612              * of String is the same in the compilation environment as
  3613              * in the environment the code will run in.  The string
  3614              * hashing algorithm in the SE JDK has been unchanged
  3615              * since at least JDK 1.2.  Since the algorithm has been
  3616              * specified since that release as well, it is very
  3617              * unlikely to be changed in the future.
  3619              * Different hashing algorithms, such as the length of the
  3620              * strings or a perfect hashing algorithm over the
  3621              * particular set of case labels, could potentially be
  3622              * used instead of String.hashCode.
  3623              */
  3625             ListBuffer<JCStatement> stmtList = new ListBuffer<JCStatement>();
  3627             // Map from String case labels to their original position in
  3628             // the list of case labels.
  3629             Map<String, Integer> caseLabelToPosition =
  3630                 new LinkedHashMap<String, Integer>(alternatives + 1, 1.0f);
  3632             // Map of hash codes to the string case labels having that hashCode.
  3633             Map<Integer, Set<String>> hashToString =
  3634                 new LinkedHashMap<Integer, Set<String>>(alternatives + 1, 1.0f);
  3636             int casePosition = 0;
  3637             for(JCCase oneCase : caseList) {
  3638                 JCExpression expression = oneCase.getExpression();
  3640                 if (expression != null) { // expression for a "default" case is null
  3641                     String labelExpr = (String) expression.type.constValue();
  3642                     Integer mapping = caseLabelToPosition.put(labelExpr, casePosition);
  3643                     Assert.checkNull(mapping);
  3644                     int hashCode = labelExpr.hashCode();
  3646                     Set<String> stringSet = hashToString.get(hashCode);
  3647                     if (stringSet == null) {
  3648                         stringSet = new LinkedHashSet<String>(1, 1.0f);
  3649                         stringSet.add(labelExpr);
  3650                         hashToString.put(hashCode, stringSet);
  3651                     } else {
  3652                         boolean added = stringSet.add(labelExpr);
  3653                         Assert.check(added);
  3656                 casePosition++;
  3659             // Synthesize a switch statement that has the effect of
  3660             // mapping from a string to the integer position of that
  3661             // string in the list of case labels.  This is done by
  3662             // switching on the hashCode of the string followed by an
  3663             // if-then-else chain comparing the input for equality
  3664             // with all the case labels having that hash value.
  3666             /*
  3667              * s$ = top of stack;
  3668              * tmp$ = -1;
  3669              * switch($s.hashCode()) {
  3670              *     case caseLabel.hashCode:
  3671              *         if (s$.equals("caseLabel_1")
  3672              *           tmp$ = caseLabelToPosition("caseLabel_1");
  3673              *         else if (s$.equals("caseLabel_2"))
  3674              *           tmp$ = caseLabelToPosition("caseLabel_2");
  3675              *         ...
  3676              *         break;
  3677              * ...
  3678              * }
  3679              */
  3681             VarSymbol dollar_s = new VarSymbol(FINAL|SYNTHETIC,
  3682                                                names.fromString("s" + tree.pos + target.syntheticNameChar()),
  3683                                                syms.stringType,
  3684                                                currentMethodSym);
  3685             stmtList.append(make.at(tree.pos()).VarDef(dollar_s, tree.getExpression()).setType(dollar_s.type));
  3687             VarSymbol dollar_tmp = new VarSymbol(SYNTHETIC,
  3688                                                  names.fromString("tmp" + tree.pos + target.syntheticNameChar()),
  3689                                                  syms.intType,
  3690                                                  currentMethodSym);
  3691             JCVariableDecl dollar_tmp_def =
  3692                 (JCVariableDecl)make.VarDef(dollar_tmp, make.Literal(INT, -1)).setType(dollar_tmp.type);
  3693             dollar_tmp_def.init.type = dollar_tmp.type = syms.intType;
  3694             stmtList.append(dollar_tmp_def);
  3695             ListBuffer<JCCase> caseBuffer = ListBuffer.lb();
  3696             // hashCode will trigger nullcheck on original switch expression
  3697             JCMethodInvocation hashCodeCall = makeCall(make.Ident(dollar_s),
  3698                                                        names.hashCode,
  3699                                                        List.<JCExpression>nil()).setType(syms.intType);
  3700             JCSwitch switch1 = make.Switch(hashCodeCall,
  3701                                         caseBuffer.toList());
  3702             for(Map.Entry<Integer, Set<String>> entry : hashToString.entrySet()) {
  3703                 int hashCode = entry.getKey();
  3704                 Set<String> stringsWithHashCode = entry.getValue();
  3705                 Assert.check(stringsWithHashCode.size() >= 1);
  3707                 JCStatement elsepart = null;
  3708                 for(String caseLabel : stringsWithHashCode ) {
  3709                     JCMethodInvocation stringEqualsCall = makeCall(make.Ident(dollar_s),
  3710                                                                    names.equals,
  3711                                                                    List.<JCExpression>of(make.Literal(caseLabel)));
  3712                     elsepart = make.If(stringEqualsCall,
  3713                                        make.Exec(make.Assign(make.Ident(dollar_tmp),
  3714                                                              make.Literal(caseLabelToPosition.get(caseLabel))).
  3715                                                  setType(dollar_tmp.type)),
  3716                                        elsepart);
  3719                 ListBuffer<JCStatement> lb = ListBuffer.lb();
  3720                 JCBreak breakStmt = make.Break(null);
  3721                 breakStmt.target = switch1;
  3722                 lb.append(elsepart).append(breakStmt);
  3724                 caseBuffer.append(make.Case(make.Literal(hashCode), lb.toList()));
  3727             switch1.cases = caseBuffer.toList();
  3728             stmtList.append(switch1);
  3730             // Make isomorphic switch tree replacing string labels
  3731             // with corresponding integer ones from the label to
  3732             // position map.
  3734             ListBuffer<JCCase> lb = ListBuffer.lb();
  3735             JCSwitch switch2 = make.Switch(make.Ident(dollar_tmp), lb.toList());
  3736             for(JCCase oneCase : caseList ) {
  3737                 // Rewire up old unlabeled break statements to the
  3738                 // replacement switch being created.
  3739                 patchTargets(oneCase, tree, switch2);
  3741                 boolean isDefault = (oneCase.getExpression() == null);
  3742                 JCExpression caseExpr;
  3743                 if (isDefault)
  3744                     caseExpr = null;
  3745                 else {
  3746                     caseExpr = make.Literal(caseLabelToPosition.get((String)TreeInfo.skipParens(oneCase.
  3747                                                                                                 getExpression()).
  3748                                                                     type.constValue()));
  3751                 lb.append(make.Case(caseExpr,
  3752                                     oneCase.getStatements()));
  3755             switch2.cases = lb.toList();
  3756             stmtList.append(switch2);
  3758             return make.Block(0L, stmtList.toList());
  3762     public void visitNewArray(JCNewArray tree) {
  3763         tree.elemtype = translate(tree.elemtype);
  3764         for (List<JCExpression> t = tree.dims; t.tail != null; t = t.tail)
  3765             if (t.head != null) t.head = translate(t.head, syms.intType);
  3766         tree.elems = translate(tree.elems, types.elemtype(tree.type));
  3767         result = tree;
  3770     public void visitSelect(JCFieldAccess tree) {
  3771         // need to special case-access of the form C.super.x
  3772         // these will always need an access method, unless C
  3773         // is a default interface subclassed by the current class.
  3774         boolean qualifiedSuperAccess =
  3775             tree.selected.hasTag(SELECT) &&
  3776             TreeInfo.name(tree.selected) == names._super &&
  3777             !types.isDirectSuperInterface(((JCFieldAccess)tree.selected).selected.type.tsym, currentClass);
  3778         tree.selected = translate(tree.selected);
  3779         if (tree.name == names._class) {
  3780             result = classOf(tree.selected);
  3782         else if (tree.name == names._super &&
  3783                 types.isDirectSuperInterface(tree.selected.type.tsym, currentClass)) {
  3784             //default super call!! Not a classic qualified super call
  3785             TypeSymbol supSym = tree.selected.type.tsym;
  3786             Assert.checkNonNull(types.asSuper(currentClass.type, supSym));
  3787             result = tree;
  3789         else if (tree.name == names._this || tree.name == names._super) {
  3790             result = makeThis(tree.pos(), tree.selected.type.tsym);
  3792         else
  3793             result = access(tree.sym, tree, enclOp, qualifiedSuperAccess);
  3796     public void visitLetExpr(LetExpr tree) {
  3797         tree.defs = translateVarDefs(tree.defs);
  3798         tree.expr = translate(tree.expr, tree.type);
  3799         result = tree;
  3802     // There ought to be nothing to rewrite here;
  3803     // we don't generate code.
  3804     public void visitAnnotation(JCAnnotation tree) {
  3805         result = tree;
  3808     @Override
  3809     public void visitTry(JCTry tree) {
  3810         /* special case of try without catchers and with finally emtpy.
  3811          * Don't give it a try, translate only the body.
  3812          */
  3813         if (tree.resources.isEmpty()) {
  3814             if (tree.catchers.isEmpty() &&
  3815                 tree.finalizer.getStatements().isEmpty()) {
  3816                 result = translate(tree.body);
  3817             } else {
  3818                 super.visitTry(tree);
  3820         } else {
  3821             result = makeTwrTry(tree);
  3825 /**************************************************************************
  3826  * main method
  3827  *************************************************************************/
  3829     /** Translate a toplevel class and return a list consisting of
  3830      *  the translated class and translated versions of all inner classes.
  3831      *  @param env   The attribution environment current at the class definition.
  3832      *               We need this for resolving some additional symbols.
  3833      *  @param cdef  The tree representing the class definition.
  3834      */
  3835     public List<JCTree> translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
  3836         ListBuffer<JCTree> translated = null;
  3837         try {
  3838             attrEnv = env;
  3839             this.make = make;
  3840             endPosTable = env.toplevel.endPositions;
  3841             currentClass = null;
  3842             currentMethodDef = null;
  3843             outermostClassDef = (cdef.hasTag(CLASSDEF)) ? (JCClassDecl)cdef : null;
  3844             outermostMemberDef = null;
  3845             this.translated = new ListBuffer<JCTree>();
  3846             classdefs = new HashMap<ClassSymbol,JCClassDecl>();
  3847             actualSymbols = new HashMap<Symbol,Symbol>();
  3848             freevarCache = new HashMap<ClassSymbol,List<VarSymbol>>();
  3849             proxies = new Scope(syms.noSymbol);
  3850             twrVars = new Scope(syms.noSymbol);
  3851             outerThisStack = List.nil();
  3852             accessNums = new HashMap<Symbol,Integer>();
  3853             accessSyms = new HashMap<Symbol,MethodSymbol[]>();
  3854             accessConstrs = new HashMap<Symbol,MethodSymbol>();
  3855             accessConstrTags = List.nil();
  3856             accessed = new ListBuffer<Symbol>();
  3857             translate(cdef, (JCExpression)null);
  3858             for (List<Symbol> l = accessed.toList(); l.nonEmpty(); l = l.tail)
  3859                 makeAccessible(l.head);
  3860             for (EnumMapping map : enumSwitchMap.values())
  3861                 map.translate();
  3862             checkConflicts(this.translated.toList());
  3863             checkAccessConstructorTags();
  3864             translated = this.translated;
  3865         } finally {
  3866             // note that recursive invocations of this method fail hard
  3867             attrEnv = null;
  3868             this.make = null;
  3869             endPosTable = null;
  3870             currentClass = null;
  3871             currentMethodDef = null;
  3872             outermostClassDef = null;
  3873             outermostMemberDef = null;
  3874             this.translated = null;
  3875             classdefs = null;
  3876             actualSymbols = null;
  3877             freevarCache = null;
  3878             proxies = null;
  3879             outerThisStack = null;
  3880             accessNums = null;
  3881             accessSyms = null;
  3882             accessConstrs = null;
  3883             accessConstrTags = null;
  3884             accessed = null;
  3885             enumSwitchMap.clear();
  3887         return translated.toList();
  3890     //////////////////////////////////////////////////////////////
  3891     // The following contributed by Borland for bootstrapping purposes
  3892     //////////////////////////////////////////////////////////////
  3893     private void addEnumCompatibleMembers(JCClassDecl cdef) {
  3894         make_at(null);
  3896         // Add the special enum fields
  3897         VarSymbol ordinalFieldSym = addEnumOrdinalField(cdef);
  3898         VarSymbol nameFieldSym = addEnumNameField(cdef);
  3900         // Add the accessor methods for name and ordinal
  3901         MethodSymbol ordinalMethodSym = addEnumFieldOrdinalMethod(cdef, ordinalFieldSym);
  3902         MethodSymbol nameMethodSym = addEnumFieldNameMethod(cdef, nameFieldSym);
  3904         // Add the toString method
  3905         addEnumToString(cdef, nameFieldSym);
  3907         // Add the compareTo method
  3908         addEnumCompareTo(cdef, ordinalFieldSym);
  3911     private VarSymbol addEnumOrdinalField(JCClassDecl cdef) {
  3912         VarSymbol ordinal = new VarSymbol(PRIVATE|FINAL|SYNTHETIC,
  3913                                           names.fromString("$ordinal"),
  3914                                           syms.intType,
  3915                                           cdef.sym);
  3916         cdef.sym.members().enter(ordinal);
  3917         cdef.defs = cdef.defs.prepend(make.VarDef(ordinal, null));
  3918         return ordinal;
  3921     private VarSymbol addEnumNameField(JCClassDecl cdef) {
  3922         VarSymbol name = new VarSymbol(PRIVATE|FINAL|SYNTHETIC,
  3923                                           names.fromString("$name"),
  3924                                           syms.stringType,
  3925                                           cdef.sym);
  3926         cdef.sym.members().enter(name);
  3927         cdef.defs = cdef.defs.prepend(make.VarDef(name, null));
  3928         return name;
  3931     private MethodSymbol addEnumFieldOrdinalMethod(JCClassDecl cdef, VarSymbol ordinalSymbol) {
  3932         // Add the accessor methods for ordinal
  3933         Symbol ordinalSym = lookupMethod(cdef.pos(),
  3934                                          names.ordinal,
  3935                                          cdef.type,
  3936                                          List.<Type>nil());
  3938         Assert.check(ordinalSym instanceof MethodSymbol);
  3940         JCStatement ret = make.Return(make.Ident(ordinalSymbol));
  3941         cdef.defs = cdef.defs.append(make.MethodDef((MethodSymbol)ordinalSym,
  3942                                                     make.Block(0L, List.of(ret))));
  3944         return (MethodSymbol)ordinalSym;
  3947     private MethodSymbol addEnumFieldNameMethod(JCClassDecl cdef, VarSymbol nameSymbol) {
  3948         // Add the accessor methods for name
  3949         Symbol nameSym = lookupMethod(cdef.pos(),
  3950                                    names._name,
  3951                                    cdef.type,
  3952                                    List.<Type>nil());
  3954         Assert.check(nameSym instanceof MethodSymbol);
  3956         JCStatement ret = make.Return(make.Ident(nameSymbol));
  3958         cdef.defs = cdef.defs.append(make.MethodDef((MethodSymbol)nameSym,
  3959                                                     make.Block(0L, List.of(ret))));
  3961         return (MethodSymbol)nameSym;
  3964     private MethodSymbol addEnumToString(JCClassDecl cdef,
  3965                                          VarSymbol nameSymbol) {
  3966         Symbol toStringSym = lookupMethod(cdef.pos(),
  3967                                           names.toString,
  3968                                           cdef.type,
  3969                                           List.<Type>nil());
  3971         JCTree toStringDecl = null;
  3972         if (toStringSym != null)
  3973             toStringDecl = TreeInfo.declarationFor(toStringSym, cdef);
  3975         if (toStringDecl != null)
  3976             return (MethodSymbol)toStringSym;
  3978         JCStatement ret = make.Return(make.Ident(nameSymbol));
  3980         JCTree resTypeTree = make.Type(syms.stringType);
  3982         MethodType toStringType = new MethodType(List.<Type>nil(),
  3983                                                  syms.stringType,
  3984                                                  List.<Type>nil(),
  3985                                                  cdef.sym);
  3986         toStringSym = new MethodSymbol(PUBLIC,
  3987                                        names.toString,
  3988                                        toStringType,
  3989                                        cdef.type.tsym);
  3990         toStringDecl = make.MethodDef((MethodSymbol)toStringSym,
  3991                                       make.Block(0L, List.of(ret)));
  3993         cdef.defs = cdef.defs.prepend(toStringDecl);
  3994         cdef.sym.members().enter(toStringSym);
  3996         return (MethodSymbol)toStringSym;
  3999     private MethodSymbol addEnumCompareTo(JCClassDecl cdef, VarSymbol ordinalSymbol) {
  4000         Symbol compareToSym = lookupMethod(cdef.pos(),
  4001                                    names.compareTo,
  4002                                    cdef.type,
  4003                                    List.of(cdef.sym.type));
  4005         Assert.check(compareToSym instanceof MethodSymbol);
  4007         JCMethodDecl compareToDecl = (JCMethodDecl) TreeInfo.declarationFor(compareToSym, cdef);
  4009         ListBuffer<JCStatement> blockStatements = new ListBuffer<JCStatement>();
  4011         JCModifiers mod1 = make.Modifiers(0L);
  4012         Name oName = names.fromString("o");
  4013         JCVariableDecl par1 = make.Param(oName, cdef.type, compareToSym);
  4015         JCIdent paramId1 = make.Ident(names.java_lang_Object);
  4016         paramId1.type = cdef.type;
  4017         paramId1.sym = par1.sym;
  4019         ((MethodSymbol)compareToSym).params = List.of(par1.sym);
  4021         JCIdent par1UsageId = make.Ident(par1.sym);
  4022         JCIdent castTargetIdent = make.Ident(cdef.sym);
  4023         JCTypeCast cast = make.TypeCast(castTargetIdent, par1UsageId);
  4024         cast.setType(castTargetIdent.type);
  4026         Name otherName = names.fromString("other");
  4028         VarSymbol otherVarSym = new VarSymbol(mod1.flags,
  4029                                               otherName,
  4030                                               cdef.type,
  4031                                               compareToSym);
  4032         JCVariableDecl otherVar = make.VarDef(otherVarSym, cast);
  4033         blockStatements.append(otherVar);
  4035         JCIdent id1 = make.Ident(ordinalSymbol);
  4037         JCIdent fLocUsageId = make.Ident(otherVarSym);
  4038         JCExpression sel = make.Select(fLocUsageId, ordinalSymbol);
  4039         JCBinary bin = makeBinary(MINUS, id1, sel);
  4040         JCReturn ret = make.Return(bin);
  4041         blockStatements.append(ret);
  4042         JCMethodDecl compareToMethod = make.MethodDef((MethodSymbol)compareToSym,
  4043                                                    make.Block(0L,
  4044                                                               blockStatements.toList()));
  4045         compareToMethod.params = List.of(par1);
  4046         cdef.defs = cdef.defs.append(compareToMethod);
  4048         return (MethodSymbol)compareToSym;
  4050     //////////////////////////////////////////////////////////////
  4051     // The above contributed by Borland for bootstrapping purposes
  4052     //////////////////////////////////////////////////////////////

mercurial