TransTypes.java revision 4184:3b9297698293
1/* 2 * Copyright (c) 1999, 2017, 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 26package com.sun.tools.javac.comp; 27 28import java.util.*; 29 30import com.sun.tools.javac.code.*; 31import com.sun.tools.javac.code.Attribute.TypeCompound; 32import com.sun.tools.javac.code.Symbol.*; 33import com.sun.tools.javac.resources.CompilerProperties.Errors; 34import com.sun.tools.javac.tree.*; 35import com.sun.tools.javac.tree.JCTree.*; 36import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind; 37import com.sun.tools.javac.util.*; 38import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 39import com.sun.tools.javac.util.List; 40 41import static com.sun.tools.javac.code.Flags.*; 42import static com.sun.tools.javac.code.Kinds.Kind.*; 43import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE; 44import static com.sun.tools.javac.code.TypeTag.CLASS; 45import static com.sun.tools.javac.code.TypeTag.TYPEVAR; 46import static com.sun.tools.javac.code.TypeTag.VOID; 47import static com.sun.tools.javac.comp.CompileStates.CompileState; 48 49/** This pass translates Generic Java to conventional Java. 50 * 51 * <p><b>This is NOT part of any supported API. 52 * If you write code that depends on this, you do so at your own risk. 53 * This code and its internal interfaces are subject to change or 54 * deletion without notice.</b> 55 */ 56public class TransTypes extends TreeTranslator { 57 /** The context key for the TransTypes phase. */ 58 protected static final Context.Key<TransTypes> transTypesKey = new Context.Key<>(); 59 60 /** Get the instance for this context. */ 61 public static TransTypes instance(Context context) { 62 TransTypes instance = context.get(transTypesKey); 63 if (instance == null) 64 instance = new TransTypes(context); 65 return instance; 66 } 67 68 private Names names; 69 private Log log; 70 private Symtab syms; 71 private TreeMaker make; 72 private Enter enter; 73 private Types types; 74 private Annotate annotate; 75 private final Resolve resolve; 76 private final CompileStates compileStates; 77 78 /** Switch: is complex graph inference supported? */ 79 private final boolean allowGraphInference; 80 81 /** Switch: are default methods supported? */ 82 private final boolean allowInterfaceBridges; 83 84 protected TransTypes(Context context) { 85 context.put(transTypesKey, this); 86 compileStates = CompileStates.instance(context); 87 names = Names.instance(context); 88 log = Log.instance(context); 89 syms = Symtab.instance(context); 90 enter = Enter.instance(context); 91 bridgeSpans = new HashMap<>(); 92 types = Types.instance(context); 93 make = TreeMaker.instance(context); 94 resolve = Resolve.instance(context); 95 Source source = Source.instance(context); 96 allowInterfaceBridges = source.allowDefaultMethods(); 97 allowGraphInference = source.allowGraphInference(); 98 annotate = Annotate.instance(context); 99 } 100 101 /** A hashtable mapping bridge methods to the pair of methods they bridge. 102 * The bridge overrides the first of the pair after type erasure and deflects 103 * to the second of the pair (which differs in type erasure from the one 104 * it overrides thereby necessitating the bridge) 105 */ 106 Map<MethodSymbol, Pair<MethodSymbol, MethodSymbol>> bridgeSpans; 107 108 /** Construct an attributed tree for a cast of expression to target type, 109 * unless it already has precisely that type. 110 * @param tree The expression tree. 111 * @param target The target type. 112 */ 113 JCExpression cast(JCExpression tree, Type target) { 114 int oldpos = make.pos; 115 make.at(tree.pos); 116 if (!types.isSameType(tree.type, target)) { 117 if (!resolve.isAccessible(env, target.tsym)) 118 resolve.logAccessErrorInternal(env, tree, target); 119 tree = make.TypeCast(make.Type(target), tree).setType(target); 120 } 121 make.pos = oldpos; 122 return tree; 123 } 124 125 /** Construct an attributed tree to coerce an expression to some erased 126 * target type, unless the expression is already assignable to that type. 127 * If target type is a constant type, use its base type instead. 128 * @param tree The expression tree. 129 * @param target The target type. 130 */ 131 public JCExpression coerce(Env<AttrContext> env, JCExpression tree, Type target) { 132 Env<AttrContext> prevEnv = this.env; 133 try { 134 this.env = env; 135 return coerce(tree, target); 136 } 137 finally { 138 this.env = prevEnv; 139 } 140 } 141 JCExpression coerce(JCExpression tree, Type target) { 142 Type btarget = target.baseType(); 143 if (tree.type.isPrimitive() == target.isPrimitive()) { 144 return types.isAssignable(tree.type, btarget, types.noWarnings) 145 ? tree 146 : cast(tree, btarget); 147 } 148 return tree; 149 } 150 151 /** Given an erased reference type, assume this type as the tree's type. 152 * Then, coerce to some given target type unless target type is null. 153 * This operation is used in situations like the following: 154 * 155 * <pre>{@code 156 * class Cell<A> { A value; } 157 * ... 158 * Cell<Integer> cell; 159 * Integer x = cell.value; 160 * }</pre> 161 * 162 * Since the erasure of Cell.value is Object, but the type 163 * of cell.value in the assignment is Integer, we need to 164 * adjust the original type of cell.value to Object, and insert 165 * a cast to Integer. That is, the last assignment becomes: 166 * 167 * <pre>{@code 168 * Integer x = (Integer)cell.value; 169 * }</pre> 170 * 171 * @param tree The expression tree whose type might need adjustment. 172 * @param erasedType The expression's type after erasure. 173 * @param target The target type, which is usually the erasure of the 174 * expression's original type. 175 */ 176 JCExpression retype(JCExpression tree, Type erasedType, Type target) { 177// System.err.println("retype " + tree + " to " + erasedType);//DEBUG 178 if (!erasedType.isPrimitive()) { 179 if (target != null && target.isPrimitive()) { 180 target = erasure(tree.type); 181 } 182 tree.type = erasedType; 183 if (target != null) { 184 return coerce(tree, target); 185 } 186 } 187 return tree; 188 } 189 190 /** Translate method argument list, casting each argument 191 * to its corresponding type in a list of target types. 192 * @param _args The method argument list. 193 * @param parameters The list of target types. 194 * @param varargsElement The erasure of the varargs element type, 195 * or null if translating a non-varargs invocation 196 */ 197 <T extends JCTree> List<T> translateArgs(List<T> _args, 198 List<Type> parameters, 199 Type varargsElement) { 200 if (parameters.isEmpty()) return _args; 201 List<T> args = _args; 202 while (parameters.tail.nonEmpty()) { 203 args.head = translate(args.head, parameters.head); 204 args = args.tail; 205 parameters = parameters.tail; 206 } 207 Type parameter = parameters.head; 208 Assert.check(varargsElement != null || args.length() == 1); 209 if (varargsElement != null) { 210 while (args.nonEmpty()) { 211 args.head = translate(args.head, varargsElement); 212 args = args.tail; 213 } 214 } else { 215 args.head = translate(args.head, parameter); 216 } 217 return _args; 218 } 219 220 public <T extends JCTree> List<T> translateArgs(List<T> _args, 221 List<Type> parameters, 222 Type varargsElement, 223 Env<AttrContext> localEnv) { 224 Env<AttrContext> prevEnv = env; 225 try { 226 env = localEnv; 227 return translateArgs(_args, parameters, varargsElement); 228 } 229 finally { 230 env = prevEnv; 231 } 232 } 233 234 /** Add a bridge definition and enter corresponding method symbol in 235 * local scope of origin. 236 * 237 * @param pos The source code position to be used for the definition. 238 * @param meth The method for which a bridge needs to be added 239 * @param impl That method's implementation (possibly the method itself) 240 * @param origin The class to which the bridge will be added 241 * @param hypothetical 242 * True if the bridge method is not strictly necessary in the 243 * binary, but is represented in the symbol table to detect 244 * erasure clashes. 245 * @param bridges The list buffer to which the bridge will be added 246 */ 247 void addBridge(DiagnosticPosition pos, 248 MethodSymbol meth, 249 MethodSymbol impl, 250 ClassSymbol origin, 251 boolean hypothetical, 252 ListBuffer<JCTree> bridges) { 253 make.at(pos); 254 Type origType = types.memberType(origin.type, meth); 255 Type origErasure = erasure(origType); 256 257 // Create a bridge method symbol and a bridge definition without a body. 258 Type bridgeType = meth.erasure(types); 259 long flags = impl.flags() & AccessFlags | SYNTHETIC | BRIDGE | 260 (origin.isInterface() ? DEFAULT : 0); 261 if (hypothetical) flags |= HYPOTHETICAL; 262 MethodSymbol bridge = new MethodSymbol(flags, 263 meth.name, 264 bridgeType, 265 origin); 266 /* once JDK-6996415 is solved it should be checked if this approach can 267 * be applied to method addOverrideBridgesIfNeeded 268 */ 269 bridge.params = createBridgeParams(impl, bridge, bridgeType); 270 bridge.setAttributes(impl); 271 272 if (!hypothetical) { 273 JCMethodDecl md = make.MethodDef(bridge, null); 274 275 // The bridge calls this.impl(..), if we have an implementation 276 // in the current class, super.impl(...) otherwise. 277 JCExpression receiver = (impl.owner == origin) 278 ? make.This(origin.erasure(types)) 279 : make.Super(types.supertype(origin.type).tsym.erasure(types), origin); 280 281 // The type returned from the original method. 282 Type calltype = erasure(impl.type.getReturnType()); 283 284 // Construct a call of this.impl(params), or super.impl(params), 285 // casting params and possibly results as needed. 286 JCExpression call = 287 make.Apply( 288 null, 289 make.Select(receiver, impl).setType(calltype), 290 translateArgs(make.Idents(md.params), origErasure.getParameterTypes(), null)) 291 .setType(calltype); 292 JCStatement stat = (origErasure.getReturnType().hasTag(VOID)) 293 ? make.Exec(call) 294 : make.Return(coerce(call, bridgeType.getReturnType())); 295 md.body = make.Block(0, List.of(stat)); 296 297 // Add bridge to `bridges' buffer 298 bridges.append(md); 299 } 300 301 // Add bridge to scope of enclosing class and keep track of the bridge span. 302 origin.members().enter(bridge); 303 bridgeSpans.put(bridge, new Pair<>(meth, impl)); 304 } 305 306 private List<VarSymbol> createBridgeParams(MethodSymbol impl, MethodSymbol bridge, 307 Type bridgeType) { 308 List<VarSymbol> bridgeParams = null; 309 if (impl.params != null) { 310 bridgeParams = List.nil(); 311 List<VarSymbol> implParams = impl.params; 312 Type.MethodType mType = (Type.MethodType)bridgeType; 313 List<Type> argTypes = mType.argtypes; 314 while (implParams.nonEmpty() && argTypes.nonEmpty()) { 315 VarSymbol param = new VarSymbol(implParams.head.flags() | SYNTHETIC | PARAMETER, 316 implParams.head.name, argTypes.head, bridge); 317 param.setAttributes(implParams.head); 318 bridgeParams = bridgeParams.append(param); 319 implParams = implParams.tail; 320 argTypes = argTypes.tail; 321 } 322 } 323 return bridgeParams; 324 } 325 326 /** Add bridge if given symbol is a non-private, non-static member 327 * of the given class, which is either defined in the class or non-final 328 * inherited, and one of the two following conditions holds: 329 * 1. The method's type changes in the given class, as compared to the 330 * class where the symbol was defined, (in this case 331 * we have extended a parameterized class with non-trivial parameters). 332 * 2. The method has an implementation with a different erased return type. 333 * (in this case we have used co-variant returns). 334 * If a bridge already exists in some other class, no new bridge is added. 335 * Instead, it is checked that the bridge symbol overrides the method symbol. 336 * (Spec ???). 337 * todo: what about bridges for privates??? 338 * 339 * @param pos The source code position to be used for the definition. 340 * @param sym The symbol for which a bridge might have to be added. 341 * @param origin The class in which the bridge would go. 342 * @param bridges The list buffer to which the bridge would be added. 343 */ 344 void addBridgeIfNeeded(DiagnosticPosition pos, 345 Symbol sym, 346 ClassSymbol origin, 347 ListBuffer<JCTree> bridges) { 348 if (sym.kind == MTH && 349 sym.name != names.init && 350 (sym.flags() & (PRIVATE | STATIC)) == 0 && 351 (sym.flags() & SYNTHETIC) != SYNTHETIC && 352 sym.isMemberOf(origin, types)) 353 { 354 MethodSymbol meth = (MethodSymbol)sym; 355 MethodSymbol bridge = meth.binaryImplementation(origin, types); 356 MethodSymbol impl = meth.implementation(origin, types, true); 357 if (bridge == null || 358 bridge == meth || 359 (impl != null && !bridge.owner.isSubClass(impl.owner, types))) { 360 // No bridge was added yet. 361 if (impl != null && isBridgeNeeded(meth, impl, origin.type)) { 362 addBridge(pos, meth, impl, origin, bridge==impl, bridges); 363 } else if (impl == meth 364 && impl.owner != origin 365 && (impl.flags() & FINAL) == 0 366 && (meth.flags() & (ABSTRACT|PUBLIC)) == PUBLIC 367 && (origin.flags() & PUBLIC) > (impl.owner.flags() & PUBLIC)) { 368 // this is to work around a horrible but permanent 369 // reflection design error. 370 addBridge(pos, meth, impl, origin, false, bridges); 371 } 372 } else if ((bridge.flags() & SYNTHETIC) == SYNTHETIC) { 373 final Pair<MethodSymbol, MethodSymbol> bridgeSpan = bridgeSpans.get(bridge); 374 MethodSymbol other = bridgeSpan == null ? null : bridgeSpan.fst; 375 if (other != null && other != meth) { 376 if (impl == null || !impl.overrides(other, origin, types, true)) { 377 // Is bridge effectively also the bridge for `meth', if so no clash. 378 MethodSymbol target = bridgeSpan == null ? null : bridgeSpan.snd; 379 if (target == null || !target.overrides(meth, origin, types, true, false)) { 380 // Bridge for other symbol pair was added 381 log.error(pos, Errors.NameClashSameErasureNoOverride( 382 other.name, types.memberType(origin.type, other).asMethodType().getParameterTypes(), 383 other.location(origin.type, types), 384 meth.name, types.memberType(origin.type, meth).asMethodType().getParameterTypes(), 385 meth.location(origin.type, types))); 386 } 387 } 388 } 389 } else if (!bridge.overrides(meth, origin, types, true)) { 390 // Accidental binary override without source override. 391 // Don't diagnose the problem if it would already 392 // have been reported in the superclass 393 if (bridge.owner == origin || 394 types.asSuper(bridge.owner.type, meth.owner) == null) { 395 log.error(pos, Errors.NameClashSameErasureNoOverride( 396 bridge.name, types.memberType(origin.type, bridge).asMethodType().getParameterTypes(), 397 bridge.location(origin.type, types), 398 meth.name, types.memberType(origin.type, meth).asMethodType().getParameterTypes(), 399 meth.location(origin.type, types))); 400 } 401 } 402 } 403 } 404 // where 405 406 /** 407 * @param method The symbol for which a bridge might have to be added 408 * @param impl The implementation of method 409 * @param dest The type in which the bridge would go 410 */ 411 private boolean isBridgeNeeded(MethodSymbol method, 412 MethodSymbol impl, 413 Type dest) { 414 if (impl != method) { 415 // If either method or impl have different erasures as 416 // members of dest, a bridge is needed. 417 Type method_erasure = method.erasure(types); 418 if (!isSameMemberWhenErased(dest, method, method_erasure)) 419 return true; 420 Type impl_erasure = impl.erasure(types); 421 if (!isSameMemberWhenErased(dest, impl, impl_erasure)) 422 return true; 423 424 /* Bottom line: A bridge is needed if the erasure of the implementation 425 is different from that of the method that it overrides. 426 */ 427 return !types.isSameType(impl_erasure, method_erasure); 428 } else { 429 // method and impl are the same... 430 if ((method.flags() & ABSTRACT) != 0) { 431 // ...and abstract so a bridge is not needed. 432 // Concrete subclasses will bridge as needed. 433 return false; 434 } 435 436 // The erasure of the return type is always the same 437 // for the same symbol. Reducing the three tests in 438 // the other branch to just one: 439 return !isSameMemberWhenErased(dest, method, method.erasure(types)); 440 } 441 } 442 /** 443 * Lookup the method as a member of the type. Compare the 444 * erasures. 445 * @param type the class where to look for the method 446 * @param method the method to look for in class 447 * @param erasure the erasure of method 448 */ 449 private boolean isSameMemberWhenErased(Type type, 450 MethodSymbol method, 451 Type erasure) { 452 return types.isSameType(erasure(types.memberType(type, method)), 453 erasure); 454 } 455 456 void addBridges(DiagnosticPosition pos, 457 TypeSymbol i, 458 ClassSymbol origin, 459 ListBuffer<JCTree> bridges) { 460 for (Symbol sym : i.members().getSymbols(NON_RECURSIVE)) 461 addBridgeIfNeeded(pos, sym, origin, bridges); 462 for (List<Type> l = types.interfaces(i.type); l.nonEmpty(); l = l.tail) 463 addBridges(pos, l.head.tsym, origin, bridges); 464 } 465 466 /** Add all necessary bridges to some class appending them to list buffer. 467 * @param pos The source code position to be used for the bridges. 468 * @param origin The class in which the bridges go. 469 * @param bridges The list buffer to which the bridges are added. 470 */ 471 void addBridges(DiagnosticPosition pos, ClassSymbol origin, ListBuffer<JCTree> bridges) { 472 Type st = types.supertype(origin.type); 473 while (st.hasTag(CLASS)) { 474// if (isSpecialization(st)) 475 addBridges(pos, st.tsym, origin, bridges); 476 st = types.supertype(st); 477 } 478 for (List<Type> l = types.interfaces(origin.type); l.nonEmpty(); l = l.tail) 479// if (isSpecialization(l.head)) 480 addBridges(pos, l.head.tsym, origin, bridges); 481 } 482 483/* ************************************************************************ 484 * Visitor methods 485 *************************************************************************/ 486 487 /** Visitor argument: proto-type. 488 */ 489 private Type pt; 490 491 /** Visitor method: perform a type translation on tree. 492 */ 493 public <T extends JCTree> T translate(T tree, Type pt) { 494 Type prevPt = this.pt; 495 try { 496 this.pt = pt; 497 return translate(tree); 498 } finally { 499 this.pt = prevPt; 500 } 501 } 502 503 /** Visitor method: perform a type translation on list of trees. 504 */ 505 public <T extends JCTree> List<T> translate(List<T> trees, Type pt) { 506 Type prevPt = this.pt; 507 List<T> res; 508 try { 509 this.pt = pt; 510 res = translate(trees); 511 } finally { 512 this.pt = prevPt; 513 } 514 return res; 515 } 516 517 public void visitClassDef(JCClassDecl tree) { 518 translateClass(tree.sym); 519 result = tree; 520 } 521 522 JCTree currentMethod = null; 523 public void visitMethodDef(JCMethodDecl tree) { 524 JCTree previousMethod = currentMethod; 525 try { 526 currentMethod = tree; 527 tree.restype = translate(tree.restype, null); 528 tree.typarams = List.nil(); 529 tree.params = translateVarDefs(tree.params); 530 tree.recvparam = translate(tree.recvparam, null); 531 tree.thrown = translate(tree.thrown, null); 532 tree.body = translate(tree.body, tree.sym.erasure(types).getReturnType()); 533 tree.type = erasure(tree.type); 534 result = tree; 535 } finally { 536 currentMethod = previousMethod; 537 } 538 539 // Check that we do not introduce a name clash by erasing types. 540 for (Symbol sym : tree.sym.owner.members().getSymbolsByName(tree.name)) { 541 if (sym != tree.sym && 542 types.isSameType(erasure(sym.type), tree.type)) { 543 log.error(tree.pos(), 544 "name.clash.same.erasure", tree.sym, 545 sym); 546 return; 547 } 548 } 549 } 550 551 public void visitVarDef(JCVariableDecl tree) { 552 tree.vartype = translate(tree.vartype, null); 553 tree.init = translate(tree.init, tree.sym.erasure(types)); 554 tree.type = erasure(tree.type); 555 result = tree; 556 } 557 558 public void visitDoLoop(JCDoWhileLoop tree) { 559 tree.body = translate(tree.body); 560 tree.cond = translate(tree.cond, syms.booleanType); 561 result = tree; 562 } 563 564 public void visitWhileLoop(JCWhileLoop tree) { 565 tree.cond = translate(tree.cond, syms.booleanType); 566 tree.body = translate(tree.body); 567 result = tree; 568 } 569 570 public void visitForLoop(JCForLoop tree) { 571 tree.init = translate(tree.init, null); 572 if (tree.cond != null) 573 tree.cond = translate(tree.cond, syms.booleanType); 574 tree.step = translate(tree.step, null); 575 tree.body = translate(tree.body); 576 result = tree; 577 } 578 579 public void visitForeachLoop(JCEnhancedForLoop tree) { 580 tree.var = translate(tree.var, null); 581 Type iterableType = tree.expr.type; 582 tree.expr = translate(tree.expr, erasure(tree.expr.type)); 583 if (types.elemtype(tree.expr.type) == null) 584 tree.expr.type = iterableType; // preserve type for Lower 585 tree.body = translate(tree.body); 586 result = tree; 587 } 588 589 public void visitLambda(JCLambda tree) { 590 JCTree prevMethod = currentMethod; 591 try { 592 currentMethod = null; 593 tree.params = translate(tree.params); 594 tree.body = translate(tree.body, tree.body.type==null? null : erasure(tree.body.type)); 595 tree.type = erasure(tree.type); 596 result = tree; 597 } 598 finally { 599 currentMethod = prevMethod; 600 } 601 } 602 603 public void visitSwitch(JCSwitch tree) { 604 Type selsuper = types.supertype(tree.selector.type); 605 boolean enumSwitch = selsuper != null && 606 selsuper.tsym == syms.enumSym; 607 Type target = enumSwitch ? erasure(tree.selector.type) : syms.intType; 608 tree.selector = translate(tree.selector, target); 609 tree.cases = translateCases(tree.cases); 610 result = tree; 611 } 612 613 public void visitCase(JCCase tree) { 614 tree.pat = translate(tree.pat, null); 615 tree.stats = translate(tree.stats); 616 result = tree; 617 } 618 619 public void visitSynchronized(JCSynchronized tree) { 620 tree.lock = translate(tree.lock, erasure(tree.lock.type)); 621 tree.body = translate(tree.body); 622 result = tree; 623 } 624 625 public void visitTry(JCTry tree) { 626 tree.resources = translate(tree.resources, syms.autoCloseableType); 627 tree.body = translate(tree.body); 628 tree.catchers = translateCatchers(tree.catchers); 629 tree.finalizer = translate(tree.finalizer); 630 result = tree; 631 } 632 633 public void visitConditional(JCConditional tree) { 634 tree.cond = translate(tree.cond, syms.booleanType); 635 tree.truepart = translate(tree.truepart, erasure(tree.type)); 636 tree.falsepart = translate(tree.falsepart, erasure(tree.type)); 637 tree.type = erasure(tree.type); 638 result = retype(tree, tree.type, pt); 639 } 640 641 public void visitIf(JCIf tree) { 642 tree.cond = translate(tree.cond, syms.booleanType); 643 tree.thenpart = translate(tree.thenpart); 644 tree.elsepart = translate(tree.elsepart); 645 result = tree; 646 } 647 648 public void visitExec(JCExpressionStatement tree) { 649 tree.expr = translate(tree.expr, null); 650 result = tree; 651 } 652 653 public void visitReturn(JCReturn tree) { 654 tree.expr = translate(tree.expr, currentMethod != null ? types.erasure(currentMethod.type).getReturnType() : null); 655 result = tree; 656 } 657 658 public void visitThrow(JCThrow tree) { 659 tree.expr = translate(tree.expr, erasure(tree.expr.type)); 660 result = tree; 661 } 662 663 public void visitAssert(JCAssert tree) { 664 tree.cond = translate(tree.cond, syms.booleanType); 665 if (tree.detail != null) 666 tree.detail = translate(tree.detail, erasure(tree.detail.type)); 667 result = tree; 668 } 669 670 public void visitApply(JCMethodInvocation tree) { 671 tree.meth = translate(tree.meth, null); 672 Symbol meth = TreeInfo.symbol(tree.meth); 673 Type mt = meth.erasure(types); 674 boolean useInstantiatedPtArgs = 675 allowGraphInference && !types.isSignaturePolymorphic((MethodSymbol)meth.baseSymbol()); 676 List<Type> argtypes = useInstantiatedPtArgs ? 677 tree.meth.type.getParameterTypes() : 678 mt.getParameterTypes(); 679 if (meth.name == names.init && meth.owner == syms.enumSym) 680 argtypes = argtypes.tail.tail; 681 if (tree.varargsElement != null) 682 tree.varargsElement = types.erasure(tree.varargsElement); 683 else 684 if (tree.args.length() != argtypes.length()) { 685 log.error(tree.pos(), 686 "method.invoked.with.incorrect.number.arguments", 687 tree.args.length(), argtypes.length()); 688 } 689 tree.args = translateArgs(tree.args, argtypes, tree.varargsElement); 690 691 tree.type = types.erasure(tree.type); 692 // Insert casts of method invocation results as needed. 693 result = retype(tree, mt.getReturnType(), pt); 694 } 695 696 public void visitNewClass(JCNewClass tree) { 697 if (tree.encl != null) 698 tree.encl = translate(tree.encl, erasure(tree.encl.type)); 699 700 Type erasedConstructorType = tree.constructorType != null ? 701 erasure(tree.constructorType) : 702 null; 703 704 List<Type> argtypes = erasedConstructorType != null && allowGraphInference ? 705 erasedConstructorType.getParameterTypes() : 706 tree.constructor.erasure(types).getParameterTypes(); 707 708 tree.clazz = translate(tree.clazz, null); 709 if (tree.varargsElement != null) 710 tree.varargsElement = types.erasure(tree.varargsElement); 711 tree.args = translateArgs( 712 tree.args, argtypes, tree.varargsElement); 713 tree.def = translate(tree.def, null); 714 if (erasedConstructorType != null) 715 tree.constructorType = erasedConstructorType; 716 tree.type = erasure(tree.type); 717 result = tree; 718 } 719 720 public void visitNewArray(JCNewArray tree) { 721 tree.elemtype = translate(tree.elemtype, null); 722 translate(tree.dims, syms.intType); 723 if (tree.type != null) { 724 tree.elems = translate(tree.elems, erasure(types.elemtype(tree.type))); 725 tree.type = erasure(tree.type); 726 } else { 727 tree.elems = translate(tree.elems, null); 728 } 729 730 result = tree; 731 } 732 733 public void visitParens(JCParens tree) { 734 tree.expr = translate(tree.expr, pt); 735 tree.type = erasure(tree.expr.type); 736 result = tree; 737 } 738 739 public void visitAssign(JCAssign tree) { 740 tree.lhs = translate(tree.lhs, null); 741 tree.rhs = translate(tree.rhs, erasure(tree.lhs.type)); 742 tree.type = erasure(tree.lhs.type); 743 result = retype(tree, tree.type, pt); 744 } 745 746 public void visitAssignop(JCAssignOp tree) { 747 tree.lhs = translate(tree.lhs, null); 748 tree.rhs = translate(tree.rhs, tree.operator.type.getParameterTypes().tail.head); 749 tree.type = erasure(tree.type); 750 result = tree; 751 } 752 753 public void visitUnary(JCUnary tree) { 754 tree.arg = translate(tree.arg, (tree.getTag() == Tag.NULLCHK) 755 ? tree.type 756 : tree.operator.type.getParameterTypes().head); 757 result = tree; 758 } 759 760 public void visitBinary(JCBinary tree) { 761 tree.lhs = translate(tree.lhs, tree.operator.type.getParameterTypes().head); 762 tree.rhs = translate(tree.rhs, tree.operator.type.getParameterTypes().tail.head); 763 result = tree; 764 } 765 766 public void visitAnnotatedType(JCAnnotatedType tree) { 767 // For now, we need to keep the annotations in the tree because of the current 768 // MultiCatch implementation wrt type annotations 769 List<TypeCompound> mirrors = annotate.fromAnnotations(tree.annotations); 770 tree.underlyingType = translate(tree.underlyingType); 771 tree.type = tree.underlyingType.type.annotatedType(mirrors); 772 result = tree; 773 } 774 775 public void visitTypeCast(JCTypeCast tree) { 776 tree.clazz = translate(tree.clazz, null); 777 Type originalTarget = tree.type; 778 tree.type = erasure(tree.type); 779 JCExpression newExpression = translate(tree.expr, tree.type); 780 if (newExpression != tree.expr) { 781 JCTypeCast typeCast = newExpression.hasTag(Tag.TYPECAST) 782 ? (JCTypeCast) newExpression 783 : null; 784 tree.expr = typeCast != null && types.isSameType(typeCast.type, originalTarget, true) 785 ? typeCast.expr 786 : newExpression; 787 } 788 if (originalTarget.isIntersection()) { 789 Type.IntersectionClassType ict = (Type.IntersectionClassType)originalTarget; 790 for (Type c : ict.getExplicitComponents()) { 791 Type ec = erasure(c); 792 if (!types.isSameType(ec, tree.type)) { 793 tree.expr = coerce(tree.expr, ec); 794 } 795 } 796 } 797 result = tree; 798 } 799 800 public void visitTypeTest(JCInstanceOf tree) { 801 tree.expr = translate(tree.expr, null); 802 tree.clazz = translate(tree.clazz, null); 803 result = tree; 804 } 805 806 public void visitIndexed(JCArrayAccess tree) { 807 tree.indexed = translate(tree.indexed, erasure(tree.indexed.type)); 808 tree.index = translate(tree.index, syms.intType); 809 810 // Insert casts of indexed expressions as needed. 811 result = retype(tree, types.elemtype(tree.indexed.type), pt); 812 } 813 814 // There ought to be nothing to rewrite here; 815 // we don't generate code. 816 public void visitAnnotation(JCAnnotation tree) { 817 result = tree; 818 } 819 820 public void visitIdent(JCIdent tree) { 821 Type et = tree.sym.erasure(types); 822 823 // Map type variables to their bounds. 824 if (tree.sym.kind == TYP && tree.sym.type.hasTag(TYPEVAR)) { 825 result = make.at(tree.pos).Type(et); 826 } else 827 // Map constants expressions to themselves. 828 if (tree.type.constValue() != null) { 829 result = tree; 830 } 831 // Insert casts of variable uses as needed. 832 else if (tree.sym.kind == VAR) { 833 result = retype(tree, et, pt); 834 } 835 else { 836 tree.type = erasure(tree.type); 837 result = tree; 838 } 839 } 840 841 public void visitSelect(JCFieldAccess tree) { 842 Type t = types.skipTypeVars(tree.selected.type, false); 843 if (t.isCompound()) { 844 tree.selected = coerce( 845 translate(tree.selected, erasure(tree.selected.type)), 846 erasure(tree.sym.owner.type)); 847 } else 848 tree.selected = translate(tree.selected, erasure(t)); 849 850 // Map constants expressions to themselves. 851 if (tree.type.constValue() != null) { 852 result = tree; 853 } 854 // Insert casts of variable uses as needed. 855 else if (tree.sym.kind == VAR) { 856 result = retype(tree, tree.sym.erasure(types), pt); 857 } 858 else { 859 tree.type = erasure(tree.type); 860 result = tree; 861 } 862 } 863 864 public void visitReference(JCMemberReference tree) { 865 Type t = types.skipTypeVars(tree.expr.type, false); 866 Type receiverTarget = t.isCompound() ? erasure(tree.sym.owner.type) : erasure(t); 867 if (tree.kind == ReferenceKind.UNBOUND) { 868 tree.expr = make.Type(receiverTarget); 869 } else { 870 tree.expr = translate(tree.expr, receiverTarget); 871 } 872 873 tree.type = erasure(tree.type); 874 if (tree.varargsElement != null) 875 tree.varargsElement = erasure(tree.varargsElement); 876 result = tree; 877 } 878 879 public void visitTypeArray(JCArrayTypeTree tree) { 880 tree.elemtype = translate(tree.elemtype, null); 881 tree.type = erasure(tree.type); 882 result = tree; 883 } 884 885 /** Visitor method for parameterized types. 886 */ 887 public void visitTypeApply(JCTypeApply tree) { 888 JCTree clazz = translate(tree.clazz, null); 889 result = clazz; 890 } 891 892 public void visitTypeIntersection(JCTypeIntersection tree) { 893 tree.bounds = translate(tree.bounds, null); 894 tree.type = erasure(tree.type); 895 result = tree; 896 } 897 898/************************************************************************** 899 * utility methods 900 *************************************************************************/ 901 902 private Type erasure(Type t) { 903 return types.erasure(t); 904 } 905 906/************************************************************************** 907 * main method 908 *************************************************************************/ 909 910 private Env<AttrContext> env; 911 912 private static final String statePreviousToFlowAssertMsg = 913 "The current compile state [%s] of class %s is previous to FLOW"; 914 915 void translateClass(ClassSymbol c) { 916 Type st = types.supertype(c.type); 917 // process superclass before derived 918 if (st.hasTag(CLASS)) { 919 translateClass((ClassSymbol)st.tsym); 920 } 921 922 Env<AttrContext> myEnv = enter.getEnv(c); 923 if (myEnv == null || (c.flags_field & TYPE_TRANSLATED) != 0) { 924 return; 925 } 926 c.flags_field |= TYPE_TRANSLATED; 927 928 /* The two assertions below are set for early detection of any attempt 929 * to translate a class that: 930 * 931 * 1) has no compile state being it the most outer class. 932 * We accept this condition for inner classes. 933 * 934 * 2) has a compile state which is previous to Flow state. 935 */ 936 boolean envHasCompState = compileStates.get(myEnv) != null; 937 if (!envHasCompState && c.outermostClass() == c) { 938 Assert.error("No info for outermost class: " + myEnv.enclClass.sym); 939 } 940 941 if (envHasCompState && 942 CompileState.FLOW.isAfter(compileStates.get(myEnv))) { 943 Assert.error(String.format(statePreviousToFlowAssertMsg, 944 compileStates.get(myEnv), myEnv.enclClass.sym)); 945 } 946 947 Env<AttrContext> oldEnv = env; 948 try { 949 env = myEnv; 950 // class has not been translated yet 951 952 TreeMaker savedMake = make; 953 Type savedPt = pt; 954 make = make.forToplevel(env.toplevel); 955 pt = null; 956 try { 957 JCClassDecl tree = (JCClassDecl) env.tree; 958 tree.typarams = List.nil(); 959 super.visitClassDef(tree); 960 make.at(tree.pos); 961 ListBuffer<JCTree> bridges = new ListBuffer<>(); 962 if (allowInterfaceBridges || (tree.sym.flags() & INTERFACE) == 0) { 963 addBridges(tree.pos(), c, bridges); 964 } 965 tree.defs = bridges.toList().prependList(tree.defs); 966 tree.type = erasure(tree.type); 967 } finally { 968 make = savedMake; 969 pt = savedPt; 970 } 971 } finally { 972 env = oldEnv; 973 } 974 } 975 976 /** Translate a toplevel class definition. 977 * @param cdef The definition to be translated. 978 */ 979 public JCTree translateTopLevelClass(JCTree cdef, TreeMaker make) { 980 // note that this method does NOT support recursion. 981 this.make = make; 982 pt = null; 983 return translate(cdef, null); 984 } 985} 986