diff options
author | James Iry <james.iry@typesafe.com> | 2013-07-30 11:22:55 -0700 |
---|---|---|
committer | James Iry <james.iry@typesafe.com> | 2013-11-06 12:28:19 -0800 |
commit | 510b8cecc4951ff8092cfa931c2dc3717e21dded (patch) | |
tree | ce63f3c54e58f927de9e6d6df1ecc6967f012bb9 /src/compiler/scala/tools/nsc/transform/Erasure.scala | |
parent | 10a061d425857c9e7bf4fa9aba9923b90467e24e (diff) | |
download | scala-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.scala | 170 |
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 */ |