summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/transform/Erasure.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/scala/tools/nsc/transform/Erasure.scala')
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala569
1 files changed, 569 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
new file mode 100644
index 0000000000..c726d2255d
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -0,0 +1,569 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author
+ */
+// $Id$
+package scala.tools.nsc.transform;
+
+import collection.mutable.HashMap;
+import symtab._;
+import Flags._;
+import scala.tools.nsc.util.Position;
+import util.ListBuffer;
+
+abstract class Erasure extends AddInterfaces with typechecker.Analyzer {
+ import global._; // the global environment
+ import definitions._; // standard classes and methods
+ import typer.{typed}; // methods to type trees
+ import posAssigner.atPos; // for filling in tree positions
+
+ val phaseName: String = "erasure";
+ def newTransformer(unit: CompilationUnit): Transformer = new ErasureTransformer(unit);
+
+// -------- erasure on types --------------------------------------------------------
+
+ /** The erasure |T| of a type T. This is:
+ * - For a constant type, itself.
+ * - For a type-bounds structure, the erasure of its upper bound.
+ * - For every other singleton type, the erasure of its supertype.
+ * - For a typeref scala.Array[T] where T is an abstract type, scala.runtime.BoxedArray.
+ * - For a typeref scala.Array[T] where T is not an abstract type, scala.Array[|T|].
+ * - For a typeref scala.Any or scala.AnyVal, java.lang.Object.
+ * - For a typeref scala.Unit, scala.runtime.BoxedUnit.
+ * - For a typeref P.C[Ts] where C refers to a class, |P|.C.
+ * - For a typeref P.C[Ts] where C refers to an alias type, the erasure of C's alias.
+ * - For a typeref P.C[Ts] where C refers to an abstract type, the erasure of C's upper bound.
+ * - For a non-empty type intersection (possibly with refinement), the erasure of its first parent.
+ * - For an empty type intersection, java.lang.Object
+ * - For a method type (Fs)scala.Unit, (|Fs|)scala#Unit.
+ * - For any other method type (Fs)Y, (|Fs|)|T|.
+ * - For a polymorphic type, the erasure of its result type
+ * - For the class info type of java.lang.Object, the same type without any parents
+ * - For a class info type of a value class, the same type without any parents
+ * - For any other class info type with parents Ps, the same type with parents |Ps|, but
+ * with duplicate references of Object removed.
+ * - for all other types, the type itself (with any sub-components erased)
+ */
+ private val erasure = new TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case ConstantType(_) =>
+ tp
+ case st: SubType =>
+ apply(st.supertype)
+ case TypeRef(pre, sym, args) =>
+ if (sym == ArrayClass)
+ args.head match {
+ case TypeRef(_, tvar, _) if (tvar.isAbstractType) => erasedTypeRef(BoxedArrayClass)
+ case _ => typeRef(apply(pre), sym, args map this)
+ }
+ else if (sym == AnyClass || sym == AnyValClass) erasedTypeRef(ObjectClass)
+ else if (sym == UnitClass) erasedTypeRef(BoxedUnitClass)
+ else if (sym.isClass) typeRef(apply(pre), sym, List())
+ else apply(sym.info)
+ case PolyType(tparams, restpe) =>
+ apply(restpe)
+ case MethodType(formals, restpe) =>
+ MethodType(
+ formals map apply,
+ if (restpe.symbol == UnitClass) erasedTypeRef(UnitClass) else apply(restpe));
+ case RefinedType(parents, decls) =>
+ if (parents.isEmpty) erasedTypeRef(ObjectClass)
+ else apply(parents.head)
+ case ClassInfoType(parents, decls, clazz) =>
+ ClassInfoType(
+ if ((clazz == ObjectClass) || (isValueClass(clazz))) List()
+ else if (clazz == ArrayClass) List(erasedTypeRef(ObjectClass))
+ else removeDoubleObject(parents map this),
+ decls, clazz)
+ case _ =>
+ mapOver(tp)
+ }
+ }
+
+ /** Type reference after erasure */
+ def erasedTypeRef(sym: Symbol): Type = typeRef(erasure(sym.owner.tpe), sym, List());
+
+ /** Remove duplicate references to class Object in a list of parent classes
+ * todo: needed?
+ */
+ private def removeDoubleObject(tps: List[Type]): List[Type] = tps match {
+ case List() => List()
+ case tp :: tps1 =>
+ if (tp.symbol == ObjectClass) tp :: tps1.filter(.symbol.!=(ObjectClass))
+ else tp :: removeDoubleObject(tps1)
+ }
+
+ /** The symbol's erased info. This is the type's erasure, except for the following symbols
+ * - For $asInstanceOf : [T]T
+ * - For $isInstanceOf : [T]scala#Boolean
+ * - For class Array : [T]C where C is the erased classinfo of the Array class
+ * - For Array[T].<init> : {scala#Int)Array[T]
+ * - For a type parameter : A type bounds type consisting of the erasures of its bounds.
+ */
+ def transformInfo(sym: Symbol, tp: Type): Type =
+ if (sym == Object_asInstanceOf)
+ sym.info
+ else if (sym == Object_isInstanceOf || sym == ArrayClass)
+ PolyType(sym.info.typeParams, erasure(sym.info.resultType))
+ else if (sym.isAbstractType)
+ TypeBounds(WildcardType, WildcardType)
+ else if (sym.isTerm && sym.owner == ArrayClass) {
+ if (sym.isClassConstructor)
+ tp match {
+ case MethodType(formals, TypeRef(pre, sym, args)) =>
+ MethodType(formals map erasure, typeRef(erasure(pre), sym, args))
+ }
+ else if (sym.name == nme.apply)
+ tp
+ else if (sym.name == nme.update)
+ tp match {
+ case MethodType(List(index, tvar), restpe) =>
+ MethodType(List(erasure(index), tvar), erasedTypeRef(UnitClass))
+ }
+ else erasure(tp)
+ } else
+ transformTraitInfo(erasure(tp));
+
+// -------- boxing/unboxing --------------------------------------------------------
+
+ override def newTyper(context: Context) = new Eraser(context);
+
+ /** The modifier typer which retypes with erased types. */
+ class Eraser(context: Context) extends Typer(context) {
+
+ private def evalOnce(expr: Tree, within: (() => Tree) => Tree): Tree =
+ if (treeInfo.isPureExpr(expr)) {
+ within(() => expr);
+ } else {
+ val temp = context.owner.newValue(expr.pos, context.unit.fresh.newName())
+ .setFlag(SYNTHETIC).setInfo(expr.tpe);
+ Block(List(ValDef(temp, expr)), within(() => Ident(temp) setType expr.tpe))
+ }
+
+ /** Box `tree' of unboxed type */
+ private def box(tree: Tree): Tree =
+ typed {
+ atPos(tree.pos) {
+ val sym = tree.tpe.symbol;
+ if (sym == UnitClass) {
+ if (treeInfo.isPureExpr(tree)) gen.mkRef(BoxedUnit_UNIT)
+ else Block(List(tree), gen.mkRef(BoxedUnit_UNIT))
+ } else if (sym == ArrayClass) {
+ val elemClass = tree.tpe.typeArgs.head.symbol;
+ val boxedClass = if (isValueClass(elemClass)) boxedArrayClass(elemClass)
+ else BoxedObjectArrayClass;
+ Apply(Select(New(TypeTree(boxedClass.tpe)), nme.CONSTRUCTOR), List(tree))
+ } else {
+ val boxedModule = boxedClass(tree.tpe.symbol).linkedModule;
+ Apply(Select(gen.mkRef(boxedModule), nme.box), List(tree))
+ }
+ }
+ }
+
+ /** The method-name xxxValue, where Xxx is a numeric value class name */
+ def unboxOp(tp: Type) = {
+ val clazzName = tp.symbol.name.toString();
+ (String.valueOf((clazzName.charAt(0) + ('a' - 'A')).asInstanceOf[char]) +
+ clazzName.substring(1) + "Value")
+ }
+
+ /** Unbox `tree' of boxed type to expected type `pt' */
+ private def unbox(tree: Tree, pt: Type): Tree =
+ typed {
+ atPos(tree.pos) {
+ if (pt.symbol == UnitClass) {
+ if (treeInfo.isPureExpr(tree)) Literal(())
+ else Block(List(tree), Literal(()))
+ } else if (pt.symbol == BooleanClass) {
+ val tree1 = adaptToType(tree, boxedClass(BooleanClass).tpe);
+ Apply(Select(tree1, "booleanValue"), List())
+ } else if (pt.symbol == ArrayClass) {
+ val tree1 = adaptToType(tree, BoxedArrayClass.tpe);
+ val elemClass = pt.typeArgs.head.symbol;
+ val elemTag =
+ if (isValueClass(elemClass))
+ Apply(
+ Select(gen.mkRef(ScalaRunTimeModule), newTermName(elemClass.name.toString() + "Tag")),
+ List())
+ else Literal(signature(pt.typeArgs.head));
+ Apply(Select(tree1, "unbox"), List(elemTag))
+ } else {
+ assert(isNumericValueClass(pt.symbol));
+ val tree1 = adaptToType(tree, BoxedNumberClass.tpe);
+ Apply(Select(tree1, unboxOp(pt)), List())
+ }
+ }
+ }
+
+ private def cast(tree: Tree, pt: Type): Tree =
+ if (pt.symbol == ArrayClass && tree.tpe.symbol == ObjectClass)
+ typed {
+ atPos(tree.pos) {
+ evalOnce(tree, x =>
+ gen.cast(
+ If(
+ Apply(
+ TypeApply(
+ Select(x(), Object_isInstanceOf),
+ List(TypeTree(BoxedArrayClass.tpe))),
+ List()),
+ unbox(x(), pt),
+ x()),
+ pt))
+ }
+ }
+ else gen.cast(tree, pt);
+
+ /** Is symbol a member of unboxed arrays (which will be expanded directly later)? */
+ private def isUnboxedArrayMember(sym: Symbol) = (
+ sym.name == nme.apply || sym.name == nme.length || sym.name == nme.update ||
+ sym.owner == ObjectClass
+ );
+
+ /** Is symbol a member of a boxed value class (which will not be expanded later)? */
+ def isBoxedValueMember(sym: Symbol) =
+ (sym.name == nme.equals_ || sym.name == nme.hashCode_ || sym.name == nme.toString_ ||
+ (sym.name == nme.EQ || sym.name == nme.NE) && sym.info.paramTypes.head.symbol == ObjectClass ||
+ sym == Object_isInstanceOf || sym == Object_asInstanceOf);
+
+ /** Adapt `tree' to expected type `pt' */
+ private def adaptToType(tree: Tree, pt: Type): Tree = {
+ if (settings.debug.value && pt != WildcardType) log("adapting " + tree + ":" + tree.tpe + " to " + pt);//debug
+ if (tree.tpe <:< pt)
+ tree
+ else if (isUnboxedClass(tree.tpe.symbol) && !isUnboxedClass(pt.symbol))
+ adaptToType(box(tree), pt)
+ else if (tree.tpe.isInstanceOf[MethodType] && tree.tpe.paramTypes.isEmpty) {
+ assert(tree.symbol.isStable);
+ adaptToType(Apply(tree, List()) setPos tree.pos setType tree.tpe.resultType, pt)
+ } else if (pt <:< tree.tpe)
+ cast(tree, pt)
+ else if (isUnboxedClass(pt.symbol) && !isUnboxedClass(tree.tpe.symbol))
+ adaptToType(unbox(tree, pt), pt)
+ else
+ cast(tree, pt)
+ }
+
+ /** Replace member references as follows:
+ * - `x == y' for `==' in class Any becomes `x equals y' with `equals' in class Object
+ * - `x != y' for `!=' in class Any becomes `!(x equals y)' with `equals' in class Object
+ * - `new BoxedArray.<init>(len)' becomes `new BoxedAnyArray.<init>(len): BoxedArray'
+ * (the widening typing is necessary so that subsequent member symbols stay the same)
+ * - `x.asInstanceOf[T]' and `x.asInstanceOf$erased[T]' become `x.$asInstanceOf[T]'
+ * - `x.isInstanceOf[T]' and `x.isInstanceOf$erased[T]' become `x.$isInstanceOf[T]'
+ * - `x.m' where `m' is some other member of Any becomes `x.m' where m is a member of class Object
+ * - `x.m' where `x' has unboxed value type `T' and `m' is not a directly
+ * translated member of `T' becomes T.box(x).m
+ * - `x.m' where `x' has type `Array[T]' and `m' is not a directly
+ * translated member of `Array' becomes new BoxedTArray.<init>(x).m
+ * - `x.m' where `x' is a reference type and `m' is a directly translated member of value type
+ * T becomes x.TValue().m
+ * - All forms of `x.m' where `x' is a boxed type and `m' is a member of an unboxed class
+ * become `x.m' where `m' is the corresponding member of the boxed class.
+ */
+ private def adaptMember(tree: Tree): Tree = {
+ tree match {
+ case Apply(Select(New(tpt), name), args) if (tpt.tpe.symbol == BoxedArrayClass) =>
+ assert(name == nme.CONSTRUCTOR);
+ atPos(tree.pos) {
+ Typed(Apply(Select(New(TypeTree(BoxedAnyArrayClass.tpe)), name), args), tpt)
+ }
+ case Apply(TypeApply(sel @ Select(qual, name), List(targ)), List())
+ if ((tree.symbol == Any_asInstanceOf || tree.symbol == Any_asInstanceOfErased)) =>
+ val qual1 = typedQualifier(qual);
+ val targClass = targ.tpe.symbol;
+ val qualClass = qual1.tpe.symbol;
+ if (isNumericValueClass(qualClass) && isNumericValueClass(targClass))
+ // convert numeric type casts
+ atPos(tree.pos)(Apply(Select(qual1, "to" + targClass.name), List()))
+ else if (isValueClass(targClass) ||
+ (targClass == ArrayClass && (qualClass isSubClass BoxedArrayClass)))
+ unbox(qual1, targ.tpe)
+ else if (targClass == ArrayClass && qualClass == ObjectClass)
+ cast(qual1, targ.tpe)
+ else
+ tree
+ case Select(qual, name) if (name != nme.CONSTRUCTOR) =>
+ if (tree.symbol == Any_asInstanceOf || tree.symbol == Any_asInstanceOfErased)
+ adaptMember(atPos(tree.pos)(Select(qual, Object_asInstanceOf)))
+ else if (tree.symbol == Any_isInstanceOf || tree.symbol == Any_isInstanceOfErased)
+ adaptMember(atPos(tree.pos)(Select(qual, Object_isInstanceOf)))
+ else if (tree.symbol != NoSymbol && tree.symbol.owner == AnyClass)
+ adaptMember(atPos(tree.pos)(Select(qual, getMember(ObjectClass, name))))
+ else {
+ var qual1 = typedQualifier(qual);
+ if ((isValueClass(qual1.tpe.symbol) && isBoxedValueMember(tree.symbol)) ||
+ (qual1.tpe.symbol == ArrayClass && !isUnboxedArrayMember(tree.symbol))) {
+ qual1 = box(qual1);
+ } else if (!isValueClass(qual1.tpe.symbol) &&
+ tree.symbol != NoSymbol &&
+ isValueClass(tree.symbol.owner) &&
+ !isBoxedValueMember(tree.symbol)) {
+ qual1 = unbox(qual1, tree.symbol.owner.tpe)
+ }
+ if (tree.symbol != NoSymbol)
+ if (isUnboxedClass(tree.symbol.owner) && !isUnboxedClass(qual1.tpe.symbol))
+ tree.symbol = NoSymbol
+ else if (qual1.tpe.isInstanceOf[MethodType] && qual1.tpe.paramTypes.isEmpty) {
+ assert(qual1.symbol.isStable);
+ qual1 = Apply(qual1, List()) setPos qual1.pos setType qual1.tpe.resultType;
+ } else if (!(qual1.isInstanceOf[Super] || (qual1.tpe.symbol isSubClass tree.symbol.owner)))
+ qual1 = cast(qual1, tree.symbol.owner.tpe);
+ copy.Select(tree, qual1, name)
+ }
+ case _ =>
+ tree
+ }
+ }
+
+ /** A replacement for the standard typer's `adapt' method */
+ override protected def adapt(tree: Tree, mode: int, pt: Type): Tree = adaptToType(tree, pt);
+
+ /** A replacement for the standard typer's `typed1' method */
+ override protected def typed1(tree: Tree, mode: int, pt: Type): Tree = {
+ val tree1 = super.typed1(adaptMember(tree), mode, pt);
+ def adaptCase(cdef: CaseDef): CaseDef = {
+ val body1 = adaptToType(cdef.body, tree1.tpe);
+ copy.CaseDef(cdef, cdef.pat, cdef.guard, body1) setType body1.tpe
+ }
+ def adaptBranch(branch: Tree): Tree =
+ if (branch == EmptyTree) branch else adaptToType(branch, tree1.tpe);
+ tree1 match {
+ case If(cond, thenp, elsep) =>
+ copy.If(tree1, cond, adaptBranch(thenp), adaptBranch(elsep))
+ case Match(selector, cases) =>
+ copy.Match(tree1, selector, cases map adaptCase)
+ case Try(block, catches, finalizer) =>
+ copy.Try(tree1, adaptBranch(block), catches map adaptCase, finalizer)
+ case _ =>
+ tree1
+ }
+ }
+ }
+
+ /** The erasure transformer */
+ class ErasureTransformer(unit: CompilationUnit) extends Transformer {
+
+ /** Emit an error if there is a double definition. This can happen in the following
+ * circumstances:
+ * - A template defines two members with the same name and erased type.
+ * - A template defines and inherits two members `m' with different types,
+ * but their erased types are the same.
+ * - A template inherits two members `m' with different types,
+ * but their erased types are the same.
+ */
+ private def checkNoDoubleDefs(root: Symbol): unit = {
+ def doubleDefError(sym1: Symbol, sym2: Symbol) = {
+ val tpe1 = atPhase(currentRun.refchecksPhase.next)(root.thisType.memberType(sym1));
+ val tpe2 = atPhase(currentRun.refchecksPhase.next)(root.thisType.memberType(sym2));
+ unit.error(
+ if (sym1.owner == root) sym1.pos else root.pos,
+ (if (sym1.owner == sym2.owner) "double definition:\n"
+ else if (sym1.owner == root) "name clash between defined and inherited member:\n"
+ else "name clash between inherited members:\n") +
+ sym1 + ":" + tpe1 +
+ (if (sym1.owner == root) "" else sym1.locationString) + " and\n" +
+ sym2 + ":" + tpe2 +
+ (if (sym2.owner == root) " at line " + Position.line(unit.source, sym2.pos) else sym2.locationString) +
+ "\nhave same type" +
+ (if (tpe1 =:= tpe2) "" else " after erasure: " + atPhase(phase.next)(sym1.tpe)))
+ }
+
+ val decls = root.info.decls;
+ var e = decls.elems;
+ while (e != null) {
+ if (e.sym.isTerm && !e.sym.isConstructor) {
+ var e1 = decls.lookupNextEntry(e);
+ while (e1 != null) {
+ if (atPhase(phase.next)(e1.sym.info =:= e.sym.info)) doubleDefError(e.sym, e1.sym);
+ e1 = decls.lookupNextEntry(e1)
+ }
+ }
+ e = e.next
+ }
+
+ val opc = new overridingPairs.Cursor(root) {
+ override def exclude(sym: Symbol): boolean =
+ !sym.isTerm || (sym hasFlag (PRIVATE | BRIDGE)) || super.exclude(sym);
+ override def matches(sym1: Symbol, sym2: Symbol): boolean =
+ atPhase(phase.next)(sym1.tpe =:= sym2.tpe)
+ }
+ while (opc.hasNext) {
+ if (!atPhase(currentRun.refchecksPhase.next)(
+ root.thisType.memberType(opc.overriding) matches
+ root.thisType.memberType(opc.overridden))) {
+ if (settings.debug.value) log("" + opc.overriding.locationString + " " + opc.overriding.infosString + opc.overridden.locationString + " " + opc.overridden.infosString);
+ doubleDefError(opc.overriding, opc.overridden)
+ }
+ opc.next
+ }
+ }
+
+/*
+ for (val bc <- root.info.baseClasses.tail; val other <- bc.info.decls.toList) {
+ if (other.isTerm && !other.isConstructor && !(other hasFlag (PRIVATE | BRIDGE))) {
+ for (val member <- root.info.nonPrivateMember(other.name).alternatives) {
+ if (member != other &&
+ !(member hasFlag BRIDGE) &&
+ atPhase(phase.next)(member.tpe =:= other.tpe) &&
+ !atPhase(refchecksPhase.next)(
+ root.thisType.memberType(member) matches root.thisType.memberType(other))) {
+ if (settings.debug.value) log("" + member.locationString + " " + member.infosString + other.locationString + " " + other.infosString);
+ doubleDefError(member, other)
+ }
+ }
+ }
+ }
+*/
+
+ /** Add bridge definitions to a template. This means:
+ * If there is a concrete member `m' which overrides a member in a base class of the template,
+ * and the erased types of the two members differ,
+ * and the two members are not inherited or defined by some parent class of the template,
+ * then a bridge from the overridden member `m1' to the member `m0' is added.
+ * The bridge has the erased type of `m1' and forwards to `m0'.
+ * No bridge is added if there is already a bridge to `m0' with the erased type of `m1'
+ * in the template.
+ */
+ private def bridgeDefs(owner: Symbol): List[Tree] = {
+ //System.out.println("computing bridges for " + owner);//DEBUG
+ val site = owner.thisType;
+ val bridgesScope = new Scope();
+ val bridgeTarget = new HashMap[Symbol, Symbol];
+ var bridges: List[Tree] = List();
+ val opc = atPhase(phase.prev) { // to avoid DEFERRED flags for interfaces
+ new overridingPairs.Cursor(owner) {
+ override def parents: List[Type] = List(owner.info.parents.head);
+ override def exclude(sym: Symbol): boolean =
+ !sym.isMethod || (sym hasFlag (PRIVATE | BRIDGE)) || super.exclude(sym);
+ }
+ }
+ while (opc.hasNext) {
+ val member = opc.overriding;
+ val other = opc.overridden;
+ //System.out.println("bridge? " + member + ":" + member.tpe + member.locationString + " to " + other + ":" + other.tpe + other.locationString);//DEBUG
+ if (!atPhase(phase.prev)(member hasFlag DEFERRED)) {
+ val otpe = erasure(other.tpe);
+ val bridgeNeeded = atPhase(phase.next) (
+ !(other.tpe =:= member.tpe) &&
+ { var e = bridgesScope.lookupEntry(member.name);
+ while (e != null && !((e.sym.tpe =:= otpe) && (bridgeTarget(e.sym) == member)))
+ e = bridgesScope.lookupNextEntry(e);
+ e == null
+ }
+ );
+ if (bridgeNeeded) {
+ val bridge = other.cloneSymbolImpl(owner)
+ .setPos(owner.pos)
+ .setFlag(member.flags | BRIDGE)
+ .resetFlag(ACCESSOR | DEFERRED | lateDEFERRED)
+ .setInfo(otpe);
+ bridgeTarget(bridge) = member;
+ owner.info.decls.enter(bridge);
+ bridgesScope enter bridge;
+ bridges =
+ atPhase(phase.next) {
+ atPos(bridge.pos) {
+ val bridgeDef =
+ DefDef(bridge, vparamss =>
+ member.tpe match {
+ case MethodType(List(), ConstantType(c)) => Literal(c)
+ case _ =>
+ (((Select(This(owner), member): Tree) /: vparamss)
+ ((fun, vparams) => Apply(fun, vparams map Ident)))
+ });
+ if (settings.debug.value)
+ log("generating bridge from " + other + "(" + Flags.flagsToString(bridge.flags) + ")" + ":" + otpe + other.locationString + " to " + member + ":" + erasure(member.tpe) + member.locationString + " =\n " + bridgeDef);
+ bridgeDef
+ }
+ } :: bridges;
+ }
+ }
+ opc.next
+ }
+ bridges
+ }
+/*
+ for (val bc <- site.baseClasses.tail; val other <- bc.info.decls.toList) {
+ if (other.isMethod && !other.isConstructor) {
+ for (val member <- site.nonPrivateMember(other.name).alternatives) {
+ if (member != other &&
+ !(member hasFlag DEFERRED) &&
+ (site.memberType(member) matches site.memberType(other)) &&
+ !(site.parents exists (p =>
+ (p.symbol isSubClass member.owner) && (p.symbol isSubClass other.owner)))) {
+...
+ }
+ }
+*/
+
+ def addBridges(stats: List[Tree], base: Symbol): List[Tree] =
+ if (base.isTrait) stats
+ else {
+ val bridges = bridgeDefs(base);
+ if (bridges.isEmpty) stats else stats ::: bridges
+ }
+
+ /** Transform tree at phase `erasure' before retyping it. This entails the following:
+ * - Remove all type parameters in class and method definitions.
+ * - Remove all abstract and alias type definitions.
+ * - Remove all type applications other than those involving a type test or cast.
+ * - Remove all empty trees in statements and definitions in a PackageDef.
+ * - Check that there are no double definitions in a template.
+ * - Add bridge definitions to a template.
+ * - Replace all types in type nodes and the EmptyTree object by their erasure.
+ * Type nodes of type Unit representing result types of methods are left alone.
+ * - Reset all other type attributes to `null, thus enforcing a retyping.
+ */
+ private val preTransformer = new Transformer {
+ override def transform(tree: Tree): Tree = {
+ if (tree.symbol == ArrayClass) return tree;
+ val tree1 = tree match {
+ case ClassDef(mods, name, tparams, tpt, impl) =>
+ if (settings.debug.value) log("defs of " + tree.symbol + " = " + tree.symbol.info.decls);
+ copy.ClassDef(tree, mods, name, List(), tpt, impl)
+ case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
+ copy.DefDef(tree, mods, name, List(), vparamss, tpt, rhs)
+ case AbsTypeDef(_, _, _, _) =>
+ EmptyTree
+ case AliasTypeDef(_, _, _, _) =>
+ EmptyTree
+ case TypeApply(fun, args) if (fun.symbol.owner != AnyClass) =>
+ // leave all other type tests/type casts, remove all other type applications
+ fun
+ case Template(parents, body) =>
+ assert(!currentOwner.isImplClass);
+ //System.out.println("checking no dble defs " + tree);//DEBUG
+ checkNoDoubleDefs(tree.symbol.owner);
+ copy.Template(tree, parents, addBridges(body, currentOwner));
+ case _ =>
+ tree
+ }
+ tree1 match {
+ case EmptyTree | TypeTree() =>
+ tree1 setType erasure(tree1.tpe)
+ case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
+ val result = super.transform(tree1) setType null;
+ tpt.tpe = erasure(tree.symbol.tpe).resultType;
+ result
+ case _ =>
+ super.transform(tree1) setType null
+ }
+ }
+ }
+
+ /** The main transform function: Pretransfom the tree, and then
+ * re-type it at phase erasure.next.
+ */
+ override def transform(tree: Tree): Tree = {
+ val tree1 = preTransformer.transform(tree);
+ atPhase(phase.next) {
+ val tree2 = traitTransformer.transform(tree1);
+ if (settings.debug.value) log("tree after addinterfaces: \n" + tree2);
+ newTyper(startContext.make(
+ unit, tree, startContext.owner, startContext.scope, startContext.imports))
+ .typed(tree2)
+ }
+ }
+ }
+}