summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2012-02-13 17:18:49 +0100
committerMartin Odersky <odersky@gmail.com>2012-02-14 18:34:42 +0100
commit5bbc2d089f0f440612d6219479ea8e5cea0f01a4 (patch)
treeee5ff64cc9305f57441106c24a9f2828d1690b2c
parentee560229d1be78294b17ba4b0b6f36e8dd68d376 (diff)
downloadscala-5bbc2d089f0f440612d6219479ea8e5cea0f01a4.tar.gz
scala-5bbc2d089f0f440612d6219479ea8e5cea0f01a4.tar.bz2
scala-5bbc2d089f0f440612d6219479ea8e5cea0f01a4.zip
Refactoring to control the effects of inline erasure, restricting them to just the erasure phase and its actions.
-rw-r--r--src/compiler/scala/reflect/internal/transform/Erasure.scala73
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala13
-rw-r--r--src/compiler/scala/tools/nsc/transform/PostErasure.scala2
3 files changed, 51 insertions, 37 deletions
diff --git a/src/compiler/scala/reflect/internal/transform/Erasure.scala b/src/compiler/scala/reflect/internal/transform/Erasure.scala
index f8dfd66fbe..2be7ec3190 100644
--- a/src/compiler/scala/reflect/internal/transform/Erasure.scala
+++ b/src/compiler/scala/reflect/internal/transform/Erasure.scala
@@ -65,17 +65,14 @@ trait Erasure {
if (cls.owner.isClass) cls.owner.tpe else pre // why not cls.isNestedClass?
}
- def valueClassErasure(clazz: Symbol): Type =
- clazz.primaryConstructor.info.params.head.tpe
-
- protected def eraseInlineClassRef(clazz: Symbol): Type =
- scalaErasure(valueClassErasure(clazz))
+ def underlyingOfValueClass(clazz: Symbol): Type =
+ clazz.firstParamAccessor.tpe.resultType
abstract class ErasureMap extends TypeMap {
def mergeParents(parents: List[Type]): Type
- def eraseNormalClassRef(pre: Type, clazz: Symbol): Type =
- typeRef(apply(rebindInnerClass(pre, clazz)), clazz, List()) // #2585
+ protected def eraseInlineClassRef(clazz: Symbol): Type =
+ scalaErasure(underlyingOfValueClass(clazz))
def apply(tp: Type): Type = {
tp match {
@@ -92,7 +89,7 @@ trait Erasure {
else if (sym == UnitClass) erasedTypeRef(BoxedUnitClass)
else if (sym.isRefinementClass) apply(mergeParents(tp.parents))
else if (sym.isInlineClass) eraseInlineClassRef(sym)
- else if (sym.isClass) eraseNormalClassRef(pre, sym)
+ else if (sym.isClass) typeRef(apply(rebindInnerClass(pre, sym)), sym, List()) // #2585
else apply(sym.info) // alias type or abstract type
case PolyType(tparams, restpe) =>
apply(restpe)
@@ -159,13 +156,23 @@ trait Erasure {
log("Identified divergence between java/scala erasure:\n scala: " + old + "\n java: " + res)
}
res
- } else if (sym.isTerm && sym.owner.isInlineClass)
- scalaErasureAvoiding(sym.owner, tp)
- else if (sym.isValue && sym.owner.isMethodWithExtension)
- scalaErasureAvoiding(sym.owner.owner, tp)
- else
+ } else
scalaErasure(tp)
}
+
+ /** This is used as the Scala erasure during the erasure phase itself
+ * It differs from normal erasure in that value classes are erased to ErasedInlineTypes which
+ * are then later converted to the underlying parameter type in phase posterasure.
+ */
+ def specialErasure(sym: Symbol, tp: Type): Type =
+ if (sym != NoSymbol && sym.enclClass.isJavaDefined)
+ erasure(sym, tp)
+ else if (sym.isTerm && sym.owner.isInlineClass)
+ specialErasureAvoiding(sym.owner, tp)
+ else if (sym.isValue && sym.owner.isMethodWithExtension)
+ specialErasureAvoiding(sym.owner.owner, tp)
+ else
+ specialErasure(tp)
/** Scala's more precise erasure than java's is problematic as follows:
*
@@ -179,29 +186,39 @@ trait Erasure {
* For this reason and others (such as distinguishing constructors from other methods)
* erasure is now (Symbol, Type) => Type rather than Type => Type.
*/
- object scalaErasure extends ErasureMap {
+ class ScalaErasureMap extends ErasureMap {
/** In scala, calculate a useful parent.
* An intersection such as `Object with Trait` erases to Trait.
*/
def mergeParents(parents: List[Type]): Type =
intersectionDominator(parents)
}
-
- def scalaErasureAvoiding(clazz: Symbol, tpe: Type): Type = {
+
+ object scalaErasure extends ScalaErasureMap
+
+ /** This is used as the Scala erasure during the erasure phase itself
+ * It differs from normal erasure in that value classes are erased to ErasedInlineTypes which
+ * are then later converted to the underlying parameter type in phase posterasure.
+ */
+ object specialErasure extends ScalaErasureMap {
+ override def eraseInlineClassRef(clazz: Symbol): Type = ErasedInlineType(clazz)
+ }
+
+ def specialErasureAvoiding(clazz: Symbol, tpe: Type): Type = {
tpe match {
case PolyType(tparams, restpe) =>
- scalaErasureAvoiding(clazz, restpe)
+ specialErasureAvoiding(clazz, restpe)
case ExistentialType(tparams, restpe) =>
- scalaErasureAvoiding(clazz, restpe)
+ specialErasureAvoiding(clazz, restpe)
case mt @ MethodType(params, restpe) =>
MethodType(
- cloneSymbolsAndModify(params, scalaErasureAvoiding(clazz, _)),
+ cloneSymbolsAndModify(params, specialErasureAvoiding(clazz, _)),
if (restpe.typeSymbol == UnitClass) erasedTypeRef(UnitClass)
- else scalaErasureAvoiding(clazz, (mt.resultType(params map (_.tpe)))))
+ else specialErasureAvoiding(clazz, (mt.resultType(params map (_.tpe)))))
case TypeRef(pre, `clazz`, args) =>
- scalaErasure.eraseNormalClassRef(pre, clazz)
+ typeRef(pre, clazz, List())
case _ =>
- scalaErasure(tpe)
+ specialErasure(tpe)
}
}
@@ -265,25 +282,25 @@ trait Erasure {
if (sym == Object_asInstanceOf)
sym.info
else if (sym == Object_isInstanceOf || sym == ArrayClass)
- PolyType(sym.info.typeParams, erasure(sym, sym.info.resultType))
+ PolyType(sym.info.typeParams, specialErasure(sym, sym.info.resultType))
else if (sym.isAbstractType)
TypeBounds(WildcardType, WildcardType)
else if (sym.isTerm && sym.owner == ArrayClass) {
if (sym.isClassConstructor)
tp match {
case MethodType(params, TypeRef(pre, sym1, args)) =>
- MethodType(cloneSymbolsAndModify(params, erasure(sym, _)),
- typeRef(erasure(sym, pre), sym1, args))
+ MethodType(cloneSymbolsAndModify(params, specialErasure(sym, _)),
+ typeRef(specialErasure(sym, pre), sym1, args))
}
else if (sym.name == nme.apply)
tp
else if (sym.name == nme.update)
(tp: @unchecked) match {
case MethodType(List(index, tvar), restpe) =>
- MethodType(List(index.cloneSymbol.setInfo(erasure(sym, index.tpe)), tvar),
+ MethodType(List(index.cloneSymbol.setInfo(specialErasure(sym, index.tpe)), tvar),
erasedTypeRef(UnitClass))
}
- else erasure(sym, tp)
+ else specialErasure(sym, tp)
} else if (
sym.owner != NoSymbol &&
sym.owner.owner == ArrayClass &&
@@ -293,7 +310,7 @@ trait Erasure {
// symbol here
tp
} else {
- erasure(sym, tp)
+ specialErasure(sym, tp)
}
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index 7eb819f058..30448b6eaa 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -335,9 +335,6 @@ abstract class Erasure extends AddInterfaces
class UnknownSig extends Exception
- override def eraseInlineClassRef(clazz: Symbol): Type = ErasedInlineType(clazz)
-
-
/** The symbol's erased info. This is the type's erasure, except for the following symbols:
*
* - For $asInstanceOf : [T]T
@@ -439,7 +436,7 @@ abstract class Erasure extends AddInterfaces
case Unboxed(arg) if arg.tpe.typeSymbol == clazz =>
log("shortcircuiting unbox -> box "+arg); arg
case _ =>
- New(clazz, cast(tree, valueClassErasure(clazz)))
+ New(clazz, cast(tree, underlyingOfValueClass(clazz)))
}
case _ =>
tree.tpe.typeSymbol match {
@@ -913,7 +910,7 @@ abstract class Erasure extends AddInterfaces
gen.mkMethodCall(
qual1(),
fun.symbol,
- List(erasure(fun.symbol, arg.tpe)),
+ List(specialErasure(fun.symbol, arg.tpe)),
Nil
),
isArrayTest(qual1())
@@ -1067,7 +1064,7 @@ abstract class Erasure extends AddInterfaces
&& ct.typeValue.typeSymbol != definitions.UnitClass =>
val erased = ct.typeValue match {
case TypeRef(pre, clazz, args) if clazz.isInlineClass => typeRef(pre, clazz, List())
- case tpe => erasure(NoSymbol, tpe)
+ case tpe => specialErasure(NoSymbol, tpe)
}
treeCopy.Literal(tree, Constant(erased))
@@ -1087,10 +1084,10 @@ abstract class Erasure extends AddInterfaces
val tree1 = preErase(tree)
tree1 match {
case EmptyTree | TypeTree() =>
- tree1 setType erasure(NoSymbol, tree1.tpe)
+ tree1 setType specialErasure(NoSymbol, tree1.tpe)
case DefDef(_, _, _, _, tpt, _) =>
val result = super.transform(tree1) setType null
- tpt.tpe = erasure(tree1.symbol, tree1.symbol.tpe).resultType
+ tpt.tpe = specialErasure(tree1.symbol, tree1.symbol.tpe).resultType
result
case _ =>
super.transform(tree1) setType null
diff --git a/src/compiler/scala/tools/nsc/transform/PostErasure.scala b/src/compiler/scala/tools/nsc/transform/PostErasure.scala
index 1efa9ef3d5..af8de11504 100644
--- a/src/compiler/scala/tools/nsc/transform/PostErasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/PostErasure.scala
@@ -14,7 +14,7 @@ trait PostErasure extends InfoTransform with TypingTransformers {
object elimErasedInline extends TypeMap {
def apply(tp: Type) = tp match {
- case ErasedInlineType(clazz) => erasure.valueClassErasure(clazz)
+ case ErasedInlineType(clazz) => erasure.underlyingOfValueClass(clazz)
case _ => mapOver(tp)
}
}