summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala293
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)
}
}