summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/transform/Erasure.scala
diff options
context:
space:
mode:
authorJames Iry <james.iry@typesafe.com>2013-07-30 11:22:55 -0700
committerJames Iry <james.iry@typesafe.com>2013-11-06 12:28:19 -0800
commit510b8cecc4951ff8092cfa931c2dc3717e21dded (patch)
treece63f3c54e58f927de9e6d6df1ecc6967f012bb9 /src/compiler/scala/tools/nsc/transform/Erasure.scala
parent10a061d425857c9e7bf4fa9aba9923b90467e24e (diff)
downloadscala-510b8cecc4951ff8092cfa931c2dc3717e21dded.tar.gz
scala-510b8cecc4951ff8092cfa931c2dc3717e21dded.tar.bz2
scala-510b8cecc4951ff8092cfa931c2dc3717e21dded.zip
Refactor Erasure for delambdafication.
This commit is purely a refactor. It pulls code needed to adapt a tree of one type into a tree of another type (by casting, boxing, coercing, etc) out of Erasure and into common locations that will be usable from the Delambdafy phase.
Diffstat (limited to 'src/compiler/scala/tools/nsc/transform/Erasure.scala')
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala170
1 files changed, 6 insertions, 164 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index f0d3db1296..68f1c81c59 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -17,11 +17,15 @@ abstract class Erasure extends AddInterfaces
with typechecker.Analyzer
with TypingTransformers
with ast.TreeDSL
+ with TypeAdaptingTransformer
{
import global._
import definitions._
import CODE._
+ val analyzer: typechecker.Analyzer { val global: Erasure.this.global.type } =
+ this.asInstanceOf[typechecker.Analyzer { val global: Erasure.this.global.type }]
+
val phaseName: String = "erasure"
def newTransformer(unit: CompilationUnit): Transformer =
@@ -352,13 +356,6 @@ abstract class Erasure extends AddInterfaces
override def newTyper(context: Context) = new Eraser(context)
- private def isSafelyRemovableUnbox(fn: Tree, arg: Tree): Boolean = {
- isUnbox(fn.symbol) && {
- val cls = arg.tpe.typeSymbol
- (cls == definitions.NullClass) || isBoxedValueClass(cls)
- }
- }
-
class ComputeBridges(unit: CompilationUnit, root: Symbol) {
assert(phase == currentRun.erasurePhase, phase)
@@ -522,158 +519,8 @@ abstract class Erasure extends AddInterfaces
}
/** The modifier typer which retypes with erased types. */
- class Eraser(_context: Context) extends Typer(_context) {
-
- private def isPrimitiveValueType(tpe: Type) = isPrimitiveValueClass(tpe.typeSymbol)
-
- private def isDifferentErasedValueType(tpe: Type, other: Type) =
- isErasedValueType(tpe) && (tpe ne other)
-
- private def isPrimitiveValueMember(sym: Symbol) = isPrimitiveValueClass(sym.owner)
-
- @inline private def box(tree: Tree, target: => String): Tree = {
- val result = box1(tree)
- if (tree.tpe =:= UnitTpe) ()
- else log(s"boxing ${tree.summaryString}: ${tree.tpe} into $target: ${result.tpe}")
- result
- }
-
- /** Box `tree` of unboxed type */
- private def box1(tree: Tree): Tree = tree match {
- case LabelDef(_, _, _) =>
- val ldef = deriveLabelDef(tree)(box1)
- ldef setType ldef.rhs.tpe
- case _ =>
- val tree1 = tree.tpe match {
- case ErasedValueType(clazz, _) =>
- New(clazz, cast(tree, underlyingOfValueClass(clazz)))
- case _ =>
- tree.tpe.typeSymbol match {
- case UnitClass =>
- if (treeInfo isExprSafeToInline tree) REF(BoxedUnit_UNIT)
- else BLOCK(tree, REF(BoxedUnit_UNIT))
- case NothingClass => tree // a non-terminating expression doesn't need boxing
- case x =>
- assert(x != ArrayClass)
- tree match {
- /* Can't always remove a Box(Unbox(x)) combination because the process of boxing x
- * may lead to throwing an exception.
- *
- * This is important for specialization: calls to the super constructor should not box/unbox specialized
- * fields (see TupleX). (ID)
- */
- case Apply(boxFun, List(arg)) if isSafelyRemovableUnbox(tree, arg) =>
- log(s"boxing an unbox: ${tree.symbol} -> ${arg.tpe}")
- arg
- case _ =>
- (REF(boxMethod(x)) APPLY tree) setPos (tree.pos) setType ObjectTpe
- }
- }
- }
- typedPos(tree.pos)(tree1)
- }
-
- private def unbox(tree: Tree, pt: Type): Tree = {
- val result = unbox1(tree, pt)
- log(s"unboxing ${tree.shortClass}: ${tree.tpe} as a ${result.tpe}")
- result
- }
-
- /** Unbox `tree` of boxed type to expected type `pt`.
- *
- * @param tree the given tree
- * @param pt the expected type.
- * @return the unboxed tree
- */
- private def unbox1(tree: Tree, pt: Type): Tree = tree match {
-/*
- case Boxed(unboxed) =>
- println("unbox shorten: "+tree) // this never seems to kick in during build and test; therefore disabled.
- adaptToType(unboxed, pt)
- */
- case LabelDef(_, _, _) =>
- val ldef = deriveLabelDef(tree)(unbox(_, pt))
- ldef setType ldef.rhs.tpe
- case _ =>
- val tree1 = pt match {
- case ErasedValueType(clazz, underlying) =>
- val tree0 =
- if (tree.tpe.typeSymbol == NullClass &&
- isPrimitiveValueClass(underlying.typeSymbol)) {
- // convert `null` directly to underlying type, as going
- // via the unboxed type would yield a NPE (see SI-5866)
- unbox1(tree, underlying)
- } else
- Apply(Select(adaptToType(tree, clazz.tpe), clazz.derivedValueClassUnbox), List())
- cast(tree0, pt)
- case _ =>
- pt.typeSymbol match {
- case UnitClass =>
- if (treeInfo isExprSafeToInline tree) UNIT
- else BLOCK(tree, UNIT)
- case x =>
- assert(x != ArrayClass)
- // don't `setType pt` the Apply tree, as the Apply's fun won't be typechecked if the Apply tree already has a type
- Apply(unboxMethod(pt.typeSymbol), tree)
- }
- }
- typedPos(tree.pos)(tree1)
- }
-
- /** Generate a synthetic cast operation from tree.tpe to pt.
- * @pre pt eq pt.normalize
- */
- private def cast(tree: Tree, pt: Type): Tree = {
- if ((tree.tpe ne null) && !(tree.tpe =:= ObjectTpe)) {
- def word = (
- if (tree.tpe <:< pt) "upcast"
- else if (pt <:< tree.tpe) "downcast"
- else if (pt weak_<:< tree.tpe) "coerce"
- else if (tree.tpe weak_<:< pt) "widen"
- else "cast"
- )
- log(s"erasure ${word}s from ${tree.tpe} to $pt")
- }
- if (pt =:= UnitTpe) {
- // See SI-4731 for one example of how this occurs.
- log("Attempted to cast to Unit: " + tree)
- tree.duplicate setType pt
- } else if (tree.tpe != null && tree.tpe.typeSymbol == ArrayClass && pt.typeSymbol == ArrayClass) {
- // See SI-2386 for one example of when this might be necessary.
- val needsExtraCast = isPrimitiveValueType(tree.tpe.typeArgs.head) && !isPrimitiveValueType(pt.typeArgs.head)
- val tree1 = if (needsExtraCast) gen.mkRuntimeCall(nme.toObjectArray, List(tree)) else tree
- gen.mkAttributedCast(tree1, pt)
- } else gen.mkAttributedCast(tree, pt)
- }
-
- /** Adapt `tree` to expected type `pt`.
- *
- * @param tree the given tree
- * @param pt the expected type
- * @return the adapted tree
- */
- private def adaptToType(tree: Tree, pt: Type): Tree = {
- if (settings.debug && pt != WildcardType)
- log("adapting " + tree + ":" + tree.tpe + " : " + tree.tpe.parents + " to " + pt)//debug
- if (tree.tpe <:< pt)
- tree
- else if (isDifferentErasedValueType(tree.tpe, pt))
- adaptToType(box(tree, pt.toString), pt)
- else if (isDifferentErasedValueType(pt, tree.tpe))
- adaptToType(unbox(tree, pt), pt)
- else if (isPrimitiveValueType(tree.tpe) && !isPrimitiveValueType(pt)) {
- adaptToType(box(tree, pt.toString), pt)
- } else if (isMethodTypeWithEmptyParams(tree.tpe)) {
- // [H] this assert fails when trying to typecheck tree !(SomeClass.this.bitmap) for single lazy val
- //assert(tree.symbol.isStable, "adapt "+tree+":"+tree.tpe+" to "+pt)
- adaptToType(Apply(tree, List()) setPos tree.pos setType tree.tpe.resultType, pt)
-// } else if (pt <:< tree.tpe)
-// cast(tree, pt)
- } else if (isPrimitiveValueType(pt) && !isPrimitiveValueType(tree.tpe))
- adaptToType(unbox(tree, pt), pt)
- else
- cast(tree, pt)
- }
+ class Eraser(_context: Context) extends Typer(_context) with TypeAdapter {
+ val typer = this.asInstanceOf[analyzer.Typer]
/** Replace member references as follows:
*
@@ -834,11 +681,6 @@ abstract class Erasure extends AddInterfaces
tree1
}
}
-
- private def isMethodTypeWithEmptyParams(tpe: Type) = tpe match {
- case MethodType(Nil, _) => true
- case _ => false
- }
}
/** The erasure transformer */