001: /*
002: * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.tools.javac.comp;
027:
028: import java.util.*;
029:
030: import com.sun.tools.javac.code.*;
031: import com.sun.tools.javac.code.Symbol.*;
032: import com.sun.tools.javac.tree.*;
033: import com.sun.tools.javac.tree.JCTree.*;
034: import com.sun.tools.javac.util.*;
035: import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
036: import com.sun.tools.javac.util.List;
037:
038: import static com.sun.tools.javac.code.Flags.*;
039: import static com.sun.tools.javac.code.Kinds.*;
040: import static com.sun.tools.javac.code.TypeTags.*;
041:
042: /** This pass translates Generic Java to conventional Java.
043: *
044: * <p><b>This is NOT part of any API supported by Sun Microsystems. If
045: * you write code that depends on this, you do so at your own risk.
046: * This code and its internal interfaces are subject to change or
047: * deletion without notice.</b>
048: */
049: @Version("@(#)TransTypes.java 1.94 07/05/05")
050: public class TransTypes extends TreeTranslator {
051: /** The context key for the TransTypes phase. */
052: protected static final Context.Key<TransTypes> transTypesKey = new Context.Key<TransTypes>();
053:
054: /** Get the instance for this context. */
055: public static TransTypes instance(Context context) {
056: TransTypes instance = context.get(transTypesKey);
057: if (instance == null)
058: instance = new TransTypes(context);
059: return instance;
060: }
061:
062: private Name.Table names;
063: private Log log;
064: private Symtab syms;
065: private TreeMaker make;
066: private Enter enter;
067: private boolean allowEnums;
068: private Types types;
069: private final Resolve resolve;
070:
071: /**
072: * Flag to indicate whether or not to generate bridge methods.
073: * For pre-Tiger source there is no need for bridge methods, so it
074: * can be skipped to get better performance for -source 1.4 etc.
075: */
076: private final boolean addBridges;
077:
078: protected TransTypes(Context context) {
079: context.put(transTypesKey, this );
080: names = Name.Table.instance(context);
081: log = Log.instance(context);
082: syms = Symtab.instance(context);
083: enter = Enter.instance(context);
084: overridden = new HashMap<MethodSymbol, MethodSymbol>();
085: Source source = Source.instance(context);
086: allowEnums = source.allowEnums();
087: addBridges = source.addBridges();
088: types = Types.instance(context);
089: make = TreeMaker.instance(context);
090: resolve = Resolve.instance(context);
091: }
092:
093: /** A hashtable mapping bridge methods to the methods they override after
094: * type erasure.
095: */
096: Map<MethodSymbol, MethodSymbol> overridden;
097:
098: /** Construct an attributed tree for a cast of expression to target type,
099: * 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(
110: target);
111: }
112: make.pos = oldpos;
113: return tree;
114: }
115:
116: /** Construct an attributed tree to coerce an expression to some erased
117: * target type, unless the expression is already assignable to that type.
118: * If target type is a constant type, use its base type instead.
119: * @param tree The expression tree.
120: * @param target The target type.
121: */
122: JCExpression coerce(JCExpression tree, Type target) {
123: Type btarget = target.baseType();
124: if (tree.type.isPrimitive() == target.isPrimitive()) {
125: return types.isAssignable(tree.type, btarget,
126: Warner.noWarnings) ? tree : 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)
159: return coerce(tree, target);
160: }
161: return tree;
162: }
163:
164: /** Translate method argument list, casting each argument
165: * to its corresponding type in a list of target types.
166: * @param _args The method argument list.
167: * @param parameters The list of target types.
168: * @param varargsElement The erasure of the varargs element type,
169: * or null if translating a non-varargs invocation
170: */
171: <T extends JCTree> List<T> translateArgs(List<T> _args,
172: List<Type> parameters, Type varargsElement) {
173: if (parameters.isEmpty())
174: return _args;
175: List<T> args = _args;
176: while (parameters.tail.nonEmpty()) {
177: args.head = translate(args.head, parameters.head);
178: args = args.tail;
179: parameters = parameters.tail;
180: }
181: Type parameter = parameters.head;
182: assert varargsElement != null || args.length() == 1;
183: if (varargsElement != null) {
184: while (args.nonEmpty()) {
185: args.head = translate(args.head, varargsElement);
186: args = args.tail;
187: }
188: } else {
189: args.head = translate(args.head, parameter);
190: }
191: return _args;
192: }
193:
194: /** Add a bridge definition and enter corresponding method symbol in
195: * local scope of origin.
196: *
197: * @param pos The source code position to be used for the definition.
198: * @param meth The method for which a bridge needs to be added
199: * @param impl That method's implementation (possibly the method itself)
200: * @param origin The class to which the bridge will be added
201: * @param hypothetical
202: * True if the bridge method is not strictly necessary in the
203: * binary, but is represented in the symbol table to detect
204: * erasure clashes.
205: * @param bridges The list buffer to which the bridge will be added
206: */
207: void addBridge(DiagnosticPosition pos, MethodSymbol meth,
208: MethodSymbol impl, ClassSymbol origin,
209: boolean hypothetical, ListBuffer<JCTree> bridges) {
210: make.at(pos);
211: Type origType = types.memberType(origin.type, meth);
212: Type origErasure = erasure(origType);
213:
214: // Create a bridge method symbol and a bridge definition without a body.
215: Type bridgeType = meth.erasure(types);
216: long flags = impl.flags() & AccessFlags | SYNTHETIC | BRIDGE;
217: if (hypothetical)
218: flags |= HYPOTHETICAL;
219: MethodSymbol bridge = new MethodSymbol(flags, meth.name,
220: bridgeType, origin);
221: if (!hypothetical) {
222: JCMethodDecl md = make.MethodDef(bridge, null);
223:
224: // The bridge calls this.impl(..), if we have an implementation
225: // in the current class, super.impl(...) otherwise.
226: JCExpression receiver = (impl.owner == origin) ? make
227: .This(origin.erasure(types)) : make
228: .Super(types.super type(origin.type).tsym
229: .erasure(types), origin);
230:
231: // The type returned from the original method.
232: Type calltype = erasure(impl.type.getReturnType());
233:
234: // Construct a call of this.impl(params), or super.impl(params),
235: // casting params and possibly results as needed.
236: JCExpression call = make.Apply(
237: null,
238: make.Select(receiver, impl).setType(calltype),
239: translateArgs(make.Idents(md.params), origErasure
240: .getParameterTypes(), null)).setType(
241: calltype);
242: JCStatement stat = (origErasure.getReturnType().tag == VOID) ? make
243: .Exec(call)
244: : make.Return(coerce(call, bridgeType
245: .getReturnType()));
246: md.body = make.Block(0, List.of(stat));
247:
248: // Add bridge to `bridges' buffer
249: bridges.append(md);
250: }
251:
252: // Add bridge to scope of enclosing class and `overridden' table.
253: origin.members().enter(bridge);
254: overridden.put(bridge, meth);
255: }
256:
257: /** Add bridge if given symbol is a non-private, non-static member
258: * of the given class, which is either defined in the class or non-final
259: * inherited, and one of the two following conditions holds:
260: * 1. The method's type changes in the given class, as compared to the
261: * class where the symbol was defined, (in this case
262: * we have extended a parameterized class with non-trivial parameters).
263: * 2. The method has an implementation with a different erased return type.
264: * (in this case we have used co-variant returns).
265: * If a bridge already exists in some other class, no new bridge is added.
266: * Instead, it is checked that the bridge symbol overrides the method symbol.
267: * (Spec ???).
268: * todo: what about bridges for privates???
269: *
270: * @param pos The source code position to be used for the definition.
271: * @param sym The symbol for which a bridge might have to be added.
272: * @param origin The class in which the bridge would go.
273: * @param bridges The list buffer to which the bridge would be added.
274: */
275: void addBridgeIfNeeded(DiagnosticPosition pos, Symbol sym,
276: ClassSymbol origin, ListBuffer<JCTree> bridges) {
277: if (sym.kind == MTH && sym.name != names.init
278: && (sym.flags() & (PRIVATE | SYNTHETIC | STATIC)) == 0
279: && sym.isMemberOf(origin, types)) {
280: MethodSymbol meth = (MethodSymbol) sym;
281: MethodSymbol bridge = meth.binaryImplementation(origin,
282: types);
283: MethodSymbol impl = meth
284: .implementation(origin, types, true);
285: if (bridge == null
286: || bridge == meth
287: || (impl != null && !bridge.owner.isSubClass(
288: impl.owner, types))) {
289: // No bridge was added yet.
290: if (impl != null
291: && isBridgeNeeded(meth, impl, origin.type)) {
292: addBridge(pos, meth, impl, origin, bridge == impl,
293: 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
299: .flags() & PUBLIC)) {
300: // this is to work around a horrible but permanent
301: // reflection design error.
302: addBridge(pos, meth, impl, origin, false, bridges);
303: }
304: } else if ((bridge.flags() & SYNTHETIC) != 0) {
305: MethodSymbol other = overridden.get(bridge);
306: if (other != null && other != meth) {
307: if (impl == null
308: || !impl.overrides(other, origin, types,
309: true)) {
310: // Bridge for other symbol pair was added
311: log.error(pos,
312: "name.clash.same.erasure.no.override",
313: other, other.location(origin.type,
314: types), meth, meth.location(
315: origin.type, types));
316: }
317: }
318: } else if (!bridge.overrides(meth, origin, types, true)) {
319: // Accidental binary override without source override.
320: if (bridge.owner == origin
321: || types.asSuper(bridge.owner.type, meth.owner) == null)
322: // Don't diagnose the problem if it would already
323: // have been reported in the superclass
324: log.error(pos,
325: "name.clash.same.erasure.no.override",
326: bridge,
327: bridge.location(origin.type, types), meth,
328: meth.location(origin.type, types));
329: }
330: }
331: }
332:
333: // where
334: /**
335: * @param method The symbol for which a bridge might have to be added
336: * @param impl The implementation of method
337: * @param dest The type in which the bridge would go
338: */
339: private boolean isBridgeNeeded(MethodSymbol method,
340: MethodSymbol impl, Type dest) {
341: if (impl != method) {
342: // If either method or impl have different erasures as
343: // members of dest, a bridge is needed.
344: Type method_erasure = method.erasure(types);
345: if (!isSameMemberWhenErased(dest, method, method_erasure))
346: return true;
347: Type impl_erasure = impl.erasure(types);
348: if (!isSameMemberWhenErased(dest, impl, impl_erasure))
349: return true;
350:
351: // If the erasure of the return type is different, a
352: // bridge is needed.
353: return !types.isSameType(impl_erasure.getReturnType(),
354: method_erasure.getReturnType());
355: } else {
356: // method and impl are the same...
357: if ((method.flags() & ABSTRACT) != 0) {
358: // ...and abstract so a bridge is not needed.
359: // Concrete subclasses will bridge as needed.
360: return false;
361: }
362:
363: // The erasure of the return type is always the same
364: // for the same symbol. Reducing the three tests in
365: // the other branch to just one:
366: return !isSameMemberWhenErased(dest, method, method
367: .erasure(types));
368: }
369: }
370:
371: /**
372: * Lookup the method as a member of the type. Compare the
373: * erasures.
374: * @param type the class where to look for the method
375: * @param method the method to look for in class
376: * @param erasure the erasure of method
377: */
378: private boolean isSameMemberWhenErased(Type type,
379: MethodSymbol method, Type erasure) {
380: return types.isSameType(
381: erasure(types.memberType(type, method)), erasure);
382: }
383:
384: void addBridges(DiagnosticPosition pos, TypeSymbol i,
385: ClassSymbol origin, ListBuffer<JCTree> bridges) {
386: for (Scope.Entry e = i.members().elems; e != null; e = e.sibling)
387: addBridgeIfNeeded(pos, e.sym, origin, bridges);
388: for (List<Type> l = types.interfaces(i.type); l.nonEmpty(); l = l.tail)
389: addBridges(pos, l.head.tsym, origin, bridges);
390: }
391:
392: /** Add all necessary bridges to some class appending them to list buffer.
393: * @param pos The source code position to be used for the bridges.
394: * @param origin The class in which the bridges go.
395: * @param bridges The list buffer to which the bridges are added.
396: */
397: void addBridges(DiagnosticPosition pos, ClassSymbol origin,
398: ListBuffer<JCTree> bridges) {
399: Type st = types.super type(origin.type);
400: while (st.tag == CLASS) {
401: // if (isSpecialization(st))
402: addBridges(pos, st.tsym, origin, bridges);
403: st = types.super type(st);
404: }
405: for (List<Type> l = types.interfaces(origin.type); l.nonEmpty(); l = l.tail)
406: // if (isSpecialization(l.head))
407: addBridges(pos, l.head.tsym, origin, bridges);
408: }
409:
410: /* ************************************************************************
411: * Visitor methods
412: *************************************************************************/
413:
414: /** Visitor argument: proto-type.
415: */
416: private Type pt;
417:
418: /** Visitor method: perform a type translation on tree.
419: */
420: public <T extends JCTree> T translate(T tree, Type pt) {
421: Type prevPt = this .pt;
422: try {
423: this .pt = pt;
424: return translate(tree);
425: } finally {
426: this .pt = prevPt;
427: }
428: }
429:
430: /** Visitor method: perform a type translation on list of trees.
431: */
432: public <T extends JCTree> List<T> translate(List<T> trees, Type pt) {
433: Type prevPt = this .pt;
434: List<T> res;
435: try {
436: this .pt = pt;
437: res = translate(trees);
438: } finally {
439: this .pt = prevPt;
440: }
441: return res;
442: }
443:
444: public void visitClassDef(JCClassDecl tree) {
445: translateClass(tree.sym);
446: result = tree;
447: }
448:
449: JCMethodDecl currentMethod = null;
450:
451: public void visitMethodDef(JCMethodDecl tree) {
452: JCMethodDecl previousMethod = currentMethod;
453: try {
454: currentMethod = tree;
455: tree.restype = translate(tree.restype, null);
456: tree.typarams = List.nil();
457: tree.params = translateVarDefs(tree.params);
458: tree.thrown = translate(tree.thrown, null);
459: tree.body = translate(tree.body, tree.sym.erasure(types)
460: .getReturnType());
461: tree.type = erasure(tree.type);
462: result = tree;
463: } finally {
464: currentMethod = previousMethod;
465: }
466:
467: // Check that we do not introduce a name clash by erasing types.
468: for (Scope.Entry e = tree.sym.owner.members().lookup(tree.name); e.sym != null; e = e
469: .next()) {
470: if (e.sym != tree.sym
471: && types.isSameType(erasure(e.sym.type), tree.type)) {
472: log.error(tree.pos(), "name.clash.same.erasure",
473: tree.sym, e.sym);
474: return;
475: }
476: }
477: }
478:
479: public void visitVarDef(JCVariableDecl tree) {
480: tree.vartype = translate(tree.vartype, null);
481: tree.init = translate(tree.init, tree.sym.erasure(types));
482: tree.type = erasure(tree.type);
483: result = tree;
484: }
485:
486: public void visitDoLoop(JCDoWhileLoop tree) {
487: tree.body = translate(tree.body);
488: tree.cond = translate(tree.cond, syms.booleanType);
489: result = tree;
490: }
491:
492: public void visitWhileLoop(JCWhileLoop tree) {
493: tree.cond = translate(tree.cond, syms.booleanType);
494: tree.body = translate(tree.body);
495: result = tree;
496: }
497:
498: public void visitForLoop(JCForLoop tree) {
499: tree.init = translate(tree.init, null);
500: if (tree.cond != null)
501: tree.cond = translate(tree.cond, syms.booleanType);
502: tree.step = translate(tree.step, null);
503: tree.body = translate(tree.body);
504: result = tree;
505: }
506:
507: public void visitForeachLoop(JCEnhancedForLoop tree) {
508: tree.var = translate(tree.var, null);
509: Type iterableType = tree.expr.type;
510: tree.expr = translate(tree.expr, erasure(tree.expr.type));
511: if (types.elemtype(tree.expr.type) == null)
512: tree.expr.type = iterableType; // preserve type for Lower
513: tree.body = translate(tree.body);
514: result = tree;
515: }
516:
517: public void visitSwitch(JCSwitch tree) {
518: Type selsuper = types.super type(tree.selector.type);
519: boolean enumSwitch = selsuper != null
520: && selsuper .tsym == syms.enumSym;
521: Type target = enumSwitch ? erasure(tree.selector.type)
522: : syms.intType;
523: tree.selector = translate(tree.selector, target);
524: tree.cases = translateCases(tree.cases);
525: result = tree;
526: }
527:
528: public void visitCase(JCCase tree) {
529: tree.pat = translate(tree.pat, null);
530: tree.stats = translate(tree.stats);
531: result = tree;
532: }
533:
534: public void visitSynchronized(JCSynchronized tree) {
535: tree.lock = translate(tree.lock, erasure(tree.lock.type));
536: tree.body = translate(tree.body);
537: result = tree;
538: }
539:
540: public void visitConditional(JCConditional tree) {
541: tree.cond = translate(tree.cond, syms.booleanType);
542: tree.truepart = translate(tree.truepart, erasure(tree.type));
543: tree.falsepart = translate(tree.falsepart, erasure(tree.type));
544: tree.type = erasure(tree.type);
545: result = tree;
546: }
547:
548: public void visitIf(JCIf tree) {
549: tree.cond = translate(tree.cond, syms.booleanType);
550: tree.thenpart = translate(tree.thenpart);
551: tree.elsepart = translate(tree.elsepart);
552: result = tree;
553: }
554:
555: public void visitExec(JCExpressionStatement tree) {
556: tree.expr = translate(tree.expr, null);
557: result = tree;
558: }
559:
560: public void visitReturn(JCReturn tree) {
561: tree.expr = translate(tree.expr, currentMethod.sym.erasure(
562: types).getReturnType());
563: result = tree;
564: }
565:
566: public void visitThrow(JCThrow tree) {
567: tree.expr = translate(tree.expr, erasure(tree.expr.type));
568: result = tree;
569: }
570:
571: public void visitAssert(JCAssert tree) {
572: tree.cond = translate(tree.cond, syms.booleanType);
573: if (tree.detail != null)
574: tree.detail = translate(tree.detail,
575: erasure(tree.detail.type));
576: result = tree;
577: }
578:
579: public void visitApply(JCMethodInvocation tree) {
580: tree.meth = translate(tree.meth, null);
581: Symbol meth = TreeInfo.symbol(tree.meth);
582: Type mt = meth.erasure(types);
583: List<Type> argtypes = mt.getParameterTypes();
584: if (allowEnums && meth.name == names.init
585: && meth.owner == syms.enumSym)
586: argtypes = argtypes.tail.tail;
587: if (tree.varargsElement != null)
588: tree.varargsElement = types.erasure(tree.varargsElement);
589: else
590: assert tree.args.length() == argtypes.length();
591: tree.args = translateArgs(tree.args, argtypes,
592: tree.varargsElement);
593:
594: // Insert casts of method invocation results as needed.
595: result = retype(tree, mt.getReturnType(), pt);
596: }
597:
598: public void visitNewClass(JCNewClass tree) {
599: if (tree.encl != null)
600: tree.encl = translate(tree.encl, erasure(tree.encl.type));
601: tree.clazz = translate(tree.clazz, null);
602: if (tree.varargsElement != null)
603: tree.varargsElement = types.erasure(tree.varargsElement);
604: tree.args = translateArgs(tree.args, tree.constructor.erasure(
605: types).getParameterTypes(), tree.varargsElement);
606: tree.def = translate(tree.def, null);
607: tree.type = erasure(tree.type);
608: result = tree;
609: }
610:
611: public void visitNewArray(JCNewArray tree) {
612: tree.elemtype = translate(tree.elemtype, null);
613: translate(tree.dims, syms.intType);
614: tree.elems = translate(tree.elems, (tree.type == null) ? null
615: : erasure(types.elemtype(tree.type)));
616: tree.type = erasure(tree.type);
617:
618: result = tree;
619: }
620:
621: public void visitParens(JCParens tree) {
622: tree.expr = translate(tree.expr, pt);
623: tree.type = erasure(tree.type);
624: result = tree;
625: }
626:
627: public void visitAssign(JCAssign tree) {
628: tree.lhs = translate(tree.lhs, null);
629: tree.rhs = translate(tree.rhs, erasure(tree.lhs.type));
630: tree.type = erasure(tree.type);
631: result = tree;
632: }
633:
634: public void visitAssignop(JCAssignOp tree) {
635: tree.lhs = translate(tree.lhs, null);
636: tree.rhs = translate(tree.rhs, erasure(tree.rhs.type));
637: tree.type = erasure(tree.type);
638: result = tree;
639: }
640:
641: public void visitUnary(JCUnary tree) {
642: tree.arg = translate(tree.arg, tree.operator.type
643: .getParameterTypes().head);
644: result = tree;
645: }
646:
647: public void visitBinary(JCBinary tree) {
648: tree.lhs = translate(tree.lhs, tree.operator.type
649: .getParameterTypes().head);
650: tree.rhs = translate(tree.rhs, tree.operator.type
651: .getParameterTypes().tail.head);
652: result = tree;
653: }
654:
655: public void visitTypeCast(JCTypeCast tree) {
656: tree.clazz = translate(tree.clazz, null);
657: tree.type = erasure(tree.type);
658: tree.expr = translate(tree.expr, tree.type);
659: result = tree;
660: }
661:
662: public void visitTypeTest(JCInstanceOf tree) {
663: tree.expr = translate(tree.expr, null);
664: tree.clazz = translate(tree.clazz, null);
665: result = tree;
666: }
667:
668: public void visitIndexed(JCArrayAccess tree) {
669: tree.indexed = translate(tree.indexed,
670: erasure(tree.indexed.type));
671: tree.index = translate(tree.index, syms.intType);
672:
673: // Insert casts of indexed expressions as needed.
674: result = retype(tree, types.elemtype(tree.indexed.type), pt);
675: }
676:
677: // There ought to be nothing to rewrite here;
678: // we don't generate code.
679: public void visitAnnotation(JCAnnotation tree) {
680: result = tree;
681: }
682:
683: public void visitIdent(JCIdent tree) {
684: Type et = tree.sym.erasure(types);
685:
686: // Map type variables to their bounds.
687: if (tree.sym.kind == TYP && tree.sym.type.tag == TYPEVAR) {
688: result = make.at(tree.pos).Type(et);
689: } else
690: // Map constants expressions to themselves.
691: if (tree.type.constValue() != null) {
692: result = tree;
693: }
694: // Insert casts of variable uses as needed.
695: else if (tree.sym.kind == VAR) {
696: result = retype(tree, et, pt);
697: } else {
698: tree.type = erasure(tree.type);
699: result = tree;
700: }
701: }
702:
703: public void visitSelect(JCFieldAccess tree) {
704: Type t = tree.selected.type;
705: if (t.isCompound()
706: || (t.tag == TYPEVAR && t.getUpperBound().isCompound())) {
707: if ((tree.sym.flags() & IPROXY) != 0) {
708: tree.sym = ((MethodSymbol) tree.sym).implemented(
709: (TypeSymbol) tree.sym.owner, types);
710: }
711: tree.selected = cast(translate(tree.selected, erasure(t)),
712: erasure(tree.sym.owner.type));
713: } else
714: tree.selected = translate(tree.selected, erasure(t));
715:
716: // Map constants expressions to themselves.
717: if (tree.type.constValue() != null) {
718: result = tree;
719: }
720: // Insert casts of variable uses as needed.
721: else if (tree.sym.kind == VAR) {
722: result = retype(tree, tree.sym.erasure(types), pt);
723: } else {
724: tree.type = erasure(tree.type);
725: result = tree;
726: }
727: }
728:
729: public void visitTypeArray(JCArrayTypeTree tree) {
730: tree.elemtype = translate(tree.elemtype, null);
731: tree.type = erasure(tree.type);
732: result = tree;
733: }
734:
735: /** Visitor method for parameterized types.
736: */
737: public void visitTypeApply(JCTypeApply tree) {
738: // Delete all type parameters.
739: result = translate(tree.clazz, null);
740: }
741:
742: /**************************************************************************
743: * utility methods
744: *************************************************************************/
745:
746: private Type erasure(Type t) {
747: return types.erasure(t);
748: }
749:
750: /**************************************************************************
751: * main method
752: *************************************************************************/
753:
754: private Env<AttrContext> env;
755:
756: void translateClass(ClassSymbol c) {
757: Type st = types.super type(c.type);
758:
759: // process superclass before derived
760: if (st.tag == CLASS)
761: translateClass((ClassSymbol) st.tsym);
762:
763: Env<AttrContext> myEnv = enter.typeEnvs.remove(c);
764: if (myEnv == null)
765: return;
766: Env<AttrContext> oldEnv = env;
767: try {
768: env = myEnv;
769: // class has not been translated yet
770:
771: TreeMaker savedMake = make;
772: Type savedPt = pt;
773: make = make.forToplevel(env.toplevel);
774: pt = null;
775: try {
776: JCClassDecl tree = (JCClassDecl) env.tree;
777: tree.typarams = List.nil();
778: super .visitClassDef(tree);
779: make.at(tree.pos);
780: if (addBridges) {
781: ListBuffer<JCTree> bridges = new ListBuffer<JCTree>();
782: if ((tree.sym.flags() & INTERFACE) == 0)
783: addBridges(tree.pos(), tree.sym, bridges);
784: tree.defs = bridges.toList().prependList(tree.defs);
785: }
786: tree.type = erasure(tree.type);
787: } finally {
788: make = savedMake;
789: pt = savedPt;
790: }
791: } finally {
792: env = oldEnv;
793: }
794: }
795:
796: /** Translate a toplevel class definition.
797: * @param cdef The definition to be translated.
798: */
799: public JCTree translateTopLevelClass(JCTree cdef, TreeMaker make) {
800: // note that this method does NOT support recursion.
801: this.make = make;
802: pt = null;
803: return translate(cdef, null);
804: }
805: }
|