1 /*
   2  * Copyright (c) 1999, 2024, 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 
  29 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
  30 import com.sun.tools.javac.code.*;
  31 import com.sun.tools.javac.code.Attribute.TypeCompound;
  32 import com.sun.tools.javac.code.Source.Feature;
  33 import com.sun.tools.javac.code.Symbol.*;
  34 import com.sun.tools.javac.code.Type.TypeVar;
  35 import com.sun.tools.javac.jvm.Target;
  36 import com.sun.tools.javac.tree.*;
  37 import com.sun.tools.javac.tree.JCTree.*;
  38 import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind;
  39 import com.sun.tools.javac.util.*;
  40 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  41 import com.sun.tools.javac.util.List;
  42 
  43 import static com.sun.tools.javac.code.Flags.*;
  44 import static com.sun.tools.javac.code.Kinds.Kind.*;
  45 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
  46 import static com.sun.tools.javac.code.TypeTag.CLASS;
  47 import static com.sun.tools.javac.code.TypeTag.TYPEVAR;
  48 import static com.sun.tools.javac.code.TypeTag.VOID;
  49 import static com.sun.tools.javac.comp.CompileStates.CompileState;
  50 import com.sun.tools.javac.tree.JCTree.JCBreak;
  51 
  52 import javax.lang.model.type.TypeKind;
  53 
  54 /** This pass translates Generic Java to conventional Java.
  55  *
  56  *  <p><b>This is NOT part of any supported API.
  57  *  If you write code that depends on this, you do so at your own risk.
  58  *  This code and its internal interfaces are subject to change or
  59  *  deletion without notice.</b>
  60  */
  61 public class TransTypes extends TreeTranslator {
  62     /** The context key for the TransTypes phase. */
  63     protected static final Context.Key<TransTypes> transTypesKey = new Context.Key<>();
  64 
  65     /** Get the instance for this context. */
  66     public static TransTypes instance(Context context) {
  67         TransTypes instance = context.get(transTypesKey);
  68         if (instance == null)
  69             instance = new TransTypes(context);
  70         return instance;
  71     }
  72 
  73     private Names names;
  74     private Log log;
  75     private Symtab syms;
  76     private TreeMaker make;
  77     private Enter enter;
  78     private Types types;
  79     private Annotate annotate;
  80     private Attr attr;
  81     private final Resolve resolve;
  82     private final CompileStates compileStates;
  83     private final Target target;
  84 
  85     @SuppressWarnings("this-escape")
  86     protected TransTypes(Context context) {
  87         context.put(transTypesKey, this);
  88         compileStates = CompileStates.instance(context);
  89         names = Names.instance(context);
  90         log = Log.instance(context);
  91         syms = Symtab.instance(context);
  92         enter = Enter.instance(context);
  93         types = Types.instance(context);
  94         make = TreeMaker.instance(context);
  95         resolve = Resolve.instance(context);
  96         annotate = Annotate.instance(context);
  97         attr = Attr.instance(context);
  98         target = Target.instance(context);
  99     }
 100 
 101     /** Construct an attributed tree for a cast of expression to target type,
 102      *  unless it already has precisely that type.
 103      *  @param tree    The expression tree.
 104      *  @param target  The target type.
 105      */
 106     JCExpression cast(JCExpression tree, Type target) {
 107         int oldpos = make.pos;
 108         make.at(tree.pos);
 109         if (!types.isSameType(tree.type, target)) {
 110             if (!resolve.isAccessible(env, target.tsym))
 111                 resolve.logAccessErrorInternal(env, tree, target);
 112             tree = make.TypeCast(make.Type(target), tree).setType(target);
 113         }
 114         make.pos = oldpos;
 115         return tree;
 116     }
 117 
 118     /** Construct an attributed tree to coerce an expression to some erased
 119      *  target type, unless the expression is already assignable to that type.
 120      *  If target type is a constant type, use its base type instead.
 121      *  @param tree    The expression tree.
 122      *  @param target  The target type.
 123      */
 124     public JCExpression coerce(Env<AttrContext> env, JCExpression tree, Type target) {
 125         Env<AttrContext> prevEnv = this.env;
 126         try {
 127             this.env = env;
 128             return coerce(tree, target);
 129         }
 130         finally {
 131             this.env = prevEnv;
 132         }
 133     }
 134     JCExpression coerce(JCExpression tree, Type target) {
 135         Type btarget = target.baseType();
 136         if (tree.type.isPrimitive() == target.isPrimitive()) {
 137             return types.isAssignable(tree.type, btarget, types.noWarnings)
 138                 ? tree
 139                 : cast(tree, btarget);
 140         }
 141         return tree;
 142     }
 143 
 144     /** Given an erased reference type, assume this type as the tree's type.
 145      *  Then, coerce to some given target type unless target type is null.
 146      *  This operation is used in situations like the following:
 147      *
 148      *  <pre>{@code
 149      *  class Cell<A> { A value; }
 150      *  ...
 151      *  Cell<Integer> cell;
 152      *  Integer x = cell.value;
 153      *  }</pre>
 154      *
 155      *  Since the erasure of Cell.value is Object, but the type
 156      *  of cell.value in the assignment is Integer, we need to
 157      *  adjust the original type of cell.value to Object, and insert
 158      *  a cast to Integer. That is, the last assignment becomes:
 159      *
 160      *  <pre>{@code
 161      *  Integer x = (Integer)cell.value;
 162      *  }</pre>
 163      *
 164      *  @param tree       The expression tree whose type might need adjustment.
 165      *  @param erasedType The expression's type after erasure.
 166      *  @param target     The target type, which is usually the erasure of the
 167      *                    expression's original type.
 168      */
 169     JCExpression retype(JCExpression tree, Type erasedType, Type target) {
 170 //      System.err.println("retype " + tree + " to " + erasedType);//DEBUG
 171         if (!erasedType.isPrimitive()) {
 172             if (target != null && target.isPrimitive()) {
 173                 target = erasure(tree.type);
 174             }
 175             tree.type = erasedType;
 176             if (target != null) {
 177                 return coerce(tree, target);
 178             }
 179         }
 180         return tree;
 181     }
 182 
 183     /** Translate method argument list, casting each argument
 184      *  to its corresponding type in a list of target types.
 185      *  @param _args            The method argument list.
 186      *  @param parameters       The list of target types.
 187      *  @param varargsElement   The erasure of the varargs element type,
 188      *  or null if translating a non-varargs invocation
 189      */
 190     <T extends JCTree> List<T> translateArgs(List<T> _args,
 191                                            List<Type> parameters,
 192                                            Type varargsElement) {
 193         if (parameters.isEmpty()) return _args;
 194         List<T> args = _args;
 195         while (parameters.tail.nonEmpty()) {
 196             args.head = translate(args.head, parameters.head);
 197             args = args.tail;
 198             parameters = parameters.tail;
 199         }
 200         Type parameter = parameters.head;
 201         Assert.check(varargsElement != null || args.length() == 1);
 202         if (varargsElement != null) {
 203             while (args.nonEmpty()) {
 204                 args.head = translate(args.head, varargsElement);
 205                 args = args.tail;
 206             }
 207         } else {
 208             args.head = translate(args.head, parameter);
 209         }
 210         return _args;
 211     }
 212 
 213     public <T extends JCTree> List<T> translateArgs(List<T> _args,
 214                                            List<Type> parameters,
 215                                            Type varargsElement,
 216                                            Env<AttrContext> localEnv) {
 217         Env<AttrContext> prevEnv = env;
 218         try {
 219             env = localEnv;
 220             return translateArgs(_args, parameters, varargsElement);
 221         }
 222         finally {
 223             env = prevEnv;
 224         }
 225     }
 226 
 227     /** Add a bridge definition and enter corresponding method symbol in
 228      *  local scope of origin.
 229      *
 230      *  @param pos     The source code position to be used for the definition.
 231      *  @param meth    The method for which a bridge needs to be added
 232      *  @param impl    That method's implementation (possibly the method itself)
 233      *  @param origin  The class to which the bridge will be added
 234      *  @param bridges The list buffer to which the bridge will be added
 235      */
 236     void addBridge(DiagnosticPosition pos,
 237                    MethodSymbol meth,
 238                    MethodSymbol impl,
 239                    ClassSymbol origin,
 240                    ListBuffer<JCTree> bridges) {
 241         make.at(pos);
 242         Type implTypeErasure = erasure(impl.type);
 243 
 244         // Create a bridge method symbol and a bridge definition without a body.
 245         Type bridgeType = meth.erasure(types);
 246         long flags = impl.flags() & AccessFlags | SYNTHETIC | BRIDGE |
 247                 (origin.isInterface() ? DEFAULT : 0);
 248         MethodSymbol bridge = new MethodSymbol(flags,
 249                                                meth.name,
 250                                                bridgeType,
 251                                                origin);
 252         /* once JDK-6996415 is solved it should be checked if this approach can
 253          * be applied to method addOverrideBridgesIfNeeded
 254          */
 255         bridge.params = createBridgeParams(impl, bridge, bridgeType);
 256         bridge.setAttributes(impl);
 257 
 258         JCMethodDecl md = make.MethodDef(bridge, null);
 259 
 260         // The bridge calls this.impl(..), if we have an implementation
 261         // in the current class, super.impl(...) otherwise.
 262         JCExpression receiver = (impl.owner == origin)
 263             ? make.This(origin.erasure(types))
 264             : make.Super(types.supertype(origin.type).tsym.erasure(types), origin);
 265 
 266         // The type returned from the original method.
 267         Type calltype = implTypeErasure.getReturnType();
 268 
 269         // Construct a call of  this.impl(params), or super.impl(params),
 270         // casting params and possibly results as needed.
 271         JCExpression call =
 272             make.Apply(
 273                        null,
 274                        make.Select(receiver, impl).setType(calltype),
 275                        translateArgs(make.Idents(md.params), implTypeErasure.getParameterTypes(), null))
 276             .setType(calltype);
 277         JCStatement stat = (implTypeErasure.getReturnType().hasTag(VOID))
 278             ? make.Exec(call)
 279             : make.Return(coerce(call, bridgeType.getReturnType()));
 280         md.body = make.Block(0, List.of(stat));
 281 
 282         // Add bridge to `bridges' buffer
 283         bridges.append(md);
 284 
 285         // Add bridge to scope of enclosing class and keep track of the bridge span.
 286         origin.members().enter(bridge);
 287     }
 288 
 289     private List<VarSymbol> createBridgeParams(MethodSymbol impl, MethodSymbol bridge,
 290             Type bridgeType) {
 291         List<VarSymbol> bridgeParams = null;
 292         if (impl.params != null) {
 293             bridgeParams = List.nil();
 294             List<VarSymbol> implParams = impl.params;
 295             Type.MethodType mType = (Type.MethodType)bridgeType;
 296             List<Type> argTypes = mType.argtypes;
 297             while (implParams.nonEmpty() && argTypes.nonEmpty()) {
 298                 VarSymbol param = new VarSymbol(implParams.head.flags() | SYNTHETIC | PARAMETER,
 299                         implParams.head.name, argTypes.head, bridge);
 300                 param.setAttributes(implParams.head);
 301                 bridgeParams = bridgeParams.append(param);
 302                 implParams = implParams.tail;
 303                 argTypes = argTypes.tail;
 304             }
 305         }
 306         return bridgeParams;
 307     }
 308 
 309     /** Add bridge if given symbol is a non-private, non-static member
 310      *  of the given class, which is either defined in the class or non-final
 311      *  inherited, and one of the two following conditions holds:
 312      *  1. The method's type changes in the given class, as compared to the
 313      *     class where the symbol was defined, (in this case
 314      *     we have extended a parameterized class with non-trivial parameters).
 315      *  2. The method has an implementation with a different erased return type.
 316      *     (in this case we have used co-variant returns).
 317      *  If a bridge already exists in some other class, no new bridge is added.
 318      *  Instead, it is checked that the bridge symbol overrides the method symbol.
 319      *  (Spec ???).
 320      *  todo: what about bridges for privates???
 321      *
 322      *  @param pos     The source code position to be used for the definition.
 323      *  @param sym     The symbol for which a bridge might have to be added.
 324      *  @param origin  The class in which the bridge would go.
 325      *  @param bridges The list buffer to which the bridge would be added.
 326      */
 327     void addBridgeIfNeeded(DiagnosticPosition pos,
 328                            Symbol sym,
 329                            ClassSymbol origin,
 330                            ListBuffer<JCTree> bridges) {
 331         if (sym.kind == MTH &&
 332                 sym.name != names.init &&
 333                 (sym.flags() & (PRIVATE | STATIC)) == 0 &&
 334                 (sym.flags() & SYNTHETIC) != SYNTHETIC &&
 335                 sym.isMemberOf(origin, types)) {
 336             MethodSymbol meth = (MethodSymbol)sym;
 337             MethodSymbol bridge = meth.binaryImplementation(origin, types);
 338             MethodSymbol impl = meth.implementation(origin, types, true);
 339             if (bridge == null ||
 340                 bridge == meth ||
 341                 (impl != null && !bridge.owner.isSubClass(impl.owner, types))) {
 342                 // No bridge was added yet.
 343                 if (impl != null && bridge != impl && isBridgeNeeded(meth, impl, origin.type)) {
 344                     addBridge(pos, meth, impl, origin, bridges);
 345                 } else if (impl == meth
 346                            && impl.owner != origin
 347                            && (impl.flags() & FINAL) == 0
 348                            && (meth.flags() & (ABSTRACT|PUBLIC)) == PUBLIC
 349                            && (origin.flags() & PUBLIC) > (impl.owner.flags() & PUBLIC)) {
 350                     // this is to work around a horrible but permanent
 351                     // reflection design error.
 352                     addBridge(pos, meth, impl, origin, bridges);
 353                 }
 354             }
 355         }
 356     }
 357     // where
 358 
 359         /**
 360          * @param method The symbol for which a bridge might have to be added
 361          * @param impl The implementation of method
 362          * @param dest The type in which the bridge would go
 363          */
 364         private boolean isBridgeNeeded(MethodSymbol method,
 365                                        MethodSymbol impl,
 366                                        Type dest) {
 367             if (impl != method) {
 368                 // If either method or impl have different erasures as
 369                 // members of dest, a bridge is needed.
 370                 Type method_erasure = method.erasure(types);
 371                 if (!isSameMemberWhenErased(dest, method, method_erasure))
 372                     return true;
 373                 Type impl_erasure = impl.erasure(types);
 374                 if (!isSameMemberWhenErased(dest, impl, impl_erasure))
 375                     return true;
 376 
 377                 /* Bottom line: A bridge is needed if the erasure of the implementation
 378                    is different from that of the method that it overrides.
 379                 */
 380                 return !types.isSameType(impl_erasure, method_erasure);
 381             } else {
 382                // method and impl are the same...
 383                 if ((method.flags() & ABSTRACT) != 0) {
 384                     // ...and abstract so a bridge is not needed.
 385                     // Concrete subclasses will bridge as needed.
 386                     return false;
 387                 }
 388 
 389                 // The erasure of the return type is always the same
 390                 // for the same symbol.  Reducing the three tests in
 391                 // the other branch to just one:
 392                 return !isSameMemberWhenErased(dest, method, method.erasure(types));
 393             }
 394         }
 395         /**
 396          * Lookup the method as a member of the type.  Compare the
 397          * erasures.
 398          * @param type the class where to look for the method
 399          * @param method the method to look for in class
 400          * @param erasure the erasure of method
 401          */
 402         private boolean isSameMemberWhenErased(Type type,
 403                                                MethodSymbol method,
 404                                                Type erasure) {
 405             return types.isSameType(erasure(types.memberType(type, method)),
 406                                     erasure);
 407         }
 408 
 409     void addBridges(DiagnosticPosition pos,
 410                     TypeSymbol i,
 411                     ClassSymbol origin,
 412                     ListBuffer<JCTree> bridges) {
 413         for (Symbol sym : i.members().getSymbols(NON_RECURSIVE))
 414             addBridgeIfNeeded(pos, sym, origin, bridges);
 415         for (List<Type> l = types.interfaces(i.type); l.nonEmpty(); l = l.tail)
 416             addBridges(pos, l.head.tsym, origin, bridges);
 417     }
 418 
 419     /** Add all necessary bridges to some class appending them to list buffer.
 420      *  @param pos     The source code position to be used for the bridges.
 421      *  @param origin  The class in which the bridges go.
 422      *  @param bridges The list buffer to which the bridges are added.
 423      */
 424     void addBridges(DiagnosticPosition pos, ClassSymbol origin, ListBuffer<JCTree> bridges) {
 425         Type st = types.supertype(origin.type);
 426         while (st.hasTag(CLASS)) {
 427 //          if (isSpecialization(st))
 428             addBridges(pos, st.tsym, origin, bridges);
 429             st = types.supertype(st);
 430         }
 431         for (List<Type> l = types.interfaces(origin.type); l.nonEmpty(); l = l.tail)
 432 //          if (isSpecialization(l.head))
 433             addBridges(pos, l.head.tsym, origin, bridges);
 434     }
 435 
 436 /* ************************************************************************
 437  * Visitor methods
 438  *************************************************************************/
 439 
 440     /** Visitor argument: proto-type.
 441      */
 442     private Type pt;
 443 
 444     /** Visitor method: perform a type translation on tree.
 445      */
 446     public <T extends JCTree> T translate(T tree, Type pt) {
 447         Type prevPt = this.pt;
 448         try {
 449             this.pt = pt;
 450             return translate(tree);
 451         } finally {
 452             this.pt = prevPt;
 453         }
 454     }
 455 
 456     /** Visitor method: perform a type translation on list of trees.
 457      */
 458     public <T extends JCTree> List<T> translate(List<T> trees, Type pt) {
 459         Type prevPt = this.pt;
 460         List<T> res;
 461         try {
 462             this.pt = pt;
 463             res = translate(trees);
 464         } finally {
 465             this.pt = prevPt;
 466         }
 467         return res;
 468     }
 469 
 470     public void visitClassDef(JCClassDecl tree) {
 471         translateClass(tree.sym);
 472         result = tree;
 473     }
 474 
 475     Type returnType = null;
 476     public void visitMethodDef(JCMethodDecl tree) {
 477         Type prevRetType = returnType;
 478         try {
 479             returnType = erasure(tree.type).getReturnType();
 480             tree.restype = translate(tree.restype, null);
 481             tree.typarams = List.nil();
 482             tree.params = translateVarDefs(tree.params);
 483             tree.recvparam = translate(tree.recvparam, null);
 484             tree.thrown = translate(tree.thrown, null);
 485             tree.body = translate(tree.body, tree.sym.erasure(types).getReturnType());
 486             tree.type = erasure(tree.type);
 487             result = tree;
 488         } finally {
 489             returnType = prevRetType;
 490         }
 491     }
 492 
 493     public void visitVarDef(JCVariableDecl tree) {
 494         tree.vartype = translate(tree.vartype, null);
 495         tree.init = translate(tree.init, tree.sym.erasure(types));
 496         tree.type = erasure(tree.type);
 497         result = tree;
 498     }
 499 
 500     public void visitDoLoop(JCDoWhileLoop tree) {
 501         tree.body = translate(tree.body);
 502         tree.cond = translate(tree.cond, syms.booleanType);
 503         result = tree;
 504     }
 505 
 506     public void visitWhileLoop(JCWhileLoop tree) {
 507         tree.cond = translate(tree.cond, syms.booleanType);
 508         tree.body = translate(tree.body);
 509         result = tree;
 510     }
 511 
 512     public void visitForLoop(JCForLoop tree) {
 513         tree.init = translate(tree.init, null);
 514         if (tree.cond != null)
 515             tree.cond = translate(tree.cond, syms.booleanType);
 516         tree.step = translate(tree.step, null);
 517         tree.body = translate(tree.body);
 518         result = tree;
 519     }
 520 
 521     public void visitForeachLoop(JCEnhancedForLoop tree) {
 522         tree.var = translate(tree.var, null);
 523         Type iterableType = tree.expr.type;
 524         tree.expr = translate(tree.expr, erasure(tree.expr.type));
 525         if (types.elemtype(tree.expr.type) == null)
 526             tree.expr.type = iterableType; // preserve type for Lower
 527         tree.body = translate(tree.body);
 528         result = tree;
 529     }
 530 
 531     public void visitLambda(JCLambda tree) {
 532         Type prevRetType = returnType;
 533         try {
 534             returnType = erasure(tree.getDescriptorType(types)).getReturnType();
 535             tree.params = translate(tree.params);
 536             tree.body = translate(tree.body, tree.body.type == null || returnType.hasTag(VOID) ? null : returnType);
 537             if (!tree.type.isIntersection()) {
 538                 tree.type = erasure(tree.type);
 539             } else {
 540                 tree.type = types.erasure(types.findDescriptorSymbol(tree.type.tsym).owner.type);
 541             }
 542             result = tree;
 543         }
 544         finally {
 545             returnType = prevRetType;
 546         }
 547     }
 548 
 549     @Override
 550     public void visitReference(JCMemberReference tree) {
 551         if (needsConversionToLambda(tree)) {
 552             // Convert to a lambda, and process as such
 553             MemberReferenceToLambda conv = new MemberReferenceToLambda(tree);
 554             result = translate(conv.lambda());
 555         } else {
 556             Type t = types.skipTypeVars(tree.expr.type, false);
 557             Type receiverTarget = t.isCompound() ? erasure(tree.sym.owner.type) : erasure(t);
 558             if (tree.kind == ReferenceKind.UNBOUND) {
 559                 tree.expr = make.Type(receiverTarget);
 560             } else {
 561                 tree.expr = translate(tree.expr, receiverTarget);
 562             }
 563             if (!tree.type.isIntersection()) {
 564                 tree.type = erasure(tree.type);
 565             } else {
 566                 tree.type = types.erasure(types.findDescriptorSymbol(tree.type.tsym).owner.type);
 567             }
 568             result = tree;
 569         }
 570     }
 571     // where
 572     boolean needsVarArgsConversion(JCMemberReference tree) {
 573         return tree.varargsElement != null;
 574     }
 575 
 576     /**
 577      * @return Is this an array operation like clone()
 578      */
 579     boolean isArrayOp(JCMemberReference tree) {
 580         return tree.sym.owner == syms.arrayClass;
 581     }
 582 
 583     boolean receiverAccessible(JCMemberReference tree) {
 584         //hack needed to workaround 292 bug (7087658)
 585         //when 292 issue is fixed we should remove this and change the backend
 586         //code to always generate a method handle to an accessible method
 587         return tree.ownerAccessible;
 588     }
 589 
 590     /**
 591      * Erasure destroys the implementation parameter subtype
 592      * relationship for intersection types.
 593      * Have similar problems for union types too.
 594      */
 595     boolean interfaceParameterIsIntersectionOrUnionType(JCMemberReference tree) {
 596         List<Type> tl = tree.getDescriptorType(types).getParameterTypes();
 597         for (; tl.nonEmpty(); tl = tl.tail) {
 598             Type pt = tl.head;
 599             if (isIntersectionOrUnionType(pt))
 600                 return true;
 601         }
 602         return false;
 603     }
 604 
 605     boolean isIntersectionOrUnionType(Type t) {
 606         return switch (t.getKind()) {
 607             case INTERSECTION, UNION -> true;
 608             case TYPEVAR -> {
 609                 TypeVar tv = (TypeVar) t;
 610                 yield isIntersectionOrUnionType(tv.getUpperBound());
 611             }
 612             default -> false;
 613         };
 614     }
 615 
 616     private boolean isProtectedInSuperClassOfEnclosingClassInOtherPackage(Symbol targetReference,
 617                                                                           Symbol currentClass) {
 618         return ((targetReference.flags() & PROTECTED) != 0 &&
 619                 targetReference.packge() != currentClass.packge());
 620     }
 621 
 622     /**
 623      * This method should be called only when target release <= 14
 624      * where LambdaMetaFactory does not spin nestmate classes.
 625      *
 626      * This method should be removed when --release 14 is not supported.
 627      */
 628     boolean isPrivateInOtherClass(JCMemberReference tree) {
 629         return (tree.sym.flags() & PRIVATE) != 0 &&
 630                 !types.isSameType(
 631                         types.erasure(tree.sym.enclClass().asType()),
 632                         types.erasure(env.enclClass.sym.asType()));
 633     }
 634 
 635     /**
 636      * Does this reference need to be converted to a lambda
 637      * (i.e. var args need to be expanded or "super" is used)
 638      */
 639     boolean needsConversionToLambda(JCMemberReference tree) {
 640         return interfaceParameterIsIntersectionOrUnionType(tree) ||
 641                 tree.hasKind(ReferenceKind.SUPER) ||
 642                 needsVarArgsConversion(tree) ||
 643                 isArrayOp(tree) ||
 644                 (!target.runtimeUseNestAccess() && isPrivateInOtherClass(tree)) ||
 645                 isProtectedInSuperClassOfEnclosingClassInOtherPackage(tree.sym, env.enclClass.sym) ||
 646                 !receiverAccessible(tree) ||
 647                 (tree.getMode() == ReferenceMode.NEW &&
 648                         tree.kind != ReferenceKind.ARRAY_CTOR &&
 649                         (tree.sym.owner.isDirectlyOrIndirectlyLocal() || tree.sym.owner.isInner()));
 650     }
 651 
 652     /**
 653      * Converts a method reference which cannot be used directly into a lambda
 654      */
 655     private class MemberReferenceToLambda {
 656 
 657         private final JCMemberReference tree;
 658         private final ListBuffer<JCExpression> args = new ListBuffer<>();
 659         private final ListBuffer<JCVariableDecl> params = new ListBuffer<>();
 660         private final MethodSymbol owner = new MethodSymbol(0, names.empty, Type.noType, env.enclClass.sym);
 661 
 662         private JCExpression receiverExpression = null;
 663 
 664         MemberReferenceToLambda(JCMemberReference tree) {
 665             this.tree = tree;
 666         }
 667 
 668         JCExpression lambda() {
 669             int prevPos = make.pos;
 670             try {
 671                 make.at(tree);
 672 
 673                 //body generation - this can be either a method call or a
 674                 //new instance creation expression, depending on the member reference kind
 675                 VarSymbol rcvr = addParametersReturnReceiver();
 676                 JCExpression expr = (tree.getMode() == ReferenceMode.INVOKE)
 677                         ? expressionInvoke(rcvr)
 678                         : expressionNew();
 679 
 680                 JCLambda slam = make.Lambda(params.toList(), expr);
 681                 slam.target = tree.target;
 682                 slam.owner = tree.owner;
 683                 slam.type = tree.type;
 684                 slam.pos = tree.pos;
 685                 slam.codeModel = tree.codeModel;
 686                 slam.wasMethodReference = true;
 687                 if (receiverExpression != null) {
 688                     // use a let expression so that the receiver expression is evaluated eagerly
 689                     return make.at(tree.pos).LetExpr(
 690                             make.VarDef(rcvr, receiverExpression), slam).setType(tree.type);
 691                 } else {
 692                     return slam;
 693                 }
 694             } finally {
 695                 make.at(prevPos);
 696             }
 697         }
 698 
 699         /**
 700          * Generate the parameter list for the converted member reference.
 701          *
 702          * @return The receiver variable symbol, if any
 703          */
 704         VarSymbol addParametersReturnReceiver() {
 705             List<Type> descPTypes = tree.getDescriptorType(types).getParameterTypes();
 706 
 707             // Determine the receiver, if any
 708             VarSymbol rcvr;
 709             switch (tree.kind) {
 710                 case BOUND:
 711                     // The receiver is explicit in the method reference
 712                     rcvr = new VarSymbol(SYNTHETIC, names.fromString("rec$"), tree.getQualifierExpression().type, owner);
 713                     rcvr.pos = tree.pos;
 714                     receiverExpression = attr.makeNullCheck(tree.getQualifierExpression());
 715                     break;
 716                 case UNBOUND:
 717                     // The receiver is the first parameter, extract it and
 718                     // adjust the SAM and unerased type lists accordingly
 719                     rcvr = addParameter("rec$", descPTypes.head, false);
 720                     descPTypes = descPTypes.tail;
 721                     break;
 722                 default:
 723                     rcvr = null;
 724                     break;
 725             }
 726             List<Type> implPTypes = tree.sym.type.getParameterTypes();
 727             int implSize = implPTypes.size();
 728             int samSize = descPTypes.size();
 729             // Last parameter to copy from referenced method, exclude final var args
 730             int last = needsVarArgsConversion(tree) ? implSize - 1 : implSize;
 731 
 732             for (int i = 0; implPTypes.nonEmpty() && i < last; ++i) {
 733                 // Use the descriptor parameter type
 734                 Type parmType = descPTypes.head;
 735                 addParameter("x$" + i, parmType, true);
 736 
 737                 // Advance to the next parameter
 738                 implPTypes = implPTypes.tail;
 739                 descPTypes = descPTypes.tail;
 740             }
 741             // Flatten out the var args
 742             for (int i = last; i < samSize; ++i) {
 743                 addParameter("xva$" + i, tree.varargsElement, true);
 744             }
 745 
 746             return rcvr;
 747         }
 748 
 749         /**
 750          * determine the receiver of the method call - the receiver can
 751          * be a type qualifier, the synthetic receiver parameter or 'super'.
 752          */
 753         private JCExpression expressionInvoke(VarSymbol rcvr) {
 754             JCExpression qualifier =
 755                     (rcvr != null) ?
 756                             make.Ident(rcvr) :
 757                             tree.getQualifierExpression();
 758 
 759             //create the qualifier expression
 760             JCFieldAccess select = make.Select(qualifier, tree.sym.name);
 761             select.sym = tree.sym;
 762             select.type = tree.referentType;
 763 
 764             //create the method call expression
 765             JCExpression apply = make.Apply(List.nil(), select,
 766                             args.toList()).setType(tree.referentType.getReturnType());
 767 
 768             TreeInfo.setVarargsElement(apply, tree.varargsElement);
 769             return apply;
 770         }
 771 
 772         /**
 773          * Lambda body to use for a 'new'.
 774          */
 775         private JCExpression expressionNew() {
 776             if (tree.kind == ReferenceKind.ARRAY_CTOR) {
 777                 //create the array creation expression
 778                 JCNewArray newArr = make.NewArray(
 779                         make.Type(types.elemtype(tree.getQualifierExpression().type)),
 780                         List.of(make.Ident(params.first())),
 781                         null);
 782                 newArr.type = tree.getQualifierExpression().type;
 783                 return newArr;
 784             } else {
 785                 //create the instance creation expression
 786                 //note that method reference syntax does not allow an explicit
 787                 //enclosing class (so the enclosing class is null)
 788                 // but this may need to be patched up later with the proxy for the outer this
 789                 JCNewClass newClass = make.NewClass(null,
 790                         List.nil(),
 791                         make.Type(tree.getQualifierExpression().type),
 792                         args.toList(),
 793                         null);
 794                 newClass.constructor = tree.sym;
 795                 newClass.constructorType = tree.sym.erasure(types);
 796                 newClass.type = tree.getQualifierExpression().type;
 797                 TreeInfo.setVarargsElement(newClass, tree.varargsElement);
 798                 return newClass;
 799             }
 800         }
 801 
 802         private VarSymbol addParameter(String name, Type p, boolean genArg) {
 803             VarSymbol vsym = new VarSymbol(PARAMETER | SYNTHETIC, names.fromString(name), p, owner);
 804             vsym.pos = tree.pos;
 805             params.append(make.VarDef(vsym, null));
 806             if (genArg) {
 807                 args.append(make.Ident(vsym));
 808             }
 809             return vsym;
 810         }
 811     }
 812 
 813     public void visitSwitch(JCSwitch tree) {
 814         Type selsuper = types.supertype(tree.selector.type);
 815         boolean enumSwitch = selsuper != null &&
 816             selsuper.tsym == syms.enumSym;
 817         Type target = enumSwitch ? erasure(tree.selector.type) : syms.intType;
 818         tree.selector = translate(tree.selector, target);
 819         tree.cases = translateCases(tree.cases);
 820         result = tree;
 821     }
 822 
 823     public void visitCase(JCCase tree) {
 824         tree.labels = translate(tree.labels, null);
 825         tree.guard = translate(tree.guard, syms.booleanType);
 826         tree.stats = translate(tree.stats);
 827         result = tree;
 828     }
 829 
 830     @Override
 831     public void visitAnyPattern(JCAnyPattern tree) {
 832         result = tree;
 833     }
 834 
 835     public void visitBindingPattern(JCBindingPattern tree) {
 836         tree.var = translate(tree.var, null);
 837         result = tree;
 838     }
 839 
 840     @Override
 841     public void visitConstantCaseLabel(JCConstantCaseLabel tree) {
 842         tree.expr = translate(tree.expr, null);
 843         result = tree;
 844     }
 845 
 846     @Override
 847     public void visitPatternCaseLabel(JCPatternCaseLabel tree) {
 848         tree.pat = translate(tree.pat, null);
 849         result = tree;
 850     }
 851 
 852     public void visitSwitchExpression(JCSwitchExpression tree) {
 853         Type selsuper = types.supertype(tree.selector.type);
 854         boolean enumSwitch = selsuper != null &&
 855             selsuper.tsym == syms.enumSym;
 856         Type target = enumSwitch ? erasure(tree.selector.type) : syms.intType;
 857         tree.selector = translate(tree.selector, target);
 858         tree.cases = translate(tree.cases, tree.type);
 859         tree.type = erasure(tree.type);
 860         result = retype(tree, tree.type, pt);
 861     }
 862 
 863     public void visitRecordPattern(JCRecordPattern tree) {
 864         tree.fullComponentTypes = tree.record.getRecordComponents()
 865                                              .map(rc -> types.memberType(tree.type, rc));
 866         tree.deconstructor = translate(tree.deconstructor, null);
 867         tree.nested = translate(tree.nested, null);
 868         result = tree;
 869     }
 870 
 871     public void visitSynchronized(JCSynchronized tree) {
 872         tree.lock = translate(tree.lock, erasure(tree.lock.type));
 873         tree.body = translate(tree.body);
 874         result = tree;
 875     }
 876 
 877     public void visitTry(JCTry tree) {
 878         tree.resources = translate(tree.resources, syms.autoCloseableType);
 879         tree.body = translate(tree.body);
 880         tree.catchers = translateCatchers(tree.catchers);
 881         tree.finalizer = translate(tree.finalizer);
 882         result = tree;
 883     }
 884 
 885     public void visitConditional(JCConditional tree) {
 886         tree.cond = translate(tree.cond, syms.booleanType);
 887         tree.truepart = translate(tree.truepart, erasure(tree.type));
 888         tree.falsepart = translate(tree.falsepart, erasure(tree.type));
 889         tree.type = erasure(tree.type);
 890         result = retype(tree, tree.type, pt);
 891     }
 892 
 893    public void visitIf(JCIf tree) {
 894         tree.cond = translate(tree.cond, syms.booleanType);
 895         tree.thenpart = translate(tree.thenpart);
 896         tree.elsepart = translate(tree.elsepart);
 897         result = tree;
 898     }
 899 
 900     public void visitExec(JCExpressionStatement tree) {
 901         tree.expr = translate(tree.expr, null);
 902         result = tree;
 903     }
 904 
 905     public void visitReturn(JCReturn tree) {
 906         if (!returnType.hasTag(VOID))
 907             tree.expr = translate(tree.expr, returnType);
 908         result = tree;
 909     }
 910 
 911     @Override
 912     public void visitBreak(JCBreak tree) {
 913         result = tree;
 914     }
 915 
 916     @Override
 917     public void visitYield(JCYield tree) {
 918         tree.value = translate(tree.value, erasure(tree.value.type));
 919         tree.value.type = erasure(tree.value.type);
 920         tree.value = retype(tree.value, tree.value.type, pt);
 921         result = tree;
 922     }
 923 
 924     public void visitThrow(JCThrow tree) {
 925         tree.expr = translate(tree.expr, erasure(tree.expr.type));
 926         result = tree;
 927     }
 928 
 929     public void visitAssert(JCAssert tree) {
 930         tree.cond = translate(tree.cond, syms.booleanType);
 931         if (tree.detail != null)
 932             tree.detail = translate(tree.detail, erasure(tree.detail.type));
 933         result = tree;
 934     }
 935 
 936     public void visitApply(JCMethodInvocation tree) {
 937         tree.meth = translate(tree.meth, null);
 938         Symbol meth = TreeInfo.symbol(tree.meth);
 939         Type mt = meth.erasure(types);
 940         boolean useInstantiatedPtArgs = !types.isSignaturePolymorphic((MethodSymbol)meth.baseSymbol());
 941         List<Type> argtypes = useInstantiatedPtArgs ?
 942                 tree.meth.type.getParameterTypes() :
 943                 mt.getParameterTypes();
 944         if (meth.name == names.init && meth.owner == syms.enumSym)
 945             argtypes = argtypes.tail.tail;
 946         if (tree.varargsElement != null)
 947             tree.varargsElement = types.erasure(tree.varargsElement);
 948         else
 949             if (tree.args.length() != argtypes.length()) {
 950                 Assert.error(String.format("Incorrect number of arguments; expected %d, found %d",
 951                         tree.args.length(), argtypes.length()));
 952             }
 953         tree.args = translateArgs(tree.args, argtypes, tree.varargsElement);
 954 
 955         tree.type = types.erasure(tree.type);
 956         // Insert casts of method invocation results as needed.
 957         result = retype(tree, mt.getReturnType(), pt);
 958     }
 959 
 960     public void visitNewClass(JCNewClass tree) {
 961         if (tree.encl != null) {
 962             if (tree.def == null) {
 963                 tree.encl = translate(tree.encl, erasure(tree.encl.type));
 964             } else {
 965                 tree.args = tree.args.prepend(attr.makeNullCheck(tree.encl));
 966                 tree.encl = null;
 967             }
 968         }
 969 
 970         Type erasedConstructorType = tree.constructorType != null ?
 971                 erasure(tree.constructorType) :
 972                 null;
 973 
 974         List<Type> argtypes = erasedConstructorType != null ?
 975                 erasedConstructorType.getParameterTypes() :
 976                 tree.constructor.erasure(types).getParameterTypes();
 977 
 978         tree.clazz = translate(tree.clazz, null);
 979         if (tree.varargsElement != null)
 980             tree.varargsElement = types.erasure(tree.varargsElement);
 981         tree.args = translateArgs(
 982             tree.args, argtypes, tree.varargsElement);
 983         tree.def = translate(tree.def, null);
 984         if (erasedConstructorType != null)
 985             tree.constructorType = erasedConstructorType;
 986         tree.type = erasure(tree.type);
 987         result = tree;
 988     }
 989 
 990     public void visitNewArray(JCNewArray tree) {
 991         tree.elemtype = translate(tree.elemtype, null);
 992         translate(tree.dims, syms.intType);
 993         if (tree.type != null) {
 994             tree.elems = translate(tree.elems, erasure(types.elemtype(tree.type)));
 995             tree.type = erasure(tree.type);
 996         } else {
 997             tree.elems = translate(tree.elems, null);
 998         }
 999 
1000         result = tree;
1001     }
1002 
1003     public void visitParens(JCParens tree) {
1004         tree.expr = translate(tree.expr, pt);
1005         tree.type = erasure(tree.expr.type);
1006         result = tree;
1007     }
1008 
1009     public void visitAssign(JCAssign tree) {
1010         tree.lhs = translate(tree.lhs, null);
1011         tree.rhs = translate(tree.rhs, erasure(tree.lhs.type));
1012         tree.type = erasure(tree.lhs.type);
1013         result = retype(tree, tree.type, pt);
1014     }
1015 
1016     public void visitAssignop(JCAssignOp tree) {
1017         tree.lhs = translate(tree.lhs, null);
1018         tree.rhs = translate(tree.rhs, tree.operator.type.getParameterTypes().tail.head);
1019         tree.type = erasure(tree.type);
1020         result = tree;
1021     }
1022 
1023     public void visitUnary(JCUnary tree) {
1024         tree.arg = translate(tree.arg, (tree.getTag() == Tag.NULLCHK)
1025             ? tree.type
1026             : tree.operator.type.getParameterTypes().head);
1027         result = tree;
1028     }
1029 
1030     public void visitBinary(JCBinary tree) {
1031         tree.lhs = translate(tree.lhs, tree.operator.type.getParameterTypes().head);
1032         tree.rhs = translate(tree.rhs, tree.operator.type.getParameterTypes().tail.head);
1033         result = tree;
1034     }
1035 
1036     public void visitAnnotatedType(JCAnnotatedType tree) {
1037         // For now, we need to keep the annotations in the tree because of the current
1038         // MultiCatch implementation wrt type annotations
1039         List<TypeCompound> mirrors = annotate.fromAnnotations(tree.annotations);
1040         tree.underlyingType = translate(tree.underlyingType);
1041         tree.type = tree.underlyingType.type.annotatedType(mirrors);
1042         result = tree;
1043     }
1044 
1045     public void visitTypeCast(JCTypeCast tree) {
1046         tree.clazz = translate(tree.clazz, null);
1047         Type originalTarget = tree.type;
1048         tree.type = erasure(tree.type);
1049         JCExpression newExpression = translate(tree.expr, tree.type);
1050         if (newExpression != tree.expr) {
1051             JCTypeCast typeCast = newExpression.hasTag(Tag.TYPECAST)
1052                 ? (JCTypeCast) newExpression
1053                 : null;
1054             tree.expr = typeCast != null && types.isSameType(typeCast.type, tree.type)
1055                 ? typeCast.expr
1056                 : newExpression;
1057         }
1058         if (originalTarget.isIntersection()) {
1059             Type.IntersectionClassType ict = (Type.IntersectionClassType)originalTarget;
1060             for (Type c : ict.getExplicitComponents()) {
1061                 Type ec = erasure(c);
1062                 if (!types.isSameType(ec, tree.type) && (!types.isSameType(ec, pt))) {
1063                     tree.expr = coerce(tree.expr, ec);
1064                 }
1065             }
1066         }
1067         result = retype(tree, tree.type, pt);
1068     }
1069 
1070     public void visitTypeTest(JCInstanceOf tree) {
1071         tree.expr = translate(tree.expr, null);
1072         tree.pattern = translate(tree.pattern, null);
1073         result = tree;
1074     }
1075 
1076     public void visitIndexed(JCArrayAccess tree) {
1077         tree.indexed = translate(tree.indexed, erasure(tree.indexed.type));
1078         tree.index = translate(tree.index, syms.intType);
1079 
1080         // Insert casts of indexed expressions as needed.
1081         result = retype(tree, types.elemtype(tree.indexed.type), pt);
1082     }
1083 
1084     // There ought to be nothing to rewrite here;
1085     // we don't generate code.
1086     public void visitAnnotation(JCAnnotation tree) {
1087         result = tree;
1088     }
1089 
1090     public void visitIdent(JCIdent tree) {
1091         Type et = tree.sym.erasure(types);
1092 
1093         // Map type variables to their bounds.
1094         if (tree.sym.kind == TYP && tree.sym.type.hasTag(TYPEVAR)) {
1095             result = make.at(tree.pos).Type(et);
1096         } else
1097         // Map constants expressions to themselves.
1098         if (tree.type.constValue() != null) {
1099             result = tree;
1100         }
1101         // Insert casts of variable uses as needed.
1102         else if (tree.sym.kind == VAR) {
1103             result = retype(tree, et, pt);
1104         }
1105         else {
1106             tree.type = erasure(tree.type);
1107             result = tree;
1108         }
1109     }
1110 
1111     public void visitSelect(JCFieldAccess tree) {
1112         Type t = types.skipTypeVars(tree.selected.type, false);
1113         if (t.isCompound()) {
1114             tree.selected = coerce(
1115                 translate(tree.selected, erasure(tree.selected.type)),
1116                 erasure(tree.sym.owner.type));
1117         } else
1118             tree.selected = translate(tree.selected, erasure(t));
1119 
1120         // Map constants expressions to themselves.
1121         if (tree.type.constValue() != null) {
1122             result = tree;
1123         }
1124         // Insert casts of variable uses as needed.
1125         else if (tree.sym.kind == VAR) {
1126             result = retype(tree, tree.sym.erasure(types), pt);
1127         }
1128         else {
1129             tree.type = erasure(tree.type);
1130             result = tree;
1131         }
1132     }
1133 
1134     public void visitTypeArray(JCArrayTypeTree tree) {
1135         tree.elemtype = translate(tree.elemtype, null);
1136         tree.type = erasure(tree.type);
1137         result = tree;
1138     }
1139 
1140     /** Visitor method for parameterized types.
1141      */
1142     public void visitTypeApply(JCTypeApply tree) {
1143         JCTree clazz = translate(tree.clazz, null);
1144         result = clazz;
1145     }
1146 
1147     public void visitTypeIntersection(JCTypeIntersection tree) {
1148         tree.bounds = translate(tree.bounds, null);
1149         tree.type = erasure(tree.type);
1150         result = tree;
1151     }
1152 
1153 /* ************************************************************************
1154  * utility methods
1155  *************************************************************************/
1156 
1157     private Type erasure(Type t) {
1158         return types.erasure(t);
1159     }
1160 
1161 /* ************************************************************************
1162  * main method
1163  *************************************************************************/
1164 
1165     private Env<AttrContext> env;
1166 
1167     private static final String statePreviousToFlowAssertMsg =
1168             "The current compile state [%s] of class %s is previous to FLOW";
1169 
1170     void translateClass(ClassSymbol c) {
1171         Type st = types.supertype(c.type);
1172         // process superclass before derived
1173         if (st.hasTag(CLASS)) {
1174             translateClass((ClassSymbol)st.tsym);
1175         }
1176 
1177         Env<AttrContext> myEnv = enter.getEnv(c);
1178         if (myEnv == null || (c.flags_field & TYPE_TRANSLATED) != 0) {
1179             return;
1180         }
1181         c.flags_field |= TYPE_TRANSLATED;
1182 
1183         /*  The two assertions below are set for early detection of any attempt
1184          *  to translate a class that:
1185          *
1186          *  1) has no compile state being it the most outer class.
1187          *     We accept this condition for inner classes.
1188          *
1189          *  2) has a compile state which is previous to Flow state.
1190          */
1191         boolean envHasCompState = compileStates.get(myEnv) != null;
1192         if (!envHasCompState && c.outermostClass() == c) {
1193             Assert.error("No info for outermost class: " + myEnv.enclClass.sym);
1194         }
1195 
1196         if (envHasCompState &&
1197                 CompileState.FLOW.isAfter(compileStates.get(myEnv))) {
1198             Assert.error(String.format(statePreviousToFlowAssertMsg,
1199                     compileStates.get(myEnv), myEnv.enclClass.sym));
1200         }
1201 
1202         Env<AttrContext> oldEnv = env;
1203         try {
1204             env = myEnv;
1205             // class has not been translated yet
1206 
1207             TreeMaker savedMake = make;
1208             Type savedPt = pt;
1209             make = make.forToplevel(env.toplevel);
1210             pt = null;
1211             try {
1212                 JCClassDecl tree = (JCClassDecl) env.tree;
1213                 tree.typarams = List.nil();
1214                 super.visitClassDef(tree);
1215                 make.at(tree.pos);
1216                 ListBuffer<JCTree> bridges = new ListBuffer<>();
1217                 addBridges(tree.pos(), c, bridges);
1218                 tree.defs = bridges.toList().prependList(tree.defs);
1219                 tree.type = erasure(tree.type);
1220             } finally {
1221                 make = savedMake;
1222                 pt = savedPt;
1223             }
1224         } finally {
1225             env = oldEnv;
1226         }
1227     }
1228 
1229     /** Translate a toplevel class definition.
1230      *  @param cdef    The definition to be translated.
1231      */
1232     public JCTree translateTopLevelClass(JCTree cdef, TreeMaker make) {
1233         // note that this method does NOT support recursion.
1234         this.make = make;
1235         pt = null;
1236         return translate(cdef, null);
1237     }
1238 }