summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/transform/Erasure.scala
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-01-26 09:26:28 +0000
committerPaul Phillips <paulp@improving.org>2011-01-26 09:26:28 +0000
commitccc81fa54cca9939e0d45487d65b1e317bef91b6 (patch)
treeab5eee55872e826c921bce1f2b167309c3ced083 /src/compiler/scala/tools/nsc/transform/Erasure.scala
parent78a48c46cf3727dd06179cb1360b2f9057647042 (diff)
downloadscala-ccc81fa54cca9939e0d45487d65b1e317bef91b6.tar.gz
scala-ccc81fa54cca9939e0d45487d65b1e317bef91b6.tar.bz2
scala-ccc81fa54cca9939e0d45487d65b1e317bef91b6.zip
Another thing we are all a bit too used to is h...
Another thing we are all a bit too used to is having lots of unreadable HTML in our code. This is key, central documentation and we all hum to ourselves and look past it rather than risk being assaulted by a swarm of angle brackets. That's why the erasure docs can still talk about BoxedAnyArray and x.asInstanceOf$erased. They could be talking about who killed JFK, we wouldn't know the difference. I also addressed some questions from decades past like "why is this here?" and "!!! needed?" One thing I don't know is whether {scala#Int)Array[T] is intentional notation or the aftermath of a tragic punctuation accident. How about I mass fix all the HTML in trunk? Wouldn't that be great? Just say the word... no review.
Diffstat (limited to 'src/compiler/scala/tools/nsc/transform/Erasure.scala')
-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)
}
}