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 }