diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Erasure.scala | 293 |
1 files changed, 100 insertions, 193 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index a46fe0683d..cd46232a21 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -11,17 +11,15 @@ import scala.collection.{ mutable, immutable } import symtab._ import Flags._ -abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast.TreeDSL +abstract class Erasure extends AddInterfaces + with typechecker.Analyzer + with ast.TreeDSL { import global._ // the global environment import definitions._ // standard classes and methods - // @S: XXX: why is this here? erasure is a typer, if you comment this - // out erasure still works, uses its own typed methods. - lazy val typerXXX = this.typer - import typerXXX.{typed} // methods to type trees - import CODE._ - def typedPos(pos: Position)(tree: Tree) = typed { atPos(pos)(tree) } + + def typedPos(pos: Position)(tree: Tree) = this.typer.typedPos(pos)(tree) val phaseName: String = "erasure" @@ -32,14 +30,14 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. // -------- erasure on types -------------------------------------------------------- - /** An extractor objec for generic arrays */ + /** An extractor object for generic arrays */ object GenericArray { /** Is `tp` an unbounded generic type (i.e. which could be instantiated * with primitive as well as class types)?. */ private def genericCore(tp: Type): Type = tp.normalize match { - case TypeRef(_, argsym, _) if (argsym.isAbstractType && !(argsym.owner hasFlag JAVA)) => + case TypeRef(_, sym, _) if sym.isAbstractType && !sym.owner.isJavaDefined => tp case ExistentialType(tparams, restp) => genericCore(restp) @@ -79,40 +77,33 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. // see also #2585 marker in javaSig: there, type arguments must be included (use pre.baseType(cls.owner)) // requires cls.isClass @inline private def rebindInnerClass(pre: Type, cls: Symbol): Type = - if(cls.owner.isClass) cls.owner.tpe else pre // why not cls.isNestedClass? + if (cls.owner.isClass) cls.owner.tpe else pre // why not cls.isNestedClass? - /** <p> - * The erasure <code>|T|</code> of a type <code>T</code>. This is: - * </p> - * <ul> - * <li>For a constant type, itself.</li> - * <li>For a type-bounds structure, the erasure of its upper bound.</li> - * <li>For every other singleton type, the erasure of its supertype.</li> - * <li> - * For a typeref <code>scala.Array+[T]</code> where <code>T</code> is - * an abstract type, <code>AnyRef</code>. - * </li> - * <li> + /** 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, AnyRef. * - 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. (Where P is first rebound to the class that directly defines C.) + * - For a typeref P.C[Ts] where C refers to a class, |P|.C. + * (Where P is first rebound to the class that directly defines 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 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 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) - * </li> - * </ul> */ object erasure extends TypeMap { // Compute the dominant part of the intersection type with given `parents` according to new spec. @@ -369,31 +360,15 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. else tp :: removeDoubleObject(tps1) } - /** <p> - * The symbol's erased info. This is the type's erasure, except for the - * following symbols: - * </p> - * <ul> - * <li> - * For <code>$asInstanceOf</code> : <code>[T]T</code> - * </li> - * <li> - * For <code>$isInstanceOf</code> : <code>[T]scala#Boolean</code> - * </li> - * <li> - * For class <code>Array</code> : <code>[T]C</code> where - * <code>C</code> is the erased classinfo of the <code>Array</code> class - * </li> - * <li> - * For <code>Array[T].<init></code> : <code>{scala#Int)Array[T]</code> - * </li> - * <li> - * For a type parameter : A type bounds type consisting of the erasures - * of its bounds. - * </li> - * </ul> + /** 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 = + def transformInfo(sym: Symbol, tp: Type): Type = { if (sym == Object_asInstanceOf) sym.info else if (sym == Object_isInstanceOf || sym == ArrayClass) @@ -434,6 +409,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. */ transformMixinInfo(erasure(tp)) } + } val deconstMap = new TypeMap { def apply(tp: Type): Type = tp match { @@ -498,7 +474,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. }) } - /** Unbox <code>tree</code> of boxed type to expected type <code>pt</code>. + /** Unbox `tree` of boxed type to expected type `pt`. * * @param tree the given tree * @param pt the expected type. @@ -524,8 +500,8 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. }) } - /** Generate a synthetic cast operation from <code>tree.tpe</code> to <code>pt</code>. - * @pre pt eq pt.normalize + /** Generate a synthetic cast operation from tree.tpe to pt. + * @pre pt eq pt.normalize */ private def cast(tree: Tree, pt: Type): Tree = tree AS_ATTR pt @@ -533,7 +509,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. private def isUnboxedValueMember(sym: Symbol) = sym != NoSymbol && isValueClass(sym.owner) - /** Adapt <code>tree</code> to expected type <code>pt</code>. + /** Adapt `tree` to expected type `pt`. * * @param tree the given tree * @param pt the expected type @@ -557,61 +533,21 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. cast(tree, pt) } - /** <p> - * Replace member references as follows: - * </p> - * <ul> - * <li> - * <code>x == y</code> for <code>==</code> in class <code>Any</code> - * becomes <code>x equals y</code> with <code>equals</code> in class - * <code>Object</code>. - * </li> - * <li> - * <code>x != y</code> for <code>!=</code> in class <code>Any</code> - * becomes <code>!(x equals y)</code> with <code>equals</code> in - * class <code>Object</code>. - * </li> - * <li> - * <code>new BoxedArray.<init>(len)</code> becomes - * <code>new BoxedAnyArray.<init>(len): BoxedArray</code> - * (the widening typing is necessary so that subsequent member - * symbols stay the same) - * </li> - * <li> - * <code>x.asInstanceOf[T]</code> and <code>x.asInstanceOf$erased[T]</code> - * become <code>x.$asInstanceOf[T]</code> - * </li> - * <li> - * <code>x.isInstanceOf[T]</code> and <code>x.isInstanceOf$erased[T]</code> - * become <code>x.$isInstanceOf[T]</code> - * </li> - * <li> - * <code>x.m</code> where <code>m</code> is some other member of - * <code>Any</code> becomes <code>x.m</code> where m is a member - * of class <code>Object</code> - * </li> - * <li> - * <code>x.m</code> where <code>x</code> has unboxed value type - * <code>T</code> and <code>m</code> is not a directly translated - * member of <code>T</code> becomes <code>T.box(x).m</code> - * </li> - * <li> - * <code>x.m</code> where <code>x</code> has type <code>Array[T]</code> - * and <code>m</code> is not a directly translated member of - * <code>Array</code> becomes <code>new BoxedTArray.<init>(x).m</code> - * </li> - * <li> - * <code>x.m</code> where <code>x</code> is a reference type and - * <code>m</code> is a directly translated member of value type - * <code>T</code> becomes <code>x.TValue().m</code> - * </li> - * <li> - * All forms of <code>x.m</code> where <code>x</code> is a boxed type - * and <code>m</code> is a member of an unboxed class become - * <code>x.m</code> where <code>m</code> is the corresponding member - * of the boxed class. - * </li> - * </ul> + // @PP 1/25/2011: This is less inaccurate than it was (I removed + // BoxedAnyArray, asInstanceOf$erased, and other long ago eliminated symbols) + // but I do not think it yet describes the code beneath it. + + /** 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. + * - x.asInstanceOf[T] becomes x.$asInstanceOf[T] + * - x.isInstanceOf[T] becomes 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 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 = { //Console.println("adaptMember: " + tree); @@ -664,30 +600,26 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. } } - /** A replacement for the standard typer's <code>adapt</code> method. - * - * @param tree ... - * @param mode ... - * @param pt ... - * @return the adapted tree + /** A replacement for the standard typer's adapt method. */ override protected def adapt(tree: Tree, mode: Int, pt: Type, original: Tree = EmptyTree): Tree = adaptToType(tree, pt) - /** A replacement for the standard typer's `typed1' method */ + /** A replacement for the standard typer's `typed1' method. + */ override protected def typed1(tree: Tree, mode: Int, pt: Type): Tree = { - var tree1 = try { + val tree1 = try { super.typed1(adaptMember(tree), mode, pt) } catch { - case ex: Exception => - //if (settings.debug.value) - Console.println("exception when typing " + tree); - throw ex case er: TypeError => Console.println("exception when typing " + tree) Console.println(er.msg + " in file " + context.owner.sourceFile) er.printStackTrace abort() + case ex: Exception => + //if (settings.debug.value) + Console.println("exception when typing " + tree); + throw ex } def adaptCase(cdef: CaseDef): CaseDef = { val body1 = adaptToType(cdef.body, tree1.tpe) @@ -723,24 +655,13 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. /** The erasure transformer */ class ErasureTransformer(unit: CompilationUnit) extends Transformer { - - /** <p> - * Emit an error if there is a double definition. This can happen in - * the following circumstances: - * </p> - * <ul> - * <li> - * A template defines two members with the same name and erased type. - * </li> - * <li> - * A template defines and inherits two members <code>m</code> with - * different types, but their erased types are the same. - * </li> - * <li> - * A template inherits two members <code>m</code> with different - * types, but their erased types are the same. - * </li> - * </ul> + /** Emit an error if there is a double definition. This can happen if: + * + * - 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) { def doubleDefError(sym1: Symbol, sym2: Symbol) { @@ -817,22 +738,17 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. } */ - /** <p> - * Add bridge definitions to a template. This means: - * </p> - * <p> - * If there is a concrete member <code>m</code> 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 <code>m1</code> to the member <code>m0</code> - * is added. The bridge has the erased type of <code>m1</code> and - * forwards to <code>m0</code>. - * </p> - * <p> - * No bridge is added if there is already a bridge to <code>m0</code> - * with the erased type of <code>m1</code> in the template. - * </p> + /** 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], immutable.Set[Symbol]) = { var toBeRemoved: immutable.Set[Symbol] = immutable.Set() @@ -923,33 +839,18 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. else (stats filterNot (stat => toBeRemoved contains stat.symbol)) ::: bridges } - /** <p> - * Transform tree at phase <code>erasure</code> before retyping it. - * This entails the following: - * </p> - * <ul> - * <li>Remove all type parameters in class and method definitions.</li> - * <li>Remove all abstract and alias type definitions.</li> - * <li> - * Remove all type applications other than those involving a type - * test or cast. - * </li> - * <li> - * Remove all empty trees in statements and definitions in a - * <code>PackageDef</code>. - * </li> - * <li>Check that there are no double definitions in a template.</li> - * <li>Add bridge definitions to a template.</li> - * <li> - * Replace all types in type nodes and the <code>EmptyTree</code> - * object by their erasure. Type nodes of type <code>Unit</code> - * representing result types of methods are left alone. - * </li> - * <li> - * Reset all other type attributes to <code>null</code>, thus - * enforcing a retyping. - * </li> - * </ul> + /** 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 { def preErase(tree: Tree): Tree = tree match { @@ -1096,24 +997,28 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. tree } - override def transform(tree: Tree): Tree = - if (tree.symbol == ArrayClass && !tree.isType) tree // !!! needed? + override def transform(tree: Tree): Tree = { + // Reply to "!!! needed?" which adorned the next line: without it, build fails with: + // Exception in thread "main" scala.tools.nsc.symtab.Types$TypeError: + // value array_this is not a member of object scala.runtime.ScalaRunTime + // + // What the heck is array_this? See preTransformer in this file: + // gen.mkRuntimeCall("array_"+name, qual :: args) + if (tree.symbol == ArrayClass && !tree.isType) tree else { val tree1 = preErase(tree) - // println("preErase: "+ tree +" = "+ tree1) - val res = tree1 match { + tree1 match { case EmptyTree | TypeTree() => tree1 setType erasure(tree1.tpe) - case DefDef(mods, name, tparams, vparamss, tpt, rhs) => + case DefDef(_, _, _, _, tpt, _) => val result = super.transform(tree1) setType null tpt.tpe = erasure(tree1.symbol.tpe).resultType result case _ => super.transform(tree1) setType null } - // println("xform: "+ res) - res } + } } /** The main transform function: Pretransfom the tree, and then @@ -1123,7 +1028,9 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. val tree1 = preTransformer.transform(tree) atPhase(phase.next) { val tree2 = mixinTransformer.transform(tree1) - if (settings.debug.value) log("tree after addinterfaces: \n" + tree2) + if (settings.debug.value) + log("tree after addinterfaces: \n" + tree2) + newTyper(rootContext(unit, tree, true)).typed(tree2) } } |