1 /*
   2  * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.tools.javac.comp;
  27 
  28 import java.util.*;
  29 import java.util.stream.Collectors;
  30 
  31 import com.sun.tools.javac.code.*;
  32 import com.sun.tools.javac.code.Kinds.KindSelector;
  33 import com.sun.tools.javac.code.Scope.WriteableScope;
  34 import com.sun.tools.javac.jvm.*;
  35 import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
  36 import com.sun.tools.javac.main.Option.PkgInfo;
  37 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
  38 import com.sun.tools.javac.tree.*;
  39 import com.sun.tools.javac.util.*;
  40 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  41 import com.sun.tools.javac.util.List;
  42 
  43 import com.sun.tools.javac.code.Symbol.*;
  44 import com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode;
  45 import com.sun.tools.javac.resources.CompilerProperties.Errors;
  46 import com.sun.tools.javac.tree.JCTree.*;
  47 import com.sun.tools.javac.code.Type.*;
  48 
  49 import com.sun.tools.javac.jvm.Target;
  50 import com.sun.tools.javac.tree.EndPosTable;
  51 
  52 import static com.sun.tools.javac.code.Flags.*;
  53 import static com.sun.tools.javac.code.Flags.BLOCK;
  54 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
  55 import static com.sun.tools.javac.code.TypeTag.*;
  56 import static com.sun.tools.javac.code.Kinds.Kind.*;
  57 import static com.sun.tools.javac.jvm.ByteCodes.*;
  58 import com.sun.tools.javac.tree.JCTree.JCBreak;
  59 import com.sun.tools.javac.tree.JCTree.JCCase;
  60 import com.sun.tools.javac.tree.JCTree.JCExpression;
  61 import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
  62 import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.LEFT;
  63 import com.sun.tools.javac.tree.JCTree.JCSwitchExpression;
  64 import static com.sun.tools.javac.tree.JCTree.Tag.*;
  65 
  66 /** This pass translates away some syntactic sugar: inner classes,
  67  *  class literals, assertions, foreach loops, etc.
  68  *
  69  *  <p><b>This is NOT part of any supported API.
  70  *  If you write code that depends on this, you do so at your own risk.
  71  *  This code and its internal interfaces are subject to change or
  72  *  deletion without notice.</b>
  73  */
  74 public class Lower extends TreeTranslator {
  75     protected static final Context.Key<Lower> lowerKey = new Context.Key<>();
  76 
  77     public static Lower instance(Context context) {
  78         Lower instance = context.get(lowerKey);
  79         if (instance == null)
  80             instance = new Lower(context);
  81         return instance;
  82     }
  83 
  84     private final Names names;
  85     private final Log log;
  86     private final Symtab syms;
  87     private final Resolve rs;
  88     private final Operators operators;
  89     private final Check chk;
  90     private final Attr attr;
  91     private TreeMaker make;
  92     private DiagnosticPosition make_pos;
  93     private final ConstFold cfolder;
  94     private final Target target;
  95     private final TypeEnvs typeEnvs;
  96     private final Name dollarAssertionsDisabled;
  97     private final Types types;
  98     private final boolean debugLower;
  99     private final boolean disableProtectedAccessors; // experimental
 100     private final PkgInfo pkginfoOpt;
 101     private final boolean optimizeOuterThis;
 102 
 103     protected Lower(Context context) {
 104         context.put(lowerKey, this);
 105         names = Names.instance(context);
 106         log = Log.instance(context);
 107         syms = Symtab.instance(context);
 108         rs = Resolve.instance(context);
 109         operators = Operators.instance(context);
 110         chk = Check.instance(context);
 111         attr = Attr.instance(context);
 112         make = TreeMaker.instance(context);
 113         cfolder = ConstFold.instance(context);
 114         target = Target.instance(context);
 115         typeEnvs = TypeEnvs.instance(context);
 116         dollarAssertionsDisabled = names.
 117             fromString(target.syntheticNameChar() + "assertionsDisabled");
 118 
 119         types = Types.instance(context);
 120         Options options = Options.instance(context);
 121         debugLower = options.isSet("debuglower");
 122         pkginfoOpt = PkgInfo.get(options);
 123         optimizeOuterThis =
 124             target.optimizeOuterThis() ||
 125             options.getBoolean("optimizeOuterThis", false);
 126         disableProtectedAccessors = options.isSet("disableProtectedAccessors");
 127     }
 128 
 129     /** The currently enclosing class.
 130      */
 131     ClassSymbol currentClass;
 132 
 133     /** A queue of all translated classes.
 134      */
 135     ListBuffer<JCTree> translated;
 136 
 137     /** Environment for symbol lookup, set by translateTopLevelClass.
 138      */
 139     Env<AttrContext> attrEnv;
 140 
 141     /** A hash table mapping syntax trees to their ending source positions.
 142      */
 143     EndPosTable endPosTable;
 144 
 145 /**************************************************************************
 146  * Global mappings
 147  *************************************************************************/
 148 
 149     /** A hash table mapping local classes to their definitions.
 150      */
 151     Map<ClassSymbol, JCClassDecl> classdefs;
 152 
 153     /** A hash table mapping local classes to a list of pruned trees.
 154      */
 155     public Map<ClassSymbol, List<JCTree>> prunedTree = new WeakHashMap<>();
 156 
 157     /** A hash table mapping virtual accessed symbols in outer subclasses
 158      *  to the actually referred symbol in superclasses.
 159      */
 160     Map<Symbol,Symbol> actualSymbols;
 161 
 162     /** The current method definition.
 163      */
 164     JCMethodDecl currentMethodDef;
 165 
 166     /** The current method symbol.
 167      */
 168     MethodSymbol currentMethodSym;
 169 
 170     /** The currently enclosing outermost class definition.
 171      */
 172     JCClassDecl outermostClassDef;
 173 
 174     /** The currently enclosing outermost member definition.
 175      */
 176     JCTree outermostMemberDef;
 177 
 178     /** A map from local variable symbols to their translation (as per LambdaToMethod).
 179      * This is required when a capturing local class is created from a lambda (in which
 180      * case the captured symbols should be replaced with the translated lambda symbols).
 181      */
 182     Map<Symbol, Symbol> lambdaTranslationMap = null;
 183 
 184     /** A navigator class for assembling a mapping from local class symbols
 185      *  to class definition trees.
 186      *  There is only one case; all other cases simply traverse down the tree.
 187      */
 188     class ClassMap extends TreeScanner {
 189 
 190         /** All encountered class defs are entered into classdefs table.
 191          */
 192         public void visitClassDef(JCClassDecl tree) {
 193             classdefs.put(tree.sym, tree);
 194             super.visitClassDef(tree);
 195         }
 196     }
 197     ClassMap classMap = new ClassMap();
 198 
 199     /** Map a class symbol to its definition.
 200      *  @param c    The class symbol of which we want to determine the definition.
 201      */
 202     JCClassDecl classDef(ClassSymbol c) {
 203         // First lookup the class in the classdefs table.
 204         JCClassDecl def = classdefs.get(c);
 205         if (def == null && outermostMemberDef != null) {
 206             // If this fails, traverse outermost member definition, entering all
 207             // local classes into classdefs, and try again.
 208             classMap.scan(outermostMemberDef);
 209             def = classdefs.get(c);
 210         }
 211         if (def == null) {
 212             // If this fails, traverse outermost class definition, entering all
 213             // local classes into classdefs, and try again.
 214             classMap.scan(outermostClassDef);
 215             def = classdefs.get(c);
 216         }
 217         return def;
 218     }
 219 
 220     /** A hash table mapping class symbols to lists of free variables.
 221      *  accessed by them. Only free variables of the method immediately containing
 222      *  a class are associated with that class.
 223      */
 224     Map<ClassSymbol,List<VarSymbol>> freevarCache;
 225 
 226     /** A navigator class for collecting the free variables accessed
 227      *  from a local class. There is only one case; all other cases simply
 228      *  traverse down the tree. This class doesn't deal with the specific
 229      *  of Lower - it's an abstract visitor that is meant to be reused in
 230      *  order to share the local variable capture logic.
 231      */
 232     abstract class BasicFreeVarCollector extends TreeScanner {
 233 
 234         /** Add all free variables of class c to fvs list
 235          *  unless they are already there.
 236          */
 237         abstract void addFreeVars(ClassSymbol c);
 238 
 239         /** If tree refers to a variable in owner of local class, add it to
 240          *  free variables list.
 241          */
 242         public void visitIdent(JCIdent tree) {
 243             visitSymbol(tree.sym);
 244         }
 245         // where
 246         abstract void visitSymbol(Symbol _sym);
 247 
 248         /** If tree refers to a class instance creation expression
 249          *  add all free variables of the freshly created class.
 250          */
 251         public void visitNewClass(JCNewClass tree) {
 252             ClassSymbol c = (ClassSymbol)tree.constructor.owner;
 253             addFreeVars(c);
 254             super.visitNewClass(tree);
 255         }
 256 
 257         /** If tree refers to a superclass constructor call,
 258          *  add all free variables of the superclass.
 259          */
 260         public void visitApply(JCMethodInvocation tree) {
 261             if (TreeInfo.name(tree.meth) == names._super) {
 262                 addFreeVars((ClassSymbol) TreeInfo.symbol(tree.meth).owner);
 263             }
 264             super.visitApply(tree);
 265         }
 266 
 267         @Override
 268         public void visitYield(JCYield tree) {
 269             scan(tree.value);
 270         }
 271 
 272     }
 273 
 274     /**
 275      * Lower-specific subclass of {@code BasicFreeVarCollector}.
 276      */
 277     class FreeVarCollector extends BasicFreeVarCollector {
 278 
 279         /** The owner of the local class.
 280          */
 281         Symbol owner;
 282 
 283         /** The local class.
 284          */
 285         ClassSymbol clazz;
 286 
 287         /** The list of owner's variables accessed from within the local class,
 288          *  without any duplicates.
 289          */
 290         List<VarSymbol> fvs;
 291 
 292         FreeVarCollector(ClassSymbol clazz) {
 293             this.clazz = clazz;
 294             this.owner = clazz.owner;
 295             this.fvs = List.nil();
 296         }
 297 
 298         /** Add free variable to fvs list unless it is already there.
 299          */
 300         private void addFreeVar(VarSymbol v) {
 301             for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail)
 302                 if (l.head == v) return;
 303             fvs = fvs.prepend(v);
 304         }
 305 
 306         @Override
 307         void addFreeVars(ClassSymbol c) {
 308             List<VarSymbol> fvs = freevarCache.get(c);
 309             if (fvs != null) {
 310                 for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail) {
 311                     addFreeVar(l.head);
 312                 }
 313             }
 314         }
 315 
 316         @Override
 317         void visitSymbol(Symbol _sym) {
 318             Symbol sym = _sym;
 319             if (sym.kind == VAR || sym.kind == MTH) {
 320                 if (sym != null && sym.owner != owner)
 321                     sym = proxies.get(sym);
 322                 if (sym != null && sym.owner == owner) {
 323                     VarSymbol v = (VarSymbol)sym;
 324                     if (v.getConstValue() == null) {
 325                         addFreeVar(v);
 326                     }
 327                 } else {
 328                     if (outerThisStack.head != null &&
 329                         outerThisStack.head != _sym)
 330                         visitSymbol(outerThisStack.head);
 331                 }
 332             }
 333         }
 334 
 335         /** If tree refers to a class instance creation expression
 336          *  add all free variables of the freshly created class.
 337          */
 338         public void visitNewClass(JCNewClass tree) {
 339             ClassSymbol c = (ClassSymbol)tree.constructor.owner;
 340             if (tree.encl == null &&
 341                 c.hasOuterInstance() &&
 342                 outerThisStack.head != null)
 343                 visitSymbol(outerThisStack.head);
 344             super.visitNewClass(tree);
 345         }
 346 
 347         /** If tree refers to a qualified this or super expression
 348          *  for anything but the current class, add the outer this
 349          *  stack as a free variable.
 350          */
 351         public void visitSelect(JCFieldAccess tree) {
 352             if ((tree.name == names._this || tree.name == names._super) &&
 353                 tree.selected.type.tsym != clazz &&
 354                 outerThisStack.head != null)
 355                 visitSymbol(outerThisStack.head);
 356             super.visitSelect(tree);
 357         }
 358 
 359         /** If tree refers to a superclass constructor call,
 360          *  add all free variables of the superclass.
 361          */
 362         public void visitApply(JCMethodInvocation tree) {
 363             if (TreeInfo.name(tree.meth) == names._super) {
 364                 Symbol constructor = TreeInfo.symbol(tree.meth);
 365                 ClassSymbol c = (ClassSymbol)constructor.owner;
 366                 if (c.hasOuterInstance() &&
 367                     !tree.meth.hasTag(SELECT) &&
 368                     outerThisStack.head != null)
 369                     visitSymbol(outerThisStack.head);
 370             }
 371             super.visitApply(tree);
 372         }
 373 
 374     }
 375 
 376     ClassSymbol ownerToCopyFreeVarsFrom(ClassSymbol c) {
 377         if (!c.isDirectlyOrIndirectlyLocal()) {
 378             return null;
 379         }
 380         Symbol currentOwner = c.owner;
 381         while (currentOwner.owner.kind.matches(KindSelector.TYP) && currentOwner.isDirectlyOrIndirectlyLocal()) {
 382             currentOwner = currentOwner.owner;
 383         }
 384         if (currentOwner.owner.kind.matches(KindSelector.VAL_MTH) && c.isSubClass(currentOwner, types)) {
 385             return (ClassSymbol)currentOwner;
 386         }
 387         return null;
 388     }
 389 
 390     /** Return the variables accessed from within a local class, which
 391      *  are declared in the local class' owner.
 392      *  (in reverse order of first access).
 393      */
 394     List<VarSymbol> freevars(ClassSymbol c)  {
 395         List<VarSymbol> fvs = freevarCache.get(c);
 396         if (fvs != null) {
 397             return fvs;
 398         }
 399         if (c.owner.kind.matches(KindSelector.VAL_MTH)) {
 400             FreeVarCollector collector = new FreeVarCollector(c);
 401             collector.scan(classDef(c));
 402             fvs = collector.fvs;
 403             freevarCache.put(c, fvs);
 404             return fvs;
 405         } else {
 406             ClassSymbol owner = ownerToCopyFreeVarsFrom(c);
 407             if (owner != null) {
 408                 fvs = freevarCache.get(owner);
 409                 freevarCache.put(c, fvs);
 410                 return fvs;
 411             } else {
 412                 return List.nil();
 413             }
 414         }
 415     }
 416 
 417     Map<TypeSymbol,EnumMapping> enumSwitchMap = new LinkedHashMap<>();
 418 
 419     EnumMapping mapForEnum(DiagnosticPosition pos, TypeSymbol enumClass) {
 420         EnumMapping map = enumSwitchMap.get(enumClass);
 421         if (map == null)
 422             enumSwitchMap.put(enumClass, map = new EnumMapping(pos, enumClass));
 423         return map;
 424     }
 425 
 426     /** This map gives a translation table to be used for enum
 427      *  switches.
 428      *
 429      *  <p>For each enum that appears as the type of a switch
 430      *  expression, we maintain an EnumMapping to assist in the
 431      *  translation, as exemplified by the following example:
 432      *
 433      *  <p>we translate
 434      *  <pre>
 435      *          switch(colorExpression) {
 436      *          case red: stmt1;
 437      *          case green: stmt2;
 438      *          }
 439      *  </pre>
 440      *  into
 441      *  <pre>
 442      *          switch(Outer$0.$EnumMap$Color[colorExpression.ordinal()]) {
 443      *          case 1: stmt1;
 444      *          case 2: stmt2
 445      *          }
 446      *  </pre>
 447      *  with the auxiliary table initialized as follows:
 448      *  <pre>
 449      *          class Outer$0 {
 450      *              synthetic final int[] $EnumMap$Color = new int[Color.values().length];
 451      *              static {
 452      *                  try { $EnumMap$Color[red.ordinal()] = 1; } catch (NoSuchFieldError ex) {}
 453      *                  try { $EnumMap$Color[green.ordinal()] = 2; } catch (NoSuchFieldError ex) {}
 454      *              }
 455      *          }
 456      *  </pre>
 457      *  class EnumMapping provides mapping data and support methods for this translation.
 458      */
 459     class EnumMapping {
 460         EnumMapping(DiagnosticPosition pos, TypeSymbol forEnum) {
 461             this.forEnum = forEnum;
 462             this.values = new LinkedHashMap<>();
 463             this.pos = pos;
 464             Name varName = names
 465                 .fromString(target.syntheticNameChar() +
 466                             "SwitchMap" +
 467                             target.syntheticNameChar() +
 468                             names.fromUtf(ClassWriter.externalize(forEnum.type.tsym.flatName())).toString()
 469                             .replace('/', '.')
 470                             .replace('.', target.syntheticNameChar()));
 471             ClassSymbol outerCacheClass = outerCacheClass();
 472             this.mapVar = new VarSymbol(STATIC | SYNTHETIC | FINAL,
 473                                         varName,
 474                                         new ArrayType(syms.intType, syms.arrayClass),
 475                                         outerCacheClass);
 476             enterSynthetic(pos, mapVar, outerCacheClass.members());
 477         }
 478 
 479         DiagnosticPosition pos = null;
 480 
 481         // the next value to use
 482         int next = 1; // 0 (unused map elements) go to the default label
 483 
 484         // the enum for which this is a map
 485         final TypeSymbol forEnum;
 486 
 487         // the field containing the map
 488         final VarSymbol mapVar;
 489 
 490         // the mapped values
 491         final Map<VarSymbol,Integer> values;
 492 
 493         JCLiteral forConstant(VarSymbol v) {
 494             Integer result = values.get(v);
 495             if (result == null)
 496                 values.put(v, result = next++);
 497             return make.Literal(result);
 498         }
 499 
 500         // generate the field initializer for the map
 501         void translate() {
 502             make.at(pos.getStartPosition());
 503             JCClassDecl owner = classDef((ClassSymbol)mapVar.owner);
 504 
 505             // synthetic static final int[] $SwitchMap$Color = new int[Color.values().length];
 506             MethodSymbol valuesMethod = lookupMethod(pos,
 507                                                      names.values,
 508                                                      forEnum.type,
 509                                                      List.nil());
 510             JCExpression size = make // Color.values().length
 511                 .Select(make.App(make.QualIdent(valuesMethod)),
 512                         syms.lengthVar);
 513             JCExpression mapVarInit = make
 514                 .NewArray(make.Type(syms.intType), List.of(size), null)
 515                 .setType(new ArrayType(syms.intType, syms.arrayClass));
 516 
 517             // try { $SwitchMap$Color[red.ordinal()] = 1; } catch (java.lang.NoSuchFieldError ex) {}
 518             ListBuffer<JCStatement> stmts = new ListBuffer<>();
 519             Symbol ordinalMethod = lookupMethod(pos,
 520                                                 names.ordinal,
 521                                                 forEnum.type,
 522                                                 List.nil());
 523             List<JCCatch> catcher = List.<JCCatch>nil()
 524                 .prepend(make.Catch(make.VarDef(new VarSymbol(PARAMETER, names.ex,
 525                                                               syms.noSuchFieldErrorType,
 526                                                               syms.noSymbol),
 527                                                 null),
 528                                     make.Block(0, List.nil())));
 529             for (Map.Entry<VarSymbol,Integer> e : values.entrySet()) {
 530                 VarSymbol enumerator = e.getKey();
 531                 Integer mappedValue = e.getValue();
 532                 JCExpression assign = make
 533                     .Assign(make.Indexed(mapVar,
 534                                          make.App(make.Select(make.QualIdent(enumerator),
 535                                                               ordinalMethod))),
 536                             make.Literal(mappedValue))
 537                     .setType(syms.intType);
 538                 JCStatement exec = make.Exec(assign);
 539                 JCStatement _try = make.Try(make.Block(0, List.of(exec)), catcher, null);
 540                 stmts.append(_try);
 541             }
 542 
 543             owner.defs = owner.defs
 544                 .prepend(make.Block(STATIC, stmts.toList()))
 545                 .prepend(make.VarDef(mapVar, mapVarInit));
 546         }
 547     }
 548 
 549 
 550 /**************************************************************************
 551  * Tree building blocks
 552  *************************************************************************/
 553 
 554     /** Equivalent to make.at(pos.getStartPosition()) with side effect of caching
 555      *  pos as make_pos, for use in diagnostics.
 556      **/
 557     TreeMaker make_at(DiagnosticPosition pos) {
 558         make_pos = pos;
 559         return make.at(pos);
 560     }
 561 
 562     /** Make an attributed tree representing a literal. This will be an
 563      *  Ident node in the case of boolean literals, a Literal node in all
 564      *  other cases.
 565      *  @param type       The literal's type.
 566      *  @param value      The literal's value.
 567      */
 568     JCExpression makeLit(Type type, Object value) {
 569         return make.Literal(type.getTag(), value).setType(type.constType(value));
 570     }
 571 
 572     /** Make an attributed tree representing null.
 573      */
 574     JCExpression makeNull() {
 575         return makeLit(syms.botType, null);
 576     }
 577 
 578     /** Make an attributed class instance creation expression.
 579      *  @param ctype    The class type.
 580      *  @param args     The constructor arguments.
 581      */
 582     JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
 583         JCNewClass tree = make.NewClass(null,
 584             null, make.QualIdent(ctype.tsym), args, null);
 585         tree.constructor = rs.resolveConstructor(
 586             make_pos, attrEnv, ctype, TreeInfo.types(args), List.nil());
 587         tree.type = ctype;
 588         return tree;
 589     }
 590 
 591     /** Make an attributed unary expression.
 592      *  @param optag    The operators tree tag.
 593      *  @param arg      The operator's argument.
 594      */
 595     JCUnary makeUnary(JCTree.Tag optag, JCExpression arg) {
 596         JCUnary tree = make.Unary(optag, arg);
 597         tree.operator = operators.resolveUnary(tree, optag, arg.type);
 598         tree.type = tree.operator.type.getReturnType();
 599         return tree;
 600     }
 601 
 602     /** Make an attributed binary expression.
 603      *  @param optag    The operators tree tag.
 604      *  @param lhs      The operator's left argument.
 605      *  @param rhs      The operator's right argument.
 606      */
 607     JCBinary makeBinary(JCTree.Tag optag, JCExpression lhs, JCExpression rhs) {
 608         JCBinary tree = make.Binary(optag, lhs, rhs);
 609         tree.operator = operators.resolveBinary(tree, optag, lhs.type, rhs.type);
 610         tree.type = tree.operator.type.getReturnType();
 611         return tree;
 612     }
 613 
 614     /** Make an attributed assignop expression.
 615      *  @param optag    The operators tree tag.
 616      *  @param lhs      The operator's left argument.
 617      *  @param rhs      The operator's right argument.
 618      */
 619     JCAssignOp makeAssignop(JCTree.Tag optag, JCTree lhs, JCTree rhs) {
 620         JCAssignOp tree = make.Assignop(optag, lhs, rhs);
 621         tree.operator = operators.resolveBinary(tree, tree.getTag().noAssignOp(), lhs.type, rhs.type);
 622         tree.type = lhs.type;
 623         return tree;
 624     }
 625 
 626     /** Convert tree into string object, unless it has already a
 627      *  reference type..
 628      */
 629     JCExpression makeString(JCExpression tree) {
 630         if (!tree.type.isPrimitiveOrVoid()) {
 631             return tree;
 632         } else {
 633             Symbol valueOfSym = lookupMethod(tree.pos(),
 634                                              names.valueOf,
 635                                              syms.stringType,
 636                                              List.of(tree.type));
 637             return make.App(make.QualIdent(valueOfSym), List.of(tree));
 638         }
 639     }
 640 
 641     /** Create an empty anonymous class definition and enter and complete
 642      *  its symbol. Return the class definition's symbol.
 643      *  and create
 644      *  @param flags    The class symbol's flags
 645      *  @param owner    The class symbol's owner
 646      */
 647     JCClassDecl makeEmptyClass(long flags, ClassSymbol owner) {
 648         return makeEmptyClass(flags, owner, null, true);
 649     }
 650 
 651     JCClassDecl makeEmptyClass(long flags, ClassSymbol owner, Name flatname,
 652             boolean addToDefs) {
 653         // Create class symbol.
 654         ClassSymbol c = syms.defineClass(names.empty, owner);
 655         if (flatname != null) {
 656             c.flatname = flatname;
 657         } else {
 658             c.flatname = chk.localClassName(c);
 659         }
 660         c.sourcefile = owner.sourcefile;
 661         c.completer = Completer.NULL_COMPLETER;
 662         c.members_field = WriteableScope.create(c);
 663         c.flags_field = flags;
 664         ClassType ctype = (ClassType) c.type;
 665         ctype.supertype_field = syms.objectType;
 666         ctype.interfaces_field = List.nil();
 667 
 668         JCClassDecl odef = classDef(owner);
 669 
 670         // Enter class symbol in owner scope and compiled table.
 671         enterSynthetic(odef.pos(), c, owner.members());
 672         chk.putCompiled(c);
 673 
 674         // Create class definition tree.
 675         JCClassDecl cdef = make.ClassDef(
 676             make.Modifiers(flags), names.empty,
 677             List.nil(),
 678             null, List.nil(), List.nil());
 679         cdef.sym = c;
 680         cdef.type = c.type;
 681 
 682         // Append class definition tree to owner's definitions.
 683         if (addToDefs) odef.defs = odef.defs.prepend(cdef);
 684         return cdef;
 685     }
 686 
 687 /**************************************************************************
 688  * Symbol manipulation utilities
 689  *************************************************************************/
 690 
 691     /** Enter a synthetic symbol in a given scope, but complain if there was already one there.
 692      *  @param pos           Position for error reporting.
 693      *  @param sym           The symbol.
 694      *  @param s             The scope.
 695      */
 696     private void enterSynthetic(DiagnosticPosition pos, Symbol sym, WriteableScope s) {
 697         s.enter(sym);
 698     }
 699 
 700     /** Create a fresh synthetic name within a given scope - the unique name is
 701      *  obtained by appending '$' chars at the end of the name until no match
 702      *  is found.
 703      *
 704      * @param name base name
 705      * @param s scope in which the name has to be unique
 706      * @return fresh synthetic name
 707      */
 708     private Name makeSyntheticName(Name name, Scope s) {
 709         do {
 710             name = name.append(
 711                     target.syntheticNameChar(),
 712                     names.empty);
 713         } while (lookupSynthetic(name, s) != null);
 714         return name;
 715     }
 716 
 717     /** Check whether synthetic symbols generated during lowering conflict
 718      *  with user-defined symbols.
 719      *
 720      *  @param translatedTrees lowered class trees
 721      */
 722     void checkConflicts(List<JCTree> translatedTrees) {
 723         for (JCTree t : translatedTrees) {
 724             t.accept(conflictsChecker);
 725         }
 726     }
 727 
 728     JCTree.Visitor conflictsChecker = new TreeScanner() {
 729 
 730         TypeSymbol currentClass;
 731 
 732         @Override
 733         public void visitMethodDef(JCMethodDecl that) {
 734             checkConflicts(that.pos(), that.sym, currentClass);
 735             super.visitMethodDef(that);
 736         }
 737 
 738         @Override
 739         public void visitVarDef(JCVariableDecl that) {
 740             if (that.sym.owner.kind == TYP) {
 741                 checkConflicts(that.pos(), that.sym, currentClass);
 742             }
 743             super.visitVarDef(that);
 744         }
 745 
 746         @Override
 747         public void visitClassDef(JCClassDecl that) {
 748             TypeSymbol prevCurrentClass = currentClass;
 749             currentClass = that.sym;
 750             try {
 751                 super.visitClassDef(that);
 752             }
 753             finally {
 754                 currentClass = prevCurrentClass;
 755             }
 756         }
 757 
 758         void checkConflicts(DiagnosticPosition pos, Symbol sym, TypeSymbol c) {
 759             for (Type ct = c.type; ct != Type.noType ; ct = types.supertype(ct)) {
 760                 for (Symbol sym2 : ct.tsym.members().getSymbolsByName(sym.name, NON_RECURSIVE)) {
 761                     // VM allows methods and variables with differing types
 762                     if (sym.kind == sym2.kind &&
 763                         types.isSameType(types.erasure(sym.type), types.erasure(sym2.type)) &&
 764                         sym != sym2 &&
 765                         (sym.flags() & Flags.SYNTHETIC) != (sym2.flags() & Flags.SYNTHETIC) &&
 766                         (sym.flags() & BRIDGE) == 0 && (sym2.flags() & BRIDGE) == 0) {
 767                         syntheticError(pos, (sym2.flags() & SYNTHETIC) == 0 ? sym2 : sym);
 768                         return;
 769                     }
 770                 }
 771             }
 772         }
 773 
 774         /** Report a conflict between a user symbol and a synthetic symbol.
 775          */
 776         private void syntheticError(DiagnosticPosition pos, Symbol sym) {
 777             if (!sym.type.isErroneous()) {
 778                 log.error(pos, Errors.CannotGenerateClass(sym.location(), Fragments.SyntheticNameConflict(sym, sym.location())));
 779             }
 780         }
 781     };
 782 
 783     /** Look up a synthetic name in a given scope.
 784      *  @param s            The scope.
 785      *  @param name         The name.
 786      */
 787     private Symbol lookupSynthetic(Name name, Scope s) {
 788         Symbol sym = s.findFirst(name);
 789         return (sym==null || (sym.flags()&SYNTHETIC)==0) ? null : sym;
 790     }
 791 
 792     /** Look up a method in a given scope.
 793      */
 794     private MethodSymbol lookupMethod(DiagnosticPosition pos, Name name, Type qual, List<Type> args) {
 795         return rs.resolveInternalMethod(pos, attrEnv, qual, name, args, List.nil());
 796     }
 797 
 798     /** Anon inner classes are used as access constructor tags.
 799      * accessConstructorTag will use an existing anon class if one is available,
 800      * and synthesize a class (with makeEmptyClass) if one is not available.
 801      * However, there is a small possibility that an existing class will not
 802      * be generated as expected if it is inside a conditional with a constant
 803      * expression. If that is found to be the case, create an empty class tree here.
 804      */
 805     private void checkAccessConstructorTags() {
 806         for (List<ClassSymbol> l = accessConstrTags; l.nonEmpty(); l = l.tail) {
 807             ClassSymbol c = l.head;
 808             if (isTranslatedClassAvailable(c))
 809                 continue;
 810             // Create class definition tree.
 811             JCClassDecl cdec = makeEmptyClass(STATIC | SYNTHETIC | IDENTITY_TYPE,
 812                     c.outermostClass(), c.flatname, false);
 813             swapAccessConstructorTag(c, cdec.sym);
 814             translated.append(cdec);
 815         }
 816     }
 817     // where
 818     private boolean isTranslatedClassAvailable(ClassSymbol c) {
 819         for (JCTree tree: translated) {
 820             if (tree.hasTag(CLASSDEF)
 821                     && ((JCClassDecl) tree).sym == c) {
 822                 return true;
 823             }
 824         }
 825         return false;
 826     }
 827 
 828     void swapAccessConstructorTag(ClassSymbol oldCTag, ClassSymbol newCTag) {
 829         for (MethodSymbol methodSymbol : accessConstrs.values()) {
 830             Assert.check(methodSymbol.type.hasTag(METHOD));
 831             MethodType oldMethodType =
 832                     (MethodType)methodSymbol.type;
 833             if (oldMethodType.argtypes.head.tsym == oldCTag)
 834                 methodSymbol.type =
 835                     types.createMethodTypeWithParameters(oldMethodType,
 836                         oldMethodType.getParameterTypes().tail
 837                             .prepend(newCTag.erasure(types)));
 838         }
 839     }
 840 
 841 /**************************************************************************
 842  * Access methods
 843  *************************************************************************/
 844 
 845     /** A mapping from symbols to their access numbers.
 846      */
 847     private Map<Symbol,Integer> accessNums;
 848 
 849     /** A mapping from symbols to an array of access symbols, indexed by
 850      *  access code.
 851      */
 852     private Map<Symbol,MethodSymbol[]> accessSyms;
 853 
 854     /** A mapping from (constructor) symbols to access constructor symbols.
 855      */
 856     private Map<Symbol,MethodSymbol> accessConstrs;
 857 
 858     /** A list of all class symbols used for access constructor tags.
 859      */
 860     private List<ClassSymbol> accessConstrTags;
 861 
 862     /** A queue for all accessed symbols.
 863      */
 864     private ListBuffer<Symbol> accessed;
 865 
 866     /** return access code for identifier,
 867      *  @param tree     The tree representing the identifier use.
 868      *  @param enclOp   The closest enclosing operation node of tree,
 869      *                  null if tree is not a subtree of an operation.
 870      */
 871     private static int accessCode(JCTree tree, JCTree enclOp) {
 872         if (enclOp == null)
 873             return AccessCode.DEREF.code;
 874         else if (enclOp.hasTag(ASSIGN) &&
 875                  tree == TreeInfo.skipParens(((JCAssign) enclOp).lhs))
 876             return AccessCode.ASSIGN.code;
 877         else if ((enclOp.getTag().isIncOrDecUnaryOp() || enclOp.getTag().isAssignop()) &&
 878                 tree == TreeInfo.skipParens(((JCOperatorExpression) enclOp).getOperand(LEFT)))
 879             return (((JCOperatorExpression) enclOp).operator).getAccessCode(enclOp.getTag());
 880         else
 881             return AccessCode.DEREF.code;
 882     }
 883 
 884     /** Return binary operator that corresponds to given access code.
 885      */
 886     private OperatorSymbol binaryAccessOperator(int acode, Tag tag) {
 887         return operators.lookupBinaryOp(op -> op.getAccessCode(tag) == acode);
 888     }
 889 
 890     /** Return tree tag for assignment operation corresponding
 891      *  to given binary operator.
 892      */
 893     private static JCTree.Tag treeTag(OperatorSymbol operator) {
 894         switch (operator.opcode) {
 895         case ByteCodes.ior: case ByteCodes.lor:
 896             return BITOR_ASG;
 897         case ByteCodes.ixor: case ByteCodes.lxor:
 898             return BITXOR_ASG;
 899         case ByteCodes.iand: case ByteCodes.land:
 900             return BITAND_ASG;
 901         case ByteCodes.ishl: case ByteCodes.lshl:
 902         case ByteCodes.ishll: case ByteCodes.lshll:
 903             return SL_ASG;
 904         case ByteCodes.ishr: case ByteCodes.lshr:
 905         case ByteCodes.ishrl: case ByteCodes.lshrl:
 906             return SR_ASG;
 907         case ByteCodes.iushr: case ByteCodes.lushr:
 908         case ByteCodes.iushrl: case ByteCodes.lushrl:
 909             return USR_ASG;
 910         case ByteCodes.iadd: case ByteCodes.ladd:
 911         case ByteCodes.fadd: case ByteCodes.dadd:
 912         case ByteCodes.string_add:
 913             return PLUS_ASG;
 914         case ByteCodes.isub: case ByteCodes.lsub:
 915         case ByteCodes.fsub: case ByteCodes.dsub:
 916             return MINUS_ASG;
 917         case ByteCodes.imul: case ByteCodes.lmul:
 918         case ByteCodes.fmul: case ByteCodes.dmul:
 919             return MUL_ASG;
 920         case ByteCodes.idiv: case ByteCodes.ldiv:
 921         case ByteCodes.fdiv: case ByteCodes.ddiv:
 922             return DIV_ASG;
 923         case ByteCodes.imod: case ByteCodes.lmod:
 924         case ByteCodes.fmod: case ByteCodes.dmod:
 925             return MOD_ASG;
 926         default:
 927             throw new AssertionError();
 928         }
 929     }
 930 
 931     /** The name of the access method with number `anum' and access code `acode'.
 932      */
 933     Name accessName(int anum, int acode) {
 934         return names.fromString(
 935             "access" + target.syntheticNameChar() + anum + acode / 10 + acode % 10);
 936     }
 937 
 938     /** Return access symbol for a private or protected symbol from an inner class.
 939      *  @param sym        The accessed private symbol.
 940      *  @param tree       The accessing tree.
 941      *  @param enclOp     The closest enclosing operation node of tree,
 942      *                    null if tree is not a subtree of an operation.
 943      *  @param protAccess Is access to a protected symbol in another
 944      *                    package?
 945      *  @param refSuper   Is access via a (qualified) C.super?
 946      */
 947     MethodSymbol accessSymbol(Symbol sym, JCTree tree, JCTree enclOp,
 948                               boolean protAccess, boolean refSuper) {
 949         ClassSymbol accOwner = refSuper && protAccess
 950             // For access via qualified super (T.super.x), place the
 951             // access symbol on T.
 952             ? (ClassSymbol)((JCFieldAccess) tree).selected.type.tsym
 953             // Otherwise pretend that the owner of an accessed
 954             // protected symbol is the enclosing class of the current
 955             // class which is a subclass of the symbol's owner.
 956             : accessClass(sym, protAccess, tree);
 957 
 958         Symbol vsym = sym;
 959         if (sym.owner != accOwner) {
 960             vsym = sym.clone(accOwner);
 961             actualSymbols.put(vsym, sym);
 962         }
 963 
 964         Integer anum              // The access number of the access method.
 965             = accessNums.get(vsym);
 966         if (anum == null) {
 967             anum = accessed.length();
 968             accessNums.put(vsym, anum);
 969             accessSyms.put(vsym, new MethodSymbol[AccessCode.numberOfAccessCodes]);
 970             accessed.append(vsym);
 971             // System.out.println("accessing " + vsym + " in " + vsym.location());
 972         }
 973 
 974         int acode;                // The access code of the access method.
 975         List<Type> argtypes;      // The argument types of the access method.
 976         Type restype;             // The result type of the access method.
 977         List<Type> thrown;        // The thrown exceptions of the access method.
 978         switch (vsym.kind) {
 979         case VAR:
 980             acode = accessCode(tree, enclOp);
 981             if (acode >= AccessCode.FIRSTASGOP.code) {
 982                 OperatorSymbol operator = binaryAccessOperator(acode, enclOp.getTag());
 983                 if (operator.opcode == string_add)
 984                     argtypes = List.of(syms.objectType);
 985                 else
 986                     argtypes = operator.type.getParameterTypes().tail;
 987             } else if (acode == AccessCode.ASSIGN.code)
 988                 argtypes = List.of(vsym.erasure(types));
 989             else
 990                 argtypes = List.nil();
 991             restype = vsym.erasure(types);
 992             thrown = List.nil();
 993             break;
 994         case MTH:
 995             acode = AccessCode.DEREF.code;
 996             argtypes = vsym.erasure(types).getParameterTypes();
 997             restype = vsym.erasure(types).getReturnType();
 998             thrown = vsym.type.getThrownTypes();
 999             break;
1000         default:
1001             throw new AssertionError();
1002         }
1003 
1004         // For references via qualified super, increment acode by one,
1005         // making it odd.
1006         if (protAccess && refSuper) acode++;
1007 
1008         // Instance access methods get instance as first parameter.
1009         // For protected symbols this needs to be the instance as a member
1010         // of the type containing the accessed symbol, not the class
1011         // containing the access method.
1012         if ((vsym.flags() & STATIC) == 0) {
1013             argtypes = argtypes.prepend(vsym.owner.erasure(types));
1014         }
1015         MethodSymbol[] accessors = accessSyms.get(vsym);
1016         MethodSymbol accessor = accessors[acode];
1017         if (accessor == null) {
1018             accessor = new MethodSymbol(
1019                 STATIC | SYNTHETIC | (accOwner.isInterface() ? PUBLIC : 0),
1020                 accessName(anum.intValue(), acode),
1021                 new MethodType(argtypes, restype, thrown, syms.methodClass),
1022                 accOwner);
1023             enterSynthetic(tree.pos(), accessor, accOwner.members());
1024             accessors[acode] = accessor;
1025         }
1026         return accessor;
1027     }
1028 
1029     /** The qualifier to be used for accessing a symbol in an outer class.
1030      *  This is either C.sym or C.this.sym, depending on whether or not
1031      *  sym is static.
1032      *  @param sym   The accessed symbol.
1033      */
1034     JCExpression accessBase(DiagnosticPosition pos, Symbol sym) {
1035         return (sym.flags() & STATIC) != 0
1036             ? access(make.at(pos.getStartPosition()).QualIdent(sym.owner))
1037             : makeOwnerThis(pos, sym, true);
1038     }
1039 
1040     /** Do we need an access method to reference private symbol?
1041      */
1042     boolean needsPrivateAccess(Symbol sym) {
1043         if (target.hasNestmateAccess()) {
1044             return false;
1045         }
1046         if ((sym.flags() & PRIVATE) == 0 || sym.owner == currentClass) {
1047             return false;
1048         } else if (sym.name == names.init && sym.owner.isDirectlyOrIndirectlyLocal()) {
1049             // private constructor in local class: relax protection
1050             sym.flags_field &= ~PRIVATE;
1051             return false;
1052         } else {
1053             return true;
1054         }
1055     }
1056 
1057     /** Do we need an access method to reference symbol in other package?
1058      */
1059     boolean needsProtectedAccess(Symbol sym, JCTree tree) {
1060         if (disableProtectedAccessors) return false;
1061         if ((sym.flags() & PROTECTED) == 0 ||
1062             sym.owner.owner == currentClass.owner || // fast special case
1063             sym.packge() == currentClass.packge())
1064             return false;
1065         if (!currentClass.isSubClass(sym.owner, types))
1066             return true;
1067         if ((sym.flags() & STATIC) != 0 ||
1068             !tree.hasTag(SELECT) ||
1069             TreeInfo.name(((JCFieldAccess) tree).selected) == names._super)
1070             return false;
1071         return !((JCFieldAccess) tree).selected.type.tsym.isSubClass(currentClass, types);
1072     }
1073 
1074     /** The class in which an access method for given symbol goes.
1075      *  @param sym        The access symbol
1076      *  @param protAccess Is access to a protected symbol in another
1077      *                    package?
1078      */
1079     ClassSymbol accessClass(Symbol sym, boolean protAccess, JCTree tree) {
1080         if (protAccess) {
1081             Symbol qualifier = null;
1082             ClassSymbol c = currentClass;
1083             if (tree.hasTag(SELECT) && (sym.flags() & STATIC) == 0) {
1084                 qualifier = ((JCFieldAccess) tree).selected.type.tsym;
1085                 while (!qualifier.isSubClass(c, types)) {
1086                     c = c.owner.enclClass();
1087                 }
1088                 return c;
1089             } else {
1090                 while (!c.isSubClass(sym.owner, types)) {
1091                     c = c.owner.enclClass();
1092                 }
1093             }
1094             return c;
1095         } else {
1096             // the symbol is private
1097             return sym.owner.enclClass();
1098         }
1099     }
1100 
1101     private void addPrunedInfo(JCTree tree) {
1102         List<JCTree> infoList = prunedTree.get(currentClass);
1103         infoList = (infoList == null) ? List.of(tree) : infoList.prepend(tree);
1104         prunedTree.put(currentClass, infoList);
1105     }
1106 
1107     /** Ensure that identifier is accessible, return tree accessing the identifier.
1108      *  @param sym      The accessed symbol.
1109      *  @param tree     The tree referring to the symbol.
1110      *  @param enclOp   The closest enclosing operation node of tree,
1111      *                  null if tree is not a subtree of an operation.
1112      *  @param refSuper Is access via a (qualified) C.super?
1113      */
1114     JCExpression access(Symbol sym, JCExpression tree, JCExpression enclOp, boolean refSuper) {
1115         // Access a free variable via its proxy, or its proxy's proxy
1116         while (sym.kind == VAR && sym.owner.kind == MTH &&
1117             sym.owner.enclClass() != currentClass) {
1118             // A constant is replaced by its constant value.
1119             Object cv = ((VarSymbol)sym).getConstValue();
1120             if (cv != null) {
1121                 make.at(tree.pos);
1122                 return makeLit(sym.type, cv);
1123             }
1124             if (lambdaTranslationMap != null && lambdaTranslationMap.get(sym) != null) {
1125                 return make.at(tree.pos).Ident(lambdaTranslationMap.get(sym));
1126             } else {
1127                 // Otherwise replace the variable by its proxy.
1128                 sym = proxies.get(sym);
1129                 Assert.check(sym != null && (sym.flags_field & FINAL) != 0);
1130                 tree = make.at(tree.pos).Ident(sym);
1131             }
1132         }
1133         JCExpression base = (tree.hasTag(SELECT)) ? ((JCFieldAccess) tree).selected : null;
1134         switch (sym.kind) {
1135         case TYP:
1136             if (sym.owner.kind != PCK) {
1137                 // Make sure not to lose type fidelity due to symbol sharing between projections
1138                 boolean requireReferenceProjection =
1139                         tree.hasTag(SELECT) && ((JCFieldAccess) tree).name == names.ref && tree.type.isReferenceProjection();
1140                 // Convert type idents to
1141                 // <flat name> or <package name> . <flat name>
1142                 Name flatname = Convert.shortName(sym.flatName());
1143                 while (base != null &&
1144                        TreeInfo.symbol(base) != null &&
1145                        TreeInfo.symbol(base).kind != PCK) {
1146                     base = (base.hasTag(SELECT))
1147                         ? ((JCFieldAccess) base).selected
1148                         : null;
1149                 }
1150                 if (tree.hasTag(IDENT)) {
1151                     ((JCIdent) tree).name = flatname;
1152                 } else if (base == null) {
1153                     tree = make.at(tree.pos).Ident(sym);
1154                     ((JCIdent) tree).name = flatname;
1155                     if (requireReferenceProjection) {
1156                         tree.setType(tree.type.referenceProjection());
1157                     }
1158                 } else {
1159                     ((JCFieldAccess) tree).selected = base;
1160                     ((JCFieldAccess) tree).name = flatname;
1161                     if (requireReferenceProjection) {
1162                         tree.setType(tree.type.referenceProjection());
1163                     }
1164                 }
1165             }
1166             break;
1167         case MTH: case VAR:
1168             if (sym.owner.kind == TYP) {
1169 
1170                 // Access methods are required for
1171                 //  - private members,
1172                 //  - protected members in a superclass of an
1173                 //    enclosing class contained in another package.
1174                 //  - all non-private members accessed via a qualified super.
1175                 boolean protAccess = refSuper && !needsPrivateAccess(sym)
1176                     || needsProtectedAccess(sym, tree);
1177                 boolean accReq = protAccess || needsPrivateAccess(sym);
1178 
1179                 // A base has to be supplied for
1180                 //  - simple identifiers accessing variables in outer classes.
1181                 boolean baseReq =
1182                     base == null &&
1183                     sym.owner != syms.predefClass &&
1184                     !sym.isMemberOf(currentClass, types);
1185 
1186                 if (accReq || baseReq) {
1187                     make.at(tree.pos);
1188 
1189                     // Constants are replaced by their constant value.
1190                     if (sym.kind == VAR) {
1191                         Object cv = ((VarSymbol)sym).getConstValue();
1192                         if (cv != null) {
1193                             addPrunedInfo(tree);
1194                             return makeLit(sym.type, cv);
1195                         }
1196                     }
1197 
1198                     // Private variables and methods are replaced by calls
1199                     // to their access methods.
1200                     if (accReq) {
1201                         List<JCExpression> args = List.nil();
1202                         if ((sym.flags() & STATIC) == 0) {
1203                             // Instance access methods get instance
1204                             // as first parameter.
1205                             if (base == null)
1206                                 base = makeOwnerThis(tree.pos(), sym, true);
1207                             args = args.prepend(base);
1208                             base = null;   // so we don't duplicate code
1209                         }
1210                         Symbol access = accessSymbol(sym, tree,
1211                                                      enclOp, protAccess,
1212                                                      refSuper);
1213                         JCExpression receiver = make.Select(
1214                             base != null ? base : make.QualIdent(access.owner),
1215                             access);
1216                         return make.App(receiver, args);
1217 
1218                     // Other accesses to members of outer classes get a
1219                     // qualifier.
1220                     } else if (baseReq) {
1221                         return make.at(tree.pos).Select(
1222                             accessBase(tree.pos(), sym), sym).setType(tree.type);
1223                     }
1224                 }
1225             } else if (sym.owner.kind == MTH && lambdaTranslationMap != null) {
1226                 //sym is a local variable - check the lambda translation map to
1227                 //see if sym has been translated to something else in the current
1228                 //scope (by LambdaToMethod)
1229                 Symbol translatedSym = lambdaTranslationMap.get(sym.baseSymbol());
1230                 if (translatedSym != null) {
1231                     tree = make.at(tree.pos).Ident(translatedSym);
1232                 }
1233             }
1234         }
1235         return tree;
1236     }
1237 
1238     /** Ensure that identifier is accessible, return tree accessing the identifier.
1239      *  @param tree     The identifier tree.
1240      */
1241     JCExpression access(JCExpression tree) {
1242         Symbol sym = TreeInfo.symbol(tree);
1243         return sym == null ? tree : access(sym, tree, null, false);
1244     }
1245 
1246     /** Return access constructor for a private constructor,
1247      *  or the constructor itself, if no access constructor is needed.
1248      *  @param pos       The position to report diagnostics, if any.
1249      *  @param constr    The private constructor.
1250      */
1251     Symbol accessConstructor(DiagnosticPosition pos, Symbol constr) {
1252         if (needsPrivateAccess(constr)) {
1253             ClassSymbol accOwner = constr.owner.enclClass();
1254             MethodSymbol aconstr = accessConstrs.get(constr);
1255             if (aconstr == null) {
1256                 List<Type> argtypes = constr.type.getParameterTypes();
1257                 if ((accOwner.flags_field & ENUM) != 0)
1258                     argtypes = argtypes
1259                         .prepend(syms.intType)
1260                         .prepend(syms.stringType);
1261                 aconstr = new MethodSymbol(
1262                     SYNTHETIC,
1263                     names.init,
1264                     new MethodType(
1265                         argtypes.append(
1266                             accessConstructorTag().erasure(types)),
1267                         constr.type.getReturnType(),
1268                         constr.type.getThrownTypes(),
1269                         syms.methodClass),
1270                     accOwner);
1271                 enterSynthetic(pos, aconstr, accOwner.members());
1272                 accessConstrs.put(constr, aconstr);
1273                 accessed.append(constr);
1274             }
1275             return aconstr;
1276         } else {
1277             return constr;
1278         }
1279     }
1280 
1281     /** Return an anonymous class nested in this toplevel class.
1282      */
1283     ClassSymbol accessConstructorTag() {
1284         ClassSymbol topClass = currentClass.outermostClass();
1285         ModuleSymbol topModle = topClass.packge().modle;
1286         for (int i = 1; ; i++) {
1287             Name flatname = names.fromString("" + topClass.getQualifiedName() +
1288                                             target.syntheticNameChar() +
1289                                             i);
1290             ClassSymbol ctag = chk.getCompiled(topModle, flatname);
1291             if (ctag == null)
1292                 ctag = makeEmptyClass(STATIC | SYNTHETIC | IDENTITY_TYPE, topClass).sym;
1293             else if (!ctag.isAnonymous())
1294                 continue;
1295             // keep a record of all tags, to verify that all are generated as required
1296             accessConstrTags = accessConstrTags.prepend(ctag);
1297             return ctag;
1298         }
1299     }
1300 
1301     /** Add all required access methods for a private symbol to enclosing class.
1302      *  @param sym       The symbol.
1303      */
1304     void makeAccessible(Symbol sym) {
1305         JCClassDecl cdef = classDef(sym.owner.enclClass());
1306         if (cdef == null) Assert.error("class def not found: " + sym + " in " + sym.owner);
1307         if (sym.name == names.init) {
1308             cdef.defs = cdef.defs.prepend(
1309                 accessConstructorDef(cdef.pos, sym, accessConstrs.get(sym)));
1310         } else {
1311             MethodSymbol[] accessors = accessSyms.get(sym);
1312             for (int i = 0; i < AccessCode.numberOfAccessCodes; i++) {
1313                 if (accessors[i] != null)
1314                     cdef.defs = cdef.defs.prepend(
1315                         accessDef(cdef.pos, sym, accessors[i], i));
1316             }
1317         }
1318     }
1319 
1320     /** Construct definition of an access method.
1321      *  @param pos        The source code position of the definition.
1322      *  @param vsym       The private or protected symbol.
1323      *  @param accessor   The access method for the symbol.
1324      *  @param acode      The access code.
1325      */
1326     JCTree accessDef(int pos, Symbol vsym, MethodSymbol accessor, int acode) {
1327 //      System.err.println("access " + vsym + " with " + accessor);//DEBUG
1328         currentClass = vsym.owner.enclClass();
1329         make.at(pos);
1330         JCMethodDecl md = make.MethodDef(accessor, null);
1331 
1332         // Find actual symbol
1333         Symbol sym = actualSymbols.get(vsym);
1334         if (sym == null) sym = vsym;
1335 
1336         JCExpression ref;           // The tree referencing the private symbol.
1337         List<JCExpression> args;    // Any additional arguments to be passed along.
1338         if ((sym.flags() & STATIC) != 0) {
1339             ref = make.Ident(sym);
1340             args = make.Idents(md.params);
1341         } else {
1342             JCExpression site = make.Ident(md.params.head);
1343             if (acode % 2 != 0) {
1344                 //odd access codes represent qualified super accesses - need to
1345                 //emit reference to the direct superclass, even if the referred
1346                 //member is from an indirect superclass (JLS 13.1)
1347                 site.setType(types.erasure(types.supertype(vsym.owner.enclClass().type)));
1348             }
1349             ref = make.Select(site, sym);
1350             args = make.Idents(md.params.tail);
1351         }
1352         JCStatement stat;          // The statement accessing the private symbol.
1353         if (sym.kind == VAR) {
1354             // Normalize out all odd access codes by taking floor modulo 2:
1355             int acode1 = acode - (acode & 1);
1356 
1357             JCExpression expr;      // The access method's return value.
1358             AccessCode aCode = AccessCode.getFromCode(acode1);
1359             switch (aCode) {
1360             case DEREF:
1361                 expr = ref;
1362                 break;
1363             case ASSIGN:
1364                 expr = make.Assign(ref, args.head);
1365                 break;
1366             case PREINC: case POSTINC: case PREDEC: case POSTDEC:
1367                 expr = makeUnary(aCode.tag, ref);
1368                 break;
1369             default:
1370                 expr = make.Assignop(
1371                     treeTag(binaryAccessOperator(acode1, JCTree.Tag.NO_TAG)), ref, args.head);
1372                 ((JCAssignOp) expr).operator = binaryAccessOperator(acode1, JCTree.Tag.NO_TAG);
1373             }
1374             stat = make.Return(expr.setType(sym.type));
1375         } else {
1376             stat = make.Call(make.App(ref, args));
1377         }
1378         md.body = make.Block(0, List.of(stat));
1379 
1380         // Make sure all parameters, result types and thrown exceptions
1381         // are accessible.
1382         for (List<JCVariableDecl> l = md.params; l.nonEmpty(); l = l.tail)
1383             l.head.vartype = access(l.head.vartype);
1384         md.restype = access(md.restype);
1385         for (List<JCExpression> l = md.thrown; l.nonEmpty(); l = l.tail)
1386             l.head = access(l.head);
1387 
1388         return md;
1389     }
1390 
1391     /** Construct definition of an access constructor.
1392      *  @param pos        The source code position of the definition.
1393      *  @param constr     The private constructor.
1394      *  @param accessor   The access method for the constructor.
1395      */
1396     JCTree accessConstructorDef(int pos, Symbol constr, MethodSymbol accessor) {
1397         make.at(pos);
1398         JCMethodDecl md = make.MethodDef(accessor,
1399                                       accessor.externalType(types),
1400                                       null);
1401         JCIdent callee = make.Ident(names._this);
1402         callee.sym = constr;
1403         callee.type = constr.type;
1404         md.body =
1405             make.Block(0, List.of(
1406                 make.Call(
1407                     make.App(
1408                         callee,
1409                         make.Idents(md.params.reverse().tail.reverse())))));
1410         return md;
1411     }
1412 
1413 /**************************************************************************
1414  * Free variables proxies and this$n
1415  *************************************************************************/
1416 
1417     /** A map which allows to retrieve the translated proxy variable for any given symbol of an
1418      *  enclosing scope that is accessed (the accessed symbol could be the synthetic 'this$n' symbol).
1419      *  Inside a constructor, the map temporarily overrides entries corresponding to proxies and any
1420      *  'this$n' symbols, where they represent the constructor parameters.
1421      */
1422     Map<Symbol, Symbol> proxies;
1423 
1424     /** A scope containing all unnamed resource variables/saved
1425      *  exception variables for translated TWR blocks
1426      */
1427     WriteableScope twrVars;
1428 
1429     /** A stack containing the this$n field of the currently translated
1430      *  classes (if needed) in innermost first order.
1431      *  Inside a constructor, proxies and any this$n symbol are duplicated
1432      *  in an additional innermost scope, where they represent the constructor
1433      *  parameters.
1434      */
1435     List<VarSymbol> outerThisStack;
1436 
1437     /** The name of a free variable proxy.
1438      */
1439     Name proxyName(Name name, int index) {
1440         Name proxyName = names.fromString("val" + target.syntheticNameChar() + name);
1441         if (index > 0) {
1442             proxyName = proxyName.append(names.fromString("" + target.syntheticNameChar() + index));
1443         }
1444         return proxyName;
1445     }
1446 
1447     /** Proxy definitions for all free variables in given list, in reverse order.
1448      *  @param pos        The source code position of the definition.
1449      *  @param freevars   The free variables.
1450      *  @param owner      The class in which the definitions go.
1451      */
1452     List<JCVariableDecl> freevarDefs(int pos, List<VarSymbol> freevars, Symbol owner) {
1453         return freevarDefs(pos, freevars, owner, 0);
1454     }
1455 
1456     List<JCVariableDecl> freevarDefs(int pos, List<VarSymbol> freevars, Symbol owner,
1457             long additionalFlags) {
1458         long flags = FINAL | SYNTHETIC | additionalFlags;
1459         List<JCVariableDecl> defs = List.nil();
1460         Set<Name> proxyNames = new HashSet<>();
1461         for (List<VarSymbol> l = freevars; l.nonEmpty(); l = l.tail) {
1462             VarSymbol v = l.head;
1463             int index = 0;
1464             Name proxyName;
1465             do {
1466                 proxyName = proxyName(v.name, index++);
1467             } while (!proxyNames.add(proxyName));
1468             final Type type = v.erasure(types);
1469             VarSymbol proxy = new VarSymbol(
1470                 flags, proxyName, type, owner);
1471             proxies.put(v, proxy);
1472             JCVariableDecl vd = make.at(pos).VarDef(proxy, null);
1473             vd.vartype = access(vd.vartype);
1474             defs = defs.prepend(vd);
1475         }
1476         return defs;
1477     }
1478 
1479     /** The name of a this$n field
1480      *  @param type   The class referenced by the this$n field
1481      */
1482     Name outerThisName(Type type, Symbol owner) {
1483         Type t = type.getEnclosingType();
1484         int nestingLevel = 0;
1485         while (t.hasTag(CLASS)) {
1486             t = t.getEnclosingType();
1487             nestingLevel++;
1488         }
1489         Name result = names.fromString("this" + target.syntheticNameChar() + nestingLevel);
1490         while (owner.kind == TYP && ((ClassSymbol)owner).members().findFirst(result) != null)
1491             result = names.fromString(result.toString() + target.syntheticNameChar());
1492         return result;
1493     }
1494 
1495     private VarSymbol makeOuterThisVarSymbol(Symbol owner, long flags) {
1496         Type target = types.erasure(owner.enclClass().type.getEnclosingType());
1497         // Set NOOUTERTHIS for all synthetic outer instance variables, and unset
1498         // it when the variable is accessed. If the variable is never accessed,
1499         // we skip creating an outer instance field and saving the constructor
1500         // parameter to it.
1501         VarSymbol outerThis =
1502             new VarSymbol(flags | NOOUTERTHIS, outerThisName(target, owner), target, owner);
1503         outerThisStack = outerThisStack.prepend(outerThis);
1504         return outerThis;
1505     }
1506 
1507     private JCVariableDecl makeOuterThisVarDecl(int pos, VarSymbol sym) {
1508         JCVariableDecl vd = make.at(pos).VarDef(sym, null);
1509         vd.vartype = access(vd.vartype);
1510         return vd;
1511     }
1512 
1513     /** Definition for this$n field.
1514      *  @param pos        The source code position of the definition.
1515      *  @param owner      The method in which the definition goes.
1516      */
1517     JCVariableDecl outerThisDef(int pos, MethodSymbol owner) {
1518         ClassSymbol c = owner.enclClass();
1519         boolean isMandated =
1520             // Anonymous constructors
1521             (owner.isConstructor() && owner.isAnonymous()) ||
1522             // Constructors of non-private inner member classes
1523             (owner.isConstructor() && c.isInner() &&
1524              !c.isPrivate() && !c.isStatic());
1525         long flags =
1526             FINAL | (isMandated ? MANDATED : SYNTHETIC) | PARAMETER;
1527         VarSymbol outerThis = makeOuterThisVarSymbol(owner, flags);
1528         owner.extraParams = owner.extraParams.prepend(outerThis);
1529         return makeOuterThisVarDecl(pos, outerThis);
1530     }
1531 
1532     /** Definition for this$n field.
1533      *  @param pos        The source code position of the definition.
1534      *  @param owner      The class in which the definition goes.
1535      */
1536     JCVariableDecl outerThisDef(int pos, ClassSymbol owner) {
1537         Type target = types.erasure(owner.enclClass().type.getEnclosingType());
1538         long flags = FINAL | SYNTHETIC;
1539         VarSymbol outerThis = makeOuterThisVarSymbol(owner, flags);
1540         return makeOuterThisVarDecl(pos, outerThis);
1541     }
1542 
1543     /** Return a list of trees that load the free variables in given list,
1544      *  in reverse order.
1545      *  @param pos          The source code position to be used for the trees.
1546      *  @param freevars     The list of free variables.
1547      */
1548     List<JCExpression> loadFreevars(DiagnosticPosition pos, List<VarSymbol> freevars) {
1549         List<JCExpression> args = List.nil();
1550         for (List<VarSymbol> l = freevars; l.nonEmpty(); l = l.tail)
1551             args = args.prepend(loadFreevar(pos, l.head));
1552         return args;
1553     }
1554 //where
1555         JCExpression loadFreevar(DiagnosticPosition pos, VarSymbol v) {
1556             return access(v, make.at(pos).Ident(v), null, false);
1557         }
1558 
1559     /** Construct a tree simulating the expression {@code C.this}.
1560      *  @param pos           The source code position to be used for the tree.
1561      *  @param c             The qualifier class.
1562      */
1563     JCExpression makeThis(DiagnosticPosition pos, TypeSymbol c) {
1564         if (currentClass == c) {
1565             // in this case, `this' works fine
1566             return make.at(pos).This(c.erasure(types));
1567         } else {
1568             // need to go via this$n
1569             return makeOuterThis(pos, c);
1570         }
1571     }
1572 
1573     /**
1574      * Optionally replace a try statement with the desugaring of a
1575      * try-with-resources statement.  The canonical desugaring of
1576      *
1577      * try ResourceSpecification
1578      *   Block
1579      *
1580      * is
1581      *
1582      * {
1583      *   final VariableModifiers_minus_final R #resource = Expression;
1584      *
1585      *   try ResourceSpecificationtail
1586      *     Block
1587      *   } body-only-finally {
1588      *     if (#resource != null) //nullcheck skipped if Expression is provably non-null
1589      *         #resource.close();
1590      *   } catch (Throwable #primaryException) {
1591      *       if (#resource != null) //nullcheck skipped if Expression is provably non-null
1592      *           try {
1593      *               #resource.close();
1594      *           } catch (Throwable #suppressedException) {
1595      *              #primaryException.addSuppressed(#suppressedException);
1596      *           }
1597      *       throw #primaryException;
1598      *   }
1599      * }
1600      *
1601      * @param tree  The try statement to inspect.
1602      * @return A a desugared try-with-resources tree, or the original
1603      * try block if there are no resources to manage.
1604      */
1605     JCTree makeTwrTry(JCTry tree) {
1606         make_at(tree.pos());
1607         twrVars = twrVars.dup();
1608         JCBlock twrBlock = makeTwrBlock(tree.resources, tree.body, 0);
1609         if (tree.catchers.isEmpty() && tree.finalizer == null)
1610             result = translate(twrBlock);
1611         else
1612             result = translate(make.Try(twrBlock, tree.catchers, tree.finalizer));
1613         twrVars = twrVars.leave();
1614         return result;
1615     }
1616 
1617     private JCBlock makeTwrBlock(List<JCTree> resources, JCBlock block, int depth) {
1618         if (resources.isEmpty())
1619             return block;
1620 
1621         // Add resource declaration or expression to block statements
1622         ListBuffer<JCStatement> stats = new ListBuffer<>();
1623         JCTree resource = resources.head;
1624         JCExpression resourceUse;
1625         boolean resourceNonNull;
1626         if (resource instanceof JCVariableDecl variableDecl) {
1627             resourceUse = make.Ident(variableDecl.sym).setType(resource.type);
1628             resourceNonNull = variableDecl.init != null && TreeInfo.skipParens(variableDecl.init).hasTag(NEWCLASS);
1629             stats.add(variableDecl);
1630         } else {
1631             Assert.check(resource instanceof JCExpression);
1632             VarSymbol syntheticTwrVar =
1633             new VarSymbol(SYNTHETIC | FINAL,
1634                           makeSyntheticName(names.fromString("twrVar" +
1635                                            depth), twrVars),
1636                           (resource.type.hasTag(BOT)) ?
1637                           syms.autoCloseableType : resource.type,
1638                           currentMethodSym);
1639             twrVars.enter(syntheticTwrVar);
1640             JCVariableDecl syntheticTwrVarDecl =
1641                 make.VarDef(syntheticTwrVar, (JCExpression)resource);
1642             resourceUse = (JCExpression)make.Ident(syntheticTwrVar);
1643             resourceNonNull = false;
1644             stats.add(syntheticTwrVarDecl);
1645         }
1646 
1647         //create (semi-) finally block that will be copied into the main try body:
1648         int oldPos = make.pos;
1649         make.at(TreeInfo.endPos(block));
1650 
1651         // if (#resource != null) { #resource.close(); }
1652         JCStatement bodyCloseStatement = makeResourceCloseInvocation(resourceUse);
1653 
1654         if (!resourceNonNull) {
1655             bodyCloseStatement = make.If(makeNonNullCheck(resourceUse),
1656                                          bodyCloseStatement,
1657                                          null);
1658         }
1659 
1660         JCBlock finallyClause = make.Block(BODY_ONLY_FINALIZE, List.of(bodyCloseStatement));
1661         make.at(oldPos);
1662 
1663         // Create catch clause that saves exception, closes the resource and then rethrows the exception:
1664         VarSymbol primaryException =
1665             new VarSymbol(FINAL|SYNTHETIC,
1666                           names.fromString("t" +
1667                                            target.syntheticNameChar()),
1668                           syms.throwableType,
1669                           currentMethodSym);
1670         JCVariableDecl primaryExceptionDecl = make.VarDef(primaryException, null);
1671 
1672         // close resource:
1673         // try {
1674         //     #resource.close();
1675         // } catch (Throwable #suppressedException) {
1676         //     #primaryException.addSuppressed(#suppressedException);
1677         // }
1678         VarSymbol suppressedException =
1679             new VarSymbol(SYNTHETIC, make.paramName(2),
1680                           syms.throwableType,
1681                           currentMethodSym);
1682         JCStatement addSuppressedStatement =
1683             make.Exec(makeCall(make.Ident(primaryException),
1684                                names.addSuppressed,
1685                                List.of(make.Ident(suppressedException))));
1686         JCBlock closeResourceTryBlock =
1687             make.Block(0L, List.of(makeResourceCloseInvocation(resourceUse)));
1688         JCVariableDecl catchSuppressedDecl = make.VarDef(suppressedException, null);
1689         JCBlock catchSuppressedBlock = make.Block(0L, List.of(addSuppressedStatement));
1690         List<JCCatch> catchSuppressedClauses =
1691                 List.of(make.Catch(catchSuppressedDecl, catchSuppressedBlock));
1692         JCTry closeResourceTry = make.Try(closeResourceTryBlock, catchSuppressedClauses, null);
1693         closeResourceTry.finallyCanCompleteNormally = true;
1694 
1695         JCStatement exceptionalCloseStatement = closeResourceTry;
1696 
1697         if (!resourceNonNull) {
1698             // if (#resource != null) {  }
1699             exceptionalCloseStatement = make.If(makeNonNullCheck(resourceUse),
1700                                                 exceptionalCloseStatement,
1701                                                 null);
1702         }
1703 
1704         JCStatement exceptionalRethrow = make.Throw(make.Ident(primaryException));
1705         JCBlock exceptionalCloseBlock = make.Block(0L, List.of(exceptionalCloseStatement, exceptionalRethrow));
1706         JCCatch exceptionalCatchClause = make.Catch(primaryExceptionDecl, exceptionalCloseBlock);
1707 
1708         //create the main try statement with the close:
1709         JCTry outerTry = make.Try(makeTwrBlock(resources.tail, block, depth + 1),
1710                                   List.of(exceptionalCatchClause),
1711                                   finallyClause);
1712 
1713         outerTry.finallyCanCompleteNormally = true;
1714         stats.add(outerTry);
1715 
1716         JCBlock newBlock = make.Block(0L, stats.toList());
1717         return newBlock;
1718     }
1719 
1720     private JCStatement makeResourceCloseInvocation(JCExpression resource) {
1721         // convert to AutoCloseable if needed
1722         if (types.asSuper(resource.type.referenceProjectionOrSelf(), syms.autoCloseableType.tsym) == null) {
1723             resource = convert(resource, syms.autoCloseableType);
1724         }
1725 
1726         // create resource.close() method invocation
1727         JCExpression resourceClose = makeCall(resource,
1728                                               names.close,
1729                                               List.nil());
1730         return make.Exec(resourceClose);
1731     }
1732 
1733     private JCExpression makeNonNullCheck(JCExpression expression) {
1734         return makeBinary(NE, expression, makeNull());
1735     }
1736 
1737     /** Construct a tree that represents the outer instance
1738      *  {@code C.this}. Never pick the current `this'.
1739      *  @param pos           The source code position to be used for the tree.
1740      *  @param c             The qualifier class.
1741      */
1742     JCExpression makeOuterThis(DiagnosticPosition pos, TypeSymbol c) {
1743         List<VarSymbol> ots = outerThisStack;
1744         if (ots.isEmpty()) {
1745             log.error(pos, Errors.NoEnclInstanceOfTypeInScope(c));
1746             Assert.error();
1747             return makeNull();
1748         }
1749         VarSymbol ot = ots.head;
1750         JCExpression tree = access(make.at(pos).Ident(ot));
1751         ot.flags_field &= ~NOOUTERTHIS;
1752         TypeSymbol otc = ot.type.tsym;
1753         while (otc != c) {
1754             do {
1755                 ots = ots.tail;
1756                 if (ots.isEmpty()) {
1757                     log.error(pos, Errors.NoEnclInstanceOfTypeInScope(c));
1758                     Assert.error(); // should have been caught in Attr
1759                     return tree;
1760                 }
1761                 ot = ots.head;
1762             } while (ot.owner != otc);
1763             if (otc.owner.kind != PCK && !otc.hasOuterInstance()) {
1764                 chk.earlyRefError(pos, c);
1765                 Assert.error(); // should have been caught in Attr
1766                 return makeNull();
1767             }
1768             tree = access(make.at(pos).Select(tree, ot));
1769             ot.flags_field &= ~NOOUTERTHIS;
1770             otc = ot.type.tsym;
1771         }
1772         return tree;
1773     }
1774 
1775     /** Construct a tree that represents the closest outer instance
1776      *  {@code C.this} such that the given symbol is a member of C.
1777      *  @param pos           The source code position to be used for the tree.
1778      *  @param sym           The accessed symbol.
1779      *  @param preciseMatch  should we accept a type that is a subtype of
1780      *                       sym's owner, even if it doesn't contain sym
1781      *                       due to hiding, overriding, or non-inheritance
1782      *                       due to protection?
1783      */
1784     JCExpression makeOwnerThis(DiagnosticPosition pos, Symbol sym, boolean preciseMatch) {
1785         Symbol c = sym.owner;
1786         if (preciseMatch ? sym.isMemberOf(currentClass, types)
1787                          : currentClass.isSubClass(sym.owner, types)) {
1788             // in this case, `this' works fine
1789             return make.at(pos).This(c.erasure(types));
1790         } else {
1791             // need to go via this$n
1792             return makeOwnerThisN(pos, sym, preciseMatch);
1793         }
1794     }
1795 
1796     /**
1797      * Similar to makeOwnerThis but will never pick "this".
1798      */
1799     JCExpression makeOwnerThisN(DiagnosticPosition pos, Symbol sym, boolean preciseMatch) {
1800         Symbol c = sym.owner;
1801         List<VarSymbol> ots = outerThisStack;
1802         if (ots.isEmpty()) {
1803             log.error(pos, Errors.NoEnclInstanceOfTypeInScope(c));
1804             Assert.error();
1805             return makeNull();
1806         }
1807         VarSymbol ot = ots.head;
1808         JCExpression tree = access(make.at(pos).Ident(ot));
1809         ot.flags_field &= ~NOOUTERTHIS;
1810         TypeSymbol otc = ot.type.tsym;
1811         while (!(preciseMatch ? sym.isMemberOf(otc, types) : otc.isSubClass(sym.owner, types))) {
1812             do {
1813                 ots = ots.tail;
1814                 if (ots.isEmpty()) {
1815                     log.error(pos, Errors.NoEnclInstanceOfTypeInScope(c));
1816                     Assert.error();
1817                     return tree;
1818                 }
1819                 ot = ots.head;
1820             } while (ot.owner != otc);
1821             tree = access(make.at(pos).Select(tree, ot));
1822             ot.flags_field &= ~NOOUTERTHIS;
1823             otc = ot.type.tsym;
1824         }
1825         return tree;
1826     }
1827 
1828     /** Return tree simulating the assignment {@code this.name = name}, where
1829      *  name is the name of a free variable.
1830      */
1831     JCStatement initField(int pos, Symbol rhs, Symbol lhs) {
1832         Assert.check(rhs.owner.kind == MTH);
1833         Assert.check(rhs.owner.owner == lhs.owner);
1834         make.at(pos);
1835         return
1836             make.Exec(
1837                 make.Assign(
1838                     make.Select(make.This(lhs.owner.erasure(types)), lhs),
1839                     make.Ident(rhs)).setType(lhs.erasure(types)));
1840     }
1841 
1842     /** Return tree simulating the assignment {@code this.this$n = this$n}.
1843      */
1844     JCStatement initOuterThis(int pos, VarSymbol rhs) {
1845         Assert.check(rhs.owner.kind == MTH);
1846         VarSymbol lhs = outerThisStack.head;
1847         Assert.check(rhs.owner.owner == lhs.owner);
1848         make.at(pos);
1849         return
1850             make.Exec(
1851                 make.Assign(
1852                     make.Select(make.This(lhs.owner.erasure(types)), lhs),
1853                     make.Ident(rhs)).setType(lhs.erasure(types)));
1854     }
1855 
1856 /**************************************************************************
1857  * Code for .class
1858  *************************************************************************/
1859 
1860     /** Return the symbol of a class to contain a cache of
1861      *  compiler-generated statics such as class$ and the
1862      *  $assertionsDisabled flag.  We create an anonymous nested class
1863      *  (unless one already exists) and return its symbol.  However,
1864      *  for backward compatibility in 1.4 and earlier we use the
1865      *  top-level class itself.
1866      */
1867     private ClassSymbol outerCacheClass() {
1868         ClassSymbol clazz = outermostClassDef.sym;
1869         Scope s = clazz.members();
1870         for (Symbol sym : s.getSymbols(NON_RECURSIVE))
1871             if (sym.kind == TYP &&
1872                 sym.name == names.empty &&
1873                 (sym.flags() & INTERFACE) == 0) return (ClassSymbol) sym;
1874         return makeEmptyClass(STATIC | SYNTHETIC | IDENTITY_TYPE, clazz).sym;
1875     }
1876 
1877     /** Create an attributed tree of the form left.name(). */
1878     private JCMethodInvocation makeCall(JCExpression left, Name name, List<JCExpression> args) {
1879         Assert.checkNonNull(left.type);
1880         Symbol funcsym = lookupMethod(make_pos, name, left.type,
1881                                       TreeInfo.types(args));
1882         return make.App(make.Select(left, funcsym), args);
1883     }
1884 
1885     /** The tree simulating a T.class expression.
1886      *  @param clazz      The tree identifying type T.
1887      */
1888     private JCExpression classOf(JCTree clazz) {
1889         return classOfType(clazz.type, clazz.pos());
1890     }
1891 
1892     private JCExpression classOfType(Type type, DiagnosticPosition pos) {
1893         switch (type.getTag()) {
1894         case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT:
1895         case DOUBLE: case BOOLEAN: case VOID:
1896             // replace with <BoxedClass>.TYPE
1897             ClassSymbol c = types.boxedClass(type);
1898             Symbol typeSym =
1899                 rs.accessBase(
1900                     rs.findIdentInType(pos, attrEnv, c.type, names.TYPE, KindSelector.VAR),
1901                     pos, c.type, names.TYPE, true);
1902             if (typeSym.kind == VAR)
1903                 ((VarSymbol)typeSym).getConstValue(); // ensure initializer is evaluated
1904             return make.QualIdent(typeSym);
1905         case CLASS: case ARRAY:
1906                 VarSymbol sym = new VarSymbol(
1907                         STATIC | PUBLIC | FINAL, names._class,
1908                         syms.classType, type.tsym);
1909                 return make_at(pos).Select(make.Type(type), sym);
1910         default:
1911             throw new AssertionError();
1912         }
1913     }
1914 
1915 /**************************************************************************
1916  * Code for enabling/disabling assertions.
1917  *************************************************************************/
1918 
1919     private ClassSymbol assertionsDisabledClassCache;
1920 
1921     /**Used to create an auxiliary class to hold $assertionsDisabled for interfaces.
1922      */
1923     private ClassSymbol assertionsDisabledClass() {
1924         if (assertionsDisabledClassCache != null) return assertionsDisabledClassCache;
1925 
1926         assertionsDisabledClassCache = makeEmptyClass(STATIC | SYNTHETIC | IDENTITY_TYPE, outermostClassDef.sym).sym;
1927 
1928         return assertionsDisabledClassCache;
1929     }
1930 
1931     // This code is not particularly robust if the user has
1932     // previously declared a member named '$assertionsDisabled'.
1933     // The same faulty idiom also appears in the translation of
1934     // class literals above.  We should report an error if a
1935     // previous declaration is not synthetic.
1936 
1937     private JCExpression assertFlagTest(DiagnosticPosition pos) {
1938         // Outermost class may be either true class or an interface.
1939         ClassSymbol outermostClass = outermostClassDef.sym;
1940 
1941         //only classes can hold a non-public field, look for a usable one:
1942         ClassSymbol container = !currentClass.isInterface() ? currentClass :
1943                 assertionsDisabledClass();
1944 
1945         VarSymbol assertDisabledSym =
1946             (VarSymbol)lookupSynthetic(dollarAssertionsDisabled,
1947                                        container.members());
1948         if (assertDisabledSym == null) {
1949             assertDisabledSym =
1950                 new VarSymbol(STATIC | FINAL | SYNTHETIC,
1951                               dollarAssertionsDisabled,
1952                               syms.booleanType,
1953                               container);
1954             enterSynthetic(pos, assertDisabledSym, container.members());
1955             Symbol desiredAssertionStatusSym = lookupMethod(pos,
1956                                                             names.desiredAssertionStatus,
1957                                                             types.erasure(syms.classType),
1958                                                             List.nil());
1959             JCClassDecl containerDef = classDef(container);
1960             make_at(containerDef.pos());
1961             JCExpression notStatus = makeUnary(NOT, make.App(make.Select(
1962                     classOfType(types.erasure(outermostClass.type),
1963                                 containerDef.pos()),
1964                     desiredAssertionStatusSym)));
1965             JCVariableDecl assertDisabledDef = make.VarDef(assertDisabledSym,
1966                                                    notStatus);
1967             containerDef.defs = containerDef.defs.prepend(assertDisabledDef);
1968 
1969             if (currentClass.isInterface()) {
1970                 //need to load the assertions enabled/disabled state while
1971                 //initializing the interface:
1972                 JCClassDecl currentClassDef = classDef(currentClass);
1973                 make_at(currentClassDef.pos());
1974                 JCStatement dummy = make.If(make.QualIdent(assertDisabledSym), make.Skip(), null);
1975                 JCBlock clinit = make.Block(STATIC, List.of(dummy));
1976                 currentClassDef.defs = currentClassDef.defs.prepend(clinit);
1977             }
1978         }
1979         make_at(pos);
1980         return makeUnary(NOT, make.Ident(assertDisabledSym));
1981     }
1982 
1983 
1984 /**************************************************************************
1985  * Building blocks for let expressions
1986  *************************************************************************/
1987 
1988     interface TreeBuilder {
1989         JCExpression build(JCExpression arg);
1990     }
1991 
1992     /** Construct an expression using the builder, with the given rval
1993      *  expression as an argument to the builder.  However, the rval
1994      *  expression must be computed only once, even if used multiple
1995      *  times in the result of the builder.  We do that by
1996      *  constructing a "let" expression that saves the rvalue into a
1997      *  temporary variable and then uses the temporary variable in
1998      *  place of the expression built by the builder.  The complete
1999      *  resulting expression is of the form
2000      *  <pre>
2001      *    (let <b>TYPE</b> <b>TEMP</b> = <b>RVAL</b>;
2002      *     in (<b>BUILDER</b>(<b>TEMP</b>)))
2003      *  </pre>
2004      *  where <code><b>TEMP</b></code> is a newly declared variable
2005      *  in the let expression.
2006      */
2007     JCExpression abstractRval(JCExpression rval, Type type, TreeBuilder builder) {
2008         rval = TreeInfo.skipParens(rval);
2009         switch (rval.getTag()) {
2010         case LITERAL:
2011             return builder.build(rval);
2012         case IDENT:
2013             JCIdent id = (JCIdent) rval;
2014             if ((id.sym.flags() & FINAL) != 0 && id.sym.owner.kind == MTH)
2015                 return builder.build(rval);
2016         }
2017         Name name = TreeInfo.name(rval);
2018         if (name == names._super || name == names._this)
2019             return builder.build(rval);
2020         VarSymbol var =
2021             new VarSymbol(FINAL|SYNTHETIC,
2022                           names.fromString(
2023                                           target.syntheticNameChar()
2024                                           + "" + rval.hashCode()),
2025                                       type,
2026                                       currentMethodSym);
2027         rval = convert(rval,type);
2028         JCVariableDecl def = make.VarDef(var, rval); // XXX cast
2029         JCExpression built = builder.build(make.Ident(var));
2030         JCExpression res = make.LetExpr(def, built);
2031         res.type = built.type;
2032         return res;
2033     }
2034 
2035     // same as above, with the type of the temporary variable computed
2036     JCExpression abstractRval(JCExpression rval, TreeBuilder builder) {
2037         return abstractRval(rval, rval.type, builder);
2038     }
2039 
2040     // same as above, but for an expression that may be used as either
2041     // an rvalue or an lvalue.  This requires special handling for
2042     // Select expressions, where we place the left-hand-side of the
2043     // select in a temporary, and for Indexed expressions, where we
2044     // place both the indexed expression and the index value in temps.
2045     JCExpression abstractLval(JCExpression lval, final TreeBuilder builder) {
2046         lval = TreeInfo.skipParens(lval);
2047         switch (lval.getTag()) {
2048         case IDENT:
2049             return builder.build(lval);
2050         case SELECT: {
2051             final JCFieldAccess s = (JCFieldAccess)lval;
2052             Symbol lid = TreeInfo.symbol(s.selected);
2053             if (lid != null && lid.kind == TYP) return builder.build(lval);
2054             return abstractRval(s.selected, selected -> builder.build(make.Select(selected, s.sym)));
2055         }
2056         case INDEXED: {
2057             final JCArrayAccess i = (JCArrayAccess)lval;
2058             return abstractRval(i.indexed, indexed -> abstractRval(i.index, syms.intType, index -> {
2059                 JCExpression newLval = make.Indexed(indexed, index);
2060                 newLval.setType(i.type);
2061                 return builder.build(newLval);
2062             }));
2063         }
2064         case TYPECAST: {
2065             return abstractLval(((JCTypeCast)lval).expr, builder);
2066         }
2067         }
2068         throw new AssertionError(lval);
2069     }
2070 
2071     // evaluate and discard the first expression, then evaluate the second.
2072     JCExpression makeComma(final JCExpression expr1, final JCExpression expr2) {
2073         JCExpression res = make.LetExpr(List.of(make.Exec(expr1)), expr2);
2074         res.type = expr2.type;
2075         return res;
2076     }
2077 
2078 /**************************************************************************
2079  * Translation methods
2080  *************************************************************************/
2081 
2082     /** Visitor argument: enclosing operator node.
2083      */
2084     private JCExpression enclOp;
2085 
2086     /** Visitor method: Translate a single node.
2087      *  Attach the source position from the old tree to its replacement tree.
2088      */
2089     @Override
2090     public <T extends JCTree> T translate(T tree) {
2091         if (tree == null) {
2092             return null;
2093         } else {
2094             make_at(tree.pos());
2095             T result = super.translate(tree);
2096             if (endPosTable != null && result != tree) {
2097                 endPosTable.replaceTree(tree, result);
2098             }
2099             return result;
2100         }
2101     }
2102 
2103     /** Visitor method: Translate a single node, boxing or unboxing if needed.
2104      */
2105     public <T extends JCExpression> T translate(T tree, Type type) {
2106         return (tree == null) ? null :
2107                 applyPrimitiveConversionsAsNeeded(boxIfNeeded(translate(tree), type), type);
2108     }
2109 
2110     /** Visitor method: Translate tree.
2111      */
2112     public <T extends JCTree> T translate(T tree, JCExpression enclOp) {
2113         JCExpression prevEnclOp = this.enclOp;
2114         this.enclOp = enclOp;
2115         T res = translate(tree);
2116         this.enclOp = prevEnclOp;
2117         return res;
2118     }
2119 
2120     /** Visitor method: Translate list of trees.
2121      */
2122     public <T extends JCExpression> List<T> translate(List<T> trees, Type type) {
2123         if (trees == null) return null;
2124         for (List<T> l = trees; l.nonEmpty(); l = l.tail)
2125             l.head = translate(l.head, type);
2126         return trees;
2127     }
2128 
2129     public void visitPackageDef(JCPackageDecl tree) {
2130         if (!needPackageInfoClass(tree))
2131                         return;
2132 
2133         long flags = Flags.ABSTRACT | Flags.INTERFACE;
2134         // package-info is marked SYNTHETIC in JDK 1.6 and later releases
2135         flags = flags | Flags.SYNTHETIC;
2136         ClassSymbol c = tree.packge.package_info;
2137         c.setAttributes(tree.packge);
2138         c.flags_field |= flags;
2139         ClassType ctype = (ClassType) c.type;
2140         ctype.supertype_field = syms.objectType;
2141         ctype.interfaces_field = List.nil();
2142         createInfoClass(tree.annotations, c);
2143     }
2144     // where
2145     private boolean needPackageInfoClass(JCPackageDecl pd) {
2146         switch (pkginfoOpt) {
2147             case ALWAYS:
2148                 return true;
2149             case LEGACY:
2150                 return pd.getAnnotations().nonEmpty();
2151             case NONEMPTY:
2152                 for (Attribute.Compound a :
2153                          pd.packge.getDeclarationAttributes()) {
2154                     Attribute.RetentionPolicy p = types.getRetention(a);
2155                     if (p != Attribute.RetentionPolicy.SOURCE)
2156                         return true;
2157                 }
2158                 return false;
2159         }
2160         throw new AssertionError();
2161     }
2162 
2163     public void visitModuleDef(JCModuleDecl tree) {
2164         ModuleSymbol msym = tree.sym;
2165         ClassSymbol c = msym.module_info;
2166         c.setAttributes(msym);
2167         c.flags_field |= Flags.MODULE;
2168         createInfoClass(List.nil(), tree.sym.module_info);
2169     }
2170 
2171     private void createInfoClass(List<JCAnnotation> annots, ClassSymbol c) {
2172         long flags = Flags.ABSTRACT | Flags.INTERFACE;
2173         JCClassDecl infoClass =
2174                 make.ClassDef(make.Modifiers(flags, annots),
2175                     c.name, List.nil(),
2176                     null, List.nil(), List.nil());
2177         infoClass.sym = c;
2178         translated.append(infoClass);
2179     }
2180 
2181     public void visitClassDef(JCClassDecl tree) {
2182         Env<AttrContext> prevEnv = attrEnv;
2183         ClassSymbol currentClassPrev = currentClass;
2184         MethodSymbol currentMethodSymPrev = currentMethodSym;
2185 
2186         currentClass = tree.sym;
2187         currentMethodSym = null;
2188         attrEnv = typeEnvs.remove(currentClass);
2189         if (attrEnv == null)
2190             attrEnv = prevEnv;
2191 
2192         classdefs.put(currentClass, tree);
2193 
2194         Map<Symbol, Symbol> prevProxies = proxies;
2195         proxies = new HashMap<>(proxies);
2196         List<VarSymbol> prevOuterThisStack = outerThisStack;
2197 
2198         // If this is an enum definition
2199         if ((tree.mods.flags & ENUM) != 0 &&
2200             (types.supertype(currentClass.type).tsym.flags() & ENUM) == 0)
2201             visitEnumDef(tree);
2202 
2203         if ((tree.mods.flags & RECORD) != 0) {
2204             visitRecordDef(tree);
2205         }
2206 
2207         // If this is a nested class, define a this$n field for
2208         // it and add to proxies.
2209         JCVariableDecl otdef = null;
2210         if (currentClass.hasOuterInstance())
2211             otdef = outerThisDef(tree.pos, currentClass);
2212 
2213         // If this is a local class, define proxies for all its free variables.
2214         List<JCVariableDecl> fvdefs = freevarDefs(
2215             tree.pos, freevars(currentClass), currentClass);
2216 
2217         // Recursively translate superclass, interfaces.
2218         tree.extending = translate(tree.extending);
2219         tree.implementing = translate(tree.implementing);
2220 
2221         if (currentClass.isDirectlyOrIndirectlyLocal()) {
2222             ClassSymbol encl = currentClass.owner.enclClass();
2223             if (encl.trans_local == null) {
2224                 encl.trans_local = List.nil();
2225             }
2226             encl.trans_local = encl.trans_local.prepend(currentClass);
2227         }
2228 
2229         // Recursively translate members, taking into account that new members
2230         // might be created during the translation and prepended to the member
2231         // list `tree.defs'.
2232         List<JCTree> seen = List.nil();
2233         while (tree.defs != seen) {
2234             List<JCTree> unseen = tree.defs;
2235             for (List<JCTree> l = unseen; l.nonEmpty() && l != seen; l = l.tail) {
2236                 JCTree outermostMemberDefPrev = outermostMemberDef;
2237                 if (outermostMemberDefPrev == null) outermostMemberDef = l.head;
2238                 l.head = translate(l.head);
2239                 outermostMemberDef = outermostMemberDefPrev;
2240             }
2241             seen = unseen;
2242         }
2243 
2244         // Convert a protected modifier to public, mask static modifier.
2245         if ((tree.mods.flags & PROTECTED) != 0) tree.mods.flags |= PUBLIC;
2246         tree.mods.flags &= AdjustedClassFlags;
2247 
2248         // Convert name to flat representation, replacing '.' by '$'.
2249         tree.name = Convert.shortName(currentClass.flatName());
2250 
2251         // Add free variables proxy definitions to class.
2252 
2253         for (List<JCVariableDecl> l = fvdefs; l.nonEmpty(); l = l.tail) {
2254             tree.defs = tree.defs.prepend(l.head);
2255             enterSynthetic(tree.pos(), l.head.sym, currentClass.members());
2256         }
2257         // If this$n was accessed, add the field definition and
2258         // update initial constructors to initialize it
2259         if (currentClass.hasOuterInstance() && shouldEmitOuterThis(currentClass)) {
2260             tree.defs = tree.defs.prepend(otdef);
2261             enterSynthetic(tree.pos(), otdef.sym, currentClass.members());
2262 
2263            for (JCTree def : tree.defs) {
2264                 if (TreeInfo.isInitialConstructor(def)) {
2265                   JCMethodDecl mdef = (JCMethodDecl) def;
2266                   mdef.body.stats = mdef.body.stats.prepend(
2267                       initOuterThis(mdef.body.pos, mdef.params.head.sym));
2268                 }
2269             }
2270         }
2271 
2272         proxies = prevProxies;
2273         outerThisStack = prevOuterThisStack;
2274 
2275         // Append translated tree to `translated' queue.
2276         translated.append(tree);
2277 
2278         attrEnv = prevEnv;
2279         currentClass = currentClassPrev;
2280         currentMethodSym = currentMethodSymPrev;
2281 
2282         // Return empty block {} as a placeholder for an inner class.
2283         result = make_at(tree.pos()).Block(SYNTHETIC, List.nil());
2284     }
2285 
2286     private boolean shouldEmitOuterThis(ClassSymbol sym) {
2287       if (!optimizeOuterThis) {
2288         // Optimization is disabled
2289         return true;
2290       }
2291       if ((outerThisStack.head.flags_field & NOOUTERTHIS) == 0)  {
2292         // Enclosing instance field is used
2293         return true;
2294       }
2295       if (rs.isSerializable(sym.type)) {
2296         // Class is serializable
2297         return true;
2298       }
2299       return false;
2300     }
2301 
2302     List<JCTree> generateMandatedAccessors(JCClassDecl tree) {
2303         List<JCVariableDecl> fields = TreeInfo.recordFields(tree);
2304         return tree.sym.getRecordComponents().stream()
2305                 .filter(rc -> (rc.accessor.flags() & Flags.GENERATED_MEMBER) != 0)
2306                 .map(rc -> {
2307                     // we need to return the field not the record component
2308                     JCVariableDecl field = fields.stream().filter(f -> f.name == rc.name).findAny().get();
2309                     make_at(tree.pos());
2310                     return make.MethodDef(rc.accessor, make.Block(0,
2311                             List.of(make.Return(make.Ident(field)))));
2312                 }).collect(List.collector());
2313     }
2314 
2315     /** Translate an enum class. */
2316     private void visitEnumDef(JCClassDecl tree) {
2317         make_at(tree.pos());
2318 
2319         // add the supertype, if needed
2320         if (tree.extending == null)
2321             tree.extending = make.Type(types.supertype(tree.type));
2322 
2323         // classOfType adds a cache field to tree.defs
2324         JCExpression e_class = classOfType(tree.sym.type, tree.pos()).
2325             setType(types.erasure(syms.classType));
2326 
2327         // process each enumeration constant, adding implicit constructor parameters
2328         int nextOrdinal = 0;
2329         ListBuffer<JCExpression> values = new ListBuffer<>();
2330         ListBuffer<JCTree> enumDefs = new ListBuffer<>();
2331         ListBuffer<JCTree> otherDefs = new ListBuffer<>();
2332         for (List<JCTree> defs = tree.defs;
2333              defs.nonEmpty();
2334              defs=defs.tail) {
2335             if (defs.head.hasTag(VARDEF) && (((JCVariableDecl) defs.head).mods.flags & ENUM) != 0) {
2336                 JCVariableDecl var = (JCVariableDecl)defs.head;
2337                 visitEnumConstantDef(var, nextOrdinal++);
2338                 values.append(make.QualIdent(var.sym));
2339                 enumDefs.append(var);
2340             } else {
2341                 otherDefs.append(defs.head);
2342             }
2343         }
2344 
2345         // synthetic private static T[] $values() { return new T[] { a, b, c }; }
2346         // synthetic private static final T[] $VALUES = $values();
2347         Name valuesName = syntheticName(tree, "VALUES");
2348         Type arrayType = new ArrayType(types.erasure(tree.type), syms.arrayClass);
2349         VarSymbol valuesVar = new VarSymbol(PRIVATE|FINAL|STATIC|SYNTHETIC,
2350                                             valuesName,
2351                                             arrayType,
2352                                             tree.type.tsym);
2353         JCNewArray newArray = make.NewArray(make.Type(types.erasure(tree.type)),
2354                                           List.nil(),
2355                                           values.toList());
2356         newArray.type = arrayType;
2357 
2358         MethodSymbol valuesMethod = new MethodSymbol(PRIVATE|STATIC|SYNTHETIC,
2359                 syntheticName(tree, "values"),
2360                 new MethodType(List.nil(), arrayType, List.nil(), tree.type.tsym),
2361                 tree.type.tsym);
2362         enumDefs.append(make.MethodDef(valuesMethod, make.Block(0, List.of(make.Return(newArray)))));
2363         tree.sym.members().enter(valuesMethod);
2364 
2365         enumDefs.append(make.VarDef(valuesVar, make.App(make.QualIdent(valuesMethod))));
2366         tree.sym.members().enter(valuesVar);
2367 
2368         MethodSymbol valuesSym = lookupMethod(tree.pos(), names.values,
2369                                         tree.type, List.nil());
2370         List<JCStatement> valuesBody;
2371         if (useClone()) {
2372             // return (T[]) $VALUES.clone();
2373             JCTypeCast valuesResult =
2374                 make.TypeCast(valuesSym.type.getReturnType(),
2375                               make.App(make.Select(make.Ident(valuesVar),
2376                                                    syms.arrayCloneMethod)));
2377             valuesBody = List.of(make.Return(valuesResult));
2378         } else {
2379             // template: T[] $result = new T[$values.length];
2380             Name resultName = syntheticName(tree, "result");
2381             VarSymbol resultVar = new VarSymbol(FINAL|SYNTHETIC,
2382                                                 resultName,
2383                                                 arrayType,
2384                                                 valuesSym);
2385             JCNewArray resultArray = make.NewArray(make.Type(types.erasure(tree.type)),
2386                                   List.of(make.Select(make.Ident(valuesVar), syms.lengthVar)),
2387                                   null);
2388             resultArray.type = arrayType;
2389             JCVariableDecl decl = make.VarDef(resultVar, resultArray);
2390 
2391             // template: System.arraycopy($VALUES, 0, $result, 0, $VALUES.length);
2392             if (systemArraycopyMethod == null) {
2393                 systemArraycopyMethod =
2394                     new MethodSymbol(PUBLIC | STATIC,
2395                                      names.fromString("arraycopy"),
2396                                      new MethodType(List.of(syms.objectType,
2397                                                             syms.intType,
2398                                                             syms.objectType,
2399                                                             syms.intType,
2400                                                             syms.intType),
2401                                                     syms.voidType,
2402                                                     List.nil(),
2403                                                     syms.methodClass),
2404                                      syms.systemType.tsym);
2405             }
2406             JCStatement copy =
2407                 make.Exec(make.App(make.Select(make.Ident(syms.systemType.tsym),
2408                                                systemArraycopyMethod),
2409                           List.of(make.Ident(valuesVar), make.Literal(0),
2410                                   make.Ident(resultVar), make.Literal(0),
2411                                   make.Select(make.Ident(valuesVar), syms.lengthVar))));
2412 
2413             // template: return $result;
2414             JCStatement ret = make.Return(make.Ident(resultVar));
2415             valuesBody = List.of(decl, copy, ret);
2416         }
2417 
2418         JCMethodDecl valuesDef =
2419              make.MethodDef(valuesSym, make.Block(0, valuesBody));
2420 
2421         enumDefs.append(valuesDef);
2422 
2423         if (debugLower)
2424             System.err.println(tree.sym + ".valuesDef = " + valuesDef);
2425 
2426         /** The template for the following code is:
2427          *
2428          *     public static E valueOf(String name) {
2429          *         return (E)Enum.valueOf(E.class, name);
2430          *     }
2431          *
2432          *  where E is tree.sym
2433          */
2434         MethodSymbol valueOfSym = lookupMethod(tree.pos(),
2435                          names.valueOf,
2436                          tree.sym.type,
2437                          List.of(syms.stringType));
2438         Assert.check((valueOfSym.flags() & STATIC) != 0);
2439         VarSymbol nameArgSym = valueOfSym.params.head;
2440         JCIdent nameVal = make.Ident(nameArgSym);
2441         JCStatement enum_ValueOf =
2442             make.Return(make.TypeCast(tree.sym.type,
2443                                       makeCall(make.Ident(syms.enumSym),
2444                                                names.valueOf,
2445                                                List.of(e_class, nameVal))));
2446         JCMethodDecl valueOf = make.MethodDef(valueOfSym,
2447                                            make.Block(0, List.of(enum_ValueOf)));
2448         nameVal.sym = valueOf.params.head.sym;
2449         if (debugLower)
2450             System.err.println(tree.sym + ".valueOf = " + valueOf);
2451         enumDefs.append(valueOf);
2452 
2453         enumDefs.appendList(otherDefs.toList());
2454         tree.defs = enumDefs.toList();
2455     }
2456         // where
2457         private MethodSymbol systemArraycopyMethod;
2458         private boolean useClone() {
2459             try {
2460                 return syms.objectType.tsym.members().findFirst(names.clone) != null;
2461             }
2462             catch (CompletionFailure e) {
2463                 return false;
2464             }
2465         }
2466 
2467         private Name syntheticName(JCClassDecl tree, String baseName) {
2468             Name valuesName = names.fromString(target.syntheticNameChar() + baseName);
2469             while (tree.sym.members().findFirst(valuesName) != null) // avoid name clash
2470                 valuesName = names.fromString(valuesName + "" + target.syntheticNameChar());
2471             return valuesName;
2472         }
2473 
2474     /** Translate an enumeration constant and its initializer. */
2475     private void visitEnumConstantDef(JCVariableDecl var, int ordinal) {
2476         JCNewClass varDef = (JCNewClass)var.init;
2477         varDef.args = varDef.args.
2478             prepend(makeLit(syms.intType, ordinal)).
2479             prepend(makeLit(syms.stringType, var.name.toString()));
2480     }
2481 
2482     private List<VarSymbol> recordVars(Type t) {
2483         List<VarSymbol> vars = List.nil();
2484         while (!t.hasTag(NONE)) {
2485             if (t.hasTag(CLASS)) {
2486                 for (Symbol s : t.tsym.members().getSymbols(s -> s.kind == VAR && (s.flags() & RECORD) != 0)) {
2487                     vars = vars.prepend((VarSymbol)s);
2488                 }
2489             }
2490             t = types.supertype(t);
2491         }
2492         return vars;
2493     }
2494 
2495     /** Translate a record. */
2496     private void visitRecordDef(JCClassDecl tree) {
2497         make_at(tree.pos());
2498         List<VarSymbol> vars = recordVars(tree.type);
2499         MethodHandleSymbol[] getterMethHandles = new MethodHandleSymbol[vars.size()];
2500         int index = 0;
2501         for (VarSymbol var : vars) {
2502             if (var.owner != tree.sym) {
2503                 var = new VarSymbol(var.flags_field, var.name, var.type, tree.sym);
2504             }
2505             getterMethHandles[index] = var.asMethodHandle(true);
2506             index++;
2507         }
2508 
2509         tree.defs = tree.defs.appendList(generateMandatedAccessors(tree));
2510         tree.defs = tree.defs.appendList(List.of(
2511                 generateRecordMethod(tree, names.toString, vars, getterMethHandles),
2512                 generateRecordMethod(tree, names.hashCode, vars, getterMethHandles),
2513                 generateRecordMethod(tree, names.equals, vars, getterMethHandles)
2514         ));
2515     }
2516 
2517     JCTree generateRecordMethod(JCClassDecl tree, Name name, List<VarSymbol> vars, MethodHandleSymbol[] getterMethHandles) {
2518         make_at(tree.pos());
2519         boolean isEquals = name == names.equals;
2520         MethodSymbol msym = lookupMethod(tree.pos(),
2521                 name,
2522                 tree.sym.type,
2523                 isEquals ? List.of(syms.objectType) : List.nil());
2524         // compiler generated methods have the record flag set, user defined ones dont
2525         if ((msym.flags() & RECORD) != 0) {
2526             /* class java.lang.runtime.ObjectMethods provides a common bootstrap that provides a customized implementation
2527              * for methods: toString, hashCode and equals. Here we just need to generate and indy call to:
2528              * java.lang.runtime.ObjectMethods::bootstrap and provide: the record class, the record component names and
2529              * the accessors.
2530              */
2531             Name bootstrapName = names.bootstrap;
2532             LoadableConstant[] staticArgsValues = new LoadableConstant[2 + getterMethHandles.length];
2533             staticArgsValues[0] = (ClassType)tree.sym.type;
2534             String concatNames = vars.stream()
2535                     .map(v -> v.name)
2536                     .collect(Collectors.joining(";", "", ""));
2537             staticArgsValues[1] = LoadableConstant.String(concatNames);
2538             int index = 2;
2539             for (MethodHandleSymbol mho : getterMethHandles) {
2540                 staticArgsValues[index] = mho;
2541                 index++;
2542             }
2543 
2544             List<Type> staticArgTypes = List.of(syms.classType,
2545                     syms.stringType,
2546                     new ArrayType(syms.methodHandleType, syms.arrayClass));
2547 
2548             JCFieldAccess qualifier = makeIndyQualifier(syms.objectMethodsType, tree, msym,
2549                     List.of(syms.methodHandleLookupType,
2550                             syms.stringType,
2551                             syms.typeDescriptorType).appendList(staticArgTypes),
2552                     staticArgsValues, bootstrapName, name, false);
2553 
2554             VarSymbol _this = new VarSymbol(SYNTHETIC, names._this, tree.sym.type, tree.sym);
2555 
2556             JCMethodInvocation proxyCall;
2557             if (!isEquals) {
2558                 proxyCall = make.Apply(List.nil(), qualifier, List.of(make.Ident(_this)));
2559             } else {
2560                 VarSymbol o = msym.params.head;
2561                 o.adr = 0;
2562                 proxyCall = make.Apply(List.nil(), qualifier, List.of(make.Ident(_this), make.Ident(o)));
2563             }
2564             proxyCall.type = qualifier.type;
2565             return make.MethodDef(msym, make.Block(0, List.of(make.Return(proxyCall))));
2566         } else {
2567             return make.Block(SYNTHETIC, List.nil());
2568         }
2569     }
2570 
2571     private String argsTypeSig(List<Type> typeList) {
2572         LowerSignatureGenerator sg = new LowerSignatureGenerator();
2573         sg.assembleSig(typeList);
2574         return sg.toString();
2575     }
2576 
2577     /**
2578      * Signature Generation
2579      */
2580     private class LowerSignatureGenerator extends Types.SignatureGenerator {
2581 
2582         /**
2583          * An output buffer for type signatures.
2584          */
2585         StringBuilder sb = new StringBuilder();
2586 
2587         LowerSignatureGenerator() {
2588             super(types);
2589         }
2590 
2591         @Override
2592         protected void append(char ch) {
2593             sb.append(ch);
2594         }
2595 
2596         @Override
2597         protected void append(byte[] ba) {
2598             sb.append(new String(ba));
2599         }
2600 
2601         @Override
2602         protected void append(Name name) {
2603             sb.append(name.toString());
2604         }
2605 
2606         @Override
2607         public String toString() {
2608             return sb.toString();
2609         }
2610     }
2611 
2612     /**
2613      * Creates an indy qualifier, helpful to be part of an indy invocation
2614      * @param site                the site
2615      * @param tree                a class declaration tree
2616      * @param msym                the method symbol
2617      * @param staticArgTypes      the static argument types
2618      * @param staticArgValues     the static argument values
2619      * @param bootstrapName       the bootstrap name to look for
2620      * @param argName             normally bootstraps receives a method name as second argument, if you want that name
2621      *                            to be different to that of the bootstrap name pass a different name here
2622      * @param isStatic            is it static or not
2623      * @return                    a field access tree
2624      */
2625     JCFieldAccess makeIndyQualifier(
2626             Type site,
2627             JCClassDecl tree,
2628             MethodSymbol msym,
2629             List<Type> staticArgTypes,
2630             LoadableConstant[] staticArgValues,
2631             Name bootstrapName,
2632             Name argName,
2633             boolean isStatic) {
2634         MethodSymbol bsm = rs.resolveInternalMethod(tree.pos(), attrEnv, site,
2635                 bootstrapName, staticArgTypes, List.nil());
2636 
2637         MethodType indyType = msym.type.asMethodType();
2638         indyType = new MethodType(
2639                 isStatic ? List.nil() : indyType.argtypes.prepend(tree.sym.type),
2640                 indyType.restype,
2641                 indyType.thrown,
2642                 syms.methodClass
2643         );
2644         DynamicMethodSymbol dynSym = new DynamicMethodSymbol(argName,
2645                 syms.noSymbol,
2646                 bsm.asHandle(),
2647                 indyType,
2648                 staticArgValues);
2649         JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), argName);
2650         qualifier.sym = dynSym;
2651         qualifier.type = msym.type.asMethodType().restype;
2652         return qualifier;
2653     }
2654 
2655     public void visitMethodDef(JCMethodDecl tree) {
2656         if (tree.name == names.init && (currentClass.flags_field&ENUM) != 0) {
2657             // Add "String $enum$name, int $enum$ordinal" to the beginning of the
2658             // argument list for each constructor of an enum.
2659             JCVariableDecl nameParam = make_at(tree.pos()).
2660                 Param(names.fromString(target.syntheticNameChar() +
2661                                        "enum" + target.syntheticNameChar() + "name"),
2662                       syms.stringType, tree.sym);
2663             nameParam.mods.flags |= SYNTHETIC; nameParam.sym.flags_field |= SYNTHETIC;
2664             JCVariableDecl ordParam = make.
2665                 Param(names.fromString(target.syntheticNameChar() +
2666                                        "enum" + target.syntheticNameChar() +
2667                                        "ordinal"),
2668                       syms.intType, tree.sym);
2669             ordParam.mods.flags |= SYNTHETIC; ordParam.sym.flags_field |= SYNTHETIC;
2670 
2671             MethodSymbol m = tree.sym;
2672             tree.params = tree.params.prepend(ordParam).prepend(nameParam);
2673 
2674             m.extraParams = m.extraParams.prepend(ordParam.sym);
2675             m.extraParams = m.extraParams.prepend(nameParam.sym);
2676             Type olderasure = m.erasure(types);
2677             m.erasure_field = new MethodType(
2678                 olderasure.getParameterTypes().prepend(syms.intType).prepend(syms.stringType),
2679                 olderasure.getReturnType(),
2680                 olderasure.getThrownTypes(),
2681                 syms.methodClass);
2682         }
2683 
2684         JCMethodDecl prevMethodDef = currentMethodDef;
2685         MethodSymbol prevMethodSym = currentMethodSym;
2686         try {
2687             currentMethodDef = tree;
2688             currentMethodSym = tree.sym;
2689             visitMethodDefInternal(tree);
2690         } finally {
2691             currentMethodDef = prevMethodDef;
2692             currentMethodSym = prevMethodSym;
2693         }
2694     }
2695 
2696     private void visitMethodDefInternal(JCMethodDecl tree) {
2697         if (tree.name == names.init &&
2698             (currentClass.isInner() || currentClass.isDirectlyOrIndirectlyLocal())) {
2699             // We are seeing a constructor of an inner class.
2700             MethodSymbol m = tree.sym;
2701 
2702             // Push a new proxy scope for constructor parameters.
2703             // and create definitions for any this$n and proxy parameters.
2704             Map<Symbol, Symbol> prevProxies = proxies;
2705             proxies = new HashMap<>(proxies);
2706             List<VarSymbol> prevOuterThisStack = outerThisStack;
2707             List<VarSymbol> fvs = freevars(currentClass);
2708             JCVariableDecl otdef = null;
2709             if (currentClass.hasOuterInstance())
2710                 otdef = outerThisDef(tree.pos, m);
2711             List<JCVariableDecl> fvdefs = freevarDefs(tree.pos, fvs, m, PARAMETER);
2712 
2713             // Recursively translate result type, parameters and thrown list.
2714             tree.restype = translate(tree.restype);
2715             tree.params = translateVarDefs(tree.params);
2716             tree.thrown = translate(tree.thrown);
2717 
2718             // when compiling stubs, don't process body
2719             if (tree.body == null) {
2720                 result = tree;
2721                 return;
2722             }
2723 
2724             // Add this$n (if needed) in front of and free variables behind
2725             // constructor parameter list.
2726             tree.params = tree.params.appendList(fvdefs);
2727             if (currentClass.hasOuterInstance()) {
2728                 tree.params = tree.params.prepend(otdef);
2729             }
2730 
2731             // If this is an initial constructor, i.e., it does not start with
2732             // this(...), insert initializers for this$n and proxies
2733             // before (pre-1.4, after) the call to superclass constructor.
2734             JCStatement selfCall = translate(tree.body.stats.head);
2735 
2736             List<JCStatement> added = List.nil();
2737             if (fvs.nonEmpty()) {
2738                 List<Type> addedargtypes = List.nil();
2739                 for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail) {
2740                     m.capturedLocals =
2741                         m.capturedLocals.prepend((VarSymbol)
2742                                                 (proxies.get(l.head)));
2743                     if (TreeInfo.isInitialConstructor(tree)) {
2744                         added = added.prepend(
2745                           initField(tree.body.pos, proxies.get(l.head), prevProxies.get(l.head)));
2746                     }
2747                     addedargtypes = addedargtypes.prepend(l.head.erasure(types));
2748                 }
2749                 Type olderasure = m.erasure(types);
2750                 m.erasure_field = new MethodType(
2751                     olderasure.getParameterTypes().appendList(addedargtypes),
2752                     olderasure.getReturnType(),
2753                     olderasure.getThrownTypes(),
2754                     syms.methodClass);
2755             }
2756 
2757             // pop local variables from proxy stack
2758             proxies = prevProxies;
2759 
2760             // recursively translate following local statements and
2761             // combine with this- or super-call
2762             List<JCStatement> stats = translate(tree.body.stats.tail);
2763             tree.body.stats = stats.prepend(selfCall).prependList(added);
2764             outerThisStack = prevOuterThisStack;
2765         } else {
2766             Map<Symbol, Symbol> prevLambdaTranslationMap =
2767                     lambdaTranslationMap;
2768             try {
2769                 lambdaTranslationMap = (tree.sym.flags() & SYNTHETIC) != 0 &&
2770                         tree.sym.name.startsWith(names.lambda) ?
2771                         makeTranslationMap(tree) : null;
2772                 super.visitMethodDef(tree);
2773             } finally {
2774                 lambdaTranslationMap = prevLambdaTranslationMap;
2775             }
2776         }
2777         if (tree.name == names.init && (tree.sym.flags_field & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0) {
2778             // lets find out if there is any field waiting to be initialized
2779             ListBuffer<VarSymbol> fields = new ListBuffer<>();
2780             for (Symbol sym : currentClass.getEnclosedElements()) {
2781                 if (sym.kind == Kinds.Kind.VAR && ((sym.flags() & RECORD) != 0))
2782                     fields.append((VarSymbol) sym);
2783             }
2784             for (VarSymbol field: fields) {
2785                 if ((field.flags_field & Flags.UNINITIALIZED_FIELD) != 0) {
2786                     VarSymbol param = tree.params.stream().filter(p -> p.name == field.name).findFirst().get().sym;
2787                     make.at(tree.pos);
2788                     tree.body.stats = tree.body.stats.append(
2789                             make.Exec(
2790                                     make.Assign(
2791                                             make.Select(make.This(field.owner.erasure(types)), field),
2792                                             make.Ident(param)).setType(field.erasure(types))));
2793                     // we don't need the flag at the field anymore
2794                     field.flags_field &= ~Flags.UNINITIALIZED_FIELD;
2795                 }
2796             }
2797         }
2798         result = tree;
2799     }
2800     //where
2801         private Map<Symbol, Symbol> makeTranslationMap(JCMethodDecl tree) {
2802             Map<Symbol, Symbol> translationMap = new HashMap<>();
2803             for (JCVariableDecl vd : tree.params) {
2804                 Symbol p = vd.sym;
2805                 if (p != p.baseSymbol()) {
2806                     translationMap.put(p.baseSymbol(), p);
2807                 }
2808             }
2809             return translationMap;
2810         }
2811 
2812     public void visitTypeCast(JCTypeCast tree) {
2813         tree.clazz = translate(tree.clazz);
2814         if (tree.type.isPrimitive() != tree.expr.type.isPrimitive())
2815             tree.expr = translate(tree.expr, tree.type);
2816         else
2817             tree.expr = translate(tree.expr);
2818         result = tree;
2819     }
2820 
2821     public void visitNewClass(JCNewClass tree) {
2822         ClassSymbol c = (ClassSymbol)tree.constructor.owner;
2823 
2824         // Box arguments, if necessary
2825         boolean isEnum = (tree.constructor.owner.flags() & ENUM) != 0;
2826         List<Type> argTypes = tree.constructor.type.getParameterTypes();
2827         if (isEnum) argTypes = argTypes.prepend(syms.intType).prepend(syms.stringType);
2828         tree.args = boxArgs(argTypes, tree.args, tree.varargsElement);
2829         tree.varargsElement = null;
2830 
2831         // If created class is local, add free variables after
2832         // explicit constructor arguments.
2833         if (c.isDirectlyOrIndirectlyLocal()) {
2834             tree.args = tree.args.appendList(loadFreevars(tree.pos(), freevars(c)));
2835         }
2836 
2837         // If an access constructor is used, append null as a last argument.
2838         Symbol constructor = accessConstructor(tree.pos(), tree.constructor);
2839         if (constructor != tree.constructor) {
2840             tree.args = tree.args.append(makeNull());
2841             tree.constructor = constructor;
2842         }
2843 
2844         // If created class has an outer instance, and new is qualified, pass
2845         // qualifier as first argument. If new is not qualified, pass the
2846         // correct outer instance as first argument.
2847         if (c.hasOuterInstance()) {
2848             JCExpression thisArg;
2849             if (tree.encl != null) {
2850                 thisArg = attr.makeNullCheck(translate(tree.encl));
2851                 thisArg.type = tree.encl.type;
2852             } else if (c.isDirectlyOrIndirectlyLocal()) {
2853                 // local class
2854                 thisArg = makeThis(tree.pos(), c.type.getEnclosingType().tsym);
2855             } else {
2856                 // nested class
2857                 thisArg = makeOwnerThis(tree.pos(), c, false);
2858             }
2859             tree.args = tree.args.prepend(thisArg);
2860         }
2861         tree.encl = null;
2862 
2863         // If we have an anonymous class, create its flat version, rather
2864         // than the class or interface following new.
2865         if (tree.def != null) {
2866             Map<Symbol, Symbol> prevLambdaTranslationMap = lambdaTranslationMap;
2867             try {
2868                 lambdaTranslationMap = null;
2869                 translate(tree.def);
2870             } finally {
2871                 lambdaTranslationMap = prevLambdaTranslationMap;
2872             }
2873 
2874             tree.clazz = access(make_at(tree.clazz.pos()).Ident(tree.def.sym));
2875             tree.def = null;
2876         } else {
2877             tree.clazz = access(c, tree.clazz, enclOp, false);
2878         }
2879         result = tree;
2880     }
2881 
2882     // Simplify conditionals with known constant controlling expressions.
2883     // This allows us to avoid generating supporting declarations for
2884     // the dead code, which will not be eliminated during code generation.
2885     // Note that Flow.isFalse and Flow.isTrue only return true
2886     // for constant expressions in the sense of JLS 15.27, which
2887     // are guaranteed to have no side-effects.  More aggressive
2888     // constant propagation would require that we take care to
2889     // preserve possible side-effects in the condition expression.
2890 
2891     // One common case is equality expressions involving a constant and null.
2892     // Since null is not a constant expression (because null cannot be
2893     // represented in the constant pool), equality checks involving null are
2894     // not captured by Flow.isTrue/isFalse.
2895     // Equality checks involving a constant and null, e.g.
2896     //     "" == null
2897     // are safe to simplify as no side-effects can occur.
2898 
2899     private boolean isTrue(JCTree exp) {
2900         if (exp.type.isTrue())
2901             return true;
2902         Boolean b = expValue(exp);
2903         return b == null ? false : b;
2904     }
2905     private boolean isFalse(JCTree exp) {
2906         if (exp.type.isFalse())
2907             return true;
2908         Boolean b = expValue(exp);
2909         return b == null ? false : !b;
2910     }
2911     /* look for (in)equality relations involving null.
2912      * return true - if expression is always true
2913      *       false - if expression is always false
2914      *        null - if expression cannot be eliminated
2915      */
2916     private Boolean expValue(JCTree exp) {
2917         while (exp.hasTag(PARENS))
2918             exp = ((JCParens)exp).expr;
2919 
2920         boolean eq;
2921         switch (exp.getTag()) {
2922         case EQ: eq = true;  break;
2923         case NE: eq = false; break;
2924         default:
2925             return null;
2926         }
2927 
2928         // we have a JCBinary(EQ|NE)
2929         // check if we have two literals (constants or null)
2930         JCBinary b = (JCBinary)exp;
2931         if (b.lhs.type.hasTag(BOT)) return expValueIsNull(eq, b.rhs);
2932         if (b.rhs.type.hasTag(BOT)) return expValueIsNull(eq, b.lhs);
2933         return null;
2934     }
2935     private Boolean expValueIsNull(boolean eq, JCTree t) {
2936         if (t.type.hasTag(BOT)) return Boolean.valueOf(eq);
2937         if (t.hasTag(LITERAL))  return Boolean.valueOf(!eq);
2938         return null;
2939     }
2940 
2941     /** Visitor method for conditional expressions.
2942      */
2943     @Override
2944     public void visitConditional(JCConditional tree) {
2945         JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
2946         if (isTrue(cond)) {
2947             result = convert(translate(tree.truepart, tree.type), tree.type);
2948             addPrunedInfo(cond);
2949         } else if (isFalse(cond)) {
2950             result = convert(translate(tree.falsepart, tree.type), tree.type);
2951             addPrunedInfo(cond);
2952         } else {
2953             // Condition is not a compile-time constant.
2954             tree.truepart = translate(tree.truepart, tree.type);
2955             tree.falsepart = translate(tree.falsepart, tree.type);
2956             result = tree;
2957         }
2958     }
2959 //where
2960     private JCExpression convert(JCExpression tree, Type pt) {
2961         if (tree.type == pt || tree.type.hasTag(BOT))
2962             return tree;
2963         JCExpression result = make_at(tree.pos()).TypeCast(make.Type(pt), tree);
2964         result.type = (tree.type.constValue() != null) ? cfolder.coerce(tree.type, pt)
2965                                                        : pt;
2966         return result;
2967     }
2968 
2969     /** Visitor method for if statements.
2970      */
2971     public void visitIf(JCIf tree) {
2972         JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
2973         if (isTrue(cond)) {
2974             result = translate(tree.thenpart);
2975             addPrunedInfo(cond);
2976         } else if (isFalse(cond)) {
2977             if (tree.elsepart != null) {
2978                 result = translate(tree.elsepart);
2979             } else {
2980                 result = make.Skip();
2981             }
2982             addPrunedInfo(cond);
2983         } else {
2984             // Condition is not a compile-time constant.
2985             tree.thenpart = translate(tree.thenpart);
2986             tree.elsepart = translate(tree.elsepart);
2987             result = tree;
2988         }
2989     }
2990 
2991     /** Visitor method for assert statements. Translate them away.
2992      */
2993     public void visitAssert(JCAssert tree) {
2994         tree.cond = translate(tree.cond, syms.booleanType);
2995         if (!tree.cond.type.isTrue()) {
2996             JCExpression cond = assertFlagTest(tree.pos());
2997             List<JCExpression> exnArgs = (tree.detail == null) ?
2998                 List.nil() : List.of(translate(tree.detail));
2999             if (!tree.cond.type.isFalse()) {
3000                 cond = makeBinary
3001                     (AND,
3002                      cond,
3003                      makeUnary(NOT, tree.cond));
3004             }
3005             result =
3006                 make.If(cond,
3007                         make_at(tree).
3008                            Throw(makeNewClass(syms.assertionErrorType, exnArgs)),
3009                         null);
3010         } else {
3011             result = make.Skip();
3012         }
3013     }
3014 
3015     public void visitApply(JCMethodInvocation tree) {
3016         Symbol meth = TreeInfo.symbol(tree.meth);
3017         List<Type> argtypes = meth.type.getParameterTypes();
3018         if (meth.name == names.init && meth.owner == syms.enumSym)
3019             argtypes = argtypes.tail.tail;
3020         tree.args = boxArgs(argtypes, tree.args, tree.varargsElement);
3021         tree.varargsElement = null;
3022         Name methName = TreeInfo.name(tree.meth);
3023         if (meth.name==names.init) {
3024             // We are seeing a this(...) or super(...) constructor call.
3025             // If an access constructor is used, append null as a last argument.
3026             Symbol constructor = accessConstructor(tree.pos(), meth);
3027             if (constructor != meth) {
3028                 tree.args = tree.args.append(makeNull());
3029                 TreeInfo.setSymbol(tree.meth, constructor);
3030             }
3031 
3032             // If we are calling a constructor of a local class, add
3033             // free variables after explicit constructor arguments.
3034             ClassSymbol c = (ClassSymbol)constructor.owner;
3035             if (c.isDirectlyOrIndirectlyLocal()) {
3036                 tree.args = tree.args.appendList(loadFreevars(tree.pos(), freevars(c)));
3037             }
3038 
3039             // If we are calling a constructor of an enum class, pass
3040             // along the name and ordinal arguments
3041             if ((c.flags_field&ENUM) != 0 || c.getQualifiedName() == names.java_lang_Enum) {
3042                 List<JCVariableDecl> params = currentMethodDef.params;
3043                 if (currentMethodSym.owner.hasOuterInstance())
3044                     params = params.tail; // drop this$n
3045                 tree.args = tree.args
3046                     .prepend(make_at(tree.pos()).Ident(params.tail.head.sym)) // ordinal
3047                     .prepend(make.Ident(params.head.sym)); // name
3048             }
3049 
3050             // If we are calling a constructor of a class with an outer
3051             // instance, and the call
3052             // is qualified, pass qualifier as first argument in front of
3053             // the explicit constructor arguments. If the call
3054             // is not qualified, pass the correct outer instance as
3055             // first argument.
3056             if (c.hasOuterInstance()) {
3057                 JCExpression thisArg;
3058                 if (tree.meth.hasTag(SELECT)) {
3059                     thisArg = attr.
3060                         makeNullCheck(translate(((JCFieldAccess) tree.meth).selected));
3061                     tree.meth = make.Ident(constructor);
3062                     ((JCIdent) tree.meth).name = methName;
3063                 } else if (c.isDirectlyOrIndirectlyLocal() || methName == names._this){
3064                     // local class or this() call
3065                     thisArg = makeThis(tree.meth.pos(), c.type.getEnclosingType().tsym);
3066                 } else {
3067                     // super() call of nested class - never pick 'this'
3068                     thisArg = makeOwnerThisN(tree.meth.pos(), c, false);
3069                 }
3070                 tree.args = tree.args.prepend(thisArg);
3071             }
3072         } else {
3073             // We are seeing a normal method invocation; translate this as usual.
3074             tree.meth = translate(tree.meth);
3075 
3076             // If the translated method itself is an Apply tree, we are
3077             // seeing an access method invocation. In this case, append
3078             // the method arguments to the arguments of the access method.
3079             if (tree.meth.hasTag(APPLY)) {
3080                 JCMethodInvocation app = (JCMethodInvocation)tree.meth;
3081                 app.args = tree.args.prependList(app.args);
3082                 result = app;
3083                 return;
3084             }
3085         }
3086         result = tree;
3087     }
3088 
3089     List<JCExpression> boxArgs(List<Type> parameters, List<JCExpression> _args, Type varargsElement) {
3090         List<JCExpression> args = _args;
3091         if (parameters.isEmpty()) return args;
3092         boolean anyChanges = false;
3093         ListBuffer<JCExpression> result = new ListBuffer<>();
3094         while (parameters.tail.nonEmpty()) {
3095             JCExpression arg = translate(args.head, parameters.head);
3096             anyChanges |= (arg != args.head);
3097             result.append(arg);
3098             args = args.tail;
3099             parameters = parameters.tail;
3100         }
3101         Type parameter = parameters.head;
3102         if (varargsElement != null) {
3103             anyChanges = true;
3104             ListBuffer<JCExpression> elems = new ListBuffer<>();
3105             while (args.nonEmpty()) {
3106                 JCExpression arg = translate(args.head, varargsElement);
3107                 elems.append(arg);
3108                 args = args.tail;
3109             }
3110             JCNewArray boxedArgs = make.NewArray(make.Type(varargsElement),
3111                                                List.nil(),
3112                                                elems.toList());
3113             boxedArgs.type = new ArrayType(varargsElement, syms.arrayClass);
3114             result.append(boxedArgs);
3115         } else {
3116             if (args.length() != 1) throw new AssertionError(args);
3117             JCExpression arg = translate(args.head, parameter);
3118             anyChanges |= (arg != args.head);
3119             result.append(arg);
3120             if (!anyChanges) return _args;
3121         }
3122         return result.toList();
3123     }
3124 
3125     /** Apply primitive value/reference conversions as needed */
3126     @SuppressWarnings("unchecked")
3127     <T extends JCExpression> T applyPrimitiveConversionsAsNeeded(T tree, Type type) {
3128         boolean haveValue = tree.type.isPrimitiveClass();
3129         if (haveValue == type.isPrimitiveClass())
3130             return tree;
3131         // For narrowing conversion, insert a cast which should trigger a null check
3132         // For widening conversions, insert a cast if emitting a unified class file.
3133         return (T) make.TypeCast(type, tree);
3134 
3135     }
3136 
3137 
3138 
3139     /** Expand a boxing or unboxing conversion if needed. */
3140     @SuppressWarnings("unchecked") // XXX unchecked
3141     <T extends JCExpression> T boxIfNeeded(T tree, Type type) {
3142         boolean havePrimitive = tree.type.isPrimitive();
3143         if (havePrimitive == type.isPrimitive())
3144             return tree;
3145         if (havePrimitive) {
3146             Type unboxedTarget = types.unboxedType(type);
3147             if (!unboxedTarget.hasTag(NONE)) {
3148                 if (!types.isSubtype(tree.type, unboxedTarget)) //e.g. Character c = 89;
3149                     tree.type = unboxedTarget.constType(tree.type.constValue());
3150                 return (T)boxPrimitive(tree, types.erasure(type));
3151             } else {
3152                 tree = (T)boxPrimitive(tree);
3153             }
3154         } else {
3155             tree = (T)unbox(tree, type);
3156         }
3157         return tree;
3158     }
3159 
3160     /** Box up a single primitive expression. */
3161     JCExpression boxPrimitive(JCExpression tree) {
3162         return boxPrimitive(tree, types.boxedClass(tree.type).type);
3163     }
3164 
3165     /** Box up a single primitive expression. */
3166     JCExpression boxPrimitive(JCExpression tree, Type box) {
3167         make_at(tree.pos());
3168         Symbol valueOfSym = lookupMethod(tree.pos(),
3169                                          names.valueOf,
3170                                          box,
3171                                          List.<Type>nil()
3172                                          .prepend(tree.type));
3173         return make.App(make.QualIdent(valueOfSym), List.of(tree));
3174     }
3175 
3176     /** Unbox an object to a primitive value. */
3177     JCExpression unbox(JCExpression tree, Type primitive) {
3178         Type unboxedType = types.unboxedType(tree.type);
3179         if (unboxedType.hasTag(NONE)) {
3180             unboxedType = primitive;
3181             if (!unboxedType.isPrimitive())
3182                 throw new AssertionError(unboxedType);
3183             make_at(tree.pos());
3184             tree = make.TypeCast(types.boxedClass(unboxedType).type, tree);
3185         } else {
3186             // There must be a conversion from unboxedType to primitive.
3187             if (!types.isSubtype(unboxedType, primitive))
3188                 throw new AssertionError(tree);
3189         }
3190         make_at(tree.pos());
3191         Symbol valueSym = lookupMethod(tree.pos(),
3192                                        unboxedType.tsym.name.append(names.Value), // x.intValue()
3193                                        tree.type,
3194                                        List.nil());
3195         return make.App(make.Select(tree, valueSym));
3196     }
3197 
3198     /** Visitor method for parenthesized expressions.
3199      *  If the subexpression has changed, omit the parens.
3200      */
3201     public void visitParens(JCParens tree) {
3202         JCTree expr = translate(tree.expr);
3203         result = ((expr == tree.expr) ? tree : expr);
3204     }
3205 
3206     public void visitIndexed(JCArrayAccess tree) {
3207         tree.indexed = translate(tree.indexed);
3208         tree.index = translate(tree.index, syms.intType);
3209         result = tree;
3210     }
3211 
3212     public void visitAssign(JCAssign tree) {
3213         tree.lhs = translate(tree.lhs, tree);
3214         tree.rhs = translate(tree.rhs, tree.lhs.type);
3215 
3216         // If translated left hand side is an Apply, we are
3217         // seeing an access method invocation. In this case, append
3218         // right hand side as last argument of the access method.
3219         if (tree.lhs.hasTag(APPLY)) {
3220             JCMethodInvocation app = (JCMethodInvocation)tree.lhs;
3221             app.args = List.of(tree.rhs).prependList(app.args);
3222             result = app;
3223         } else {
3224             result = tree;
3225         }
3226     }
3227 
3228     public void visitAssignop(final JCAssignOp tree) {
3229         final boolean boxingReq = !tree.lhs.type.isPrimitive() &&
3230             tree.operator.type.getReturnType().isPrimitive();
3231 
3232         AssignopDependencyScanner depScanner = new AssignopDependencyScanner(tree);
3233         depScanner.scan(tree.rhs);
3234 
3235         if (boxingReq || depScanner.dependencyFound) {
3236             // boxing required; need to rewrite as x = (unbox typeof x)(x op y);
3237             // or if x == (typeof x)z then z = (unbox typeof x)((typeof x)z op y)
3238             // (but without recomputing x)
3239             JCTree newTree = abstractLval(tree.lhs, lhs -> {
3240                 Tag newTag = tree.getTag().noAssignOp();
3241                 // Erasure (TransTypes) can change the type of
3242                 // tree.lhs.  However, we can still get the
3243                 // unerased type of tree.lhs as it is stored
3244                 // in tree.type in Attr.
3245                 OperatorSymbol newOperator = operators.resolveBinary(tree,
3246                                                               newTag,
3247                                                               tree.type,
3248                                                               tree.rhs.type);
3249                 //Need to use the "lhs" at two places, once on the future left hand side
3250                 //and once in the future binary operator. But further processing may change
3251                 //the components of the tree in place (see visitSelect for e.g. <Class>.super.<ident>),
3252                 //so cloning the tree to avoid interference between the uses:
3253                 JCExpression expr = (JCExpression) lhs.clone();
3254                 if (expr.type != tree.type)
3255                     expr = make.TypeCast(tree.type, expr);
3256                 JCBinary opResult = make.Binary(newTag, expr, tree.rhs);
3257                 opResult.operator = newOperator;
3258                 opResult.type = newOperator.type.getReturnType();
3259                 JCExpression newRhs = boxingReq ?
3260                     make.TypeCast(types.unboxedType(tree.type), opResult) :
3261                     opResult;
3262                 return make.Assign(lhs, newRhs).setType(tree.type);
3263             });
3264             result = translate(newTree);
3265             return;
3266         }
3267         tree.lhs = translate(tree.lhs, tree);
3268         tree.rhs = translate(tree.rhs, tree.operator.type.getParameterTypes().tail.head);
3269 
3270         // If translated left hand side is an Apply, we are
3271         // seeing an access method invocation. In this case, append
3272         // right hand side as last argument of the access method.
3273         if (tree.lhs.hasTag(APPLY)) {
3274             JCMethodInvocation app = (JCMethodInvocation)tree.lhs;
3275             // if operation is a += on strings,
3276             // make sure to convert argument to string
3277             JCExpression rhs = tree.operator.opcode == string_add
3278               ? makeString(tree.rhs)
3279               : tree.rhs;
3280             app.args = List.of(rhs).prependList(app.args);
3281             result = app;
3282         } else {
3283             result = tree;
3284         }
3285     }
3286 
3287     class AssignopDependencyScanner extends TreeScanner {
3288 
3289         Symbol sym;
3290         boolean dependencyFound = false;
3291 
3292         AssignopDependencyScanner(JCAssignOp tree) {
3293             this.sym = TreeInfo.symbol(tree.lhs);
3294         }
3295 
3296         @Override
3297         public void scan(JCTree tree) {
3298             if (tree != null && sym != null) {
3299                 tree.accept(this);
3300             }
3301         }
3302 
3303         @Override
3304         public void visitAssignop(JCAssignOp tree) {
3305             if (TreeInfo.symbol(tree.lhs) == sym) {
3306                 dependencyFound = true;
3307                 return;
3308             }
3309             super.visitAssignop(tree);
3310         }
3311 
3312         @Override
3313         public void visitUnary(JCUnary tree) {
3314             if (TreeInfo.symbol(tree.arg) == sym) {
3315                 dependencyFound = true;
3316                 return;
3317             }
3318             super.visitUnary(tree);
3319         }
3320     }
3321 
3322     /** Lower a tree of the form e++ or e-- where e is an object type */
3323     JCExpression lowerBoxedPostop(final JCUnary tree) {
3324         // translate to tmp1=lval(e); tmp2=tmp1; tmp1 OP 1; tmp2
3325         // or
3326         // translate to tmp1=lval(e); tmp2=tmp1; (typeof tree)tmp1 OP 1; tmp2
3327         // where OP is += or -=
3328         final boolean cast = TreeInfo.skipParens(tree.arg).hasTag(TYPECAST);
3329         return abstractLval(tree.arg, tmp1 -> abstractRval(tmp1, tree.arg.type, tmp2 -> {
3330             Tag opcode = (tree.hasTag(POSTINC))
3331                 ? PLUS_ASG : MINUS_ASG;
3332             //"tmp1" and "tmp2" may refer to the same instance
3333             //(for e.g. <Class>.super.<ident>). But further processing may
3334             //change the components of the tree in place (see visitSelect),
3335             //so cloning the tree to avoid interference between the two uses:
3336             JCExpression lhs = (JCExpression)tmp1.clone();
3337             lhs = cast
3338                 ? make.TypeCast(tree.arg.type, lhs)
3339                 : lhs;
3340             JCExpression update = makeAssignop(opcode,
3341                                          lhs,
3342                                          make.Literal(1));
3343             return makeComma(update, tmp2);
3344         }));
3345     }
3346 
3347     public void visitUnary(JCUnary tree) {
3348         boolean isUpdateOperator = tree.getTag().isIncOrDecUnaryOp();
3349         if (isUpdateOperator && !tree.arg.type.isPrimitive()) {
3350             switch(tree.getTag()) {
3351             case PREINC:            // ++ e
3352                     // translate to e += 1
3353             case PREDEC:            // -- e
3354                     // translate to e -= 1
3355                 {
3356                     JCTree.Tag opcode = (tree.hasTag(PREINC))
3357                         ? PLUS_ASG : MINUS_ASG;
3358                     JCAssignOp newTree = makeAssignop(opcode,
3359                                                     tree.arg,
3360                                                     make.Literal(1));
3361                     result = translate(newTree, tree.type);
3362                     return;
3363                 }
3364             case POSTINC:           // e ++
3365             case POSTDEC:           // e --
3366                 {
3367                     result = translate(lowerBoxedPostop(tree), tree.type);
3368                     return;
3369                 }
3370             }
3371             throw new AssertionError(tree);
3372         }
3373 
3374         tree.arg = boxIfNeeded(translate(tree.arg, tree), tree.type);
3375 
3376         if (tree.hasTag(NOT) && tree.arg.type.constValue() != null) {
3377             tree.type = cfolder.fold1(bool_not, tree.arg.type);
3378         }
3379 
3380         // If translated left hand side is an Apply, we are
3381         // seeing an access method invocation. In this case, return
3382         // that access method invocation as result.
3383         if (isUpdateOperator && tree.arg.hasTag(APPLY)) {
3384             result = tree.arg;
3385         } else {
3386             result = tree;
3387         }
3388     }
3389 
3390     public void visitBinary(JCBinary tree) {
3391         List<Type> formals = tree.operator.type.getParameterTypes();
3392         JCTree lhs = tree.lhs = translate(tree.lhs, formals.head);
3393         switch (tree.getTag()) {
3394         case OR:
3395             if (isTrue(lhs)) {
3396                 result = lhs;
3397                 return;
3398             }
3399             if (isFalse(lhs)) {
3400                 result = translate(tree.rhs, formals.tail.head);
3401                 return;
3402             }
3403             break;
3404         case AND:
3405             if (isFalse(lhs)) {
3406                 result = lhs;
3407                 return;
3408             }
3409             if (isTrue(lhs)) {
3410                 result = translate(tree.rhs, formals.tail.head);
3411                 return;
3412             }
3413             break;
3414         }
3415         tree.rhs = translate(tree.rhs, formals.tail.head);
3416         result = tree;
3417     }
3418 
3419     public void visitIdent(JCIdent tree) {
3420         result = access(tree.sym, tree, enclOp, false);
3421     }
3422 
3423     /** Translate away the foreach loop.  */
3424     public void visitForeachLoop(JCEnhancedForLoop tree) {
3425         if (types.elemtype(tree.expr.type) == null)
3426             visitIterableForeachLoop(tree);
3427         else
3428             visitArrayForeachLoop(tree);
3429     }
3430         // where
3431         /**
3432          * A statement of the form
3433          *
3434          * <pre>
3435          *     for ( T v : arrayexpr ) stmt;
3436          * </pre>
3437          *
3438          * (where arrayexpr is of an array type) gets translated to
3439          *
3440          * <pre>{@code
3441          *     for ( { arraytype #arr = arrayexpr;
3442          *             int #len = array.length;
3443          *             int #i = 0; };
3444          *           #i < #len; i$++ ) {
3445          *         T v = arr$[#i];
3446          *         stmt;
3447          *     }
3448          * }</pre>
3449          *
3450          * where #arr, #len, and #i are freshly named synthetic local variables.
3451          */
3452         private void visitArrayForeachLoop(JCEnhancedForLoop tree) {
3453             make_at(tree.expr.pos());
3454             VarSymbol arraycache = new VarSymbol(SYNTHETIC,
3455                                                  names.fromString("arr" + target.syntheticNameChar()),
3456                                                  tree.expr.type,
3457                                                  currentMethodSym);
3458             JCStatement arraycachedef = make.VarDef(arraycache, tree.expr);
3459             VarSymbol lencache = new VarSymbol(SYNTHETIC,
3460                                                names.fromString("len" + target.syntheticNameChar()),
3461                                                syms.intType,
3462                                                currentMethodSym);
3463             JCStatement lencachedef = make.
3464                 VarDef(lencache, make.Select(make.Ident(arraycache), syms.lengthVar));
3465             VarSymbol index = new VarSymbol(SYNTHETIC,
3466                                             names.fromString("i" + target.syntheticNameChar()),
3467                                             syms.intType,
3468                                             currentMethodSym);
3469 
3470             JCVariableDecl indexdef = make.VarDef(index, make.Literal(INT, 0));
3471             indexdef.init.type = indexdef.type = syms.intType.constType(0);
3472 
3473             List<JCStatement> loopinit = List.of(arraycachedef, lencachedef, indexdef);
3474             JCBinary cond = makeBinary(LT, make.Ident(index), make.Ident(lencache));
3475 
3476             JCExpressionStatement step = make.Exec(makeUnary(PREINC, make.Ident(index)));
3477 
3478             Type elemtype = types.elemtype(tree.expr.type);
3479             JCExpression loopvarinit = make.Indexed(make.Ident(arraycache),
3480                                                     make.Ident(index)).setType(elemtype);
3481             JCVariableDecl loopvardef = (JCVariableDecl)make.VarDef(tree.var.mods,
3482                                                   tree.var.name,
3483                                                   tree.var.vartype,
3484                                                   loopvarinit).setType(tree.var.type);
3485             loopvardef.sym = tree.var.sym;
3486             JCBlock body = make.
3487                 Block(0, List.of(loopvardef, tree.body));
3488 
3489             result = translate(make.
3490                                ForLoop(loopinit,
3491                                        cond,
3492                                        List.of(step),
3493                                        body));
3494             patchTargets(body, tree, result);
3495         }
3496         /** Patch up break and continue targets. */
3497         private void patchTargets(JCTree body, final JCTree src, final JCTree dest) {
3498             class Patcher extends TreeScanner {
3499                 public void visitBreak(JCBreak tree) {
3500                     if (tree.target == src)
3501                         tree.target = dest;
3502                 }
3503                 public void visitYield(JCYield tree) {
3504                     if (tree.target == src)
3505                         tree.target = dest;
3506                     scan(tree.value);
3507                 }
3508                 public void visitContinue(JCContinue tree) {
3509                     if (tree.target == src)
3510                         tree.target = dest;
3511                 }
3512                 public void visitClassDef(JCClassDecl tree) {}
3513             }
3514             new Patcher().scan(body);
3515         }
3516         /**
3517          * A statement of the form
3518          *
3519          * <pre>
3520          *     for ( T v : coll ) stmt ;
3521          * </pre>
3522          *
3523          * (where coll implements {@code Iterable<? extends T>}) gets translated to
3524          *
3525          * <pre>{@code
3526          *     for ( Iterator<? extends T> #i = coll.iterator(); #i.hasNext(); ) {
3527          *         T v = (T) #i.next();
3528          *         stmt;
3529          *     }
3530          * }</pre>
3531          *
3532          * where #i is a freshly named synthetic local variable.
3533          */
3534         private void visitIterableForeachLoop(JCEnhancedForLoop tree) {
3535             make_at(tree.expr.pos());
3536             Type iteratorTarget = syms.objectType;
3537             Type iterableType = types.asSuper(types.cvarUpperBound(tree.expr.type.referenceProjectionOrSelf()),
3538                                               syms.iterableType.tsym);
3539             if (iterableType.getTypeArguments().nonEmpty())
3540                 iteratorTarget = types.erasure(iterableType.getTypeArguments().head);
3541             Type eType = types.skipTypeVars(tree.expr.type, false);
3542             tree.expr.type = types.erasure(eType);
3543             if (eType.isCompound())
3544                 tree.expr = make.TypeCast(types.erasure(iterableType), tree.expr);
3545             Symbol iterator = lookupMethod(tree.expr.pos(),
3546                                            names.iterator,
3547                                            eType,
3548                                            List.nil());
3549             VarSymbol itvar = new VarSymbol(SYNTHETIC, names.fromString("i" + target.syntheticNameChar()),
3550                                             types.erasure(types.asSuper(iterator.type.getReturnType().referenceProjectionOrSelf(), syms.iteratorType.tsym)),
3551                                             currentMethodSym);
3552 
3553              JCStatement init = make.
3554                 VarDef(itvar, make.App(make.Select(tree.expr, iterator)
3555                      .setType(types.erasure(iterator.type))));
3556 
3557             Symbol hasNext = lookupMethod(tree.expr.pos(),
3558                                           names.hasNext,
3559                                           itvar.type,
3560                                           List.nil());
3561             JCMethodInvocation cond = make.App(make.Select(make.Ident(itvar), hasNext));
3562             Symbol next = lookupMethod(tree.expr.pos(),
3563                                        names.next,
3564                                        itvar.type,
3565                                        List.nil());
3566             JCExpression vardefinit = make.App(make.Select(make.Ident(itvar), next));
3567             if (tree.var.type.isPrimitive())
3568                 vardefinit = make.TypeCast(types.cvarUpperBound(iteratorTarget), vardefinit);
3569             else
3570                 vardefinit = make.TypeCast(tree.var.type, vardefinit);
3571             JCVariableDecl indexDef = (JCVariableDecl)make.VarDef(tree.var.mods,
3572                                                   tree.var.name,
3573                                                   tree.var.vartype,
3574                                                   vardefinit).setType(tree.var.type);
3575             indexDef.sym = tree.var.sym;
3576             JCBlock body = make.Block(0, List.of(indexDef, tree.body));
3577             body.endpos = TreeInfo.endPos(tree.body);
3578             result = translate(make.
3579                 ForLoop(List.of(init),
3580                         cond,
3581                         List.nil(),
3582                         body));
3583             patchTargets(body, tree, result);
3584         }
3585 
3586     public void visitVarDef(JCVariableDecl tree) {
3587         MethodSymbol oldMethodSym = currentMethodSym;
3588         tree.mods = translate(tree.mods);
3589         tree.vartype = translate(tree.vartype);
3590         if (currentMethodSym == null) {
3591             // A class or instance field initializer.
3592             currentMethodSym =
3593                 new MethodSymbol((tree.mods.flags&STATIC) | BLOCK,
3594                                  names.empty, null,
3595                                  currentClass);
3596         }
3597         if (tree.init != null) tree.init = translate(tree.init, tree.type);
3598         result = tree;
3599         currentMethodSym = oldMethodSym;
3600     }
3601 
3602     public void visitBlock(JCBlock tree) {
3603         MethodSymbol oldMethodSym = currentMethodSym;
3604         if (currentMethodSym == null) {
3605             // Block is a static or instance initializer.
3606             currentMethodSym =
3607                 new MethodSymbol(tree.flags | BLOCK,
3608                                  names.empty, null,
3609                                  currentClass);
3610         }
3611         super.visitBlock(tree);
3612         currentMethodSym = oldMethodSym;
3613     }
3614 
3615     public void visitDoLoop(JCDoWhileLoop tree) {
3616         tree.body = translate(tree.body);
3617         tree.cond = translate(tree.cond, syms.booleanType);
3618         result = tree;
3619     }
3620 
3621     public void visitWhileLoop(JCWhileLoop tree) {
3622         tree.cond = translate(tree.cond, syms.booleanType);
3623         tree.body = translate(tree.body);
3624         result = tree;
3625     }
3626 
3627     public void visitWithField(JCWithField tree) {
3628         Type fieldType = tree.field.type;
3629         tree.field = translate(tree.field, tree);
3630         tree.value = translate(tree.value, fieldType); // important to use pre-translation type.
3631 
3632         // If translated field is an Apply, we are
3633         // seeing an access method invocation. In this case, append
3634         // right hand side as last argument of the access method.
3635         if (tree.field.hasTag(APPLY)) {
3636             JCMethodInvocation app = (JCMethodInvocation) tree.field;
3637             app.args = List.of(tree.value).prependList(app.args);
3638             result = app;
3639         } else {
3640             result = tree;
3641         }
3642     }
3643 
3644     public void visitForLoop(JCForLoop tree) {
3645         tree.init = translate(tree.init);
3646         if (tree.cond != null)
3647             tree.cond = translate(tree.cond, syms.booleanType);
3648         tree.step = translate(tree.step);
3649         tree.body = translate(tree.body);
3650         result = tree;
3651     }
3652 
3653     public void visitReturn(JCReturn tree) {
3654         if (tree.expr != null)
3655             tree.expr = translate(tree.expr,
3656                                   types.erasure(currentMethodDef
3657                                                 .restype.type));
3658         result = tree;
3659     }
3660 
3661     public void visitSwitch(JCSwitch tree) {
3662         List<JCCase> cases = tree.patternSwitch ? addDefaultIfNeeded(tree.cases) : tree.cases;
3663         handleSwitch(tree, tree.selector, cases);
3664     }
3665 
3666     @Override
3667     public void visitSwitchExpression(JCSwitchExpression tree) {
3668         List<JCCase> cases = addDefaultIfNeeded(tree.cases);
3669         handleSwitch(tree, tree.selector, cases);
3670     }
3671 
3672     private List<JCCase> addDefaultIfNeeded(List<JCCase> cases) {
3673         if (cases.stream().flatMap(c -> c.labels.stream()).noneMatch(p -> p.hasTag(Tag.DEFAULTCASELABEL))) {
3674             JCThrow thr = make.Throw(makeNewClass(syms.incompatibleClassChangeErrorType,
3675                                                   List.nil()));
3676             JCCase c = make.Case(JCCase.STATEMENT, List.of(make.DefaultCaseLabel()), List.of(thr), null);
3677             cases = cases.prepend(c);
3678         }
3679 
3680         return cases;
3681     }
3682 
3683     private void handleSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {
3684         //expand multiple label cases:
3685         ListBuffer<JCCase> convertedCases = new ListBuffer<>();
3686 
3687         for (JCCase c : cases) {
3688             switch (c.labels.size()) {
3689                 case 0: //default
3690                 case 1: //single label
3691                     convertedCases.append(c);
3692                     break;
3693                 default: //multiple labels, expand:
3694                     //case C1, C2, C3: ...
3695                     //=>
3696                     //case C1:
3697                     //case C2:
3698                     //case C3: ...
3699                     List<JCCaseLabel> patterns = c.labels;
3700                     while (patterns.tail.nonEmpty()) {
3701                         convertedCases.append(make_at(c.pos()).Case(JCCase.STATEMENT,
3702                                                            List.of(patterns.head),
3703                                                            List.nil(),
3704                                                            null));
3705                         patterns = patterns.tail;
3706                     }
3707                     c.labels = patterns;
3708                     convertedCases.append(c);
3709                     break;
3710             }
3711         }
3712 
3713         for (JCCase c : convertedCases) {
3714             if (c.caseKind == JCCase.RULE && c.completesNormally) {
3715                 JCBreak b = make.at(TreeInfo.endPos(c.stats.last())).Break(null);
3716                 b.target = tree;
3717                 c.stats = c.stats.append(b);
3718             }
3719         }
3720 
3721         cases = convertedCases.toList();
3722 
3723         Type selsuper = types.supertype(selector.type);
3724         boolean enumSwitch = selsuper != null &&
3725             (selector.type.tsym.flags() & ENUM) != 0;
3726         boolean stringSwitch = selsuper != null &&
3727             types.isSameType(selector.type, syms.stringType);
3728         boolean boxedSwitch = !enumSwitch && !stringSwitch && !selector.type.isPrimitive();
3729         selector = translate(selector, selector.type);
3730         cases = translateCases(cases);
3731         if (tree.hasTag(SWITCH)) {
3732             ((JCSwitch) tree).selector = selector;
3733             ((JCSwitch) tree).cases = cases;
3734         } else if (tree.hasTag(SWITCH_EXPRESSION)) {
3735             ((JCSwitchExpression) tree).selector = selector;
3736             ((JCSwitchExpression) tree).cases = cases;
3737         } else {
3738             Assert.error();
3739         }
3740         if (enumSwitch) {
3741             result = visitEnumSwitch(tree, selector, cases);
3742         } else if (stringSwitch) {
3743             result = visitStringSwitch(tree, selector, cases);
3744         } else if (boxedSwitch) {
3745             //An switch over boxed primitive. Pattern matching switches are already translated
3746             //by TransPatterns, so all non-primitive types are only boxed primitives:
3747             result = visitBoxedPrimitiveSwitch(tree, selector, cases);
3748         } else {
3749             result = tree;
3750         }
3751     }
3752 
3753     public JCTree visitEnumSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {
3754         TypeSymbol enumSym = selector.type.tsym;
3755         EnumMapping map = mapForEnum(tree.pos(), enumSym);
3756         make_at(tree.pos());
3757         Symbol ordinalMethod = lookupMethod(tree.pos(),
3758                                             names.ordinal,
3759                                             selector.type,
3760                                             List.nil());
3761         JCExpression newSelector;
3762 
3763         if (cases.stream().anyMatch(c -> TreeInfo.isNull(c.labels.head))) {
3764             //for enum switches with case null, do:
3765             //switch ($selector != null ? $mapVar[$selector.ordinal()] : -1) {...}
3766             //replacing case null with case -1:
3767             VarSymbol dollar_s = new VarSymbol(FINAL|SYNTHETIC,
3768                                                names.fromString("s" + tree.pos + this.target.syntheticNameChar()),
3769                                                selector.type,
3770                                                currentMethodSym);
3771             JCStatement var = make.at(tree.pos()).VarDef(dollar_s, selector).setType(dollar_s.type);
3772             newSelector = make.Indexed(map.mapVar,
3773                     make.App(make.Select(make.Ident(dollar_s),
3774                             ordinalMethod)));
3775             newSelector =
3776                     make.LetExpr(List.of(var),
3777                                  make.Conditional(makeBinary(NE, make.Ident(dollar_s), makeNull()),
3778                                                   newSelector,
3779                                                   makeLit(syms.intType, -1))
3780                                      .setType(newSelector.type))
3781                         .setType(newSelector.type);
3782         } else {
3783             newSelector = make.Indexed(map.mapVar,
3784                     make.App(make.Select(selector,
3785                             ordinalMethod)));
3786         }
3787         ListBuffer<JCCase> newCases = new ListBuffer<>();
3788         for (JCCase c : cases) {
3789             if (c.labels.head.isExpression()) {
3790                 JCExpression pat;
3791                 if (TreeInfo.isNull(c.labels.head)) {
3792                     pat = makeLit(syms.intType, -1);
3793                 } else {
3794                     VarSymbol label = (VarSymbol)TreeInfo.symbol((JCExpression) c.labels.head);
3795                     pat = map.forConstant(label);
3796                 }
3797                 newCases.append(make.Case(JCCase.STATEMENT, List.of(pat), c.stats, null));
3798             } else {
3799                 newCases.append(c);
3800             }
3801         }
3802         JCTree enumSwitch;
3803         if (tree.hasTag(SWITCH)) {
3804             enumSwitch = make.Switch(newSelector, newCases.toList());
3805         } else if (tree.hasTag(SWITCH_EXPRESSION)) {
3806             enumSwitch = make.SwitchExpression(newSelector, newCases.toList());
3807             enumSwitch.setType(tree.type);
3808         } else {
3809             Assert.error();
3810             throw new AssertionError();
3811         }
3812         patchTargets(enumSwitch, tree, enumSwitch);
3813         return enumSwitch;
3814     }
3815 
3816     public JCTree visitStringSwitch(JCTree tree, JCExpression selector, List<JCCase> caseList) {
3817         int alternatives = caseList.size();
3818 
3819         if (alternatives == 0) { // Strange but legal possibility (only legal for switch statement)
3820             return make.at(tree.pos()).Exec(attr.makeNullCheck(selector));
3821         } else {
3822             /*
3823              * The general approach used is to translate a single
3824              * string switch statement into a series of two chained
3825              * switch statements: the first a synthesized statement
3826              * switching on the argument string's hash value and
3827              * computing a string's position in the list of original
3828              * case labels, if any, followed by a second switch on the
3829              * computed integer value.  The second switch has the same
3830              * code structure as the original string switch statement
3831              * except that the string case labels are replaced with
3832              * positional integer constants starting at 0.
3833              *
3834              * The first switch statement can be thought of as an
3835              * inlined map from strings to their position in the case
3836              * label list.  An alternate implementation would use an
3837              * actual Map for this purpose, as done for enum switches.
3838              *
3839              * With some additional effort, it would be possible to
3840              * use a single switch statement on the hash code of the
3841              * argument, but care would need to be taken to preserve
3842              * the proper control flow in the presence of hash
3843              * collisions and other complications, such as
3844              * fallthroughs.  Switch statements with one or two
3845              * alternatives could also be specially translated into
3846              * if-then statements to omit the computation of the hash
3847              * code.
3848              *
3849              * The generated code assumes that the hashing algorithm
3850              * of String is the same in the compilation environment as
3851              * in the environment the code will run in.  The string
3852              * hashing algorithm in the SE JDK has been unchanged
3853              * since at least JDK 1.2.  Since the algorithm has been
3854              * specified since that release as well, it is very
3855              * unlikely to be changed in the future.
3856              *
3857              * Different hashing algorithms, such as the length of the
3858              * strings or a perfect hashing algorithm over the
3859              * particular set of case labels, could potentially be
3860              * used instead of String.hashCode.
3861              */
3862 
3863             ListBuffer<JCStatement> stmtList = new ListBuffer<>();
3864 
3865             // Map from String case labels to their original position in
3866             // the list of case labels.
3867             Map<String, Integer> caseLabelToPosition = new LinkedHashMap<>(alternatives + 1, 1.0f);
3868 
3869             // Map of hash codes to the string case labels having that hashCode.
3870             Map<Integer, Set<String>> hashToString = new LinkedHashMap<>(alternatives + 1, 1.0f);
3871 
3872             int casePosition = 0;
3873             JCCase nullCase = null;
3874             int nullCaseLabel = -1;
3875 
3876             for(JCCase oneCase : caseList) {
3877                 if (oneCase.labels.head.isExpression()) {
3878                     if (TreeInfo.isNull(oneCase.labels.head)) {
3879                         nullCase = oneCase;
3880                         nullCaseLabel = casePosition;
3881                     } else {
3882                         JCExpression expression = (JCExpression) oneCase.labels.head;
3883                         String labelExpr = (String) expression.type.constValue();
3884                         Integer mapping = caseLabelToPosition.put(labelExpr, casePosition);
3885                         Assert.checkNull(mapping);
3886                         int hashCode = labelExpr.hashCode();
3887 
3888                         Set<String> stringSet = hashToString.get(hashCode);
3889                         if (stringSet == null) {
3890                             stringSet = new LinkedHashSet<>(1, 1.0f);
3891                             stringSet.add(labelExpr);
3892                             hashToString.put(hashCode, stringSet);
3893                         } else {
3894                             boolean added = stringSet.add(labelExpr);
3895                             Assert.check(added);
3896                         }
3897                     }
3898                 }
3899                 casePosition++;
3900             }
3901 
3902             // Synthesize a switch statement that has the effect of
3903             // mapping from a string to the integer position of that
3904             // string in the list of case labels.  This is done by
3905             // switching on the hashCode of the string followed by an
3906             // if-then-else chain comparing the input for equality
3907             // with all the case labels having that hash value.
3908 
3909             /*
3910              * s$ = top of stack;
3911              * tmp$ = -1;
3912              * switch($s.hashCode()) {
3913              *     case caseLabel.hashCode:
3914              *         if (s$.equals("caseLabel_1")
3915              *           tmp$ = caseLabelToPosition("caseLabel_1");
3916              *         else if (s$.equals("caseLabel_2"))
3917              *           tmp$ = caseLabelToPosition("caseLabel_2");
3918              *         ...
3919              *         break;
3920              * ...
3921              * }
3922              */
3923 
3924             VarSymbol dollar_s = new VarSymbol(FINAL|SYNTHETIC,
3925                                                names.fromString("s" + tree.pos + target.syntheticNameChar()),
3926                                                syms.stringType,
3927                                                currentMethodSym);
3928             stmtList.append(make.at(tree.pos()).VarDef(dollar_s, selector).setType(dollar_s.type));
3929 
3930             VarSymbol dollar_tmp = new VarSymbol(SYNTHETIC,
3931                                                  names.fromString("tmp" + tree.pos + target.syntheticNameChar()),
3932                                                  syms.intType,
3933                                                  currentMethodSym);
3934             JCVariableDecl dollar_tmp_def =
3935                 (JCVariableDecl)make.VarDef(dollar_tmp, make.Literal(INT, -1)).setType(dollar_tmp.type);
3936             dollar_tmp_def.init.type = dollar_tmp.type = syms.intType;
3937             stmtList.append(dollar_tmp_def);
3938             ListBuffer<JCCase> caseBuffer = new ListBuffer<>();
3939             // hashCode will trigger nullcheck on original switch expression
3940             JCMethodInvocation hashCodeCall = makeCall(make.Ident(dollar_s),
3941                                                        names.hashCode,
3942                                                        List.nil()).setType(syms.intType);
3943             JCSwitch switch1 = make.Switch(hashCodeCall,
3944                                         caseBuffer.toList());
3945             for(Map.Entry<Integer, Set<String>> entry : hashToString.entrySet()) {
3946                 int hashCode = entry.getKey();
3947                 Set<String> stringsWithHashCode = entry.getValue();
3948                 Assert.check(stringsWithHashCode.size() >= 1);
3949 
3950                 JCStatement elsepart = null;
3951                 for(String caseLabel : stringsWithHashCode ) {
3952                     JCMethodInvocation stringEqualsCall = makeCall(make.Ident(dollar_s),
3953                                                                    names.equals,
3954                                                                    List.of(make.Literal(caseLabel)));
3955                     elsepart = make.If(stringEqualsCall,
3956                                        make.Exec(make.Assign(make.Ident(dollar_tmp),
3957                                                              make.Literal(caseLabelToPosition.get(caseLabel))).
3958                                                  setType(dollar_tmp.type)),
3959                                        elsepart);
3960                 }
3961 
3962                 ListBuffer<JCStatement> lb = new ListBuffer<>();
3963                 JCBreak breakStmt = make.Break(null);
3964                 breakStmt.target = switch1;
3965                 lb.append(elsepart).append(breakStmt);
3966 
3967                 caseBuffer.append(make.Case(JCCase.STATEMENT, List.of(make.Literal(hashCode)), lb.toList(), null));
3968             }
3969 
3970             switch1.cases = caseBuffer.toList();
3971 
3972             if (nullCase != null) {
3973                 stmtList.append(make.If(makeBinary(NE, make.Ident(dollar_s), makeNull()), switch1, make.Exec(make.Assign(make.Ident(dollar_tmp),
3974                                                              make.Literal(nullCaseLabel)).
3975                                                  setType(dollar_tmp.type))).setType(syms.intType));
3976             } else {
3977                 stmtList.append(switch1);
3978             }
3979 
3980             // Make isomorphic switch tree replacing string labels
3981             // with corresponding integer ones from the label to
3982             // position map.
3983 
3984             ListBuffer<JCCase> lb = new ListBuffer<>();
3985             for(JCCase oneCase : caseList ) {
3986                 boolean isDefault = !oneCase.labels.head.isExpression();
3987                 JCCaseLabel caseExpr;
3988                 if (isDefault)
3989                     caseExpr = null;
3990                 else if (oneCase == nullCase) {
3991                     caseExpr = make.Literal(nullCaseLabel);
3992                 } else {
3993                     caseExpr = make.Literal(caseLabelToPosition.get((String)TreeInfo.skipParens((JCExpression) oneCase.labels.head).
3994                                                                     type.constValue()));
3995                 }
3996 
3997                 lb.append(make.Case(JCCase.STATEMENT, caseExpr == null ? List.of(make.DefaultCaseLabel()) : List.of(caseExpr),
3998                                     oneCase.stats, null));
3999             }
4000 
4001             if (tree.hasTag(SWITCH)) {
4002                 JCSwitch switch2 = make.Switch(make.Ident(dollar_tmp), lb.toList());
4003                 // Rewire up old unlabeled break statements to the
4004                 // replacement switch being created.
4005                 patchTargets(switch2, tree, switch2);
4006 
4007                 stmtList.append(switch2);
4008 
4009                 JCBlock res = make.Block(0L, stmtList.toList());
4010                 res.endpos = TreeInfo.endPos(tree);
4011                 return res;
4012             } else {
4013                 JCSwitchExpression switch2 = make.SwitchExpression(make.Ident(dollar_tmp), lb.toList());
4014 
4015                 // Rewire up old unlabeled break statements to the
4016                 // replacement switch being created.
4017                 patchTargets(switch2, tree, switch2);
4018 
4019                 switch2.setType(tree.type);
4020 
4021                 LetExpr res = make.LetExpr(stmtList.toList(), switch2);
4022 
4023                 res.needsCond = true;
4024                 res.setType(tree.type);
4025 
4026                 return res;
4027             }
4028         }
4029     }
4030 
4031     private JCTree visitBoxedPrimitiveSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {
4032         JCExpression newSelector;
4033 
4034         if (cases.stream().anyMatch(c -> TreeInfo.isNull(c.labels.head))) {
4035             //a switch over a boxed primitive, with a null case. Pick two constants that are
4036             //not used by any branch in the case (c1 and c2), close to other constants that are
4037             //used in the switch. Then do:
4038             //switch ($selector != null ? $selector != c1 ? $selector : c2 : c1) {...}
4039             //replacing case null with case c1
4040             Set<Integer> constants = new LinkedHashSet<>();
4041             JCCase nullCase = null;
4042 
4043             for (JCCase c : cases) {
4044                 if (TreeInfo.isNull(c.labels.head)) {
4045                     nullCase = c;
4046                 } else if (!c.labels.head.hasTag(DEFAULTCASELABEL)) {
4047                     constants.add((int) c.labels.head.type.constValue());
4048                 }
4049             }
4050 
4051             Assert.checkNonNull(nullCase);
4052 
4053             int nullValue = constants.isEmpty() ? 0 : constants.iterator().next();
4054 
4055             while (constants.contains(nullValue)) nullValue++;
4056 
4057             constants.add(nullValue);
4058             nullCase.labels.head = makeLit(syms.intType, nullValue);
4059 
4060             int replacementValue = nullValue;
4061 
4062             while (constants.contains(replacementValue)) replacementValue++;
4063 
4064             VarSymbol dollar_s = new VarSymbol(FINAL|SYNTHETIC,
4065                                                names.fromString("s" + tree.pos + this.target.syntheticNameChar()),
4066                                                selector.type,
4067                                                currentMethodSym);
4068             JCStatement var = make.at(tree.pos()).VarDef(dollar_s, selector).setType(dollar_s.type);
4069             JCExpression nullValueReplacement =
4070                     make.Conditional(makeBinary(NE,
4071                                                  unbox(make.Ident(dollar_s), syms.intType),
4072                                                  makeLit(syms.intType, nullValue)),
4073                                      unbox(make.Ident(dollar_s), syms.intType),
4074                                      makeLit(syms.intType, replacementValue))
4075                         .setType(syms.intType);
4076             JCExpression nullCheck =
4077                     make.Conditional(makeBinary(NE, make.Ident(dollar_s), makeNull()),
4078                                      nullValueReplacement,
4079                                      makeLit(syms.intType, nullValue))
4080                         .setType(syms.intType);
4081             newSelector = make.LetExpr(List.of(var), nullCheck).setType(syms.intType);
4082         } else {
4083             newSelector = unbox(selector, syms.intType);
4084         }
4085 
4086         if (tree.hasTag(SWITCH)) {
4087             ((JCSwitch) tree).selector = newSelector;
4088         } else {
4089             ((JCSwitchExpression) tree).selector = newSelector;
4090         }
4091 
4092         return tree;
4093     }
4094 
4095     @Override
4096     public void visitBreak(JCBreak tree) {
4097         result = tree;
4098     }
4099 
4100     @Override
4101     public void visitYield(JCYield tree) {
4102         tree.value = translate(tree.value, tree.target.type);
4103         result = tree;
4104     }
4105 
4106     public void visitNewArray(JCNewArray tree) {
4107         tree.elemtype = translate(tree.elemtype);
4108         for (List<JCExpression> t = tree.dims; t.tail != null; t = t.tail)
4109             if (t.head != null) t.head = translate(t.head, syms.intType);
4110         tree.elems = translate(tree.elems, types.elemtype(tree.type));
4111         result = tree;
4112     }
4113 
4114     public void visitSelect(JCFieldAccess tree) {
4115         // need to special case-access of the form C.super.x
4116         // these will always need an access method, unless C
4117         // is a default interface subclassed by the current class.
4118         boolean qualifiedSuperAccess =
4119             tree.selected.hasTag(SELECT) &&
4120             TreeInfo.name(tree.selected) == names._super &&
4121             !types.isDirectSuperInterface(((JCFieldAccess)tree.selected).selected.type.tsym, currentClass);
4122         /* JDK-8269956: Where a reflective (class) literal is needed, the unqualified Point.class is
4123          * always the "primary" mirror - representing the primitive reference runtime type - thereby
4124          * always matching the behavior of Object::getClass
4125          */
4126         boolean needPrimaryMirror = tree.name == names._class && tree.selected.type.isReferenceProjection();
4127         tree.selected = translate(tree.selected);
4128         if (needPrimaryMirror && tree.selected.type.isPrimitiveClass()) {
4129             tree.selected.setType(tree.selected.type.referenceProjection());
4130         }
4131         if (tree.name == names._class) {
4132             result = classOf(tree.selected);
4133         }
4134         else if (tree.name == names._super &&
4135                 types.isDirectSuperInterface(tree.selected.type.tsym, currentClass)) {
4136             //default super call!! Not a classic qualified super call
4137             TypeSymbol supSym = tree.selected.type.tsym;
4138             Assert.checkNonNull(types.asSuper(currentClass.type.referenceProjectionOrSelf(), supSym));
4139             result = tree;
4140         }
4141         else if (tree.name == names._this || tree.name == names._super) {
4142             result = makeThis(tree.pos(), tree.selected.type.tsym);
4143         }
4144         else
4145             result = access(tree.sym, tree, enclOp, qualifiedSuperAccess);
4146     }
4147 
4148     public void visitLetExpr(LetExpr tree) {
4149         tree.defs = translate(tree.defs);
4150         tree.expr = translate(tree.expr, tree.type);
4151         result = tree;
4152     }
4153 
4154     // There ought to be nothing to rewrite here;
4155     // we don't generate code.
4156     public void visitAnnotation(JCAnnotation tree) {
4157         result = tree;
4158     }
4159 
4160     @Override
4161     public void visitTry(JCTry tree) {
4162         if (tree.resources.nonEmpty()) {
4163             result = makeTwrTry(tree);
4164             return;
4165         }
4166 
4167         boolean hasBody = tree.body.getStatements().nonEmpty();
4168         boolean hasCatchers = tree.catchers.nonEmpty();
4169         boolean hasFinally = tree.finalizer != null &&
4170                 tree.finalizer.getStatements().nonEmpty();
4171 
4172         if (!hasCatchers && !hasFinally) {
4173             result = translate(tree.body);
4174             return;
4175         }
4176 
4177         if (!hasBody) {
4178             if (hasFinally) {
4179                 result = translate(tree.finalizer);
4180             } else {
4181                 result = translate(tree.body);
4182             }
4183             return;
4184         }
4185 
4186         // no optimizations possible
4187         super.visitTry(tree);
4188     }
4189 
4190 /**************************************************************************
4191  * main method
4192  *************************************************************************/
4193 
4194     /** Translate a toplevel class and return a list consisting of
4195      *  the translated class and translated versions of all inner classes.
4196      *  @param env   The attribution environment current at the class definition.
4197      *               We need this for resolving some additional symbols.
4198      *  @param cdef  The tree representing the class definition.
4199      */
4200     public List<JCTree> translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
4201         ListBuffer<JCTree> translated = null;
4202         try {
4203             attrEnv = env;
4204             this.make = make;
4205             endPosTable = env.toplevel.endPositions;
4206             currentClass = null;
4207             currentMethodDef = null;
4208             outermostClassDef = (cdef.hasTag(CLASSDEF)) ? (JCClassDecl)cdef : null;
4209             outermostMemberDef = null;
4210             this.translated = new ListBuffer<>();
4211             classdefs = new HashMap<>();
4212             actualSymbols = new HashMap<>();
4213             freevarCache = new HashMap<>();
4214             proxies = new HashMap<>();
4215             twrVars = WriteableScope.create(syms.noSymbol);
4216             outerThisStack = List.nil();
4217             accessNums = new HashMap<>();
4218             accessSyms = new HashMap<>();
4219             accessConstrs = new HashMap<>();
4220             accessConstrTags = List.nil();
4221             accessed = new ListBuffer<>();
4222             translate(cdef, (JCExpression)null);
4223             for (List<Symbol> l = accessed.toList(); l.nonEmpty(); l = l.tail)
4224                 makeAccessible(l.head);
4225             for (EnumMapping map : enumSwitchMap.values())
4226                 map.translate();
4227             checkConflicts(this.translated.toList());
4228             checkAccessConstructorTags();
4229             translated = this.translated;
4230         } finally {
4231             // note that recursive invocations of this method fail hard
4232             attrEnv = null;
4233             this.make = null;
4234             endPosTable = null;
4235             currentClass = null;
4236             currentMethodDef = null;
4237             outermostClassDef = null;
4238             outermostMemberDef = null;
4239             this.translated = null;
4240             classdefs = null;
4241             actualSymbols = null;
4242             freevarCache = null;
4243             proxies = null;
4244             outerThisStack = null;
4245             accessNums = null;
4246             accessSyms = null;
4247             accessConstrs = null;
4248             accessConstrTags = null;
4249             accessed = null;
4250             enumSwitchMap.clear();
4251             assertionsDisabledClassCache = null;
4252         }
4253         return translated.toList();
4254     }
4255 }