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