001    /*
002     * Copyright 1999-2008 Sun Microsystems, Inc.  All Rights Reserved.
003     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004     *
005     * This code is free software; you can redistribute it and/or modify it
006     * under the terms of the GNU General Public License version 2 only, as
007     * published by the Free Software Foundation.  Sun designates this
008     * particular file as subject to the "Classpath" exception as provided
009     * by Sun in the LICENSE file that accompanied this code.
010     *
011     * This code is distributed in the hope that it will be useful, but WITHOUT
012     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013     * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014     * version 2 for more details (a copy is included in the LICENSE file that
015     * accompanied this code).
016     *
017     * You should have received a copy of the GNU General Public License version
018     * 2 along with this work; if not, write to the Free Software Foundation,
019     * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020     *
021     * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022     * CA 95054 USA or visit www.sun.com if you need additional information or
023     * have any questions.
024     */
025    
026    package com.sun.tools.javac.comp;
027    
028    import java.util.*;
029    
030    import com.sun.tools.javac.code.*;
031    import com.sun.tools.javac.jvm.*;
032    import com.sun.tools.javac.tree.*;
033    import com.sun.tools.javac.util.*;
034    import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
035    import com.sun.tools.javac.util.List;
036    
037    import com.sun.tools.javac.code.Symbol.*;
038    import com.sun.tools.javac.tree.JCTree.*;
039    import com.sun.tools.javac.code.Type.*;
040    
041    import com.sun.tools.javac.jvm.Target;
042    
043    import static com.sun.tools.javac.code.Flags.*;
044    import static com.sun.tools.javac.code.Kinds.*;
045    import static com.sun.tools.javac.code.TypeTags.*;
046    import static com.sun.tools.javac.jvm.ByteCodes.*;
047    
048    import edu.rice.cs.mint.comp.*;
049    
050    /** This pass translates away some syntactic sugar: inner classes,
051     *  class literals, assertions, foreach loops, etc.
052     *
053     *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
054     *  you write code that depends on this, you do so at your own risk.
055     *  This code and its internal interfaces are subject to change or
056     *  deletion without notice.</b>
057     */
058    public class Lower extends TreeTranslator {
059        protected static final Context.Key<Lower> lowerKey =
060            new Context.Key<Lower>();
061    
062        public static Lower instance(Context context) {
063            Lower instance = context.get(lowerKey);
064            if (instance == null)
065                instance = new Lower(context);
066            return instance;
067        }
068    
069        private Names names;
070        private Log log;
071        private Symtab syms;
072        private Resolve rs;
073        private Check chk;
074        private Attr attr;
075        private TreeMaker make;
076        private DiagnosticPosition make_pos;
077        private ClassWriter writer;
078        private ClassReader reader;
079        private ConstFold cfolder;
080        private Target target;
081        private Source source;
082        private boolean allowEnums;
083        private final Name dollarAssertionsDisabled;
084        private final Name classDollar;
085        private Types types;
086        private boolean debugLower;
087    
088        protected Lower(Context context) {
089            context.put(lowerKey, this);
090            names = Names.instance(context);
091            log = Log.instance(context);
092            syms = Symtab.instance(context);
093            rs = Resolve.instance(context);
094            chk = Check.instance(context);
095            attr = Attr.instance(context);
096            make = TreeMaker.instance(context);
097            writer = ClassWriter.instance(context);
098            reader = ClassReader.instance(context);
099            cfolder = ConstFold.instance(context);
100            target = Target.instance(context);
101            source = Source.instance(context);
102            allowEnums = source.allowEnums();
103            dollarAssertionsDisabled = names.
104                fromString(target.syntheticNameChar() + "assertionsDisabled");
105            classDollar = names.
106                fromString("class" + target.syntheticNameChar());
107    
108            types = Types.instance(context);
109            Options options = Options.instance(context);
110            debugLower = options.get("debuglower") != null;
111        }
112    
113        /** The currently enclosing class.
114         */
115        ClassSymbol currentClass;
116    
117        /** A queue of all translated classes.
118         */
119        ListBuffer<JCTree> translated;
120    
121        /** Environment for symbol lookup, set by translateTopLevelClass.
122         */
123        Env<AttrContext> attrEnv;
124    
125        /** A hash table mapping syntax trees to their ending source positions.
126         */
127        Map<JCTree, Integer> endPositions;
128    
129    /**************************************************************************
130     * Global mappings
131     *************************************************************************/
132    
133        /** A hash table mapping local classes to their definitions.
134         */
135        Map<ClassSymbol, JCClassDecl> classdefs;
136    
137        /** A hash table mapping virtual accessed symbols in outer subclasses
138         *  to the actually referred symbol in superclasses.
139         */
140        Map<Symbol,Symbol> actualSymbols;
141    
142        /** The current method definition.
143         */
144        JCMethodDecl currentMethodDef;
145    
146        /** The current method symbol.
147         */
148        MethodSymbol currentMethodSym;
149    
150        /** The currently enclosing outermost class definition.
151         */
152        JCClassDecl outermostClassDef;
153    
154        /** The currently enclosing outermost member definition.
155         */
156        JCTree outermostMemberDef;
157    
158        /** A navigator class for assembling a mapping from local class symbols
159         *  to class definition trees.
160         *  There is only one case; all other cases simply traverse down the tree.
161         */
162        class ClassMap extends TreeScanner {
163    
164            /** All encountered class defs are entered into classdefs table.
165             */
166            public void visitClassDef(JCClassDecl tree) {
167                classdefs.put(tree.sym, tree);
168                super.visitClassDef(tree);
169            }
170        }
171        ClassMap classMap = new ClassMap();
172    
173        /** Map a class symbol to its definition.
174         *  @param c    The class symbol of which we want to determine the definition.
175         */
176        JCClassDecl classDef(ClassSymbol c) {
177            // First lookup the class in the classdefs table.
178            JCClassDecl def = classdefs.get(c);
179            if (def == null && outermostMemberDef != null) {
180                // If this fails, traverse outermost member definition, entering all
181                // local classes into classdefs, and try again.
182                classMap.scan(outermostMemberDef);
183                def = classdefs.get(c);
184            }
185            if (def == null) {
186                // If this fails, traverse outermost class definition, entering all
187                // local classes into classdefs, and try again.
188                classMap.scan(outermostClassDef);
189                def = classdefs.get(c);
190            }
191            return def;
192        }
193    
194        /** A hash table mapping class symbols to lists of free variables.
195         *  accessed by them. Only free variables of the method immediately containing
196         *  a class are associated with that class.
197         */
198        Map<ClassSymbol,List<VarSymbol>> freevarCache;
199    
200        /** A navigator class for collecting the free variables accessed
201         *  from a local class.
202         *  There is only one case; all other cases simply traverse down the tree.
203         */
204        class FreeVarCollector extends TreeScanner {
205    
206            /** The owner of the local class.
207             */
208            Symbol owner;
209    
210            /** The local class.
211             */
212            ClassSymbol clazz;
213    
214            /** The list of owner's variables accessed from within the local class,
215             *  without any duplicates.
216             */
217            List<VarSymbol> fvs;
218    
219            FreeVarCollector(ClassSymbol clazz) {
220                this.clazz = clazz;
221                this.owner = clazz.owner;
222                this.fvs = List.nil();
223            }
224    
225            /** Add free variable to fvs list unless it is already there.
226             */
227            private void addFreeVar(VarSymbol v) {
228                for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail)
229                    if (l.head == v) return;
230                fvs = fvs.prepend(v);
231            }
232    
233            /** Add all free variables of class c to fvs list
234             *  unless they are already there.
235             */
236            private void addFreeVars(ClassSymbol c) {
237                List<VarSymbol> fvs = freevarCache.get(c);
238                if (fvs != null) {
239                    for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail) {
240                        addFreeVar(l.head);
241                    }
242                }
243            }
244    
245            /** If tree refers to a variable in owner of local class, add it to
246             *  free variables list.
247             */
248            public void visitIdent(JCIdent tree) {
249                result = tree;
250                visitSymbol(tree.sym);
251            }
252            // where
253            private void visitSymbol(Symbol _sym) {
254                Symbol sym = _sym;
255                if (sym.kind == VAR || sym.kind == MTH) {
256                    while (sym != null && sym.owner != owner)
257                        sym = proxies.lookup(proxyName(sym.name)).sym;
258                    if (sym != null && sym.owner == owner) {
259                        VarSymbol v = (VarSymbol)sym;
260                        if (v.getConstValue() == null) {
261                            addFreeVar(v);
262                        }
263                    } else {
264                        if (outerThisStack.head != null &&
265                            outerThisStack.head != _sym)
266                            visitSymbol(outerThisStack.head);
267                    }
268                }
269            }
270    
271            /** If tree refers to a class instance creation expression
272             *  add all free variables of the freshly created class.
273             */
274            public void visitNewClass(JCNewClass tree) {
275                ClassSymbol c = (ClassSymbol)tree.constructor.owner;
276                addFreeVars(c);
277                if (tree.encl == null &&
278                    c.hasOuterInstance() &&
279                    outerThisStack.head != null)
280                    visitSymbol(outerThisStack.head);
281                super.visitNewClass(tree);
282            }
283    
284            /** If tree refers to a qualified this or super expression
285             *  for anything but the current class, add the outer this
286             *  stack as a free variable.
287             */
288            public void visitSelect(JCFieldAccess tree) {
289                if ((tree.name == names._this || tree.name == names._super) &&
290                    tree.selected.type.tsym != clazz &&
291                    outerThisStack.head != null)
292                    visitSymbol(outerThisStack.head);
293                super.visitSelect(tree);
294            }
295    
296            /** If tree refers to a superclass constructor call,
297             *  add all free variables of the superclass.
298             */
299            public void visitApply(JCMethodInvocation tree) {
300                if (TreeInfo.name(tree.meth) == names._super) {
301                    addFreeVars((ClassSymbol) TreeInfo.symbol(tree.meth).owner);
302                    Symbol constructor = TreeInfo.symbol(tree.meth);
303                    ClassSymbol c = (ClassSymbol)constructor.owner;
304                    if (c.hasOuterInstance() &&
305                        tree.meth.getTag() != JCTree.SELECT &&
306                        outerThisStack.head != null)
307                        visitSymbol(outerThisStack.head);
308                }
309                super.visitApply(tree);
310            }
311        }
312    
313        /** Return the variables accessed from within a local class, which
314         *  are declared in the local class' owner.
315         *  (in reverse order of first access).
316         */
317        List<VarSymbol> freevars(ClassSymbol c)  {
318            if ((c.owner.kind & (VAR | MTH)) != 0) {
319                List<VarSymbol> fvs = freevarCache.get(c);
320                if (fvs == null) {
321                    FreeVarCollector collector = new FreeVarCollector(c);
322                    collector.scan(classDef(c));
323                    fvs = collector.fvs;
324                    freevarCache.put(c, fvs);
325                }
326                return fvs;
327            } else {
328                return List.nil();
329            }
330        }
331    
332        Map<TypeSymbol,EnumMapping> enumSwitchMap = new LinkedHashMap<TypeSymbol,EnumMapping>();
333    
334        EnumMapping mapForEnum(DiagnosticPosition pos, TypeSymbol enumClass) {
335            EnumMapping map = enumSwitchMap.get(enumClass);
336            if (map == null)
337                enumSwitchMap.put(enumClass, map = new EnumMapping(pos, enumClass));
338            return map;
339        }
340    
341        /** This map gives a translation table to be used for enum
342         *  switches.
343         *
344         *  <p>For each enum that appears as the type of a switch
345         *  expression, we maintain an EnumMapping to assist in the
346         *  translation, as exemplified by the following example:
347         *
348         *  <p>we translate
349         *  <pre>
350         *          switch(colorExpression) {
351         *          case red: stmt1;
352         *          case green: stmt2;
353         *          }
354         *  </pre>
355         *  into
356         *  <pre>
357         *          switch(Outer$0.$EnumMap$Color[colorExpression.ordinal()]) {
358         *          case 1: stmt1;
359         *          case 2: stmt2
360         *          }
361         *  </pre>
362         *  with the auxilliary table intialized as follows:
363         *  <pre>
364         *          class Outer$0 {
365         *              synthetic final int[] $EnumMap$Color = new int[Color.values().length];
366         *              static {
367         *                  try { $EnumMap$Color[red.ordinal()] = 1; } catch (NoSuchFieldError ex) {}
368         *                  try { $EnumMap$Color[green.ordinal()] = 2; } catch (NoSuchFieldError ex) {}
369         *              }
370         *          }
371         *  </pre>
372         *  class EnumMapping provides mapping data and support methods for this translation.
373         */
374        class EnumMapping {
375            EnumMapping(DiagnosticPosition pos, TypeSymbol forEnum) {
376                this.forEnum = forEnum;
377                this.values = new LinkedHashMap<VarSymbol,Integer>();
378                this.pos = pos;
379                Name varName = names
380                    .fromString(target.syntheticNameChar() +
381                                "SwitchMap" +
382                                target.syntheticNameChar() +
383                                writer.xClassName(forEnum.type).toString()
384                                .replace('/', '.')
385                                .replace('.', target.syntheticNameChar()));
386                ClassSymbol outerCacheClass = outerCacheClass();
387                this.mapVar = new VarSymbol(STATIC | SYNTHETIC | FINAL,
388                                            varName,
389                                            new ArrayType(syms.intType, syms.arrayClass),
390                                            outerCacheClass);
391                enterSynthetic(pos, mapVar, outerCacheClass.members());
392            }
393    
394            DiagnosticPosition pos = null;
395    
396            // the next value to use
397            int next = 1; // 0 (unused map elements) go to the default label
398    
399            // the enum for which this is a map
400            final TypeSymbol forEnum;
401    
402            // the field containing the map
403            final VarSymbol mapVar;
404    
405            // the mapped values
406            final Map<VarSymbol,Integer> values;
407    
408            JCLiteral forConstant(VarSymbol v) {
409                Integer result = values.get(v);
410                if (result == null)
411                    values.put(v, result = next++);
412                return make.Literal(result);
413            }
414    
415            // generate the field initializer for the map
416            void translate() {
417                make.at(pos.getStartPosition());
418                JCClassDecl owner = classDef((ClassSymbol)mapVar.owner);
419    
420                // synthetic static final int[] $SwitchMap$Color = new int[Color.values().length];
421                MethodSymbol valuesMethod = lookupMethod(pos,
422                                                         names.values,
423                                                         forEnum.type,
424                                                         List.<Type>nil());
425                JCExpression size = make // Color.values().length
426                    .Select(make.App(make.QualIdent(valuesMethod)),
427                            syms.lengthVar);
428                JCExpression mapVarInit = make
429                    .NewArray(make.Type(syms.intType), List.of(size), null)
430                    .setType(new ArrayType(syms.intType, syms.arrayClass));
431    
432                // try { $SwitchMap$Color[red.ordinal()] = 1; } catch (java.lang.NoSuchFieldError ex) {}
433                ListBuffer<JCStatement> stmts = new ListBuffer<JCStatement>();
434                Symbol ordinalMethod = lookupMethod(pos,
435                                                    names.ordinal,
436                                                    forEnum.type,
437                                                    List.<Type>nil());
438                List<JCCatch> catcher = List.<JCCatch>nil()
439                    .prepend(make.Catch(make.VarDef(new VarSymbol(PARAMETER, names.ex,
440                                                                  syms.noSuchFieldErrorType,
441                                                                  syms.noSymbol),
442                                                    null),
443                                        make.Block(0, List.<JCStatement>nil())));
444                for (Map.Entry<VarSymbol,Integer> e : values.entrySet()) {
445                    VarSymbol enumerator = e.getKey();
446                    Integer mappedValue = e.getValue();
447                    JCExpression assign = make
448                        .Assign(make.Indexed(mapVar,
449                                             make.App(make.Select(make.QualIdent(enumerator),
450                                                                  ordinalMethod))),
451                                make.Literal(mappedValue))
452                        .setType(syms.intType);
453                    JCStatement exec = make.Exec(assign);
454                    JCStatement _try = make.Try(make.Block(0, List.of(exec)), catcher, null);
455                    stmts.append(_try);
456                }
457    
458                owner.defs = owner.defs
459                    .prepend(make.Block(STATIC, stmts.toList()))
460                    .prepend(make.VarDef(mapVar, mapVarInit));
461            }
462        }
463    
464    
465    /**************************************************************************
466     * Tree building blocks
467     *************************************************************************/
468    
469        /** Equivalent to make.at(pos.getStartPosition()) with side effect of caching
470         *  pos as make_pos, for use in diagnostics.
471         **/
472        TreeMaker make_at(DiagnosticPosition pos) {
473            make_pos = pos;
474            return make.at(pos);
475        }
476    
477        /** Make an attributed tree representing a literal. This will be an
478         *  Ident node in the case of boolean literals, a Literal node in all
479         *  other cases.
480         *  @param type       The literal's type.
481         *  @param value      The literal's value.
482         */
483        JCExpression makeLit(Type type, Object value) {
484            return make.Literal(type.tag, value).setType(type.constType(value));
485        }
486    
487        /** Make an attributed tree representing null.
488         */
489        JCExpression makeNull() {
490            return makeLit(syms.botType, null);
491        }
492    
493        /** Make an attributed class instance creation expression.
494         *  @param ctype    The class type.
495         *  @param args     The constructor arguments.
496         */
497        JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
498            JCNewClass tree = make.NewClass(null,
499                null, make.QualIdent(ctype.tsym), args, null);
500            tree.constructor = rs.resolveConstructor(
501                make_pos, attrEnv, ctype, TreeInfo.types(args), null, false, false);
502            tree.type = ctype;
503            return tree;
504        }
505    
506        /** Make an attributed unary expression.
507         *  @param optag    The operators tree tag.
508         *  @param arg      The operator's argument.
509         */
510        JCUnary makeUnary(int optag, JCExpression arg) {
511            JCUnary tree = make.Unary(optag, arg);
512            tree.operator = rs.resolveUnaryOperator(
513                make_pos, optag, attrEnv, arg.type);
514            tree.type = tree.operator.type.getReturnType();
515            return tree;
516        }
517    
518        /** Make an attributed binary expression.
519         *  @param optag    The operators tree tag.
520         *  @param lhs      The operator's left argument.
521         *  @param rhs      The operator's right argument.
522         */
523        JCBinary makeBinary(int optag, JCExpression lhs, JCExpression rhs) {
524            JCBinary tree = make.Binary(optag, lhs, rhs);
525            tree.operator = rs.resolveBinaryOperator(
526                make_pos, optag, attrEnv, lhs.type, rhs.type);
527            tree.type = tree.operator.type.getReturnType();
528            return tree;
529        }
530    
531        /** Make an attributed assignop expression.
532         *  @param optag    The operators tree tag.
533         *  @param lhs      The operator's left argument.
534         *  @param rhs      The operator's right argument.
535         */
536        JCAssignOp makeAssignop(int optag, JCTree lhs, JCTree rhs) {
537            JCAssignOp tree = make.Assignop(optag, lhs, rhs);
538            tree.operator = rs.resolveBinaryOperator(
539                make_pos, tree.getTag() - JCTree.ASGOffset, attrEnv, lhs.type, rhs.type);
540            tree.type = lhs.type;
541            return tree;
542        }
543    
544        /** Convert tree into string object, unless it has already a
545         *  reference type..
546         */
547        JCExpression makeString(JCExpression tree) {
548            if (tree.type.tag >= CLASS) {
549                return tree;
550            } else {
551                Symbol valueOfSym = lookupMethod(tree.pos(),
552                                                 names.valueOf,
553                                                 syms.stringType,
554                                                 List.of(tree.type));
555                return make.App(make.QualIdent(valueOfSym), List.of(tree));
556            }
557        }
558    
559        /** Create an empty anonymous class definition and enter and complete
560         *  its symbol. Return the class definition's symbol.
561         *  and create
562         *  @param flags    The class symbol's flags
563         *  @param owner    The class symbol's owner
564         */
565        ClassSymbol makeEmptyClass(long flags, ClassSymbol owner) {
566            // Create class symbol.
567            ClassSymbol c = reader.defineClass(names.empty, owner);
568            c.flatname = chk.localClassName(c);
569            c.sourcefile = owner.sourcefile;
570            c.completer = null;
571            c.members_field = new Scope(c);
572            c.flags_field = flags;
573            ClassType ctype = (ClassType) c.type;
574            ctype.supertype_field = syms.objectType;
575            ctype.interfaces_field = List.nil();
576    
577            JCClassDecl odef = classDef(owner);
578    
579            // Enter class symbol in owner scope and compiled table.
580            enterSynthetic(odef.pos(), c, owner.members());
581            chk.compiled.put(c.flatname, c);
582    
583            // Create class definition tree.
584            JCClassDecl cdef = make.ClassDef(
585                make.Modifiers(flags), names.empty,
586                List.<JCTypeParameter>nil(),
587                null, List.<JCExpression>nil(), List.<JCTree>nil());
588            cdef.sym = c;
589            cdef.type = c.type;
590    
591            // Append class definition tree to owner's definitions.
592            odef.defs = odef.defs.prepend(cdef);
593    
594            return c;
595        }
596    
597    /**************************************************************************
598     * Symbol manipulation utilities
599     *************************************************************************/
600    
601        /** Report a conflict between a user symbol and a synthetic symbol.
602         */
603        private void duplicateError(DiagnosticPosition pos, Symbol sym) {
604            if (!sym.type.isErroneous()) {
605                log.error(pos, "synthetic.name.conflict", sym, sym.location());
606            }
607        }
608    
609        /** Enter a synthetic symbol in a given scope, but complain if there was already one there.
610         *  @param pos           Position for error reporting.
611         *  @param sym           The symbol.
612         *  @param s             The scope.
613         */
614        private void enterSynthetic(DiagnosticPosition pos, Symbol sym, Scope s) {
615            if (sym.name != names.error && sym.name != names.empty) {
616                for (Scope.Entry e = s.lookup(sym.name); e.scope == s; e = e.next()) {
617                    if (sym != e.sym && sym.kind == e.sym.kind) {
618                        // VM allows methods and variables with differing types
619                        if ((sym.kind & (MTH|VAR)) != 0 &&
620                            !types.erasure(sym.type).equals(types.erasure(e.sym.type)))
621                            continue;
622                        duplicateError(pos, e.sym);
623                        break;
624                    }
625                }
626            }
627            s.enter(sym);
628        }
629    
630        /** Look up a synthetic name in a given scope.
631         *  @param scope        The scope.
632         *  @param name         The name.
633         */
634        private Symbol lookupSynthetic(Name name, Scope s) {
635            Symbol sym = s.lookup(name).sym;
636            return (sym==null || (sym.flags()&SYNTHETIC)==0) ? null : sym;
637        }
638    
639        /** Look up a method in a given scope.
640         */
641        private MethodSymbol lookupMethod(DiagnosticPosition pos, Name name, Type qual, List<Type> args) {
642            return rs.resolveInternalMethod(pos, attrEnv, qual, name, args, null);
643        }
644    
645        /** Look up a constructor.
646         */
647        private MethodSymbol lookupConstructor(DiagnosticPosition pos, Type qual, List<Type> args) {
648            return rs.resolveInternalConstructor(pos, attrEnv, qual, args, null);
649        }
650    
651        /** Look up a field.
652         */
653        private VarSymbol lookupField(DiagnosticPosition pos, Type qual, Name name) {
654            return rs.resolveInternalField(pos, attrEnv, qual, name);
655        }
656    
657    /**************************************************************************
658     * Access methods
659     *************************************************************************/
660    
661        /** Access codes for dereferencing, assignment,
662         *  and pre/post increment/decrement.
663         *  Access codes for assignment operations are determined by method accessCode
664         *  below.
665         *
666         *  All access codes for accesses to the current class are even.
667         *  If a member of the superclass should be accessed instead (because
668         *  access was via a qualified super), add one to the corresponding code
669         *  for the current class, making the number odd.
670         *  This numbering scheme is used by the backend to decide whether
671         *  to issue an invokevirtual or invokespecial call.
672         *
673         *  @see Gen.visitSelect(Select tree)
674         */
675        private static final int
676            DEREFcode = 0,
677            ASSIGNcode = 2,
678            PREINCcode = 4,
679            PREDECcode = 6,
680            POSTINCcode = 8,
681            POSTDECcode = 10,
682            FIRSTASGOPcode = 12;
683    
684        /** Number of access codes
685         */
686        private static final int NCODES = accessCode(ByteCodes.lushrl) + 2;
687    
688        /** A mapping from symbols to their access numbers.
689         */
690        private Map<Symbol,Integer> accessNums;
691    
692        /** A mapping from symbols to an array of access symbols, indexed by
693         *  access code.
694         */
695        private Map<Symbol,MethodSymbol[]> accessSyms;
696    
697        /** A mapping from (constructor) symbols to access constructor symbols.
698         */
699        private Map<Symbol,MethodSymbol> accessConstrs;
700    
701        /** A queue for all accessed symbols.
702         */
703        private ListBuffer<Symbol> accessed;
704    
705        /** Map bytecode of binary operation to access code of corresponding
706         *  assignment operation. This is always an even number.
707         */
708        private static int accessCode(int bytecode) {
709            if (ByteCodes.iadd <= bytecode && bytecode <= ByteCodes.lxor)
710                return (bytecode - iadd) * 2 + FIRSTASGOPcode;
711            else if (bytecode == ByteCodes.string_add)
712                return (ByteCodes.lxor + 1 - iadd) * 2 + FIRSTASGOPcode;
713            else if (ByteCodes.ishll <= bytecode && bytecode <= ByteCodes.lushrl)
714                return (bytecode - ishll + ByteCodes.lxor + 2 - iadd) * 2 + FIRSTASGOPcode;
715            else
716                return -1;
717        }
718    
719        /** return access code for identifier,
720         *  @param tree     The tree representing the identifier use.
721         *  @param enclOp   The closest enclosing operation node of tree,
722         *                  null if tree is not a subtree of an operation.
723         */
724        private static int accessCode(JCTree tree, JCTree enclOp) {
725            if (enclOp == null)
726                return DEREFcode;
727            else if (enclOp.getTag() == JCTree.ASSIGN &&
728                     tree == TreeInfo.skipParens(((JCAssign) enclOp).lhs))
729                return ASSIGNcode;
730            else if (JCTree.PREINC <= enclOp.getTag() && enclOp.getTag() <= JCTree.POSTDEC &&
731                     tree == TreeInfo.skipParens(((JCUnary) enclOp).arg))
732                return (enclOp.getTag() - JCTree.PREINC) * 2 + PREINCcode;
733            else if (JCTree.BITOR_ASG <= enclOp.getTag() && enclOp.getTag() <= JCTree.MOD_ASG &&
734                     tree == TreeInfo.skipParens(((JCAssignOp) enclOp).lhs))
735                return accessCode(((OperatorSymbol) ((JCAssignOp) enclOp).operator).opcode);
736            else
737                return DEREFcode;
738        }
739    
740        /** Return binary operator that corresponds to given access code.
741         */
742        private OperatorSymbol binaryAccessOperator(int acode) {
743            for (Scope.Entry e = syms.predefClass.members().elems;
744                 e != null;
745                 e = e.sibling) {
746                if (e.sym instanceof OperatorSymbol) {
747                    OperatorSymbol op = (OperatorSymbol)e.sym;
748                    if (accessCode(op.opcode) == acode) return op;
749                }
750            }
751            return null;
752        }
753    
754        /** Return tree tag for assignment operation corresponding
755         *  to given binary operator.
756         */
757        private static int treeTag(OperatorSymbol operator) {
758            switch (operator.opcode) {
759            case ByteCodes.ior: case ByteCodes.lor:
760                return JCTree.BITOR_ASG;
761            case ByteCodes.ixor: case ByteCodes.lxor:
762                return JCTree.BITXOR_ASG;
763            case ByteCodes.iand: case ByteCodes.land:
764                return JCTree.BITAND_ASG;
765            case ByteCodes.ishl: case ByteCodes.lshl:
766            case ByteCodes.ishll: case ByteCodes.lshll:
767                return JCTree.SL_ASG;
768            case ByteCodes.ishr: case ByteCodes.lshr:
769            case ByteCodes.ishrl: case ByteCodes.lshrl:
770                return JCTree.SR_ASG;
771            case ByteCodes.iushr: case ByteCodes.lushr:
772            case ByteCodes.iushrl: case ByteCodes.lushrl:
773                return JCTree.USR_ASG;
774            case ByteCodes.iadd: case ByteCodes.ladd:
775            case ByteCodes.fadd: case ByteCodes.dadd:
776            case ByteCodes.string_add:
777                return JCTree.PLUS_ASG;
778            case ByteCodes.isub: case ByteCodes.lsub:
779            case ByteCodes.fsub: case ByteCodes.dsub:
780                return JCTree.MINUS_ASG;
781            case ByteCodes.imul: case ByteCodes.lmul:
782            case ByteCodes.fmul: case ByteCodes.dmul:
783                return JCTree.MUL_ASG;
784            case ByteCodes.idiv: case ByteCodes.ldiv:
785            case ByteCodes.fdiv: case ByteCodes.ddiv:
786                return JCTree.DIV_ASG;
787            case ByteCodes.imod: case ByteCodes.lmod:
788            case ByteCodes.fmod: case ByteCodes.dmod:
789                return JCTree.MOD_ASG;
790            default:
791                throw new AssertionError();
792            }
793        }
794    
795        /** The name of the access method with number `anum' and access code `acode'.
796         */
797        Name accessName(int anum, int acode) {
798            return names.fromString(
799                "access" + target.syntheticNameChar() + anum + acode / 10 + acode % 10);
800        }
801    
802        /** Return access symbol for a private or protected symbol from an inner class.
803         *  @param sym        The accessed private symbol.
804         *  @param tree       The accessing tree.
805         *  @param enclOp     The closest enclosing operation node of tree,
806         *                    null if tree is not a subtree of an operation.
807         *  @param protAccess Is access to a protected symbol in another
808         *                    package?
809         *  @param refSuper   Is access via a (qualified) C.super?
810         */
811        MethodSymbol accessSymbol(Symbol sym, JCTree tree, JCTree enclOp,
812                                  boolean protAccess, boolean refSuper) {
813            ClassSymbol accOwner = refSuper && protAccess
814                // For access via qualified super (T.super.x), place the
815                // access symbol on T.
816                ? (ClassSymbol)((JCFieldAccess) tree).selected.type.tsym
817                // Otherwise pretend that the owner of an accessed
818                // protected symbol is the enclosing class of the current
819                // class which is a subclass of the symbol's owner.
820                : accessClass(sym, protAccess, tree);
821    
822            Symbol vsym = sym;
823            if (sym.owner != accOwner) {
824                vsym = sym.clone(accOwner);
825                actualSymbols.put(vsym, sym);
826            }
827    
828            Integer anum              // The access number of the access method.
829                = accessNums.get(vsym);
830            if (anum == null) {
831                anum = accessed.length();
832                accessNums.put(vsym, anum);
833                accessSyms.put(vsym, new MethodSymbol[NCODES]);
834                accessed.append(vsym);
835                // System.out.println("accessing " + vsym + " in " + vsym.location());
836            }
837    
838            int acode;                // The access code of the access method.
839            List<Type> argtypes;      // The argument types of the access method.
840            Type restype;             // The result type of the access method.
841            List<Type> thrown;        // The thrown execeptions of the access method.
842            switch (vsym.kind) {
843            case VAR:
844                acode = accessCode(tree, enclOp);
845                if (acode >= FIRSTASGOPcode) {
846                    OperatorSymbol operator = binaryAccessOperator(acode);
847                    if (operator.opcode == string_add)
848                        argtypes = List.of(syms.objectType);
849                    else
850                        argtypes = operator.type.getParameterTypes().tail;
851                } else if (acode == ASSIGNcode)
852                    argtypes = List.of(vsym.erasure(types));
853                else
854                    argtypes = List.nil();
855                restype = vsym.erasure(types);
856                thrown = List.nil();
857                break;
858            case MTH:
859                acode = DEREFcode;
860                argtypes = vsym.erasure(types).getParameterTypes();
861                restype = vsym.erasure(types).getReturnType();
862                thrown = vsym.type.getThrownTypes();
863                break;
864            default:
865                throw new AssertionError();
866            }
867    
868            // For references via qualified super, increment acode by one,
869            // making it odd.
870            if (protAccess && refSuper) acode++;
871    
872            // Instance access methods get instance as first parameter.
873            // For protected symbols this needs to be the instance as a member
874            // of the type containing the accessed symbol, not the class
875            // containing the access method.
876            if ((vsym.flags() & STATIC) == 0) {
877                argtypes = argtypes.prepend(vsym.owner.erasure(types));
878            }
879            MethodSymbol[] accessors = accessSyms.get(vsym);
880            MethodSymbol accessor = accessors[acode];
881            if (accessor == null) {
882                accessor = new MethodSymbol(
883                    STATIC | SYNTHETIC,
884                    accessName(anum.intValue(), acode),
885                    new MethodType(argtypes, restype, thrown, syms.methodClass),
886                    accOwner);
887                enterSynthetic(tree.pos(), accessor, accOwner.members());
888                accessors[acode] = accessor;
889            }
890            return accessor;
891        }
892    
893        /** The qualifier to be used for accessing a symbol in an outer class.
894         *  This is either C.sym or C.this.sym, depending on whether or not
895         *  sym is static.
896         *  @param sym   The accessed symbol.
897         */
898        JCExpression accessBase(DiagnosticPosition pos, Symbol sym) {
899            return (sym.flags() & STATIC) != 0
900                ? access(make.at(pos.getStartPosition()).QualIdent(sym.owner))
901                : makeOwnerThis(pos, sym, true);
902        }
903    
904        /** Do we need an access method to reference private symbol?
905         */
906        boolean needsPrivateAccess(Symbol sym) {
907            if ((sym.flags() & PRIVATE) == 0 || sym.owner == currentClass) {
908                return false;
909            } else if (sym.name == names.init && (sym.owner.owner.kind & (VAR | MTH)) != 0) {
910                // private constructor in local class: relax protection
911                sym.flags_field &= ~PRIVATE;
912                return false;
913            } else {
914                return true;
915            }
916        }
917    
918        /** Do we need an access method to reference symbol in other package?
919         */
920        boolean needsProtectedAccess(Symbol sym, JCTree tree) {
921            if ((sym.flags() & PROTECTED) == 0 ||
922                sym.owner.owner == currentClass.owner || // fast special case
923                sym.packge() == currentClass.packge())
924                return false;
925            if (!currentClass.isSubClass(sym.owner, types))
926                return true;
927            if ((sym.flags() & STATIC) != 0 ||
928                tree.getTag() != JCTree.SELECT ||
929                TreeInfo.name(((JCFieldAccess) tree).selected) == names._super)
930                return false;
931            return !((JCFieldAccess) tree).selected.type.tsym.isSubClass(currentClass, types);
932        }
933    
934        /** The class in which an access method for given symbol goes.
935         *  @param sym        The access symbol
936         *  @param protAccess Is access to a protected symbol in another
937         *                    package?
938         */
939        ClassSymbol accessClass(Symbol sym, boolean protAccess, JCTree tree) {
940            if (protAccess) {
941                Symbol qualifier = null;
942                ClassSymbol c = currentClass;
943                if (tree.getTag() == JCTree.SELECT && (sym.flags() & STATIC) == 0) {
944                    qualifier = ((JCFieldAccess) tree).selected.type.tsym;
945                    while (!qualifier.isSubClass(c, types)) {
946                        c = c.owner.enclClass();
947                    }
948                    return c;
949                } else {
950                    while (!c.isSubClass(sym.owner, types)) {
951                        c = c.owner.enclClass();
952                    }
953                }
954                return c;
955            } else {
956                // the symbol is private
957                return sym.owner.enclClass();
958            }
959        }
960    
961        /** Ensure that identifier is accessible, return tree accessing the identifier.
962         *  @param sym      The accessed symbol.
963         *  @param tree     The tree referring to the symbol.
964         *  @param enclOp   The closest enclosing operation node of tree,
965         *                  null if tree is not a subtree of an operation.
966         *  @param refSuper Is access via a (qualified) C.super?
967         */
968        JCExpression access(Symbol sym, JCExpression tree, JCExpression enclOp, boolean refSuper) {
969            // Access a free variable via its proxy, or its proxy's proxy
970            while (sym.kind == VAR && sym.owner.kind == MTH &&
971                sym.owner.enclClass() != currentClass) {
972                // A constant is replaced by its constant value.
973                Object cv = ((VarSymbol)sym).getConstValue();
974                if (cv != null) {
975                    make.at(tree.pos);
976                    return makeLit(sym.type, cv);
977                }
978                // Otherwise replace the variable by its proxy.
979                sym = proxies.lookup(proxyName(sym.name)).sym;
980                assert sym != null && (sym.flags_field & FINAL) != 0;
981                tree = make.at(tree.pos).Ident(sym);
982            }
983            JCExpression base = (tree.getTag() == JCTree.SELECT) ? ((JCFieldAccess) tree).selected : null;
984            switch (sym.kind) {
985            case TYP:
986                if (sym.owner.kind != PCK) {
987                    // Convert type idents to
988                    // <flat name> or <package name> . <flat name>
989                    Name flatname = Convert.shortName(sym.flatName());
990                    while (base != null &&
991                           TreeInfo.symbol(base) != null &&
992                           TreeInfo.symbol(base).kind != PCK) {
993                        base = (base.getTag() == JCTree.SELECT)
994                            ? ((JCFieldAccess) base).selected
995                            : null;
996                    }
997                    if (tree.getTag() == JCTree.IDENT) {
998                        ((JCIdent) tree).name = flatname;
999                    } else if (base == null) {
1000                        tree = make.at(tree.pos).Ident(sym);
1001                        ((JCIdent) tree).name = flatname;
1002                    } else {
1003                        ((JCFieldAccess) tree).selected = base;
1004                        ((JCFieldAccess) tree).name = flatname;
1005                    }
1006                }
1007                break;
1008            case MTH: case VAR:
1009                if (sym.owner.kind == TYP) {
1010    
1011                    // Access methods are required for
1012                    //  - private members,
1013                    //  - protected members in a superclass of an
1014                    //    enclosing class contained in another package.
1015                    //  - all non-private members accessed via a qualified super.
1016                    boolean protAccess = refSuper && !needsPrivateAccess(sym)
1017                        || needsProtectedAccess(sym, tree);
1018                    boolean accReq = protAccess || needsPrivateAccess(sym);
1019    
1020                    // A base has to be supplied for
1021                    //  - simple identifiers accessing variables in outer classes.
1022                    boolean baseReq =
1023                        base == null &&
1024                        sym.owner != syms.predefClass &&
1025                        !sym.isMemberOf(currentClass, types);
1026    
1027                    if (accReq || baseReq) {
1028                        make.at(tree.pos);
1029    
1030                        // Constants are replaced by their constant value.
1031                        if (sym.kind == VAR) {
1032                            Object cv = ((VarSymbol)sym).getConstValue();
1033                            if (cv != null) return makeLit(sym.type, cv);
1034                        }
1035    
1036                        // Private variables and methods are replaced by calls
1037                        // to their access methods.
1038                        if (accReq) {
1039                            List<JCExpression> args = List.nil();
1040                            if ((sym.flags() & STATIC) == 0) {
1041                                // Instance access methods get instance
1042                                // as first parameter.
1043                                if (base == null)
1044                                    base = makeOwnerThis(tree.pos(), sym, true);
1045                                args = args.prepend(base);
1046                                base = null;   // so we don't duplicate code
1047                            }
1048                            Symbol access = accessSymbol(sym, tree,
1049                                                         enclOp, protAccess,
1050                                                         refSuper);
1051                            JCExpression receiver = make.Select(
1052                                base != null ? base : make.QualIdent(access.owner),
1053                                access);
1054                            return make.App(receiver, args);
1055    
1056                        // Other accesses to members of outer classes get a
1057                        // qualifier.
1058                        } else if (baseReq) {
1059                            return make.at(tree.pos).Select(
1060                                accessBase(tree.pos(), sym), sym).setType(tree.type);
1061                        }
1062                    }
1063                }
1064            }
1065            return tree;
1066        }
1067    
1068        /** Ensure that identifier is accessible, return tree accessing the identifier.
1069         *  @param tree     The identifier tree.
1070         */
1071        JCExpression access(JCExpression tree) {
1072            Symbol sym = TreeInfo.symbol(tree);
1073            return sym == null ? tree : access(sym, tree, null, false);
1074        }
1075    
1076        /** Return access constructor for a private constructor,
1077         *  or the constructor itself, if no access constructor is needed.
1078         *  @param pos       The position to report diagnostics, if any.
1079         *  @param constr    The private constructor.
1080         */
1081        Symbol accessConstructor(DiagnosticPosition pos, Symbol constr) {
1082            if (needsPrivateAccess(constr)) {
1083                ClassSymbol accOwner = constr.owner.enclClass();
1084                MethodSymbol aconstr = accessConstrs.get(constr);
1085                if (aconstr == null) {
1086                    List<Type> argtypes = constr.type.getParameterTypes();
1087                    if ((accOwner.flags_field & ENUM) != 0)
1088                        argtypes = argtypes
1089                            .prepend(syms.intType)
1090                            .prepend(syms.stringType);
1091                    aconstr = new MethodSymbol(
1092                        SYNTHETIC,
1093                        names.init,
1094                        new MethodType(
1095                            argtypes.append(
1096                                accessConstructorTag().erasure(types)),
1097                            constr.type.getReturnType(),
1098                            constr.type.getThrownTypes(),
1099                            syms.methodClass),
1100                        accOwner);
1101                    enterSynthetic(pos, aconstr, accOwner.members());
1102                    accessConstrs.put(constr, aconstr);
1103                    accessed.append(constr);
1104                }
1105                return aconstr;
1106            } else {
1107                return constr;
1108            }
1109        }
1110    
1111        /** Return an anonymous class nested in this toplevel class.
1112         */
1113        ClassSymbol accessConstructorTag() {
1114            ClassSymbol topClass = currentClass.outermostClass();
1115            Name flatname = names.fromString("" + topClass.getQualifiedName() +
1116                                             target.syntheticNameChar() +
1117                                             "1");
1118            ClassSymbol ctag = chk.compiled.get(flatname);
1119            if (ctag == null)
1120                ctag = makeEmptyClass(STATIC | SYNTHETIC, topClass);
1121            return ctag;
1122        }
1123    
1124        /** Add all required access methods for a private symbol to enclosing class.
1125         *  @param sym       The symbol.
1126         */
1127        void makeAccessible(Symbol sym) {
1128            JCClassDecl cdef = classDef(sym.owner.enclClass());
1129            assert cdef != null : "class def not found: " + sym + " in " + sym.owner;
1130            if (sym.name == names.init) {
1131                cdef.defs = cdef.defs.prepend(
1132                    accessConstructorDef(cdef.pos, sym, accessConstrs.get(sym)));
1133            } else {
1134                MethodSymbol[] accessors = accessSyms.get(sym);
1135                for (int i = 0; i < NCODES; i++) {
1136                    if (accessors[i] != null)
1137                        cdef.defs = cdef.defs.prepend(
1138                            accessDef(cdef.pos, sym, accessors[i], i));
1139                }
1140            }
1141        }
1142    
1143        /** Construct definition of an access method.
1144         *  @param pos        The source code position of the definition.
1145         *  @param vsym       The private or protected symbol.
1146         *  @param accessor   The access method for the symbol.
1147         *  @param acode      The access code.
1148         */
1149        JCTree accessDef(int pos, Symbol vsym, MethodSymbol accessor, int acode) {
1150    //      System.err.println("access " + vsym + " with " + accessor);//DEBUG
1151            currentClass = vsym.owner.enclClass();
1152            // System.out.println("========accessDef, currentClass = "+currentClass+", type = "+((currentClass!=null)?currentClass.type.toString():"n/a"));
1153            make.at(pos);
1154            JCMethodDecl md = make.MethodDef(accessor, null);
1155    
1156            // Find actual symbol
1157            Symbol sym = actualSymbols.get(vsym);
1158            if (sym == null) sym = vsym;
1159    
1160            JCExpression ref;           // The tree referencing the private symbol.
1161            List<JCExpression> args;    // Any additional arguments to be passed along.
1162            if ((sym.flags() & STATIC) != 0) {
1163                ref = make.Ident(sym);
1164                args = make.Idents(md.params);
1165            } else {
1166                ref = make.Select(make.Ident(md.params.head), sym);
1167                args = make.Idents(md.params.tail);
1168            }
1169            JCStatement stat;          // The statement accessing the private symbol.
1170            if (sym.kind == VAR) {
1171                // Normalize out all odd access codes by taking floor modulo 2:
1172                int acode1 = acode - (acode & 1);
1173    
1174                JCExpression expr;      // The access method's return value.
1175                switch (acode1) {
1176                case DEREFcode:
1177                    expr = ref;
1178                    break;
1179                case ASSIGNcode:
1180                    expr = make.Assign(ref, args.head);
1181                    break;
1182                case PREINCcode: case POSTINCcode: case PREDECcode: case POSTDECcode:
1183                    expr = makeUnary(
1184                        ((acode1 - PREINCcode) >> 1) + JCTree.PREINC, ref);
1185                    break;
1186                default:
1187                    expr = make.Assignop(
1188                        treeTag(binaryAccessOperator(acode1)), ref, args.head);
1189                    ((JCAssignOp) expr).operator = binaryAccessOperator(acode1);
1190                }
1191                stat = make.Return(expr.setType(sym.type));
1192            } else {
1193                stat = make.Call(make.App(ref, args));
1194            }
1195            md.body = make.Block(0, List.of(stat));
1196    
1197            // Make sure all parameters, result types and thrown exceptions
1198            // are accessible.
1199            for (List<JCVariableDecl> l = md.params; l.nonEmpty(); l = l.tail)
1200                l.head.vartype = access(l.head.vartype);
1201            md.restype = access(md.restype);
1202            for (List<JCExpression> l = md.thrown; l.nonEmpty(); l = l.tail)
1203                l.head = access(l.head);
1204    
1205            return md;
1206        }
1207    
1208        /** Construct definition of an access constructor.
1209         *  @param pos        The source code position of the definition.
1210         *  @param constr     The private constructor.
1211         *  @param accessor   The access method for the constructor.
1212         */
1213        JCTree accessConstructorDef(int pos, Symbol constr, MethodSymbol accessor) {
1214            make.at(pos);
1215            JCMethodDecl md = make.MethodDef(accessor,
1216                                          accessor.externalType(types),
1217                                          null);
1218            JCIdent callee = make.Ident(names._this);
1219            callee.sym = constr;
1220            callee.type = constr.type;
1221            md.body =
1222                make.Block(0, List.<JCStatement>of(
1223                    make.Call(
1224                        make.App(
1225                            callee,
1226                            make.Idents(md.params.reverse().tail.reverse())))));
1227            return md;
1228        }
1229    
1230    /**************************************************************************
1231     * Free variables proxies and this$n
1232     *************************************************************************/
1233    
1234        /** A scope containing all free variable proxies for currently translated
1235         *  class, as well as its this$n symbol (if needed).
1236         *  Proxy scopes are nested in the same way classes are.
1237         *  Inside a constructor, proxies and any this$n symbol are duplicated
1238         *  in an additional innermost scope, where they represent the constructor
1239         *  parameters.
1240         */
1241        Scope proxies;
1242    
1243        /** A stack containing the this$n field of the currently translated
1244         *  classes (if needed) in innermost first order.
1245         *  Inside a constructor, proxies and any this$n symbol are duplicated
1246         *  in an additional innermost scope, where they represent the constructor
1247         *  parameters.
1248         */
1249        List<VarSymbol> outerThisStack;
1250    
1251        /** The name of a free variable proxy.
1252         */
1253        Name proxyName(Name name) {
1254            return names.fromString("val" + target.syntheticNameChar() + name);
1255        }
1256    
1257        /** Proxy definitions for all free variables in given list, in reverse order.
1258         *  @param pos        The source code position of the definition.
1259         *  @param freevars   The free variables.
1260         *  @param owner      The class in which the definitions go.
1261         */
1262        List<JCVariableDecl> freevarDefs(int pos, List<VarSymbol> freevars, Symbol owner) {
1263            long flags = FINAL | SYNTHETIC;
1264            if (owner.kind == TYP &&
1265                target.usePrivateSyntheticFields())
1266                flags |= PRIVATE;
1267            List<JCVariableDecl> defs = List.nil();
1268            for (List<VarSymbol> l = freevars; l.nonEmpty(); l = l.tail) {
1269                VarSymbol v = l.head;
1270                VarSymbol proxy = new VarSymbol(
1271                    flags, proxyName(v.name), v.erasure(types), owner);
1272                proxies.enter(proxy);
1273                JCVariableDecl vd = make.at(pos).VarDef(proxy, null);
1274                vd.vartype = access(vd.vartype);
1275                defs = defs.prepend(vd);
1276            }
1277            return defs;
1278        }
1279    
1280        /** The name of a this$n field
1281         *  @param type   The class referenced by the this$n field
1282         */
1283        Name outerThisName(Type type, Symbol owner) {
1284            Type t = type.getEnclosingType();
1285            int nestingLevel = 0;
1286            while (t.tag == CLASS) {
1287                t = t.getEnclosingType();
1288                nestingLevel++;
1289            }
1290            Name result = names.fromString("this" + target.syntheticNameChar() + nestingLevel);
1291            while (owner.kind == TYP && ((ClassSymbol)owner).members().lookup(result).scope != null)
1292                result = names.fromString(result.toString() + target.syntheticNameChar());
1293            return result;
1294        }
1295    
1296        /** Definition for this$n field.
1297         *  @param pos        The source code position of the definition.
1298         *  @param owner      The class in which the definition goes.
1299         */
1300        JCVariableDecl outerThisDef(int pos, Symbol owner) {
1301            long flags = FINAL | SYNTHETIC;
1302            if (owner.kind == TYP &&
1303                target.usePrivateSyntheticFields())
1304                flags |= PRIVATE;
1305            Type target = types.erasure(owner.enclClass().type.getEnclosingType());
1306            VarSymbol outerThis = new VarSymbol(
1307                flags, outerThisName(target, owner), target, owner);
1308            outerThisStack = outerThisStack.prepend(outerThis);
1309            JCVariableDecl vd = make.at(pos).VarDef(outerThis, null);
1310            vd.vartype = access(vd.vartype);
1311            // System.out.print("outerThisDef owner="+owner+" outerThisStack=");
1312            // for(VarSymbol vs: outerThisStack) { System.out.print(vs+"("+vs.type+") "); }
1313            // System.out.println();
1314            return vd;
1315        }
1316    
1317        /** Return a list of trees that load the free variables in given list,
1318         *  in reverse order.
1319         *  @param pos          The source code position to be used for the trees.
1320         *  @param freevars     The list of free variables.
1321         */
1322        List<JCExpression> loadFreevars(DiagnosticPosition pos, List<VarSymbol> freevars) {
1323            List<JCExpression> args = List.nil();
1324            for (List<VarSymbol> l = freevars; l.nonEmpty(); l = l.tail)
1325                args = args.prepend(loadFreevar(pos, l.head));
1326            return args;
1327        }
1328    //where
1329            JCExpression loadFreevar(DiagnosticPosition pos, VarSymbol v) {
1330                return access(v, make.at(pos).Ident(v), null, false);
1331            }
1332    
1333        /** Construct a tree simulating the expression <C.this>.
1334         *  @param pos           The source code position to be used for the tree.
1335         *  @param c             The qualifier class.
1336         */
1337        JCExpression makeThis(DiagnosticPosition pos, TypeSymbol c) {
1338            // System.out.println("\tmakeThis, currentClass="+currentClass+", c="+c);
1339            if (currentClass == c) {
1340                // in this case, `this' works fine
1341                return make.at(pos).This(c.erasure(types));
1342            } else {
1343                // need to go via this$n
1344                return makeOuterThis(pos, c);
1345            }
1346        }
1347    
1348        /** Construct a tree that represents the outer instance
1349         *  <C.this>. Never pick the current `this'.
1350         *  @param pos           The source code position to be used for the tree.
1351         *  @param c             The qualifier class.
1352         */
1353        JCExpression makeOuterThis(DiagnosticPosition pos, TypeSymbol c) {
1354            List<VarSymbol> ots = outerThisStack;
1355            // System.out.println("\tots = "+ots);
1356            if (ots.isEmpty()) {
1357                log.error(pos, "no.encl.instance.of.type.in.scope", c);
1358                assert false;
1359                return makeNull();
1360            }
1361            VarSymbol ot = ots.head;
1362            JCExpression tree = access(make.at(pos).Ident(ot));
1363            TypeSymbol otc = ot.type.tsym;
1364            while (otc != c) {
1365                do {
1366                    ots = ots.tail;
1367                    if (ots.isEmpty()) {
1368                        log.error(pos,
1369                                  "no.encl.instance.of.type.in.scope",
1370                                  c);
1371                        assert false; // should have been caught in Attr
1372                        return tree;
1373                    }
1374                    ot = ots.head;
1375                } while (ot.owner != otc);
1376                if (otc.owner.kind != PCK && !otc.hasOuterInstance()) {
1377                    chk.earlyRefError(pos, c);
1378                    assert false; // should have been caught in Attr
1379                    return makeNull();
1380                }
1381                tree = access(make.at(pos).Select(tree, ot));
1382                otc = ot.type.tsym;
1383            }
1384            return tree;
1385        }
1386    
1387        /** Construct a tree that represents the closest outer instance
1388         *  <C.this> such that the given symbol is a member of C.
1389         *  @param pos           The source code position to be used for the tree.
1390         *  @param sym           The accessed symbol.
1391         *  @param preciseMatch  should we accept a type that is a subtype of
1392         *                       sym's owner, even if it doesn't contain sym
1393         *                       due to hiding, overriding, or non-inheritance
1394         *                       due to protection?
1395         */
1396        JCExpression makeOwnerThis(DiagnosticPosition pos, Symbol sym, boolean preciseMatch) {
1397            Symbol c = sym.owner;
1398            if (preciseMatch ? sym.isMemberOf(currentClass, types)
1399                             : currentClass.isSubClass(sym.owner, types)) {
1400                // in this case, `this' works fine
1401                return make.at(pos).This(c.erasure(types));
1402            } else {
1403                // need to go via this$n
1404                return makeOwnerThisN(pos, sym, preciseMatch);
1405            }
1406        }
1407    
1408        /**
1409         * Similar to makeOwnerThis but will never pick "this".
1410         */
1411        JCExpression makeOwnerThisN(DiagnosticPosition pos, Symbol sym, boolean preciseMatch) {
1412            Symbol c = sym.owner;
1413            List<VarSymbol> ots = outerThisStack;
1414            if (ots.isEmpty()) {
1415                log.error(pos, "no.encl.instance.of.type.in.scope", c);
1416                assert false;
1417                return makeNull();
1418            }
1419            VarSymbol ot = ots.head;
1420            JCExpression tree = access(make.at(pos).Ident(ot));
1421            TypeSymbol otc = ot.type.tsym;
1422            while (!(preciseMatch ? sym.isMemberOf(otc, types) : otc.isSubClass(sym.owner, types))) {
1423                do {
1424                    ots = ots.tail;
1425                    if (ots.isEmpty()) {
1426                        log.error(pos,
1427                            "no.encl.instance.of.type.in.scope",
1428                            c);
1429                        assert false;
1430                        return tree;
1431                    }
1432                    ot = ots.head;
1433                } while (ot.owner != otc);
1434                tree = access(make.at(pos).Select(tree, ot));
1435                otc = ot.type.tsym;
1436            }
1437            return tree;
1438        }
1439    
1440        /** Return tree simulating the assignment <this.name = name>, where
1441         *  name is the name of a free variable.
1442         */
1443        JCStatement initField(int pos, Name name) {
1444            Scope.Entry e = proxies.lookup(name);
1445            Symbol rhs = e.sym;
1446            assert rhs.owner.kind == MTH;
1447            Symbol lhs = e.next().sym;
1448            assert rhs.owner.owner == lhs.owner;
1449            make.at(pos);
1450            return
1451                make.Exec(
1452                    make.Assign(
1453                        make.Select(make.This(lhs.owner.erasure(types)), lhs),
1454                        make.Ident(rhs)).setType(lhs.erasure(types)));
1455        }
1456    
1457        /** Return tree simulating the assignment <this.this$n = this$n>.
1458         */
1459        JCStatement initOuterThis(int pos) {
1460            VarSymbol rhs = outerThisStack.head;
1461            assert rhs.owner.kind == MTH;
1462            VarSymbol lhs = outerThisStack.tail.head;
1463            assert rhs.owner.owner == lhs.owner;
1464            make.at(pos);
1465            return
1466                make.Exec(
1467                    make.Assign(
1468                        make.Select(make.This(lhs.owner.erasure(types)), lhs),
1469                        make.Ident(rhs)).setType(lhs.erasure(types)));
1470        }
1471    
1472    /**************************************************************************
1473     * Code for .class
1474     *************************************************************************/
1475    
1476        /** Return the symbol of a class to contain a cache of
1477         *  compiler-generated statics such as class$ and the
1478         *  $assertionsDisabled flag.  We create an anonymous nested class
1479         *  (unless one already exists) and return its symbol.  However,
1480         *  for backward compatibility in 1.4 and earlier we use the
1481         *  top-level class itself.
1482         */
1483        private ClassSymbol outerCacheClass() {
1484            ClassSymbol clazz = outermostClassDef.sym;
1485            if ((clazz.flags() & INTERFACE) == 0 &&
1486                !target.useInnerCacheClass()) return clazz;
1487            Scope s = clazz.members();
1488            for (Scope.Entry e = s.elems; e != null; e = e.sibling)
1489                if (e.sym.kind == TYP &&
1490                    e.sym.name == names.empty &&
1491                    (e.sym.flags() & INTERFACE) == 0) return (ClassSymbol) e.sym;
1492            return makeEmptyClass(STATIC | SYNTHETIC, clazz);
1493        }
1494    
1495        /** Return symbol for "class$" method. If there is no method definition
1496         *  for class$, construct one as follows:
1497         *
1498         *    class class$(String x0) {
1499         *      try {
1500         *        return Class.forName(x0);
1501         *      } catch (ClassNotFoundException x1) {
1502         *        throw new NoClassDefFoundError(x1.getMessage());
1503         *      }
1504         *    }
1505         */
1506        private MethodSymbol classDollarSym(DiagnosticPosition pos) {
1507            ClassSymbol outerCacheClass = outerCacheClass();
1508            MethodSymbol classDollarSym =
1509                (MethodSymbol)lookupSynthetic(classDollar,
1510                                              outerCacheClass.members());
1511            if (classDollarSym == null) {
1512                classDollarSym = new MethodSymbol(
1513                    STATIC | SYNTHETIC,
1514                    classDollar,
1515                    new MethodType(
1516                        List.of(syms.stringType),
1517                        types.erasure(syms.classType),
1518                        List.<Type>nil(),
1519                        syms.methodClass),
1520                    outerCacheClass);
1521                enterSynthetic(pos, classDollarSym, outerCacheClass.members());
1522    
1523                JCMethodDecl md = make.MethodDef(classDollarSym, null);
1524                try {
1525                    md.body = classDollarSymBody(pos, md);
1526                } catch (CompletionFailure ex) {
1527                    md.body = make.Block(0, List.<JCStatement>nil());
1528                    chk.completionError(pos, ex);
1529                }
1530                JCClassDecl outerCacheClassDef = classDef(outerCacheClass);
1531                outerCacheClassDef.defs = outerCacheClassDef.defs.prepend(md);
1532            }
1533            return classDollarSym;
1534        }
1535    
1536        /** Generate code for class$(String name). */
1537        JCBlock classDollarSymBody(DiagnosticPosition pos, JCMethodDecl md) {
1538            MethodSymbol classDollarSym = md.sym;
1539            ClassSymbol outerCacheClass = (ClassSymbol)classDollarSym.owner;
1540    
1541            JCBlock returnResult;
1542    
1543            // in 1.4.2 and above, we use
1544            // Class.forName(String name, boolean init, ClassLoader loader);
1545            // which requires we cache the current loader in cl$
1546            if (target.classLiteralsNoInit()) {
1547                // clsym = "private static ClassLoader cl$"
1548                VarSymbol clsym = new VarSymbol(STATIC|SYNTHETIC,
1549                                                names.fromString("cl" + target.syntheticNameChar()),
1550                                                syms.classLoaderType,
1551                                                outerCacheClass);
1552                enterSynthetic(pos, clsym, outerCacheClass.members());
1553    
1554                // emit "private static ClassLoader cl$;"
1555                JCVariableDecl cldef = make.VarDef(clsym, null);
1556                JCClassDecl outerCacheClassDef = classDef(outerCacheClass);
1557                outerCacheClassDef.defs = outerCacheClassDef.defs.prepend(cldef);
1558    
1559                // newcache := "new cache$1[0]"
1560                JCNewArray newcache = make.
1561                    NewArray(make.Type(outerCacheClass.type),
1562                             List.<JCExpression>of(make.Literal(INT, 0).setType(syms.intType)),
1563                             null);
1564                newcache.type = new ArrayType(types.erasure(outerCacheClass.type),
1565                                              syms.arrayClass);
1566    
1567                // forNameSym := java.lang.Class.forName(
1568                //     String s,boolean init,ClassLoader loader)
1569                Symbol forNameSym = lookupMethod(make_pos, names.forName,
1570                                                 types.erasure(syms.classType),
1571                                                 List.of(syms.stringType,
1572                                                         syms.booleanType,
1573                                                         syms.classLoaderType));
1574                // clvalue := "(cl$ == null) ?
1575                // $newcache.getClass().getComponentType().getClassLoader() : cl$"
1576                JCExpression clvalue =
1577                    make.Conditional(
1578                        makeBinary(JCTree.EQ, make.Ident(clsym), makeNull()),
1579                        make.Assign(
1580                            make.Ident(clsym),
1581                            makeCall(
1582                                makeCall(makeCall(newcache,
1583                                                  names.getClass,
1584                                                  List.<JCExpression>nil()),
1585                                         names.getComponentType,
1586                                         List.<JCExpression>nil()),
1587                                names.getClassLoader,
1588                                List.<JCExpression>nil())).setType(syms.classLoaderType),
1589                        make.Ident(clsym)).setType(syms.classLoaderType);
1590    
1591                // returnResult := "{ return Class.forName(param1, false, cl$); }"
1592                List<JCExpression> args = List.of(make.Ident(md.params.head.sym),
1593                                                  makeLit(syms.booleanType, 0),
1594                                                  clvalue);
1595                returnResult = make.
1596                    Block(0, List.<JCStatement>of(make.
1597                                  Call(make. // return
1598                                       App(make.
1599                                           Ident(forNameSym), args))));
1600            } else {
1601                // forNameSym := java.lang.Class.forName(String s)
1602                Symbol forNameSym = lookupMethod(make_pos,
1603                                                 names.forName,
1604                                                 types.erasure(syms.classType),
1605                                                 List.of(syms.stringType));
1606                // returnResult := "{ return Class.forName(param1); }"
1607                returnResult = make.
1608                    Block(0, List.of(make.
1609                              Call(make. // return
1610                                  App(make.
1611                                      QualIdent(forNameSym),
1612                                      List.<JCExpression>of(make.
1613                                                            Ident(md.params.
1614                                                                  head.sym))))));
1615            }
1616    
1617            // catchParam := ClassNotFoundException e1
1618            VarSymbol catchParam =
1619                new VarSymbol(0, make.paramName(1),
1620                              syms.classNotFoundExceptionType,
1621                              classDollarSym);
1622    
1623            JCStatement rethrow;
1624            if (target.hasInitCause()) {
1625                // rethrow = "throw new NoClassDefFoundError().initCause(e);
1626                JCTree throwExpr =
1627                    makeCall(makeNewClass(syms.noClassDefFoundErrorType,
1628                                          List.<JCExpression>nil()),
1629                             names.initCause,
1630                             List.<JCExpression>of(make.Ident(catchParam)));
1631                rethrow = make.Throw(throwExpr);
1632            } else {
1633                // getMessageSym := ClassNotFoundException.getMessage()
1634                Symbol getMessageSym = lookupMethod(make_pos,
1635                                                    names.getMessage,
1636                                                    syms.classNotFoundExceptionType,
1637                                                    List.<Type>nil());
1638                // rethrow = "throw new NoClassDefFoundError(e.getMessage());"
1639                rethrow = make.
1640                    Throw(makeNewClass(syms.noClassDefFoundErrorType,
1641                              List.<JCExpression>of(make.App(make.Select(make.Ident(catchParam),
1642                                                                         getMessageSym),
1643                                                             List.<JCExpression>nil()))));
1644            }
1645    
1646            // rethrowStmt := "( $rethrow )"
1647            JCBlock rethrowStmt = make.Block(0, List.of(rethrow));
1648    
1649            // catchBlock := "catch ($catchParam) $rethrowStmt"
1650            JCCatch catchBlock = make.Catch(make.VarDef(catchParam, null),
1651                                          rethrowStmt);
1652    
1653            // tryCatch := "try $returnResult $catchBlock"
1654            JCStatement tryCatch = make.Try(returnResult,
1655                                            List.of(catchBlock), null);
1656    
1657            return make.Block(0, List.of(tryCatch));
1658        }
1659        // where
1660            /** Create an attributed tree of the form left.name(). */
1661            private JCMethodInvocation makeCall(JCExpression left, Name name, List<JCExpression> args) {
1662                assert left.type != null;
1663                Symbol funcsym = lookupMethod(make_pos, name, left.type,
1664                                              TreeInfo.types(args));
1665                return make.App(make.Select(left, funcsym), args);
1666            }
1667    
1668        /** The Name Of The variable to cache T.class values.
1669         *  @param sig      The signature of type T.
1670         */
1671        private Name cacheName(String sig) {
1672            StringBuffer buf = new StringBuffer();
1673            if (sig.startsWith("[")) {
1674                buf = buf.append("array");
1675                while (sig.startsWith("[")) {
1676                    buf = buf.append(target.syntheticNameChar());
1677                    sig = sig.substring(1);
1678                }
1679                if (sig.startsWith("L")) {
1680                    sig = sig.substring(0, sig.length() - 1);
1681                }
1682            } else {
1683                buf = buf.append("class" + target.syntheticNameChar());
1684            }
1685            buf = buf.append(sig.replace('.', target.syntheticNameChar()));
1686            return names.fromString(buf.toString());
1687        }
1688    
1689        /** The variable symbol that caches T.class values.
1690         *  If none exists yet, create a definition.
1691         *  @param sig      The signature of type T.
1692         *  @param pos      The position to report diagnostics, if any.
1693         */
1694        private VarSymbol cacheSym(DiagnosticPosition pos, String sig) {
1695            ClassSymbol outerCacheClass = outerCacheClass();
1696            Name cname = cacheName(sig);
1697            VarSymbol cacheSym =
1698                (VarSymbol)lookupSynthetic(cname, outerCacheClass.members());
1699            if (cacheSym == null) {
1700                cacheSym = new VarSymbol(
1701                    STATIC | SYNTHETIC, cname, types.erasure(syms.classType), outerCacheClass);
1702                enterSynthetic(pos, cacheSym, outerCacheClass.members());
1703    
1704                JCVariableDecl cacheDef = make.VarDef(cacheSym, null);
1705                JCClassDecl outerCacheClassDef = classDef(outerCacheClass);
1706                outerCacheClassDef.defs = outerCacheClassDef.defs.prepend(cacheDef);
1707            }
1708            return cacheSym;
1709        }
1710    
1711        /** The tree simulating a T.class expression.
1712         *  @param clazz      The tree identifying type T.
1713         */
1714        private JCExpression classOf(JCTree clazz) {
1715            return classOfType(clazz.type, clazz.pos());
1716        }
1717    
1718        private JCExpression classOfType(Type type, DiagnosticPosition pos) {
1719            switch (type.tag) {
1720            case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT:
1721            case DOUBLE: case BOOLEAN: case VOID:
1722                // replace with <BoxedClass>.TYPE
1723                ClassSymbol c = types.boxedClass(type);
1724                Symbol typeSym =
1725                    rs.access(
1726                        rs.findIdentInType(attrEnv, c.type, names.TYPE, VAR),
1727                        pos, c.type, names.TYPE, true);
1728                if (typeSym.kind == VAR)
1729                    ((VarSymbol)typeSym).getConstValue(); // ensure initializer is evaluated
1730                return make.QualIdent(typeSym);
1731            case CLASS: case ARRAY:
1732                if (target.hasClassLiterals()) {
1733                    VarSymbol sym = new VarSymbol(
1734                            STATIC | PUBLIC | FINAL, names._class,
1735                            syms.classType, type.tsym);
1736                    return make_at(pos).Select(make.Type(type), sym);
1737                }
1738                // replace with <cache == null ? cache = class$(tsig) : cache>
1739                // where
1740                //  - <tsig>  is the type signature of T,
1741                //  - <cache> is the cache variable for tsig.
1742                String sig =
1743                    writer.xClassName(type).toString().replace('/', '.');
1744                Symbol cs = cacheSym(pos, sig);
1745                return make_at(pos).Conditional(
1746                    makeBinary(JCTree.EQ, make.Ident(cs), makeNull()),
1747                    make.Assign(
1748                        make.Ident(cs),
1749                        make.App(
1750                            make.Ident(classDollarSym(pos)),
1751                            List.<JCExpression>of(make.Literal(CLASS, sig)
1752                                                  .setType(syms.stringType))))
1753                    .setType(types.erasure(syms.classType)),
1754                    make.Ident(cs)).setType(types.erasure(syms.classType));
1755            default:
1756                throw new AssertionError();
1757            }
1758        }
1759    
1760    /**************************************************************************
1761     * Code for enabling/disabling assertions.
1762     *************************************************************************/
1763    
1764        // This code is not particularly robust if the user has
1765        // previously declared a member named '$assertionsDisabled'.
1766        // The same faulty idiom also appears in the translation of
1767        // class literals above.  We should report an error if a
1768        // previous declaration is not synthetic.
1769    
1770        private JCExpression assertFlagTest(DiagnosticPosition pos) {
1771            // Outermost class may be either true class or an interface.
1772            ClassSymbol outermostClass = outermostClassDef.sym;
1773    
1774            // note that this is a class, as an interface can't contain a statement.
1775            ClassSymbol container = currentClass;
1776    
1777            VarSymbol assertDisabledSym =
1778                (VarSymbol)lookupSynthetic(dollarAssertionsDisabled,
1779                                           container.members());
1780            if (assertDisabledSym == null) {
1781                assertDisabledSym =
1782                    new VarSymbol(STATIC | FINAL | SYNTHETIC,
1783                                  dollarAssertionsDisabled,
1784                                  syms.booleanType,
1785                                  container);
1786                enterSynthetic(pos, assertDisabledSym, container.members());
1787                Symbol desiredAssertionStatusSym = lookupMethod(pos,
1788                                                                names.desiredAssertionStatus,
1789                                                                types.erasure(syms.classType),
1790                                                                List.<Type>nil());
1791                JCClassDecl containerDef = classDef(container);
1792                make_at(containerDef.pos());
1793                JCExpression notStatus = makeUnary(JCTree.NOT, make.App(make.Select(
1794                        classOfType(types.erasure(outermostClass.type),
1795                                    containerDef.pos()),
1796                        desiredAssertionStatusSym)));
1797                JCVariableDecl assertDisabledDef = make.VarDef(assertDisabledSym,
1798                                                       notStatus);
1799                containerDef.defs = containerDef.defs.prepend(assertDisabledDef);
1800            }
1801            make_at(pos);
1802            return makeUnary(JCTree.NOT, make.Ident(assertDisabledSym));
1803        }
1804    
1805    
1806    /**************************************************************************
1807     * Building blocks for let expressions
1808     *************************************************************************/
1809    
1810        interface TreeBuilder {
1811            JCTree build(JCTree arg);
1812        }
1813    
1814        /** Construct an expression using the builder, with the given rval
1815         *  expression as an argument to the builder.  However, the rval
1816         *  expression must be computed only once, even if used multiple
1817         *  times in the result of the builder.  We do that by
1818         *  constructing a "let" expression that saves the rvalue into a
1819         *  temporary variable and then uses the temporary variable in
1820         *  place of the expression built by the builder.  The complete
1821         *  resulting expression is of the form
1822         *  <pre>
1823         *    (let <b>TYPE</b> <b>TEMP</b> = <b>RVAL</b>;
1824         *     in (<b>BUILDER</b>(<b>TEMP</b>)))
1825         *  </pre>
1826         *  where <code><b>TEMP</b></code> is a newly declared variable
1827         *  in the let expression.
1828         */
1829        JCTree abstractRval(JCTree rval, Type type, TreeBuilder builder) {
1830            rval = TreeInfo.skipParens(rval);
1831            switch (rval.getTag()) {
1832            case JCTree.LITERAL:
1833                return builder.build(rval);
1834            case JCTree.IDENT:
1835                JCIdent id = (JCIdent) rval;
1836                if ((id.sym.flags() & FINAL) != 0 && id.sym.owner.kind == MTH)
1837                    return builder.build(rval);
1838            }
1839            VarSymbol var =
1840                new VarSymbol(FINAL|SYNTHETIC,
1841                              names.fromString(
1842                                              target.syntheticNameChar()
1843                                              + "" + rval.hashCode()),
1844                                          type,
1845                                          currentMethodSym);
1846            rval = convert(rval,type);
1847            JCVariableDecl def = make.VarDef(var, (JCExpression)rval); // XXX cast
1848            JCTree built = builder.build(make.Ident(var));
1849            JCTree res = make.LetExpr(def, built);
1850            res.type = built.type;
1851            return res;
1852        }
1853    
1854        // same as above, with the type of the temporary variable computed
1855        JCTree abstractRval(JCTree rval, TreeBuilder builder) {
1856            return abstractRval(rval, rval.type, builder);
1857        }
1858    
1859        // same as above, but for an expression that may be used as either
1860        // an rvalue or an lvalue.  This requires special handling for
1861        // Select expressions, where we place the left-hand-side of the
1862        // select in a temporary, and for Indexed expressions, where we
1863        // place both the indexed expression and the index value in temps.
1864        JCTree abstractLval(JCTree lval, final TreeBuilder builder) {
1865            lval = TreeInfo.skipParens(lval);
1866            switch (lval.getTag()) {
1867            case JCTree.IDENT:
1868                return builder.build(lval);
1869            case JCTree.SELECT: {
1870                final JCFieldAccess s = (JCFieldAccess)lval;
1871                JCTree selected = TreeInfo.skipParens(s.selected);
1872                Symbol lid = TreeInfo.symbol(s.selected);
1873                if (lid != null && lid.kind == TYP) return builder.build(lval);
1874                return abstractRval(s.selected, new TreeBuilder() {
1875                        public JCTree build(final JCTree selected) {
1876                            return builder.build(make.Select((JCExpression)selected, s.sym));
1877                        }
1878                    });
1879            }
1880            case JCTree.INDEXED: {
1881                final JCArrayAccess i = (JCArrayAccess)lval;
1882                return abstractRval(i.indexed, new TreeBuilder() {
1883                        public JCTree build(final JCTree indexed) {
1884                            return abstractRval(i.index, syms.intType, new TreeBuilder() {
1885                                    public JCTree build(final JCTree index) {
1886                                        JCTree newLval = make.Indexed((JCExpression)indexed,
1887                                                                    (JCExpression)index);
1888                                        newLval.setType(i.type);
1889                                        return builder.build(newLval);
1890                                    }
1891                                });
1892                        }
1893                    });
1894            }
1895            case JCTree.TYPECAST: {
1896                return abstractLval(((JCTypeCast)lval).expr, builder);
1897            }
1898            }
1899            throw new AssertionError(lval);
1900        }
1901    
1902        // evaluate and discard the first expression, then evaluate the second.
1903        JCTree makeComma(final JCTree expr1, final JCTree expr2) {
1904            return abstractRval(expr1, new TreeBuilder() {
1905                    public JCTree build(final JCTree discarded) {
1906                        return expr2;
1907                    }
1908                });
1909        }
1910    
1911    /**************************************************************************
1912     * Translation methods
1913     *************************************************************************/
1914    
1915        /** Visitor argument: enclosing operator node.
1916         */
1917        private JCExpression enclOp;
1918    
1919        /** Visitor method: Translate a single node.
1920         *  Attach the source position from the old tree to its replacement tree.
1921         */
1922        public <T extends JCTree> T translate(T tree) {
1923            if (tree == null) {
1924                return null;
1925            } else {
1926                make_at(tree.pos());
1927                T result = super.translate(tree);
1928                if (endPositions != null && result != tree) {
1929                    Integer endPos = endPositions.remove(tree);
1930                    if (endPos != null) endPositions.put(result, endPos);
1931                }
1932                return result;
1933            }
1934        }
1935    
1936        /** Visitor method: Translate a single node, boxing or unboxing if needed.
1937         */
1938        public <T extends JCTree> T translate(T tree, Type type) {
1939            return (tree == null) ? null : boxIfNeeded(translate(tree), type);
1940        }
1941    
1942        /** Visitor method: Translate tree.
1943         */
1944        public <T extends JCTree> T translate(T tree, JCExpression enclOp) {
1945            JCExpression prevEnclOp = this.enclOp;
1946            this.enclOp = enclOp;
1947            T res = translate(tree);
1948            this.enclOp = prevEnclOp;
1949            return res;
1950        }
1951    
1952        /** Visitor method: Translate list of trees.
1953         */
1954        public <T extends JCTree> List<T> translate(List<T> trees, JCExpression enclOp) {
1955            JCExpression prevEnclOp = this.enclOp;
1956            this.enclOp = enclOp;
1957            List<T> res = translate(trees);
1958            this.enclOp = prevEnclOp;
1959            return res;
1960        }
1961    
1962        /** Visitor method: Translate list of trees.
1963         */
1964        public <T extends JCTree> List<T> translate(List<T> trees, Type type) {
1965            if (trees == null) return null;
1966            for (List<T> l = trees; l.nonEmpty(); l = l.tail)
1967                l.head = translate(l.head, type);
1968            return trees;
1969        }
1970    
1971        public void visitTopLevel(JCCompilationUnit tree) {
1972            if (tree.packageAnnotations.nonEmpty()) {
1973                Name name = names.package_info;
1974                long flags = Flags.ABSTRACT | Flags.INTERFACE;
1975                if (target.isPackageInfoSynthetic())
1976                    // package-info is marked SYNTHETIC in JDK 1.6 and later releases
1977                    flags = flags | Flags.SYNTHETIC;
1978                JCClassDecl packageAnnotationsClass
1979                    = make.ClassDef(make.Modifiers(flags,
1980                                                   tree.packageAnnotations),
1981                                    name, List.<JCTypeParameter>nil(),
1982                                    null, List.<JCExpression>nil(), List.<JCTree>nil());
1983                ClassSymbol c = reader.enterClass(name, tree.packge);
1984                c.flatname = names.fromString(tree.packge + "." + name);
1985                c.sourcefile = tree.sourcefile;
1986                c.completer = null;
1987                c.members_field = new Scope(c);
1988                c.flags_field = flags;
1989                c.attributes_field = tree.packge.attributes_field;
1990                tree.packge.attributes_field = List.nil();
1991                ClassType ctype = (ClassType) c.type;
1992                ctype.supertype_field = syms.objectType;
1993                ctype.interfaces_field = List.nil();
1994                packageAnnotationsClass.sym = c;
1995    
1996    
1997                translated.append(packageAnnotationsClass);
1998            }
1999        }
2000    
2001        public void visitClassDef(JCClassDecl tree) {
2002            ClassSymbol currentClassPrev = currentClass;
2003            MethodSymbol currentMethodSymPrev = currentMethodSym;
2004            currentClass = tree.sym;
2005            // System.out.println("========visitClassDef, currentClass = "+currentClass+", type = "+((currentClass!=null)?currentClass.type.toString():"n/a"));
2006            currentMethodSym = null;
2007            classdefs.put(currentClass, tree);
2008    
2009            proxies = proxies.dup(currentClass);
2010            List<VarSymbol> prevOuterThisStack = outerThisStack;
2011    
2012            // If this is an enum definition
2013            if ((tree.mods.flags & ENUM) != 0 &&
2014                (types.supertype(currentClass.type).tsym.flags() & ENUM) == 0)
2015                visitEnumDef(tree);
2016    
2017            // If this is a nested class, define a this$n field for
2018            // it and add to proxies.
2019            JCVariableDecl otdef = null;
2020            if (currentClass.hasOuterInstance())
2021                otdef = outerThisDef(tree.pos, currentClass);
2022    
2023            // If this is a local class, define proxies for all its free variables.
2024            List<JCVariableDecl> fvdefs = freevarDefs(
2025                tree.pos, freevars(currentClass), currentClass);
2026    
2027            // Recursively translate superclass, interfaces.
2028            tree.extending = translate(tree.extending);
2029            tree.implementing = translate(tree.implementing);
2030    
2031            // Recursively translate members, taking into account that new members
2032            // might be created during the translation and prepended to the member
2033            // list `tree.defs'.
2034            List<JCTree> seen = List.nil();
2035            while (tree.defs != seen) {
2036                List<JCTree> unseen = tree.defs;
2037                for (List<JCTree> l = unseen; l.nonEmpty() && l != seen; l = l.tail) {
2038                    JCTree outermostMemberDefPrev = outermostMemberDef;
2039                    if (outermostMemberDefPrev == null) outermostMemberDef = l.head;
2040                    l.head = translate(l.head);
2041                    outermostMemberDef = outermostMemberDefPrev;
2042                }
2043                seen = unseen;
2044            }
2045    
2046            // Convert a protected modifier to public, mask static modifier.
2047            if ((tree.mods.flags & PROTECTED) != 0) tree.mods.flags |= PUBLIC;
2048            tree.mods.flags &= ClassFlags;
2049    
2050            // Convert name to flat representation, replacing '.' by '$'.
2051            tree.name = Convert.shortName(currentClass.flatName());
2052    
2053            // Add this$n and free variables proxy definitions to class.
2054            for (List<JCVariableDecl> l = fvdefs; l.nonEmpty(); l = l.tail) {
2055                tree.defs = tree.defs.prepend(l.head);
2056                enterSynthetic(tree.pos(), l.head.sym, currentClass.members());
2057            }
2058            if (currentClass.hasOuterInstance()) {
2059                tree.defs = tree.defs.prepend(otdef);
2060                enterSynthetic(tree.pos(), otdef.sym, currentClass.members());
2061            }
2062    
2063            proxies = proxies.leave();
2064            outerThisStack = prevOuterThisStack;
2065    
2066            // Append translated tree to `translated' queue.
2067            translated.append(tree);
2068    
2069            currentClass = currentClassPrev;
2070            // System.out.println("========end visitClassDef, currentClass = "+currentClass+", type = "+((currentClass!=null)?currentClass.type.toString():"n/a"));
2071            currentMethodSym = currentMethodSymPrev;
2072    
2073            // Return empty block {} as a placeholder for an inner class.
2074            result = make_at(tree.pos()).Block(0, List.<JCStatement>nil());
2075        }
2076    
2077        /** Translate an enum class. */
2078        private void visitEnumDef(JCClassDecl tree) {
2079            make_at(tree.pos());
2080    
2081            // add the supertype, if needed
2082            if (tree.extending == null)
2083                tree.extending = make.Type(types.supertype(tree.type));
2084    
2085            // classOfType adds a cache field to tree.defs unless
2086            // target.hasClassLiterals().
2087            JCExpression e_class = classOfType(tree.sym.type, tree.pos()).
2088                setType(types.erasure(syms.classType));
2089    
2090            // process each enumeration constant, adding implicit constructor parameters
2091            int nextOrdinal = 0;
2092            ListBuffer<JCExpression> values = new ListBuffer<JCExpression>();
2093            ListBuffer<JCTree> enumDefs = new ListBuffer<JCTree>();
2094            ListBuffer<JCTree> otherDefs = new ListBuffer<JCTree>();
2095            for (List<JCTree> defs = tree.defs;
2096                 defs.nonEmpty();
2097                 defs=defs.tail) {
2098                if (defs.head.getTag() == JCTree.VARDEF && (((JCVariableDecl) defs.head).mods.flags & ENUM) != 0) {
2099                    JCVariableDecl var = (JCVariableDecl)defs.head;
2100                    visitEnumConstantDef(var, nextOrdinal++);
2101                    values.append(make.QualIdent(var.sym));
2102                    enumDefs.append(var);
2103                } else {
2104                    otherDefs.append(defs.head);
2105                }
2106            }
2107    
2108            // private static final T[] #VALUES = { a, b, c };
2109            Name valuesName = names.fromString(target.syntheticNameChar() + "VALUES");
2110            while (tree.sym.members().lookup(valuesName).scope != null) // avoid name clash
2111                valuesName = names.fromString(valuesName + "" + target.syntheticNameChar());
2112            Type arrayType = new ArrayType(types.erasure(tree.type), syms.arrayClass);
2113            VarSymbol valuesVar = new VarSymbol(PRIVATE|FINAL|STATIC|SYNTHETIC,
2114                                                valuesName,
2115                                                arrayType,
2116                                                tree.type.tsym);
2117            JCNewArray newArray = make.NewArray(make.Type(types.erasure(tree.type)),
2118                                              List.<JCExpression>nil(),
2119                                              values.toList());
2120            newArray.type = arrayType;
2121            enumDefs.append(make.VarDef(valuesVar, newArray));
2122            tree.sym.members().enter(valuesVar);
2123    
2124            Symbol valuesSym = lookupMethod(tree.pos(), names.values,
2125                                            tree.type, List.<Type>nil());
2126            List<JCStatement> valuesBody;
2127            if (useClone()) {
2128                // return (T[]) $VALUES.clone();
2129                JCTypeCast valuesResult =
2130                    make.TypeCast(valuesSym.type.getReturnType(),
2131                                  make.App(make.Select(make.Ident(valuesVar),
2132                                                       syms.arrayCloneMethod)));
2133                valuesBody = List.<JCStatement>of(make.Return(valuesResult));
2134            } else {
2135                // template: T[] $result = new T[$values.length];
2136                Name resultName = names.fromString(target.syntheticNameChar() + "result");
2137                while (tree.sym.members().lookup(resultName).scope != null) // avoid name clash
2138                    resultName = names.fromString(resultName + "" + target.syntheticNameChar());
2139                VarSymbol resultVar = new VarSymbol(FINAL|SYNTHETIC,
2140                                                    resultName,
2141                                                    arrayType,
2142                                                    valuesSym);
2143                JCNewArray resultArray = make.NewArray(make.Type(types.erasure(tree.type)),
2144                                      List.of(make.Select(make.Ident(valuesVar), syms.lengthVar)),
2145                                      null);
2146                resultArray.type = arrayType;
2147                JCVariableDecl decl = make.VarDef(resultVar, resultArray);
2148    
2149                // template: System.arraycopy($VALUES, 0, $result, 0, $VALUES.length);
2150                if (systemArraycopyMethod == null) {
2151                    systemArraycopyMethod =
2152                        new MethodSymbol(PUBLIC | STATIC,
2153                                         names.fromString("arraycopy"),
2154                                         new MethodType(List.<Type>of(syms.objectType,
2155                                                                syms.intType,
2156                                                                syms.objectType,
2157                                                                syms.intType,
2158                                                                syms.intType),
2159                                                        syms.voidType,
2160                                                        List.<Type>nil(),
2161                                                        syms.methodClass),
2162                                         syms.systemType.tsym);
2163                }
2164                JCStatement copy =
2165                    make.Exec(make.App(make.Select(make.Ident(syms.systemType.tsym),
2166                                                   systemArraycopyMethod),
2167                              List.of(make.Ident(valuesVar), make.Literal(0),
2168                                      make.Ident(resultVar), make.Literal(0),
2169                                      make.Select(make.Ident(valuesVar), syms.lengthVar))));
2170    
2171                // template: return $result;
2172                JCStatement ret = make.Return(make.Ident(resultVar));
2173                valuesBody = List.<JCStatement>of(decl, copy, ret);
2174            }
2175    
2176            JCMethodDecl valuesDef =
2177                 make.MethodDef((MethodSymbol)valuesSym, make.Block(0, valuesBody));
2178    
2179            enumDefs.append(valuesDef);
2180    
2181            if (debugLower)
2182                System.err.println(tree.sym + ".valuesDef = " + valuesDef);
2183    
2184            /** The template for the following code is:
2185             *
2186             *     public static E valueOf(String name) {
2187             *         return (E)Enum.valueOf(E.class, name);
2188             *     }
2189             *
2190             *  where E is tree.sym
2191             */
2192            MethodSymbol valueOfSym = lookupMethod(tree.pos(),
2193                             names.valueOf,
2194                             tree.sym.type,
2195                             List.of(syms.stringType));
2196            assert (valueOfSym.flags() & STATIC) != 0;
2197            VarSymbol nameArgSym = valueOfSym.params.head;
2198            JCIdent nameVal = make.Ident(nameArgSym);
2199            JCStatement enum_ValueOf =
2200                make.Return(make.TypeCast(tree.sym.type,
2201                                          makeCall(make.Ident(syms.enumSym),
2202                                                   names.valueOf,
2203                                                   List.of(e_class, nameVal))));
2204            JCMethodDecl valueOf = make.MethodDef(valueOfSym,
2205                                               make.Block(0, List.of(enum_ValueOf)));
2206            nameVal.sym = valueOf.params.head.sym;
2207            if (debugLower)
2208                System.err.println(tree.sym + ".valueOf = " + valueOf);
2209            enumDefs.append(valueOf);
2210    
2211            enumDefs.appendList(otherDefs.toList());
2212            tree.defs = enumDefs.toList();
2213    
2214            // Add the necessary members for the EnumCompatibleMode
2215            if (target.compilerBootstrap(tree.sym)) {
2216                addEnumCompatibleMembers(tree);
2217            }
2218        }
2219            // where
2220            private MethodSymbol systemArraycopyMethod;
2221            private boolean useClone() {
2222                try {
2223                    Scope.Entry e = syms.objectType.tsym.members().lookup(names.clone);
2224                    return (e.sym != null);
2225                }
2226                catch (CompletionFailure e) {
2227                    return false;
2228                }
2229            }
2230    
2231        /** Translate an enumeration constant and its initializer. */
2232        private void visitEnumConstantDef(JCVariableDecl var, int ordinal) {
2233            JCNewClass varDef = (JCNewClass)var.init;
2234            varDef.args = varDef.args.
2235                prepend(makeLit(syms.intType, ordinal)).
2236                prepend(makeLit(syms.stringType, var.name.toString()));
2237        }
2238    
2239        public void visitMethodDef(JCMethodDecl tree) {
2240            if (tree.name == names.init && (currentClass.flags_field&ENUM) != 0) {
2241                // Add "String $enum$name, int $enum$ordinal" to the beginning of the
2242                // argument list for each constructor of an enum.
2243                JCVariableDecl nameParam = make_at(tree.pos()).
2244                    Param(names.fromString(target.syntheticNameChar() +
2245                                           "enum" + target.syntheticNameChar() + "name"),
2246                          syms.stringType, tree.sym);
2247                nameParam.mods.flags |= SYNTHETIC; nameParam.sym.flags_field |= SYNTHETIC;
2248    
2249                JCVariableDecl ordParam = make.
2250                    Param(names.fromString(target.syntheticNameChar() +
2251                                           "enum" + target.syntheticNameChar() +
2252                                           "ordinal"),
2253                          syms.intType, tree.sym);
2254                ordParam.mods.flags |= SYNTHETIC; ordParam.sym.flags_field |= SYNTHETIC;
2255    
2256                tree.params = tree.params.prepend(ordParam).prepend(nameParam);
2257    
2258                MethodSymbol m = tree.sym;
2259                Type olderasure = m.erasure(types);
2260                m.erasure_field = new MethodType(
2261                    olderasure.getParameterTypes().prepend(syms.intType).prepend(syms.stringType),
2262                    olderasure.getReturnType(),
2263                    olderasure.getThrownTypes(),
2264                    syms.methodClass);
2265    
2266                if (target.compilerBootstrap(m.owner)) {
2267                    // Initialize synthetic name field
2268                    Symbol nameVarSym = lookupSynthetic(names.fromString("$name"),
2269                                                        tree.sym.owner.members());
2270                    JCIdent nameIdent = make.Ident(nameParam.sym);
2271                    JCIdent id1 = make.Ident(nameVarSym);
2272                    JCAssign newAssign = make.Assign(id1, nameIdent);
2273                    newAssign.type = id1.type;
2274                    JCExpressionStatement nameAssign = make.Exec(newAssign);
2275                    nameAssign.type = id1.type;
2276                    tree.body.stats = tree.body.stats.prepend(nameAssign);
2277    
2278                    // Initialize synthetic ordinal field
2279                    Symbol ordinalVarSym = lookupSynthetic(names.fromString("$ordinal"),
2280                                                           tree.sym.owner.members());
2281                    JCIdent ordIdent = make.Ident(ordParam.sym);
2282                    id1 = make.Ident(ordinalVarSym);
2283                    newAssign = make.Assign(id1, ordIdent);
2284                    newAssign.type = id1.type;
2285                    JCExpressionStatement ordinalAssign = make.Exec(newAssign);
2286                    ordinalAssign.type = id1.type;
2287                    tree.body.stats = tree.body.stats.prepend(ordinalAssign);
2288                }
2289            }
2290    
2291            JCMethodDecl prevMethodDef = currentMethodDef;
2292            MethodSymbol prevMethodSym = currentMethodSym;
2293            try {
2294                currentMethodDef = tree;
2295                currentMethodSym = tree.sym;
2296                visitMethodDefInternal(tree);
2297            } finally {
2298                currentMethodDef = prevMethodDef;
2299                currentMethodSym = prevMethodSym;
2300            }
2301        }
2302        //where
2303        private void visitMethodDefInternal(JCMethodDecl tree) {
2304            if (tree.name == names.init &&
2305                (currentClass.isInner() ||
2306                 (currentClass.owner.kind & (VAR | MTH)) != 0)) {
2307                // We are seeing a constructor of an inner class.
2308                MethodSymbol m = tree.sym;
2309    
2310                // Push a new proxy scope for constructor parameters.
2311                // and create definitions for any this$n and proxy parameters.
2312                proxies = proxies.dup(m);
2313                List<VarSymbol> prevOuterThisStack = outerThisStack;
2314                List<VarSymbol> fvs = freevars(currentClass);
2315                JCVariableDecl otdef = null;
2316                if (currentClass.hasOuterInstance())
2317                    otdef = outerThisDef(tree.pos, m);
2318                List<JCVariableDecl> fvdefs = freevarDefs(tree.pos, fvs, m);
2319    
2320                // Recursively translate result type, parameters and thrown list.
2321                tree.restype = translate(tree.restype);
2322                tree.params = translateVarDefs(tree.params);
2323                tree.thrown = translate(tree.thrown);
2324    
2325                // when compiling stubs, don't process body
2326                if (tree.body == null) {
2327                    result = tree;
2328                    return;
2329                }
2330    
2331                // Add this$n (if needed) in front of and free variables behind
2332                // constructor parameter list.
2333                tree.params = tree.params.appendList(fvdefs);
2334                if (currentClass.hasOuterInstance())
2335                    tree.params = tree.params.prepend(otdef);
2336    
2337                // If this is an initial constructor, i.e., it does not start with
2338                // this(...), insert initializers for this$n and proxies
2339                // before (pre-1.4, after) the call to superclass constructor.
2340                JCStatement selfCall = translate(tree.body.stats.head);
2341    
2342                List<JCStatement> added = List.nil();
2343                if (fvs.nonEmpty()) {
2344                    List<Type> addedargtypes = List.nil();
2345                    for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail) {
2346                        if (TreeInfo.isInitialConstructor(tree))
2347                            added = added.prepend(
2348                                initField(tree.body.pos, proxyName(l.head.name)));
2349                        addedargtypes = addedargtypes.prepend(l.head.erasure(types));
2350                    }
2351                    Type olderasure = m.erasure(types);
2352                    m.erasure_field = new MethodType(
2353                        olderasure.getParameterTypes().appendList(addedargtypes),
2354                        olderasure.getReturnType(),
2355                        olderasure.getThrownTypes(),
2356                        syms.methodClass);
2357                }
2358                if (currentClass.hasOuterInstance() &&
2359                    TreeInfo.isInitialConstructor(tree))
2360                {
2361                    added = added.prepend(initOuterThis(tree.body.pos));
2362                }
2363    
2364                // pop local variables from proxy stack
2365                proxies = proxies.leave();
2366    
2367                // recursively translate following local statements and
2368                // combine with this- or super-call
2369                List<JCStatement> stats = translate(tree.body.stats.tail);
2370                if (target.initializeFieldsBeforeSuper())
2371                    tree.body.stats = stats.prepend(selfCall).prependList(added);
2372                else
2373                    tree.body.stats = stats.prependList(added).prepend(selfCall);
2374    
2375                outerThisStack = prevOuterThisStack;
2376            } else {
2377                super.visitMethodDef(tree);
2378            }
2379            result = tree;
2380        }
2381    
2382        public void visitTypeCast(JCTypeCast tree) {
2383            tree.clazz = translate(tree.clazz);
2384            if (tree.type.isPrimitive() != tree.expr.type.isPrimitive())
2385                tree.expr = translate(tree.expr, tree.type);
2386            else
2387                tree.expr = translate(tree.expr);
2388            result = tree;
2389        }
2390    
2391        public void visitNewClass(JCNewClass tree) {
2392            ClassSymbol c = (ClassSymbol)tree.constructor.owner;
2393    
2394            // Box arguments, if necessary
2395            boolean isEnum = (tree.constructor.owner.flags() & ENUM) != 0;
2396            List<Type> argTypes = tree.constructor.type.getParameterTypes();
2397            if (isEnum) argTypes = argTypes.prepend(syms.intType).prepend(syms.stringType);
2398            tree.args = boxArgs(argTypes, tree.args, tree.varargsElement);
2399            tree.varargsElement = null;
2400    
2401            // If created class is local, add free variables after
2402            // explicit constructor arguments.
2403            if ((c.owner.kind & (VAR | MTH)) != 0) {
2404                tree.args = tree.args.appendList(loadFreevars(tree.pos(), freevars(c)));
2405            }
2406    
2407            // If an access constructor is used, append null as a last argument.
2408            Symbol constructor = accessConstructor(tree.pos(), tree.constructor);
2409            if (constructor != tree.constructor) {
2410                tree.args = tree.args.append(makeNull());
2411                tree.constructor = constructor;
2412            }
2413    
2414            // If created class has an outer instance, and new is qualified, pass
2415            // qualifier as first argument. If new is not qualified, pass the
2416            // correct outer instance as first argument.
2417            if (c.hasOuterInstance()) {
2418                // System.out.println("\n\nlower newclass; tree="+tree);
2419                // System.out.println("\ttree.encl="+tree.encl+
2420                //                    " c.owner.kind MTH? "+((c.owner.kind & MTH)!=0)+
2421                //                    " c.owner.kind VAR? "+((c.owner.kind & VAR)!=0)+
2422                //                    " c.type="+c.type+" c.type.getEnclosingType="+c.type.getEnclosingType());
2423                JCExpression thisArg;
2424                if (tree.encl != null) {
2425                    // System.out.println("\tmakeNullCheck");
2426                    thisArg = attr.makeNullCheck(translate(tree.encl));
2427                    thisArg.type = tree.encl.type;
2428                } else if ((c.owner.kind & (MTH | VAR)) != 0) {
2429                    // local class
2430                    // System.out.println("\tlocal class, makeThis");
2431                    thisArg = makeThis(tree.pos(), c.type.getEnclosingType().tsym);
2432                } else {
2433                    // nested class
2434                    // System.out.println("\tnested class, makeOwnerThis");
2435                    thisArg = makeOwnerThis(tree.pos(), c, false);
2436                }
2437                tree.args = tree.args.prepend(thisArg);
2438            }
2439            tree.encl = null;
2440    
2441            // If we have an anonymous class, create its flat version, rather
2442            // than the class or interface following new.
2443            if (tree.def != null) {
2444                translate(tree.def);
2445                tree.clazz = access(make_at(tree.clazz.pos()).Ident(tree.def.sym));
2446                tree.def = null;
2447            } else {
2448                tree.clazz = access(c, tree.clazz, enclOp, false);
2449            }
2450            result = tree;
2451        }
2452    
2453        // Simplify conditionals with known constant controlling expressions.
2454        // This allows us to avoid generating supporting declarations for
2455        // the dead code, which will not be eliminated during code generation.
2456        // Note that Flow.isFalse and Flow.isTrue only return true
2457        // for constant expressions in the sense of JLS 15.27, which
2458        // are guaranteed to have no side-effects.  More agressive
2459        // constant propagation would require that we take care to
2460        // preserve possible side-effects in the condition expression.
2461    
2462        /** Visitor method for conditional expressions.
2463         */
2464        public void visitConditional(JCConditional tree) {
2465            JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
2466            if (cond.type.isTrue()) {
2467                result = convert(translate(tree.truepart, tree.type), tree.type);
2468            } else if (cond.type.isFalse()) {
2469                result = convert(translate(tree.falsepart, tree.type), tree.type);
2470            } else {
2471                // Condition is not a compile-time constant.
2472                tree.truepart = translate(tree.truepart, tree.type);
2473                tree.falsepart = translate(tree.falsepart, tree.type);
2474                result = tree;
2475            }
2476        }
2477    //where
2478            private JCTree convert(JCTree tree, Type pt) {
2479                if (tree.type == pt) return tree;
2480                JCTree result = make_at(tree.pos()).TypeCast(make.Type(pt), (JCExpression)tree);
2481                result.type = (tree.type.constValue() != null) ? cfolder.coerce(tree.type, pt)
2482                                                               : pt;
2483                return result;
2484            }
2485    
2486        /** Visitor method for if statements.
2487         */
2488        public void visitIf(JCIf tree) {
2489            JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
2490            if (cond.type.isTrue()) {
2491                result = translate(tree.thenpart);
2492            } else if (cond.type.isFalse()) {
2493                if (tree.elsepart != null) {
2494                    result = translate(tree.elsepart);
2495                } else {
2496                    result = make.Skip();
2497                }
2498            } else {
2499                // Condition is not a compile-time constant.
2500                tree.thenpart = translate(tree.thenpart);
2501                tree.elsepart = translate(tree.elsepart);
2502                result = tree;
2503            }
2504        }
2505    
2506        /** Visitor method for assert statements. Translate them away.
2507         */
2508        public void visitAssert(JCAssert tree) {
2509            DiagnosticPosition detailPos = (tree.detail == null) ? tree.pos() : tree.detail.pos();
2510            tree.cond = translate(tree.cond, syms.booleanType);
2511            if (!tree.cond.type.isTrue()) {
2512                JCExpression cond = assertFlagTest(tree.pos());
2513                List<JCExpression> exnArgs = (tree.detail == null) ?
2514                    List.<JCExpression>nil() : List.of(translate(tree.detail));
2515                if (!tree.cond.type.isFalse()) {
2516                    cond = makeBinary
2517                        (JCTree.AND,
2518                         cond,
2519                         makeUnary(JCTree.NOT, tree.cond));
2520                }
2521                result =
2522                    make.If(cond,
2523                            make_at(detailPos).
2524                               Throw(makeNewClass(syms.assertionErrorType, exnArgs)),
2525                            null);
2526            } else {
2527                result = make.Skip();
2528            }
2529        }
2530    
2531        public void visitApply(JCMethodInvocation tree) {
2532            Symbol meth = TreeInfo.symbol(tree.meth);
2533            List<Type> argtypes = meth.type.getParameterTypes();
2534            if (allowEnums &&
2535                meth.name==names.init &&
2536                meth.owner == syms.enumSym)
2537                argtypes = argtypes.tail.tail;
2538            tree.args = boxArgs(argtypes, tree.args, tree.varargsElement);
2539            tree.varargsElement = null;
2540            Name methName = TreeInfo.name(tree.meth);
2541            if (meth.name==names.init) {
2542                // We are seeing a this(...) or super(...) constructor call.
2543                // If an access constructor is used, append null as a last argument.
2544                Symbol constructor = accessConstructor(tree.pos(), meth);
2545                if (constructor != meth) {
2546                    tree.args = tree.args.append(makeNull());
2547                    TreeInfo.setSymbol(tree.meth, constructor);
2548                }
2549    
2550                // If we are calling a constructor of a local class, add
2551                // free variables after explicit constructor arguments.
2552                ClassSymbol c = (ClassSymbol)constructor.owner;
2553                if ((c.owner.kind & (VAR | MTH)) != 0) {
2554                    tree.args = tree.args.appendList(loadFreevars(tree.pos(), freevars(c)));
2555                }
2556    
2557                // If we are calling a constructor of an enum class, pass
2558                // along the name and ordinal arguments
2559                if ((c.flags_field&ENUM) != 0 || c.getQualifiedName() == names.java_lang_Enum) {
2560                    List<JCVariableDecl> params = currentMethodDef.params;
2561                    if (currentMethodSym.owner.hasOuterInstance())
2562                        params = params.tail; // drop this$n
2563                    tree.args = tree.args
2564                        .prepend(make_at(tree.pos()).Ident(params.tail.head.sym)) // ordinal
2565                        .prepend(make.Ident(params.head.sym)); // name
2566                }
2567    
2568                // If we are calling a constructor of a class with an outer
2569                // instance, and the call
2570                // is qualified, pass qualifier as first argument in front of
2571                // the explicit constructor arguments. If the call
2572                // is not qualified, pass the correct outer instance as
2573                // first argument.
2574                if (c.hasOuterInstance()) {
2575                    JCExpression thisArg;
2576                    if (tree.meth.getTag() == JCTree.SELECT) {
2577                        thisArg = attr.
2578                            makeNullCheck(translate(((JCFieldAccess) tree.meth).selected));
2579                        tree.meth = make.Ident(constructor);
2580                        ((JCIdent) tree.meth).name = methName;
2581                    } else if ((c.owner.kind & (MTH | VAR)) != 0 || methName == names._this){
2582                        // local class or this() call
2583                        thisArg = makeThis(tree.meth.pos(), c.type.getEnclosingType().tsym);
2584                    } else {
2585                        // super() call of nested class
2586                        thisArg = makeOwnerThis(tree.meth.pos(), c, false);
2587                    }
2588                    tree.args = tree.args.prepend(thisArg);
2589                }
2590            } else {
2591                // We are seeing a normal method invocation; translate this as usual.
2592                tree.meth = translate(tree.meth);
2593    
2594                // If the translated method itself is an Apply tree, we are
2595                // seeing an access method invocation. In this case, append
2596                // the method arguments to the arguments of the access method.
2597                if (tree.meth.getTag() == JCTree.APPLY) {
2598                    JCMethodInvocation app = (JCMethodInvocation)tree.meth;
2599                    app.args = tree.args.prependList(app.args);
2600                    result = app;
2601                    return;
2602                }
2603            }
2604            result = tree;
2605        }
2606    
2607        List<JCExpression> boxArgs(List<Type> parameters, List<JCExpression> _args, Type varargsElement) {
2608            List<JCExpression> args = _args;
2609            if (parameters.isEmpty()) return args;
2610            boolean anyChanges = false;
2611            ListBuffer<JCExpression> result = new ListBuffer<JCExpression>();
2612            while (parameters.tail.nonEmpty()) {
2613                JCExpression arg = translate(args.head, parameters.head);
2614                anyChanges |= (arg != args.head);
2615                result.append(arg);
2616                args = args.tail;
2617                parameters = parameters.tail;
2618            }
2619            Type parameter = parameters.head;
2620            if (varargsElement != null) {
2621                anyChanges = true;
2622                ListBuffer<JCExpression> elems = new ListBuffer<JCExpression>();
2623                while (args.nonEmpty()) {
2624                    JCExpression arg = translate(args.head, varargsElement);
2625                    elems.append(arg);
2626                    args = args.tail;
2627                }
2628                JCNewArray boxedArgs = make.NewArray(make.Type(varargsElement),
2629                                                   List.<JCExpression>nil(),
2630                                                   elems.toList());
2631                boxedArgs.type = new ArrayType(varargsElement, syms.arrayClass);
2632                result.append(boxedArgs);
2633            } else {
2634                if (args.length() != 1) throw new AssertionError(args);
2635                JCExpression arg = translate(args.head, parameter);
2636                anyChanges |= (arg != args.head);
2637                result.append(arg);
2638                if (!anyChanges) return _args;
2639            }
2640            return result.toList();
2641        }
2642    
2643        /** Expand a boxing or unboxing conversion if needed. */
2644        @SuppressWarnings("unchecked") // XXX unchecked
2645        <T extends JCTree> T boxIfNeeded(T tree, Type type) {
2646            boolean havePrimitive = tree.type.isPrimitive();
2647            if (havePrimitive == type.isPrimitive())
2648                return tree;
2649            if (havePrimitive) {
2650                Type unboxedTarget = types.unboxedType(type);
2651                if (unboxedTarget.tag != NONE) {
2652                    if (!types.isSubtype(tree.type, unboxedTarget))
2653                        tree.type = unboxedTarget; // e.g. Character c = 89;
2654                    return (T)boxPrimitive((JCExpression)tree, type);
2655                } else {
2656                    tree = (T)boxPrimitive((JCExpression)tree);
2657                }
2658            } else {
2659                tree = (T)unbox((JCExpression)tree, type);
2660            }
2661            return tree;
2662        }
2663    
2664        /** Box up a single primitive expression. */
2665        JCExpression boxPrimitive(JCExpression tree) {
2666            return boxPrimitive(tree, types.boxedClass(tree.type).type);
2667        }
2668    
2669        /** Box up a single primitive expression. */
2670        JCExpression boxPrimitive(JCExpression tree, Type box) {
2671            make_at(tree.pos());
2672            if (target.boxWithConstructors()) {
2673                Symbol ctor = lookupConstructor(tree.pos(),
2674                                                box,
2675                                                List.<Type>nil()
2676                                                .prepend(tree.type));
2677                return make.Create(ctor, List.of(tree));
2678            } else {
2679                Symbol valueOfSym = lookupMethod(tree.pos(),
2680                                                 names.valueOf,
2681                                                 box,
2682                                                 List.<Type>nil()
2683                                                 .prepend(tree.type));
2684                return make.App(make.QualIdent(valueOfSym), List.of(tree));
2685            }
2686        }
2687    
2688        /** Unbox an object to a primitive value. */
2689        JCExpression unbox(JCExpression tree, Type primitive) {
2690            Type unboxedType = types.unboxedType(tree.type);
2691            // note: the "primitive" parameter is not used.  There muse be
2692            // a conversion from unboxedType to primitive.
2693            make_at(tree.pos());
2694            Symbol valueSym = lookupMethod(tree.pos(),
2695                                           unboxedType.tsym.name.append(names.Value), // x.intValue()
2696                                           tree.type,
2697                                           List.<Type>nil());
2698            return make.App(make.Select(tree, valueSym));
2699        }
2700    
2701        /** Visitor method for parenthesized expressions.
2702         *  If the subexpression has changed, omit the parens.
2703         */
2704        public void visitParens(JCParens tree) {
2705            JCTree expr = translate(tree.expr);
2706            result = ((expr == tree.expr) ? tree : expr);
2707        }
2708    
2709        public void visitIndexed(JCArrayAccess tree) {
2710            tree.indexed = translate(tree.indexed);
2711            tree.index = translate(tree.index, syms.intType);
2712            result = tree;
2713        }
2714    
2715        public void visitAssign(JCAssign tree) {
2716            tree.lhs = translate(tree.lhs, tree);
2717            tree.rhs = translate(tree.rhs, tree.lhs.type);
2718    
2719            // If translated left hand side is an Apply, we are
2720            // seeing an access method invocation. In this case, append
2721            // right hand side as last argument of the access method.
2722            if (tree.lhs.getTag() == JCTree.APPLY) {
2723                JCMethodInvocation app = (JCMethodInvocation)tree.lhs;
2724                app.args = List.of(tree.rhs).prependList(app.args);
2725                result = app;
2726            } else {
2727                result = tree;
2728            }
2729        }
2730    
2731        public void visitAssignop(final JCAssignOp tree) {
2732            if (!tree.lhs.type.isPrimitive() &&
2733                tree.operator.type.getReturnType().isPrimitive()) {
2734                // boxing required; need to rewrite as x = (unbox typeof x)(x op y);
2735                // or if x == (typeof x)z then z = (unbox typeof x)((typeof x)z op y)
2736                // (but without recomputing x)
2737                JCTree newTree = abstractLval(tree.lhs, new TreeBuilder() {
2738                        public JCTree build(final JCTree lhs) {
2739                            int newTag = tree.getTag() - JCTree.ASGOffset;
2740                            // Erasure (TransTypes) can change the type of
2741                            // tree.lhs.  However, we can still get the
2742                            // unerased type of tree.lhs as it is stored
2743                            // in tree.type in Attr.
2744                            Symbol newOperator = rs.resolveBinaryOperator(tree.pos(),
2745                                                                          newTag,
2746                                                                          attrEnv,
2747                                                                          tree.type,
2748                                                                          tree.rhs.type);
2749                            JCExpression expr = (JCExpression)lhs;
2750                            if (expr.type != tree.type)
2751                                expr = make.TypeCast(tree.type, expr);
2752                            JCBinary opResult = make.Binary(newTag, expr, tree.rhs);
2753                            opResult.operator = newOperator;
2754                            opResult.type = newOperator.type.getReturnType();
2755                            JCTypeCast newRhs = make.TypeCast(types.unboxedType(tree.type),
2756                                                              opResult);
2757                            return make.Assign((JCExpression)lhs, newRhs).setType(tree.type);
2758                        }
2759                    });
2760                result = translate(newTree);
2761                return;
2762            }
2763            tree.lhs = translate(tree.lhs, tree);
2764            tree.rhs = translate(tree.rhs, tree.operator.type.getParameterTypes().tail.head);
2765    
2766            // If translated left hand side is an Apply, we are
2767            // seeing an access method invocation. In this case, append
2768            // right hand side as last argument of the access method.
2769            if (tree.lhs.getTag() == JCTree.APPLY) {
2770                JCMethodInvocation app = (JCMethodInvocation)tree.lhs;
2771                // if operation is a += on strings,
2772                // make sure to convert argument to string
2773                JCExpression rhs = (((OperatorSymbol)tree.operator).opcode == string_add)
2774                  ? makeString(tree.rhs)
2775                  : tree.rhs;
2776                app.args = List.of(rhs).prependList(app.args);
2777                result = app;
2778            } else {
2779                result = tree;
2780            }
2781        }
2782    
2783        /** Lower a tree of the form e++ or e-- where e is an object type */
2784        JCTree lowerBoxedPostop(final JCUnary tree) {
2785            // translate to tmp1=lval(e); tmp2=tmp1; tmp1 OP 1; tmp2
2786            // or
2787            // translate to tmp1=lval(e); tmp2=tmp1; (typeof tree)tmp1 OP 1; tmp2
2788            // where OP is += or -=
2789            final boolean cast = TreeInfo.skipParens(tree.arg).getTag() == JCTree.TYPECAST;
2790            return abstractLval(tree.arg, new TreeBuilder() {
2791                    public JCTree build(final JCTree tmp1) {
2792                        return abstractRval(tmp1, tree.arg.type, new TreeBuilder() {
2793                                public JCTree build(final JCTree tmp2) {
2794                                    int opcode = (tree.getTag() == JCTree.POSTINC)
2795                                        ? JCTree.PLUS_ASG : JCTree.MINUS_ASG;
2796                                    JCTree lhs = cast
2797                                        ? make.TypeCast(tree.arg.type, (JCExpression)tmp1)
2798                                        : tmp1;
2799                                    JCTree update = makeAssignop(opcode,
2800                                                                 lhs,
2801                                                                 make.Literal(1));
2802                                    return makeComma(update, tmp2);
2803                                }
2804                            });
2805                    }
2806                });
2807        }
2808    
2809        public void visitUnary(JCUnary tree) {
2810            boolean isUpdateOperator =
2811                JCTree.PREINC <= tree.getTag() && tree.getTag() <= JCTree.POSTDEC;
2812            if (isUpdateOperator && !tree.arg.type.isPrimitive()) {
2813                switch(tree.getTag()) {
2814                case JCTree.PREINC:            // ++ e
2815                        // translate to e += 1
2816                case JCTree.PREDEC:            // -- e
2817                        // translate to e -= 1
2818                    {
2819                        int opcode = (tree.getTag() == JCTree.PREINC)
2820                            ? JCTree.PLUS_ASG : JCTree.MINUS_ASG;
2821                        JCAssignOp newTree = makeAssignop(opcode,
2822                                                        tree.arg,
2823                                                        make.Literal(1));
2824                        result = translate(newTree, tree.type);
2825                        return;
2826                    }
2827                case JCTree.POSTINC:           // e ++
2828                case JCTree.POSTDEC:           // e --
2829                    {
2830                        result = translate(lowerBoxedPostop(tree), tree.type);
2831                        return;
2832                    }
2833                }
2834                throw new AssertionError(tree);
2835            }
2836    
2837            tree.arg = boxIfNeeded(translate(tree.arg, tree), tree.type);
2838    
2839            if (tree.getTag() == JCTree.NOT && tree.arg.type.constValue() != null) {
2840                tree.type = cfolder.fold1(bool_not, tree.arg.type);
2841            }
2842    
2843            // If translated left hand side is an Apply, we are
2844            // seeing an access method invocation. In this case, return
2845            // that access method invokation as result.
2846            if (isUpdateOperator && tree.arg.getTag() == JCTree.APPLY) {
2847                result = tree.arg;
2848            } else {
2849                result = tree;
2850            }
2851        }
2852    
2853        public void visitBinary(JCBinary tree) {
2854            List<Type> formals = tree.operator.type.getParameterTypes();
2855            JCTree lhs = tree.lhs = translate(tree.lhs, formals.head);
2856            switch (tree.getTag()) {
2857            case JCTree.OR:
2858                if (lhs.type.isTrue()) {
2859                    result = lhs;
2860                    return;
2861                }
2862                if (lhs.type.isFalse()) {
2863                    result = translate(tree.rhs, formals.tail.head);
2864                    return;
2865                }
2866                break;
2867            case JCTree.AND:
2868                if (lhs.type.isFalse()) {
2869                    result = lhs;
2870                    return;
2871                }
2872                if (lhs.type.isTrue()) {
2873                    result = translate(tree.rhs, formals.tail.head);
2874                    return;
2875                }
2876                break;
2877            }
2878            tree.rhs = translate(tree.rhs, formals.tail.head);
2879            result = tree;
2880        }
2881    
2882        public void visitIdent(JCIdent tree) {
2883            result = access(tree.sym, tree, enclOp, false);
2884        }
2885    
2886        /** Translate away the foreach loop.  */
2887        public void visitForeachLoop(JCEnhancedForLoop tree) {
2888            if (types.elemtype(tree.expr.type) == null)
2889                visitIterableForeachLoop(tree);
2890            else
2891                visitArrayForeachLoop(tree);
2892        }
2893            // where
2894            /**
2895             * A statment of the form
2896             *
2897             * <pre>
2898             *     for ( T v : arrayexpr ) stmt;
2899             * </pre>
2900             *
2901             * (where arrayexpr is of an array type) gets translated to
2902             *
2903             * <pre>
2904             *     for ( { arraytype #arr = arrayexpr;
2905             *             int #len = array.length;
2906             *             int #i = 0; };
2907             *           #i < #len; i$++ ) {
2908             *         T v = arr$[#i];
2909             *         stmt;
2910             *     }
2911             * </pre>
2912             *
2913             * where #arr, #len, and #i are freshly named synthetic local variables.
2914             */
2915            private void visitArrayForeachLoop(JCEnhancedForLoop tree) {
2916                make_at(tree.expr.pos());
2917                VarSymbol arraycache = new VarSymbol(0,
2918                                                     names.fromString("arr" + target.syntheticNameChar()),
2919                                                     tree.expr.type,
2920                                                     currentMethodSym);
2921                JCStatement arraycachedef = make.VarDef(arraycache, tree.expr);
2922                VarSymbol lencache = new VarSymbol(0,
2923                                                   names.fromString("len" + target.syntheticNameChar()),
2924                                                   syms.intType,
2925                                                   currentMethodSym);
2926                JCStatement lencachedef = make.
2927                    VarDef(lencache, make.Select(make.Ident(arraycache), syms.lengthVar));
2928                VarSymbol index = new VarSymbol(0,
2929                                                names.fromString("i" + target.syntheticNameChar()),
2930                                                syms.intType,
2931                                                currentMethodSym);
2932    
2933                JCVariableDecl indexdef = make.VarDef(index, make.Literal(INT, 0));
2934                indexdef.init.type = indexdef.type = syms.intType.constType(0);
2935    
2936                List<JCStatement> loopinit = List.of(arraycachedef, lencachedef, indexdef);
2937                JCBinary cond = makeBinary(JCTree.LT, make.Ident(index), make.Ident(lencache));
2938    
2939                JCExpressionStatement step = make.Exec(makeUnary(JCTree.PREINC, make.Ident(index)));
2940    
2941                Type elemtype = types.elemtype(tree.expr.type);
2942                JCExpression loopvarinit = make.Indexed(make.Ident(arraycache),
2943                                                        make.Ident(index)).setType(elemtype);
2944                JCVariableDecl loopvardef = (JCVariableDecl)make.VarDef(tree.var.mods,
2945                                                      tree.var.name,
2946                                                      tree.var.vartype,
2947                                                      loopvarinit).setType(tree.var.type);
2948                loopvardef.sym = tree.var.sym;
2949                JCBlock body = make.
2950                    Block(0, List.of(loopvardef, tree.body));
2951    
2952                result = translate(make.
2953                                   ForLoop(loopinit,
2954                                           cond,
2955                                           List.of(step),
2956                                           body));
2957                patchTargets(body, tree, result);
2958            }
2959            /** Patch up break and continue targets. */
2960            private void patchTargets(JCTree body, final JCTree src, final JCTree dest) {
2961                class Patcher extends TreeScanner {
2962                    public void visitBreak(JCBreak tree) {
2963                        if (tree.target == src)
2964                            tree.target = dest;
2965                    }
2966                    public void visitContinue(JCContinue tree) {
2967                        if (tree.target == src)
2968                            tree.target = dest;
2969                    }
2970                    public void visitClassDef(JCClassDecl tree) {}
2971                }
2972                new Patcher().scan(body);
2973            }
2974            /**
2975             * A statement of the form
2976             *
2977             * <pre>
2978             *     for ( T v : coll ) stmt ;
2979             * </pre>
2980             *
2981             * (where coll implements Iterable<? extends T>) gets translated to
2982             *
2983             * <pre>
2984             *     for ( Iterator<? extends T> #i = coll.iterator(); #i.hasNext(); ) {
2985             *         T v = (T) #i.next();
2986             *         stmt;
2987             *     }
2988             * </pre>
2989             *
2990             * where #i is a freshly named synthetic local variable.
2991             */
2992            private void visitIterableForeachLoop(JCEnhancedForLoop tree) {
2993                make_at(tree.expr.pos());
2994                Type iteratorTarget = syms.objectType;
2995                Type iterableType = types.asSuper(types.upperBound(tree.expr.type),
2996                                                  syms.iterableType.tsym);
2997                if (iterableType.getTypeArguments().nonEmpty())
2998                    iteratorTarget = types.erasure(iterableType.getTypeArguments().head);
2999                Type eType = tree.expr.type;
3000                tree.expr.type = types.erasure(eType);
3001                if (eType.tag == TYPEVAR && eType.getUpperBound().isCompound())
3002                    tree.expr = make.TypeCast(types.erasure(iterableType), tree.expr);
3003                Symbol iterator = lookupMethod(tree.expr.pos(),
3004                                               names.iterator,
3005                                               types.erasure(syms.iterableType),
3006                                               List.<Type>nil());
3007                VarSymbol itvar = new VarSymbol(0, names.fromString("i" + target.syntheticNameChar()),
3008                                                types.erasure(iterator.type.getReturnType()),
3009                                                currentMethodSym);
3010                JCStatement init = make.
3011                    VarDef(itvar,
3012                           make.App(make.Select(tree.expr, iterator)));
3013                Symbol hasNext = lookupMethod(tree.expr.pos(),
3014                                              names.hasNext,
3015                                              itvar.type,
3016                                              List.<Type>nil());
3017                JCMethodInvocation cond = make.App(make.Select(make.Ident(itvar), hasNext));
3018                Symbol next = lookupMethod(tree.expr.pos(),
3019                                           names.next,
3020                                           itvar.type,
3021                                           List.<Type>nil());
3022                JCExpression vardefinit = make.App(make.Select(make.Ident(itvar), next));
3023                if (tree.var.type.isPrimitive())
3024                    vardefinit = make.TypeCast(types.upperBound(iteratorTarget), vardefinit);
3025                else
3026                    vardefinit = make.TypeCast(tree.var.type, vardefinit);
3027                JCVariableDecl indexDef = (JCVariableDecl)make.VarDef(tree.var.mods,
3028                                                      tree.var.name,
3029                                                      tree.var.vartype,
3030                                                      vardefinit).setType(tree.var.type);
3031                indexDef.sym = tree.var.sym;
3032                JCBlock body = make.Block(0, List.of(indexDef, tree.body));
3033                result = translate(make.
3034                    ForLoop(List.of(init),
3035                            cond,
3036                            List.<JCExpressionStatement>nil(),
3037                            body));
3038                patchTargets(body, tree, result);
3039            }
3040    
3041        public void visitVarDef(JCVariableDecl tree) {
3042            MethodSymbol oldMethodSym = currentMethodSym;
3043            tree.mods = translate(tree.mods);
3044            tree.vartype = translate(tree.vartype);
3045            if (currentMethodSym == null) {
3046                // A class or instance field initializer.
3047                currentMethodSym =
3048                    new MethodSymbol((tree.mods.flags&STATIC) | BLOCK,
3049                                     names.empty, null,
3050                                     currentClass);
3051            }
3052            if (tree.init != null) tree.init = translate(tree.init, tree.type);
3053            result = tree;
3054            currentMethodSym = oldMethodSym;
3055        }
3056    
3057        public void visitBlock(JCBlock tree) {
3058            MethodSymbol oldMethodSym = currentMethodSym;
3059            if (currentMethodSym == null) {
3060                // Block is a static or instance initializer.
3061                currentMethodSym =
3062                    new MethodSymbol(tree.flags | BLOCK,
3063                                     names.empty, null,
3064                                     currentClass);
3065            }
3066            super.visitBlock(tree);
3067            currentMethodSym = oldMethodSym;
3068        }
3069    
3070        public void visitDoLoop(JCDoWhileLoop tree) {
3071            tree.body = translate(tree.body);
3072            tree.cond = translate(tree.cond, syms.booleanType);
3073            result = tree;
3074        }
3075    
3076        public void visitWhileLoop(JCWhileLoop tree) {
3077            tree.cond = translate(tree.cond, syms.booleanType);
3078            tree.body = translate(tree.body);
3079            result = tree;
3080        }
3081    
3082        public void visitForLoop(JCForLoop tree) {
3083            tree.init = translate(tree.init);
3084            if (tree.cond != null)
3085                tree.cond = translate(tree.cond, syms.booleanType);
3086            tree.step = translate(tree.step);
3087            tree.body = translate(tree.body);
3088            result = tree;
3089        }
3090    
3091        public void visitReturn(JCReturn tree) {
3092            if (tree.expr != null)
3093                tree.expr = translate(tree.expr,
3094                                      types.erasure(currentMethodDef
3095                                                    .restype.type));
3096            result = tree;
3097        }
3098    
3099        public void visitSwitch(JCSwitch tree) {
3100            Type selsuper = types.supertype(tree.selector.type);
3101            boolean enumSwitch = selsuper != null &&
3102                (tree.selector.type.tsym.flags() & ENUM) != 0;
3103            Type target = enumSwitch ? tree.selector.type : syms.intType;
3104            tree.selector = translate(tree.selector, target);
3105            tree.cases = translateCases(tree.cases);
3106            if (enumSwitch) {
3107                result = visitEnumSwitch(tree);
3108                patchTargets(result, tree, result);
3109            } else {
3110                result = tree;
3111            }
3112        }
3113    
3114        public JCTree visitEnumSwitch(JCSwitch tree) {
3115            TypeSymbol enumSym = tree.selector.type.tsym;
3116            EnumMapping map = mapForEnum(tree.pos(), enumSym);
3117            make_at(tree.pos());
3118            Symbol ordinalMethod = lookupMethod(tree.pos(),
3119                                                names.ordinal,
3120                                                tree.selector.type,
3121                                                List.<Type>nil());
3122            JCArrayAccess selector = make.Indexed(map.mapVar,
3123                                            make.App(make.Select(tree.selector,
3124                                                                 ordinalMethod)));
3125            ListBuffer<JCCase> cases = new ListBuffer<JCCase>();
3126            for (JCCase c : tree.cases) {
3127                if (c.pat != null) {
3128                    VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pat);
3129                    JCLiteral pat = map.forConstant(label);
3130                    cases.append(make.Case(pat, c.stats));
3131                } else {
3132                    cases.append(c);
3133                }
3134            }
3135            return make.Switch(selector, cases.toList());
3136        }
3137    
3138        public void visitNewArray(JCNewArray tree) {
3139            tree.elemtype = translate(tree.elemtype);
3140            for (List<JCExpression> t = tree.dims; t.tail != null; t = t.tail)
3141                if (t.head != null) t.head = translate(t.head, syms.intType);
3142            tree.elems = translate(tree.elems, types.elemtype(tree.type));
3143            result = tree;
3144        }
3145    
3146        public void visitSelect(JCFieldAccess tree) {
3147            // need to special case-access of the form C.super.x
3148            // these will always need an access method.
3149            boolean qualifiedSuperAccess =
3150                tree.selected.getTag() == JCTree.SELECT &&
3151                TreeInfo.name(tree.selected) == names._super;
3152            tree.selected = translate(tree.selected);
3153            if (tree.name == names._class)
3154                result = classOf(tree.selected);
3155            else if (tree.name == names._this || tree.name == names._super)
3156                result = makeThis(tree.pos(), tree.selected.type.tsym);
3157            else
3158                result = access(tree.sym, tree, enclOp, qualifiedSuperAccess);
3159        }
3160    
3161        public void visitLetExpr(LetExpr tree) {
3162            tree.defs = translateVarDefs(tree.defs);
3163            tree.expr = translate(tree.expr, tree.type);
3164            result = tree;
3165        }
3166    
3167        // There ought to be nothing to rewrite here;
3168        // we don't generate code.
3169        public void visitAnnotation(JCAnnotation tree) {
3170            result = tree;
3171        }
3172    
3173    /**************************************************************************
3174     * main method
3175     *************************************************************************/
3176    
3177        /** Translate a toplevel class and return a list consisting of
3178         *  the translated class and translated versions of all inner classes.
3179         *  @param env   The attribution environment current at the class definition.
3180         *               We need this for resolving some additional symbols.
3181         *  @param cdef  The tree representing the class definition.
3182         */
3183        public List<JCTree> translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
3184            ListBuffer<JCTree> translated = null;
3185            try {
3186                attrEnv = env;
3187                this.make = make;
3188                endPositions = env.toplevel.endPositions;
3189                currentClass = null;
3190                currentMethodDef = null;
3191                outermostClassDef = (cdef.getTag() == JCTree.CLASSDEF) ? (JCClassDecl)cdef : null;
3192                outermostMemberDef = null;
3193                this.translated = new ListBuffer<JCTree>();
3194                classdefs = new HashMap<ClassSymbol,JCClassDecl>();
3195                actualSymbols = new HashMap<Symbol,Symbol>();
3196                freevarCache = new HashMap<ClassSymbol,List<VarSymbol>>();
3197                proxies = new Scope(syms.noSymbol);
3198                outerThisStack = List.nil();
3199                accessNums = new HashMap<Symbol,Integer>();
3200                accessSyms = new HashMap<Symbol,MethodSymbol[]>();
3201                accessConstrs = new HashMap<Symbol,MethodSymbol>();
3202                accessed = new ListBuffer<Symbol>();
3203                translate(cdef, (JCExpression)null);
3204                for (List<Symbol> l = accessed.toList(); l.nonEmpty(); l = l.tail)
3205                    makeAccessible(l.head);
3206                for (EnumMapping map : enumSwitchMap.values())
3207                    map.translate();
3208                translated = this.translated;
3209            } finally {
3210                // note that recursive invocations of this method fail hard
3211                attrEnv = null;
3212                this.make = null;
3213                endPositions = null;
3214                currentClass = null;
3215                currentMethodDef = null;
3216                outermostClassDef = null;
3217                outermostMemberDef = null;
3218                this.translated = null;
3219                classdefs = null;
3220                actualSymbols = null;
3221                freevarCache = null;
3222                proxies = null;
3223                outerThisStack = null;
3224                accessNums = null;
3225                accessSyms = null;
3226                accessConstrs = null;
3227                accessed = null;
3228                enumSwitchMap.clear();
3229            }
3230            return translated.toList();
3231        }
3232    
3233        //////////////////////////////////////////////////////////////
3234        // The following contributed by Borland for bootstrapping purposes
3235        //////////////////////////////////////////////////////////////
3236        private void addEnumCompatibleMembers(JCClassDecl cdef) {
3237            make_at(null);
3238    
3239            // Add the special enum fields
3240            VarSymbol ordinalFieldSym = addEnumOrdinalField(cdef);
3241            VarSymbol nameFieldSym = addEnumNameField(cdef);
3242    
3243            // Add the accessor methods for name and ordinal
3244            MethodSymbol ordinalMethodSym = addEnumFieldOrdinalMethod(cdef, ordinalFieldSym);
3245            MethodSymbol nameMethodSym = addEnumFieldNameMethod(cdef, nameFieldSym);
3246    
3247            // Add the toString method
3248            addEnumToString(cdef, nameFieldSym);
3249    
3250            // Add the compareTo method
3251            addEnumCompareTo(cdef, ordinalFieldSym);
3252        }
3253    
3254        private VarSymbol addEnumOrdinalField(JCClassDecl cdef) {
3255            VarSymbol ordinal = new VarSymbol(PRIVATE|FINAL|SYNTHETIC,
3256                                              names.fromString("$ordinal"),
3257                                              syms.intType,
3258                                              cdef.sym);
3259            cdef.sym.members().enter(ordinal);
3260            cdef.defs = cdef.defs.prepend(make.VarDef(ordinal, null));
3261            return ordinal;
3262        }
3263    
3264        private VarSymbol addEnumNameField(JCClassDecl cdef) {
3265            VarSymbol name = new VarSymbol(PRIVATE|FINAL|SYNTHETIC,
3266                                              names.fromString("$name"),
3267                                              syms.stringType,
3268                                              cdef.sym);
3269            cdef.sym.members().enter(name);
3270            cdef.defs = cdef.defs.prepend(make.VarDef(name, null));
3271            return name;
3272        }
3273    
3274        private MethodSymbol addEnumFieldOrdinalMethod(JCClassDecl cdef, VarSymbol ordinalSymbol) {
3275            // Add the accessor methods for ordinal
3276            Symbol ordinalSym = lookupMethod(cdef.pos(),
3277                                             names.ordinal,
3278                                             cdef.type,
3279                                             List.<Type>nil());
3280    
3281            assert(ordinalSym != null);
3282            assert(ordinalSym instanceof MethodSymbol);
3283    
3284            JCStatement ret = make.Return(make.Ident(ordinalSymbol));
3285            cdef.defs = cdef.defs.append(make.MethodDef((MethodSymbol)ordinalSym,
3286                                                        make.Block(0L, List.of(ret))));
3287    
3288            return (MethodSymbol)ordinalSym;
3289        }
3290    
3291        private MethodSymbol addEnumFieldNameMethod(JCClassDecl cdef, VarSymbol nameSymbol) {
3292            // Add the accessor methods for name
3293            Symbol nameSym = lookupMethod(cdef.pos(),
3294                                       names._name,
3295                                       cdef.type,
3296                                       List.<Type>nil());
3297    
3298            assert(nameSym != null);
3299            assert(nameSym instanceof MethodSymbol);
3300    
3301            JCStatement ret = make.Return(make.Ident(nameSymbol));
3302    
3303            cdef.defs = cdef.defs.append(make.MethodDef((MethodSymbol)nameSym,
3304                                                        make.Block(0L, List.of(ret))));
3305    
3306            return (MethodSymbol)nameSym;
3307        }
3308    
3309        private MethodSymbol addEnumToString(JCClassDecl cdef,
3310                                             VarSymbol nameSymbol) {
3311            Symbol toStringSym = lookupMethod(cdef.pos(),
3312                                              names.toString,
3313                                              cdef.type,
3314                                              List.<Type>nil());
3315    
3316            JCTree toStringDecl = null;
3317            if (toStringSym != null)
3318                toStringDecl = TreeInfo.declarationFor(toStringSym, cdef);
3319    
3320            if (toStringDecl != null)
3321                return (MethodSymbol)toStringSym;
3322    
3323            JCStatement ret = make.Return(make.Ident(nameSymbol));
3324    
3325            JCTree resTypeTree = make.Type(syms.stringType);
3326    
3327            MethodType toStringType = new MethodType(List.<Type>nil(),
3328                                                     syms.stringType,
3329                                                     List.<Type>nil(),
3330                                                     cdef.sym);
3331            toStringSym = new MethodSymbol(PUBLIC,
3332                                           names.toString,
3333                                           toStringType,
3334                                           cdef.type.tsym);
3335            toStringDecl = make.MethodDef((MethodSymbol)toStringSym,
3336                                          make.Block(0L, List.of(ret)));
3337    
3338            cdef.defs = cdef.defs.prepend(toStringDecl);
3339            cdef.sym.members().enter(toStringSym);
3340    
3341            return (MethodSymbol)toStringSym;
3342        }
3343    
3344        private MethodSymbol addEnumCompareTo(JCClassDecl cdef, VarSymbol ordinalSymbol) {
3345            Symbol compareToSym = lookupMethod(cdef.pos(),
3346                                       names.compareTo,
3347                                       cdef.type,
3348                                       List.of(cdef.sym.type));
3349    
3350            assert(compareToSym != null);
3351            assert(compareToSym instanceof MethodSymbol);
3352    
3353            JCMethodDecl compareToDecl = (JCMethodDecl) TreeInfo.declarationFor(compareToSym, cdef);
3354    
3355            ListBuffer<JCStatement> blockStatements = new ListBuffer<JCStatement>();
3356    
3357            JCModifiers mod1 = make.Modifiers(0L);
3358            Name oName = names.fromString("o");
3359            JCVariableDecl par1 = make.Param(oName, cdef.type, compareToSym);
3360    
3361            JCIdent paramId1 = make.Ident(names.java_lang_Object);
3362            paramId1.type = cdef.type;
3363            paramId1.sym = par1.sym;
3364    
3365            ((MethodSymbol)compareToSym).params = List.of(par1.sym);
3366    
3367            JCIdent par1UsageId = make.Ident(par1.sym);
3368            JCIdent castTargetIdent = make.Ident(cdef.sym);
3369            JCTypeCast cast = make.TypeCast(castTargetIdent, par1UsageId);
3370            cast.setType(castTargetIdent.type);
3371    
3372            Name otherName = names.fromString("other");
3373    
3374            VarSymbol otherVarSym = new VarSymbol(mod1.flags,
3375                                                  otherName,
3376                                                  cdef.type,
3377                                                  compareToSym);
3378            JCVariableDecl otherVar = make.VarDef(otherVarSym, cast);
3379            blockStatements.append(otherVar);
3380    
3381            JCIdent id1 = make.Ident(ordinalSymbol);
3382    
3383            JCIdent fLocUsageId = make.Ident(otherVarSym);
3384            JCExpression sel = make.Select(fLocUsageId, ordinalSymbol);
3385            JCBinary bin = makeBinary(JCTree.MINUS, id1, sel);
3386            JCReturn ret = make.Return(bin);
3387            blockStatements.append(ret);
3388            JCMethodDecl compareToMethod = make.MethodDef((MethodSymbol)compareToSym,
3389                                                       make.Block(0L,
3390                                                                  blockStatements.toList()));
3391            compareToMethod.params = List.of(par1);
3392            cdef.defs = cdef.defs.append(compareToMethod);
3393    
3394            return (MethodSymbol)compareToSym;
3395        }
3396        //////////////////////////////////////////////////////////////
3397        // The above contributed by Borland for bootstrapping purposes
3398        //////////////////////////////////////////////////////////////
3399    }