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