| 1 | /* | 
| 2 |  * Copyright 1999-2006 Sun Microsystems, Inc.  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.  Sun designates this | 
| 8 |  * particular file as subject to the "Classpath" exception as provided | 
| 9 |  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | 
| 22 |  * CA 95054 USA or visit www.sun.com if you need additional information or | 
| 23 |  * have any questions. | 
| 24 |  */ | 
| 25 |   | 
| 26 | package com.sun.tools.javac.comp; | 
| 27 |   | 
| 28 | import java.util.*; | 
| 29 |   | 
| 30 | import com.sun.tools.javac.code.*; | 
| 31 | import com.sun.tools.javac.code.Symbol.*; | 
| 32 | import com.sun.tools.javac.tree.*; | 
| 33 | import com.sun.tools.javac.tree.JCTree.*; | 
| 34 | import com.sun.tools.javac.util.*; | 
| 35 | import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; | 
| 36 | import com.sun.tools.javac.util.List; | 
| 37 |   | 
| 38 | import static com.sun.tools.javac.code.Flags.*; | 
| 39 | import static com.sun.tools.javac.code.Kinds.*; | 
| 40 | import static com.sun.tools.javac.code.TypeTags.*; | 
| 41 |   | 
| 42 | /** This pass translates Generic Java to conventional Java. | 
| 43 |  * | 
| 44 |  *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If | 
| 45 |  *  you write code that depends on this, you do so at your own risk. | 
| 46 |  *  This code and its internal interfaces are subject to change or | 
| 47 |  *  deletion without notice.</b> | 
| 48 |  */ | 
| 49 | public class TransTypes extends TreeTranslator { | 
| 50 |     /** The context key for the TransTypes phase. */ | 
| 51 |     protected static final Context.Key<TransTypes> transTypesKey = | 
| 52 |         new Context.Key<TransTypes>(); | 
| 53 |   | 
| 54 |     /** Get the instance for this context. */ | 
| 55 |     public static TransTypes instance(Context context) { | 
| 56 |         TransTypes instance = context.get(transTypesKey); | 
| 57 |         if (instance == null) | 
| 58 |             instance = new TransTypes(context); | 
| 59 |         return instance; | 
| 60 |     } | 
| 61 |   | 
| 62 |     private Name.Table names; | 
| 63 |     private Log log; | 
| 64 |     private Symtab syms; | 
| 65 |     private TreeMaker make; | 
| 66 |     private Enter enter; | 
| 67 |     private boolean allowEnums; | 
| 68 |     private Types types; | 
| 69 |     private final Resolve resolve; | 
| 70 |   | 
| 71 |     /** | 
| 72 |      * Flag to indicate whether or not to generate bridge methods. | 
| 73 |      * For pre-Tiger source there is no need for bridge methods, so it | 
| 74 |      * can be skipped to get better performance for -source 1.4 etc. | 
| 75 |      */ | 
| 76 |     private final boolean addBridges; | 
| 77 |   | 
| 78 |     protected TransTypes(Context context) { | 
| 79 |         context.put(transTypesKey, this); | 
| 80 |         names = Name.Table.instance(context); | 
| 81 |         log = Log.instance(context); | 
| 82 |         syms = Symtab.instance(context); | 
| 83 |         enter = Enter.instance(context); | 
| 84 |         overridden = new HashMap<MethodSymbol,MethodSymbol>(); | 
| 85 |         Source source = Source.instance(context); | 
| 86 |         allowEnums = source.allowEnums(); | 
| 87 |         addBridges = source.addBridges(); | 
| 88 |         types = Types.instance(context); | 
| 89 |         make = TreeMaker.instance(context); | 
| 90 |         resolve = Resolve.instance(context); | 
| 91 |     } | 
| 92 |   | 
| 93 |     /** A hashtable mapping bridge methods to the methods they override after | 
| 94 |      *  type erasure. | 
| 95 |      */ | 
| 96 |     Map<MethodSymbol,MethodSymbol> overridden; | 
| 97 |   | 
| 98 |     /** Construct an attributed tree for a cast of expression to target type, | 
| 99 |      *  unless it already has precisely that type. | 
| 100 |      *  @param tree    The expression tree. | 
| 101 |      *  @param target  The target type. | 
| 102 |      */ | 
| 103 |     JCExpression cast(JCExpression tree, Type target) { | 
| 104 |         int oldpos = make.pos; | 
| 105 |         make.at(tree.pos); | 
| 106 |         if (!types.isSameType(tree.type, target)) { | 
| 107 |             if (!resolve.isAccessible(env, target.tsym)) | 
| 108 |                 resolve.logAccessError(env, tree, target); | 
| 109 |             tree = make.TypeCast(make.Type(target), tree).setType(target); | 
| 110 |         } | 
| 111 |         make.pos = oldpos; | 
| 112 |         return tree; | 
| 113 |     } | 
| 114 |   | 
| 115 |     /** Construct an attributed tree to coerce an expression to some erased | 
| 116 |      *  target type, unless the expression is already assignable to that type. | 
| 117 |      *  If target type is a constant type, use its base type instead. | 
| 118 |      *  @param tree    The expression tree. | 
| 119 |      *  @param target  The target type. | 
| 120 |      */ | 
| 121 |     JCExpression coerce(JCExpression tree, Type target) { | 
| 122 |         Type btarget = target.baseType(); | 
| 123 |         if (tree.type.isPrimitive() == target.isPrimitive()) { | 
| 124 |             return types.isAssignable(tree.type, btarget, Warner.noWarnings) | 
| 125 |                 ? tree | 
| 126 |                 : cast(tree, btarget); | 
| 127 |         } | 
| 128 |         return tree; | 
| 129 |     } | 
| 130 |   | 
| 131 |     /** Given an erased reference type, assume this type as the tree's type. | 
| 132 |      *  Then, coerce to some given target type unless target type is null. | 
| 133 |      *  This operation is used in situations like the following: | 
| 134 |      * | 
| 135 |      *  class Cell<A> { A value; } | 
| 136 |      *  ... | 
| 137 |      *  Cell<Integer> cell; | 
| 138 |      *  Integer x = cell.value; | 
| 139 |      * | 
| 140 |      *  Since the erasure of Cell.value is Object, but the type | 
| 141 |      *  of cell.value in the assignment is Integer, we need to | 
| 142 |      *  adjust the original type of cell.value to Object, and insert | 
| 143 |      *  a cast to Integer. That is, the last assignment becomes: | 
| 144 |      * | 
| 145 |      *  Integer x = (Integer)cell.value; | 
| 146 |      * | 
| 147 |      *  @param tree       The expression tree whose type might need adjustment. | 
| 148 |      *  @param erasedType The expression's type after erasure. | 
| 149 |      *  @param target     The target type, which is usually the erasure of the | 
| 150 |      *                    expression's original type. | 
| 151 |      */ | 
| 152 |     JCExpression retype(JCExpression tree, Type erasedType, Type target) { | 
| 153 | //      System.err.println("retype " + tree + " to " + erasedType);//DEBUG | 
| 154 |         if (erasedType.tag > lastBaseTag) { | 
| 155 |             if (target != null && target.isPrimitive()) | 
| 156 |                 target = erasure(tree.type); | 
| 157 |             tree.type = erasedType; | 
| 158 |             if (target != null) return coerce(tree, target); | 
| 159 |         } | 
| 160 |         return tree; | 
| 161 |     } | 
| 162 |   | 
| 163 |     /** Translate method argument list, casting each argument | 
| 164 |      *  to its corresponding type in a list of target types. | 
| 165 |      *  @param _args            The method argument list. | 
| 166 |      *  @param parameters       The list of target types. | 
| 167 |      *  @param varargsElement   The erasure of the varargs element type, | 
| 168 |      *  or null if translating a non-varargs invocation | 
| 169 |      */ | 
| 170 |     <T extends JCTree> List<T> translateArgs(List<T> _args, | 
| 171 |                                            List<Type> parameters, | 
| 172 |                                            Type varargsElement) { | 
| 173 |         if (parameters.isEmpty()) return _args; | 
| 174 |         List<T> args = _args; | 
| 175 |         while (parameters.tail.nonEmpty()) { | 
| 176 |             args.head = translate(args.head, parameters.head); | 
| 177 |             args = args.tail; | 
| 178 |             parameters = parameters.tail; | 
| 179 |         } | 
| 180 |         Type parameter = parameters.head; | 
| 181 |         assert varargsElement != null || args.length() == 1; | 
| 182 |         if (varargsElement != null) { | 
| 183 |             while (args.nonEmpty()) { | 
| 184 |                 args.head = translate(args.head, varargsElement); | 
| 185 |                 args = args.tail; | 
| 186 |             } | 
| 187 |         } else { | 
| 188 |             args.head = translate(args.head, parameter); | 
| 189 |         } | 
| 190 |         return _args; | 
| 191 |     } | 
| 192 |   | 
| 193 |     /** Add a bridge definition and enter corresponding method symbol in | 
| 194 |      *  local scope of origin. | 
| 195 |      * | 
| 196 |      *  @param pos     The source code position to be used for the definition. | 
| 197 |      *  @param meth    The method for which a bridge needs to be added | 
| 198 |      *  @param impl    That method's implementation (possibly the method itself) | 
| 199 |      *  @param origin  The class to which the bridge will be added | 
| 200 |      *  @param hypothetical | 
| 201 |      *                 True if the bridge method is not strictly necessary in the | 
| 202 |      *                 binary, but is represented in the symbol table to detect | 
| 203 |      *                 erasure clashes. | 
| 204 |      *  @param bridges The list buffer to which the bridge will be added | 
| 205 |      */ | 
| 206 |     void addBridge(DiagnosticPosition pos, | 
| 207 |                    MethodSymbol meth, | 
| 208 |                    MethodSymbol impl, | 
| 209 |                    ClassSymbol origin, | 
| 210 |                    boolean hypothetical, | 
| 211 |                    ListBuffer<JCTree> bridges) { | 
| 212 |         make.at(pos); | 
| 213 |         Type origType = types.memberType(origin.type, meth); | 
| 214 |         Type origErasure = erasure(origType); | 
| 215 |   | 
| 216 |         // Create a bridge method symbol and a bridge definition without a body. | 
| 217 |         Type bridgeType = meth.erasure(types); | 
| 218 |         long flags = impl.flags() & AccessFlags | SYNTHETIC | BRIDGE; | 
| 219 |         if (hypothetical) flags |= HYPOTHETICAL; | 
| 220 |         MethodSymbol bridge = new MethodSymbol(flags, | 
| 221 |                                                meth.name, | 
| 222 |                                                bridgeType, | 
| 223 |                                                origin); | 
| 224 |         if (!hypothetical) { | 
| 225 |             JCMethodDecl md = make.MethodDef(bridge, null); | 
| 226 |   | 
| 227 |             // The bridge calls this.impl(..), if we have an implementation | 
| 228 |             // in the current class, super.impl(...) otherwise. | 
| 229 |             JCExpression receiver = (impl.owner == origin) | 
| 230 |                 ? make.This(origin.erasure(types)) | 
| 231 |                 : make.Super(types.supertype(origin.type).tsym.erasure(types), origin); | 
| 232 |   | 
| 233 |             // The type returned from the original method. | 
| 234 |             Type calltype = erasure(impl.type.getReturnType()); | 
| 235 |   | 
| 236 |             // Construct a call of  this.impl(params), or super.impl(params), | 
| 237 |             // casting params and possibly results as needed. | 
| 238 |             JCExpression call = | 
| 239 |                 make.Apply( | 
| 240 |                            null, | 
| 241 |                            make.Select(receiver, impl).setType(calltype), | 
| 242 |                            translateArgs(make.Idents(md.params), origErasure.getParameterTypes(), null)) | 
| 243 |                 .setType(calltype); | 
| 244 |             JCStatement stat = (origErasure.getReturnType().tag == VOID) | 
| 245 |                 ? make.Exec(call) | 
| 246 |                 : make.Return(coerce(call, bridgeType.getReturnType())); | 
| 247 |             md.body = make.Block(0, List.of(stat)); | 
| 248 |   | 
| 249 |             // Add bridge to `bridges' buffer | 
| 250 |             bridges.append(md); | 
| 251 |         } | 
| 252 |   | 
| 253 |         // Add bridge to scope of enclosing class and `overridden' table. | 
| 254 |         origin.members().enter(bridge); | 
| 255 |         overridden.put(bridge, meth); | 
| 256 |     } | 
| 257 |   | 
| 258 |     /** Add bridge if given symbol is a non-private, non-static member | 
| 259 |      *  of the given class, which is either defined in the class or non-final | 
| 260 |      *  inherited, and one of the two following conditions holds: | 
| 261 |      *  1. The method's type changes in the given class, as compared to the | 
| 262 |      *     class where the symbol was defined, (in this case | 
| 263 |      *     we have extended a parameterized class with non-trivial parameters). | 
| 264 |      *  2. The method has an implementation with a different erased return type. | 
| 265 |      *     (in this case we have used co-variant returns). | 
| 266 |      *  If a bridge already exists in some other class, no new bridge is added. | 
| 267 |      *  Instead, it is checked that the bridge symbol overrides the method symbol. | 
| 268 |      *  (Spec ???). | 
| 269 |      *  todo: what about bridges for privates??? | 
| 270 |      * | 
| 271 |      *  @param pos     The source code position to be used for the definition. | 
| 272 |      *  @param sym     The symbol for which a bridge might have to be added. | 
| 273 |      *  @param origin  The class in which the bridge would go. | 
| 274 |      *  @param bridges The list buffer to which the bridge would be added. | 
| 275 |      */ | 
| 276 |     void addBridgeIfNeeded(DiagnosticPosition pos, | 
| 277 |                            Symbol sym, | 
| 278 |                            ClassSymbol origin, | 
| 279 |                            ListBuffer<JCTree> bridges) { | 
| 280 |         if (sym.kind == MTH && | 
| 281 |             sym.name != names.init && | 
| 282 |             (sym.flags() & (PRIVATE | SYNTHETIC | STATIC)) == 0 && | 
| 283 |             sym.isMemberOf(origin, types)) | 
| 284 |         { | 
| 285 |             MethodSymbol meth = (MethodSymbol)sym; | 
| 286 |             MethodSymbol bridge = meth.binaryImplementation(origin, types); | 
| 287 |             MethodSymbol impl = meth.implementation(origin, types, true); | 
| 288 |             if (bridge == null || | 
| 289 |                 bridge == meth || | 
| 290 |                 (impl != null && !bridge.owner.isSubClass(impl.owner, types))) { | 
| 291 |                 // No bridge was added yet. | 
| 292 |                 if (impl != null && isBridgeNeeded(meth, impl, origin.type)) { | 
| 293 |                     addBridge(pos, meth, impl, origin, bridge==impl, bridges); | 
| 294 |                 } else if (impl == meth | 
| 295 |                            && impl.owner != origin | 
| 296 |                            && (impl.flags() & FINAL) == 0 | 
| 297 |                            && (meth.flags() & (ABSTRACT|PUBLIC)) == PUBLIC | 
| 298 |                            && (origin.flags() & PUBLIC) > (impl.owner.flags() & PUBLIC)) { | 
| 299 |                     // this is to work around a horrible but permanent | 
| 300 |                     // reflection design error. | 
| 301 |                     addBridge(pos, meth, impl, origin, false, bridges); | 
| 302 |                 } | 
| 303 |             } else if ((bridge.flags() & SYNTHETIC) != 0) { | 
| 304 |                 MethodSymbol other = overridden.get(bridge); | 
| 305 |                 if (other != null && other != meth) { | 
| 306 |                     if (impl == null || !impl.overrides(other, origin, types, true)) { | 
| 307 |                         // Bridge for other symbol pair was added | 
| 308 |                         log.error(pos, "name.clash.same.erasure.no.override", | 
| 309 |                                   other, other.location(origin.type, types), | 
| 310 |                                   meth,  meth.location(origin.type, types)); | 
| 311 |                     } | 
| 312 |                 } | 
| 313 |             } else if (!bridge.overrides(meth, origin, types, true)) { | 
| 314 |                 // Accidental binary override without source override. | 
| 315 |                 if (bridge.owner == origin || | 
| 316 |                     types.asSuper(bridge.owner.type, meth.owner) == null) | 
| 317 |                     // Don't diagnose the problem if it would already | 
| 318 |                     // have been reported in the superclass | 
| 319 |                     log.error(pos, "name.clash.same.erasure.no.override", | 
| 320 |                               bridge, bridge.location(origin.type, types), | 
| 321 |                               meth,  meth.location(origin.type, types)); | 
| 322 |             } | 
| 323 |         } | 
| 324 |     } | 
| 325 |     // where | 
| 326 |         /** | 
| 327 |          * @param method The symbol for which a bridge might have to be added | 
| 328 |          * @param impl The implementation of method | 
| 329 |          * @param dest The type in which the bridge would go | 
| 330 |          */ | 
| 331 |         private boolean isBridgeNeeded(MethodSymbol method, | 
| 332 |                                        MethodSymbol impl, | 
| 333 |                                        Type dest) { | 
| 334 |             if (impl != method) { | 
| 335 |                 // If either method or impl have different erasures as | 
| 336 |                 // members of dest, a bridge is needed. | 
| 337 |                 Type method_erasure = method.erasure(types); | 
| 338 |                 if (!isSameMemberWhenErased(dest, method, method_erasure)) | 
| 339 |                     return true; | 
| 340 |                 Type impl_erasure = impl.erasure(types); | 
| 341 |                 if (!isSameMemberWhenErased(dest, impl, impl_erasure)) | 
| 342 |                     return true; | 
| 343 |   | 
| 344 |                 // If the erasure of the return type is different, a | 
| 345 |                 // bridge is needed. | 
| 346 |                 return !types.isSameType(impl_erasure.getReturnType(), | 
| 347 |                                          method_erasure.getReturnType()); | 
| 348 |             } else { | 
| 349 |                // method and impl are the same... | 
| 350 |                 if ((method.flags() & ABSTRACT) != 0) { | 
| 351 |                     // ...and abstract so a bridge is not needed. | 
| 352 |                     // Concrete subclasses will bridge as needed. | 
| 353 |                     return false; | 
| 354 |                 } | 
| 355 |   | 
| 356 |                 // The erasure of the return type is always the same | 
| 357 |                 // for the same symbol.  Reducing the three tests in | 
| 358 |                 // the other branch to just one: | 
| 359 |                 return !isSameMemberWhenErased(dest, method, method.erasure(types)); | 
| 360 |             } | 
| 361 |         } | 
| 362 |         /** | 
| 363 |          * Lookup the method as a member of the type.  Compare the | 
| 364 |          * erasures. | 
| 365 |          * @param type the class where to look for the method | 
| 366 |          * @param method the method to look for in class | 
| 367 |          * @param erasure the erasure of method | 
| 368 |          */ | 
| 369 |         private boolean isSameMemberWhenErased(Type type, | 
| 370 |                                                MethodSymbol method, | 
| 371 |                                                Type erasure) { | 
| 372 |             return types.isSameType(erasure(types.memberType(type, method)), | 
| 373 |                                     erasure); | 
| 374 |         } | 
| 375 |   | 
| 376 |     void addBridges(DiagnosticPosition pos, | 
| 377 |                     TypeSymbol i, | 
| 378 |                     ClassSymbol origin, | 
| 379 |                     ListBuffer<JCTree> bridges) { | 
| 380 |         for (Scope.Entry e = i.members().elems; e != null; e = e.sibling) | 
| 381 |             addBridgeIfNeeded(pos, e.sym, origin, bridges); | 
| 382 |         for (List<Type> l = types.interfaces(i.type); l.nonEmpty(); l = l.tail) | 
| 383 |             addBridges(pos, l.head.tsym, origin, bridges); | 
| 384 |     } | 
| 385 |   | 
| 386 |     /** Add all necessary bridges to some class appending them to list buffer. | 
| 387 |      *  @param pos     The source code position to be used for the bridges. | 
| 388 |      *  @param origin  The class in which the bridges go. | 
| 389 |      *  @param bridges The list buffer to which the bridges are added. | 
| 390 |      */ | 
| 391 |     void addBridges(DiagnosticPosition pos, ClassSymbol origin, ListBuffer<JCTree> bridges) { | 
| 392 |         Type st = types.supertype(origin.type); | 
| 393 |         while (st.tag == CLASS) { | 
| 394 | //          if (isSpecialization(st)) | 
| 395 |             addBridges(pos, st.tsym, origin, bridges); | 
| 396 |             st = types.supertype(st); | 
| 397 |         } | 
| 398 |         for (List<Type> l = types.interfaces(origin.type); l.nonEmpty(); l = l.tail) | 
| 399 | //          if (isSpecialization(l.head)) | 
| 400 |             addBridges(pos, l.head.tsym, origin, bridges); | 
| 401 |     } | 
| 402 |   | 
| 403 | /* ************************************************************************ | 
| 404 |  * Visitor methods | 
| 405 |  *************************************************************************/ | 
| 406 |   | 
| 407 |     /** Visitor argument: proto-type. | 
| 408 |      */ | 
| 409 |     private Type pt; | 
| 410 |   | 
| 411 |     /** Visitor method: perform a type translation on tree. | 
| 412 |      */ | 
| 413 |     public <T extends JCTree> T translate(T tree, Type pt) { | 
| 414 |         Type prevPt = this.pt; | 
| 415 |         try { | 
| 416 |             this.pt = pt; | 
| 417 |             return translate(tree); | 
| 418 |         } finally { | 
| 419 |             this.pt = prevPt; | 
| 420 |         } | 
| 421 |     } | 
| 422 |   | 
| 423 |     /** Visitor method: perform a type translation on list of trees. | 
| 424 |      */ | 
| 425 |     public <T extends JCTree> List<T> translate(List<T> trees, Type pt) { | 
| 426 |         Type prevPt = this.pt; | 
| 427 |         List<T> res; | 
| 428 |         try { | 
| 429 |             this.pt = pt; | 
| 430 |             res = translate(trees); | 
| 431 |         } finally { | 
| 432 |             this.pt = prevPt; | 
| 433 |         } | 
| 434 |         return res; | 
| 435 |     } | 
| 436 |   | 
| 437 |     public void visitClassDef(JCClassDecl tree) { | 
| 438 |         translateClass(tree.sym); | 
| 439 |         result = tree; | 
| 440 |     } | 
| 441 |   | 
| 442 |     JCMethodDecl currentMethod = null; | 
| 443 |     public void visitMethodDef(JCMethodDecl tree) { | 
| 444 |         JCMethodDecl previousMethod = currentMethod; | 
| 445 |         try { | 
| 446 |             currentMethod = tree; | 
| 447 |             tree.restype = translate(tree.restype, null); | 
| 448 |             tree.typarams = List.nil(); | 
| 449 |             tree.params = translateVarDefs(tree.params); | 
| 450 |             tree.thrown = translate(tree.thrown, null); | 
| 451 |             tree.body = translate(tree.body, tree.sym.erasure(types).getReturnType()); | 
| 452 |             tree.type = erasure(tree.type); | 
| 453 |             result = tree; | 
| 454 |         } finally { | 
| 455 |             currentMethod = previousMethod; | 
| 456 |         } | 
| 457 |   | 
| 458 |         // Check that we do not introduce a name clash by erasing types. | 
| 459 |         for (Scope.Entry e = tree.sym.owner.members().lookup(tree.name); | 
| 460 |              e.sym != null; | 
| 461 |              e = e.next()) { | 
| 462 |             if (e.sym != tree.sym && | 
| 463 |                 types.isSameType(erasure(e.sym.type), tree.type)) { | 
| 464 |                 log.error(tree.pos(), | 
| 465 |                           "name.clash.same.erasure", tree.sym, | 
| 466 |                           e.sym); | 
| 467 |                 return; | 
| 468 |             } | 
| 469 |         } | 
| 470 |     } | 
| 471 |   | 
| 472 |     public void visitVarDef(JCVariableDecl tree) { | 
| 473 |         tree.vartype = translate(tree.vartype, null); | 
| 474 |         tree.init = translate(tree.init, tree.sym.erasure(types)); | 
| 475 |         tree.type = erasure(tree.type); | 
| 476 |         result = tree; | 
| 477 |     } | 
| 478 |   | 
| 479 |     public void visitDoLoop(JCDoWhileLoop tree) { | 
| 480 |         tree.body = translate(tree.body); | 
| 481 |         tree.cond = translate(tree.cond, syms.booleanType); | 
| 482 |         result = tree; | 
| 483 |     } | 
| 484 |   | 
| 485 |     public void visitWhileLoop(JCWhileLoop tree) { | 
| 486 |         tree.cond = translate(tree.cond, syms.booleanType); | 
| 487 |         tree.body = translate(tree.body); | 
| 488 |         result = tree; | 
| 489 |     } | 
| 490 |   | 
| 491 |     public void visitForLoop(JCForLoop tree) { | 
| 492 |         tree.init = translate(tree.init, null); | 
| 493 |         if (tree.cond != null) | 
| 494 |             tree.cond = translate(tree.cond, syms.booleanType); | 
| 495 |         tree.step = translate(tree.step, null); | 
| 496 |         tree.body = translate(tree.body); | 
| 497 |         result = tree; | 
| 498 |     } | 
| 499 |   | 
| 500 |     public void visitForeachLoop(JCEnhancedForLoop tree) { | 
| 501 |         tree.var = translate(tree.var, null); | 
| 502 |         Type iterableType = tree.expr.type; | 
| 503 |         tree.expr = translate(tree.expr, erasure(tree.expr.type)); | 
| 504 |         if (types.elemtype(tree.expr.type) == null) | 
| 505 |             tree.expr.type = iterableType; // preserve type for Lower | 
| 506 |         tree.body = translate(tree.body); | 
| 507 |         result = tree; | 
| 508 |     } | 
| 509 |   | 
| 510 |     public void visitSwitch(JCSwitch tree) { | 
| 511 |         Type selsuper = types.supertype(tree.selector.type); | 
| 512 |         boolean enumSwitch = selsuper != null && | 
| 513 |             selsuper.tsym == syms.enumSym; | 
| 514 |         Type target = enumSwitch ? erasure(tree.selector.type) : syms.intType; | 
| 515 |         tree.selector = translate(tree.selector, target); | 
| 516 |         tree.cases = translateCases(tree.cases); | 
| 517 |         result = tree; | 
| 518 |     } | 
| 519 |   | 
| 520 |     public void visitCase(JCCase tree) { | 
| 521 |         tree.pat = translate(tree.pat, null); | 
| 522 |         tree.stats = translate(tree.stats); | 
| 523 |         result = tree; | 
| 524 |     } | 
| 525 |   | 
| 526 |     public void visitSynchronized(JCSynchronized tree) { | 
| 527 |         tree.lock = translate(tree.lock, erasure(tree.lock.type)); | 
| 528 |         tree.body = translate(tree.body); | 
| 529 |         result = tree; | 
| 530 |     } | 
| 531 |   | 
| 532 |     public void visitConditional(JCConditional tree) { | 
| 533 |         tree.cond = translate(tree.cond, syms.booleanType); | 
| 534 |         tree.truepart = translate(tree.truepart, erasure(tree.type)); | 
| 535 |         tree.falsepart = translate(tree.falsepart, erasure(tree.type)); | 
| 536 |         tree.type = erasure(tree.type); | 
| 537 |         result = tree; | 
| 538 |     } | 
| 539 |   | 
| 540 |    public void visitIf(JCIf tree) { | 
| 541 |         tree.cond = translate(tree.cond, syms.booleanType); | 
| 542 |         tree.thenpart = translate(tree.thenpart); | 
| 543 |         tree.elsepart = translate(tree.elsepart); | 
| 544 |         result = tree; | 
| 545 |     } | 
| 546 |   | 
| 547 |     public void visitExec(JCExpressionStatement tree) { | 
| 548 |         tree.expr = translate(tree.expr, null); | 
| 549 |         result = tree; | 
| 550 |     } | 
| 551 |   | 
| 552 |     public void visitReturn(JCReturn tree) { | 
| 553 |         tree.expr = translate(tree.expr, currentMethod.sym.erasure(types).getReturnType()); | 
| 554 |         result = tree; | 
| 555 |     } | 
| 556 |   | 
| 557 |     public void visitThrow(JCThrow tree) { | 
| 558 |         tree.expr = translate(tree.expr, erasure(tree.expr.type)); | 
| 559 |         result = tree; | 
| 560 |     } | 
| 561 |   | 
| 562 |     public void visitAssert(JCAssert tree) { | 
| 563 |         tree.cond = translate(tree.cond, syms.booleanType); | 
| 564 |         if (tree.detail != null) | 
| 565 |             tree.detail = translate(tree.detail, erasure(tree.detail.type)); | 
| 566 |         result = tree; | 
| 567 |     } | 
| 568 |   | 
| 569 |     public void visitApply(JCMethodInvocation tree) { | 
| 570 |         tree.meth = translate(tree.meth, null); | 
| 571 |         Symbol meth = TreeInfo.symbol(tree.meth); | 
| 572 |         Type mt = meth.erasure(types); | 
| 573 |         List<Type> argtypes = mt.getParameterTypes(); | 
| 574 |         if (allowEnums && | 
| 575 |             meth.name==names.init && | 
| 576 |             meth.owner == syms.enumSym) | 
| 577 |             argtypes = argtypes.tail.tail; | 
| 578 |         if (tree.varargsElement != null) | 
| 579 |             tree.varargsElement = types.erasure(tree.varargsElement); | 
| 580 |         else | 
| 581 |             assert tree.args.length() == argtypes.length(); | 
| 582 |         tree.args = translateArgs(tree.args, argtypes, tree.varargsElement); | 
| 583 |   | 
| 584 |         // Insert casts of method invocation results as needed. | 
| 585 |         result = retype(tree, mt.getReturnType(), pt); | 
| 586 |     } | 
| 587 |   | 
| 588 |     public void visitNewClass(JCNewClass tree) { | 
| 589 |         if (tree.encl != null) | 
| 590 |             tree.encl = translate(tree.encl, erasure(tree.encl.type)); | 
| 591 |         tree.clazz = translate(tree.clazz, null); | 
| 592 |         if (tree.varargsElement != null) | 
| 593 |             tree.varargsElement = types.erasure(tree.varargsElement); | 
| 594 |         tree.args = translateArgs( | 
| 595 |             tree.args, tree.constructor.erasure(types).getParameterTypes(), tree.varargsElement); | 
| 596 |         tree.def = translate(tree.def, null); | 
| 597 |         tree.type = erasure(tree.type); | 
| 598 |         result = tree; | 
| 599 |     } | 
| 600 |   | 
| 601 |     public void visitNewArray(JCNewArray tree) { | 
| 602 |         tree.elemtype = translate(tree.elemtype, null); | 
| 603 |         translate(tree.dims, syms.intType); | 
| 604 |         tree.elems = translate(tree.elems, | 
| 605 |                                (tree.type == null) ? null | 
| 606 |                                : erasure(types.elemtype(tree.type))); | 
| 607 |         tree.type = erasure(tree.type); | 
| 608 |   | 
| 609 |         result = tree; | 
| 610 |     } | 
| 611 |   | 
| 612 |     public void visitParens(JCParens tree) { | 
| 613 |         tree.expr = translate(tree.expr, pt); | 
| 614 |         tree.type = erasure(tree.type); | 
| 615 |         result = tree; | 
| 616 |     } | 
| 617 |   | 
| 618 |     public void visitAssign(JCAssign tree) { | 
| 619 |         tree.lhs = translate(tree.lhs, null); | 
| 620 |         tree.rhs = translate(tree.rhs, erasure(tree.lhs.type)); | 
| 621 |         tree.type = erasure(tree.type); | 
| 622 |         result = tree; | 
| 623 |     } | 
| 624 |   | 
| 625 |     public void visitAssignop(JCAssignOp tree) { | 
| 626 |         tree.lhs = translate(tree.lhs, null); | 
| 627 |         tree.rhs = translate(tree.rhs, erasure(tree.rhs.type)); | 
| 628 |         tree.type = erasure(tree.type); | 
| 629 |         result = tree; | 
| 630 |     } | 
| 631 |   | 
| 632 |     public void visitUnary(JCUnary tree) { | 
| 633 |         tree.arg = translate(tree.arg, tree.operator.type.getParameterTypes().head); | 
| 634 |         result = tree; | 
| 635 |     } | 
| 636 |   | 
| 637 |     public void visitBinary(JCBinary tree) { | 
| 638 |         tree.lhs = translate(tree.lhs, tree.operator.type.getParameterTypes().head); | 
| 639 |         tree.rhs = translate(tree.rhs, tree.operator.type.getParameterTypes().tail.head); | 
| 640 |         result = tree; | 
| 641 |     } | 
| 642 |   | 
| 643 |     public void visitTypeCast(JCTypeCast tree) { | 
| 644 |         tree.clazz = translate(tree.clazz, null); | 
| 645 |         tree.type = erasure(tree.type); | 
| 646 |         tree.expr = translate(tree.expr, tree.type); | 
| 647 |         result = tree; | 
| 648 |     } | 
| 649 |   | 
| 650 |     public void visitTypeTest(JCInstanceOf tree) { | 
| 651 |         tree.expr = translate(tree.expr, null); | 
| 652 |         tree.clazz = translate(tree.clazz, null); | 
| 653 |         result = tree; | 
| 654 |     } | 
| 655 |   | 
| 656 |     public void visitIndexed(JCArrayAccess tree) { | 
| 657 |         tree.indexed = translate(tree.indexed, erasure(tree.indexed.type)); | 
| 658 |         tree.index = translate(tree.index, syms.intType); | 
| 659 |   | 
| 660 |         // Insert casts of indexed expressions as needed. | 
| 661 |         result = retype(tree, types.elemtype(tree.indexed.type), pt); | 
| 662 |     } | 
| 663 |   | 
| 664 |     // There ought to be nothing to rewrite here; | 
| 665 |     // we don't generate code. | 
| 666 |     public void visitAnnotation(JCAnnotation tree) { | 
| 667 |         result = tree; | 
| 668 |     } | 
| 669 |   | 
| 670 |     public void visitIdent(JCIdent tree) { | 
| 671 |         Type et = tree.sym.erasure(types); | 
| 672 |   | 
| 673 |         // Map type variables to their bounds. | 
| 674 |         if (tree.sym.kind == TYP && tree.sym.type.tag == TYPEVAR) { | 
| 675 |             result = make.at(tree.pos).Type(et); | 
| 676 |         } else | 
| 677 |         // Map constants expressions to themselves. | 
| 678 |         if (tree.type.constValue() != null) { | 
| 679 |             result = tree; | 
| 680 |         } | 
| 681 |         // Insert casts of variable uses as needed. | 
| 682 |         else if (tree.sym.kind == VAR) { | 
| 683 |             result = retype(tree, et, pt); | 
| 684 |         } | 
| 685 |         else { | 
| 686 |             tree.type = erasure(tree.type); | 
| 687 |             result = tree; | 
| 688 |         } | 
| 689 |     } | 
| 690 |   | 
| 691 |     public void visitSelect(JCFieldAccess tree) { | 
| 692 |         Type t = tree.selected.type; | 
| 693 |         if (t.isCompound() || (t.tag == TYPEVAR && t.getUpperBound().isCompound())) { | 
| 694 |             if ((tree.sym.flags() & IPROXY) != 0) { | 
| 695 |                 tree.sym = ((MethodSymbol)tree.sym). | 
| 696 |                     implemented((TypeSymbol)tree.sym.owner, types); | 
| 697 |             } | 
| 698 |             tree.selected = cast( | 
| 699 |                 translate(tree.selected, erasure(t)), | 
| 700 |                 erasure(tree.sym.owner.type)); | 
| 701 |         } else | 
| 702 |             tree.selected = translate(tree.selected, erasure(t)); | 
| 703 |   | 
| 704 |         // Map constants expressions to themselves. | 
| 705 |         if (tree.type.constValue() != null) { | 
| 706 |             result = tree; | 
| 707 |         } | 
| 708 |         // Insert casts of variable uses as needed. | 
| 709 |         else if (tree.sym.kind == VAR) { | 
| 710 |             result = retype(tree, tree.sym.erasure(types), pt); | 
| 711 |         } | 
| 712 |         else { | 
| 713 |             tree.type = erasure(tree.type); | 
| 714 |             result = tree; | 
| 715 |         } | 
| 716 |     } | 
| 717 |   | 
| 718 |     public void visitTypeArray(JCArrayTypeTree tree) { | 
| 719 |         tree.elemtype = translate(tree.elemtype, null); | 
| 720 |         tree.type = erasure(tree.type); | 
| 721 |         result = tree; | 
| 722 |     } | 
| 723 |   | 
| 724 |     /** Visitor method for parameterized types. | 
| 725 |      */ | 
| 726 |     public void visitTypeApply(JCTypeApply tree) { | 
| 727 |         // Delete all type parameters. | 
| 728 |         result = translate(tree.clazz, null); | 
| 729 |     } | 
| 730 |   | 
| 731 | /************************************************************************** | 
| 732 |  * utility methods | 
| 733 |  *************************************************************************/ | 
| 734 |   | 
| 735 |     private Type erasure(Type t) { | 
| 736 |         return types.erasure(t); | 
| 737 |     } | 
| 738 |   | 
| 739 | /************************************************************************** | 
| 740 |  * main method | 
| 741 |  *************************************************************************/ | 
| 742 |   | 
| 743 |     private Env<AttrContext> env; | 
| 744 |   | 
| 745 |     void translateClass(ClassSymbol c) { | 
| 746 |         Type st = types.supertype(c.type); | 
| 747 |   | 
| 748 |         // process superclass before derived | 
| 749 |         if (st.tag == CLASS) | 
| 750 |             translateClass((ClassSymbol)st.tsym); | 
| 751 |   | 
| 752 |         Env<AttrContext> myEnv = enter.typeEnvs.remove(c); | 
| 753 |         if (myEnv == null) | 
| 754 |             return; | 
| 755 |         Env<AttrContext> oldEnv = env; | 
| 756 |         try { | 
| 757 |             env = myEnv; | 
| 758 |             // class has not been translated yet | 
| 759 |   | 
| 760 |             TreeMaker savedMake = make; | 
| 761 |             Type savedPt = pt; | 
| 762 |             make = make.forToplevel(env.toplevel); | 
| 763 |             pt = null; | 
| 764 |             try { | 
| 765 |                 JCClassDecl tree = (JCClassDecl) env.tree; | 
| 766 |                 tree.typarams = List.nil(); | 
| 767 |                 super.visitClassDef(tree); | 
| 768 |                 make.at(tree.pos); | 
| 769 |                 if (addBridges) { | 
| 770 |                     ListBuffer<JCTree> bridges = new ListBuffer<JCTree>(); | 
| 771 |                     if ((tree.sym.flags() & INTERFACE) == 0) | 
| 772 |                         addBridges(tree.pos(), tree.sym, bridges); | 
| 773 |                     tree.defs = bridges.toList().prependList(tree.defs); | 
| 774 |                 } | 
| 775 |                 tree.type = erasure(tree.type); | 
| 776 |             } finally { | 
| 777 |                 make = savedMake; | 
| 778 |                 pt = savedPt; | 
| 779 |             } | 
| 780 |         } finally { | 
| 781 |             env = oldEnv; | 
| 782 |         } | 
| 783 |     } | 
| 784 |   | 
| 785 |     /** Translate a toplevel class definition. | 
| 786 |      *  @param cdef    The definition to be translated. | 
| 787 |      */ | 
| 788 |     public JCTree translateTopLevelClass(JCTree cdef, TreeMaker make) { | 
| 789 |         // note that this method does NOT support recursion. | 
| 790 |         this.make = make; | 
| 791 |         pt = null; | 
| 792 |         return translate(cdef, null); | 
| 793 |     } | 
| 794 | } |