summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2012-02-15 12:04:36 +0100
committerMartin Odersky <odersky@gmail.com>2012-02-15 12:04:36 +0100
commitcd6426a8c501eda2105196fc5a254d8f0dd77633 (patch)
tree19f5640aa4aacc3ea34c48ae4882f6170258b93c
parentea96b48d9274e90b64b66e51507460c004c01643 (diff)
downloadscala-cd6426a8c501eda2105196fc5a254d8f0dd77633.tar.gz
scala-cd6426a8c501eda2105196fc5a254d8f0dd77633.tar.bz2
scala-cd6426a8c501eda2105196fc5a254d8f0dd77633.zip
Changed array erasure scheme to never unbox elements of inline classes.
-rw-r--r--src/compiler/scala/reflect/internal/transform/Erasure.scala100
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala6
-rw-r--r--src/compiler/scala/tools/nsc/transform/AddInterfaces.scala14
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala21
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala3
-rw-r--r--test/files/run/Meter.scala34
6 files changed, 90 insertions, 88 deletions
diff --git a/src/compiler/scala/reflect/internal/transform/Erasure.scala b/src/compiler/scala/reflect/internal/transform/Erasure.scala
index bd6a77fb07..2cf171aad3 100644
--- a/src/compiler/scala/reflect/internal/transform/Erasure.scala
+++ b/src/compiler/scala/reflect/internal/transform/Erasure.scala
@@ -118,7 +118,7 @@ trait Erasure {
mapOver(tp)
}
- private def applyInArray(tp: Type): Type = tp match {
+ def applyInArray(tp: Type): Type = tp match {
case TypeRef(pre, sym, args) if (sym.isInlineClass) => eraseNormalClassRef(pre, sym)
case _ => apply(tp)
}
@@ -153,32 +153,42 @@ trait Erasure {
* parents |Ps|, but with duplicate references of Object removed.
* - for all other types, the type itself (with any sub-components erased)
*/
- def erasure(sym: Symbol, tp: Type): Type = {
- if (sym != NoSymbol && sym.enclClass.isJavaDefined) {
- val res = javaErasure(tp)
- if (verifyJavaErasure && sym.isMethod) {
- val old = scalaErasure(tp)
- if (!(res =:= old))
- log("Identified divergence between java/scala erasure:\n scala: " + old + "\n java: " + res)
- }
- res
- } else
- scalaErasure(tp)
- }
+ def erasure(sym: Symbol): ErasureMap =
+ if (sym == NoSymbol || !sym.enclClass.isJavaDefined) scalaErasure
+ else if (verifyJavaErasure && sym.isMethod) verifiedJavaErasure
+ else javaErasure
/** 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 =
+ def specialErasure(sym: Symbol)(tp: Type): Type =
if (sym != NoSymbol && sym.enclClass.isJavaDefined)
- erasure(sym, tp)
+ 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)
+ specialScalaErasure(tp)
+
+ def specialErasureAvoiding(clazz: Symbol, tpe: Type): Type = {
+ tpe match {
+ case PolyType(tparams, restpe) =>
+ specialErasureAvoiding(clazz, restpe)
+ case ExistentialType(tparams, restpe) =>
+ specialErasureAvoiding(clazz, restpe)
+ case mt @ MethodType(params, restpe) =>
+ MethodType(
+ cloneSymbolsAndModify(params, specialErasureAvoiding(clazz, _)),
+ if (restpe.typeSymbol == UnitClass) erasedTypeRef(UnitClass)
+ else specialErasureAvoiding(clazz, (mt.resultType(params map (_.tpe)))))
+ case TypeRef(pre, `clazz`, args) =>
+ typeRef(pre, clazz, List())
+ case _ =>
+ specialScalaErasure(tpe)
+ }
+ }
/** Scala's more precise erasure than java's is problematic as follows:
*
@@ -200,31 +210,34 @@ trait Erasure {
intersectionDominator(parents)
}
+ class JavaErasureMap extends ErasureMap {
+ /** In java, always take the first parent.
+ * An intersection such as `Object with Trait` erases to Object.
+ */
+ def mergeParents(parents: List[Type]): Type =
+ if (parents.isEmpty) ObjectClass.tpe
+ else parents.head
+ }
+
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 {
+ object specialScalaErasure extends ScalaErasureMap {
override def eraseInlineClassRef(clazz: Symbol): Type = ErasedInlineType(clazz)
}
- def specialErasureAvoiding(clazz: Symbol, tpe: Type): Type = {
- tpe match {
- case PolyType(tparams, restpe) =>
- specialErasureAvoiding(clazz, restpe)
- case ExistentialType(tparams, restpe) =>
- specialErasureAvoiding(clazz, restpe)
- case mt @ MethodType(params, restpe) =>
- MethodType(
- cloneSymbolsAndModify(params, specialErasureAvoiding(clazz, _)),
- if (restpe.typeSymbol == UnitClass) erasedTypeRef(UnitClass)
- else specialErasureAvoiding(clazz, (mt.resultType(params map (_.tpe)))))
- case TypeRef(pre, `clazz`, args) =>
- typeRef(pre, clazz, List())
- case _ =>
- specialErasure(tpe)
+ object javaErasure extends JavaErasureMap
+
+ object verifiedJavaErasure extends JavaErasureMap {
+ override def apply(tp: Type): Type = {
+ val res = javaErasure(tp)
+ val old = scalaErasure(tp)
+ if (!(res =:= old))
+ log("Identified divergence between java/scala erasure:\n scala: " + old + "\n java: " + res)
+ res
}
}
@@ -263,18 +276,9 @@ trait Erasure {
}
}
- object javaErasure extends ErasureMap {
- /** In java, always take the first parent.
- * An intersection such as `Object with Trait` erases to Object.
- */
- def mergeParents(parents: List[Type]): Type =
- if (parents.isEmpty) ObjectClass.tpe
- else parents.head
- }
-
/** Type reference after erasure */
def erasedTypeRef(sym: Symbol): Type =
- typeRef(erasure(sym, sym.owner.tpe), sym, Nil)
+ typeRef(erasure(sym)(sym.owner.tpe), sym, Nil)
/** The symbol's erased info. This is the type's erasure, except for the following symbols:
*
@@ -288,25 +292,25 @@ trait Erasure {
if (sym == Object_asInstanceOf)
sym.info
else if (sym == Object_isInstanceOf || sym == ArrayClass)
- PolyType(sym.info.typeParams, specialErasure(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, specialErasure(sym, _)),
- typeRef(specialErasure(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(specialErasure(sym, index.tpe)), tvar),
+ MethodType(List(index.cloneSymbol.setInfo(specialErasure(sym)(index.tpe)), tvar),
erasedTypeRef(UnitClass))
}
- else specialErasure(sym, tp)
+ else specialErasure(sym)(tp)
} else if (
sym.owner != NoSymbol &&
sym.owner.owner == ArrayClass &&
@@ -316,7 +320,7 @@ trait Erasure {
// symbol here
tp
} else {
- specialErasure(sym, tp)
+ specialErasure(sym)(tp)
}
}
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
index b5232fff09..cc38979487 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -154,7 +154,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
if (settings.Ygenjavap.isDefault) {
if(settings.Ydumpclasses.isDefault)
new ClassBytecodeWriter { }
- else
+ else
new ClassBytecodeWriter with DumpBytecodeWriter { }
}
else new ClassBytecodeWriter with JavapBytecodeWriter { }
@@ -209,7 +209,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
val BeanInfoSkipAttr = definitions.getRequiredClass("scala.beans.BeanInfoSkip")
val BeanDisplayNameAttr = definitions.getRequiredClass("scala.beans.BeanDisplayName")
val BeanDescriptionAttr = definitions.getRequiredClass("scala.beans.BeanDescription")
-
+
final val ExcludedForwarderFlags = {
import Flags._
( CASE | SPECIALIZED | LIFTED | PROTECTED | STATIC | BridgeAndPrivateFlags )
@@ -702,7 +702,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
if ((settings.check.value contains "genjvm")) {
val normalizedTpe = atPhase(currentRun.erasurePhase)(erasure.prepareSigMap(memberTpe))
val bytecodeTpe = owner.thisType.memberInfo(sym)
- if (!sym.isType && !sym.isConstructor && !(erasure.erasure(sym, normalizedTpe) =:= bytecodeTpe)) {
+ if (!sym.isType && !sym.isConstructor && !(erasure.erasure(sym)(normalizedTpe) =:= bytecodeTpe)) {
clasz.cunit.warning(sym.pos,
"""|compiler bug: created generic signature for %s in %s that does not conform to its erasure
|signature: %s
diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
index 531a475bc6..cab440ef52 100644
--- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
+++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
@@ -11,7 +11,7 @@ import Flags._
import scala.collection.{ mutable, immutable }
import collection.mutable.ListBuffer
-abstract class AddInterfaces extends InfoTransform {
+abstract class AddInterfaces extends InfoTransform { self: Erasure =>
import global._ // the global environment
import definitions._ // standard classes and methods
@@ -21,14 +21,6 @@ abstract class AddInterfaces extends InfoTransform {
*/
override def phaseNewFlags: Long = lateDEFERRED | lateINTERFACE
- /** Type reference after erasure; defined in Erasure.
- */
- def erasedTypeRef(sym: Symbol): Type
-
- /** Erasure calculation; defined in Erasure.
- */
- def erasure(sym: Symbol, tpe: Type): Type
-
/** A lazily constructed map that associates every non-interface trait with
* its implementation class.
*/
@@ -175,14 +167,14 @@ abstract class AddInterfaces extends InfoTransform {
/** If `tp` refers to a non-interface trait, return a
* reference to its implementation class. Otherwise return `tp`.
*/
- def mixinToImplClass(tp: Type): Type = erasure(sym,
+ def mixinToImplClass(tp: Type): Type = erasure(sym) {
tp match { //@MATN: no normalize needed (comes after erasure)
case TypeRef(pre, sym, _) if sym.needsImplClass =>
typeRef(pre, implClass(sym), Nil)
case _ =>
tp
}
- )
+ }
def implType(tp: Type): Type = tp match {
case ClassInfoType(parents, decls, _) =>
assert(phase == implClassPhase, tp)
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index 5e481f570d..306e00e38d 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -290,7 +290,7 @@ abstract class Erasure extends AddInterfaces
)
)
}
- else jsig(erasure(sym0, tp), existentiallyBound, toplevel, primitiveOK)
+ else jsig(erasure(sym0)(tp), existentiallyBound, toplevel, primitiveOK)
case PolyType(tparams, restpe) =>
assert(tparams.nonEmpty)
val poly = if (toplevel) polyParamSig(tparams) else ""
@@ -310,7 +310,7 @@ abstract class Erasure extends AddInterfaces
println("something's wrong: "+sym0+":"+sym0.tpe+" has a bounded wildcard type")
jsig(bounds.hi, existentiallyBound, toplevel, primitiveOK)
case _ =>
- val etp = erasure(sym0, tp)
+ val etp = erasure(sym0)(tp)
if (etp eq tp) throw new UnknownSig
else jsig(etp)
}
@@ -793,7 +793,7 @@ abstract class Erasure extends AddInterfaces
val other = opc.overridden
//println("bridge? " + member + ":" + member.tpe + member.locationString + " to " + other + ":" + other.tpe + other.locationString)//DEBUG
if (atPhase(currentRun.explicitouterPhase)(!member.isDeferred)) {
- val otpe = erasure(owner, other.tpe)
+ val otpe = erasure(owner)(other.tpe)
val bridgeNeeded = atPhase(phase.next) (
!(other.tpe =:= member.tpe) &&
!(deconstMap(other.tpe) =:= deconstMap(member.tpe)) &&
@@ -838,7 +838,7 @@ abstract class Erasure extends AddInterfaces
IF (typeTest) THEN bridgingCall ELSE REF(NoneModule)
} else bridgingCall
});
- debuglog("generating bridge from " + other + "(" + Flags.flagsToString(bridge.flags) + ")" + ":" + otpe + other.locationString + " to " + member + ":" + erasure(owner, member.tpe) + member.locationString + " =\n " + bridgeDef);
+ debuglog("generating bridge from " + other + "(" + Flags.flagsToString(bridge.flags) + ")" + ":" + otpe + other.locationString + " to " + member + ":" + erasure(owner)(member.tpe) + member.locationString + " =\n " + bridgeDef);
bridgeDef
}
} :: bridges
@@ -910,7 +910,7 @@ abstract class Erasure extends AddInterfaces
gen.mkMethodCall(
qual1(),
fun.symbol,
- List(specialErasure(fun.symbol, arg.tpe)),
+ List(specialErasure(fun.symbol)(arg.tpe)),
Nil
),
isArrayTest(qual1())
@@ -943,7 +943,7 @@ abstract class Erasure extends AddInterfaces
// need to do the cast in adaptMember
treeCopy.Apply(
tree,
- SelectFromArray(qual, name, erasure(tree.symbol, qual.tpe)).copyAttrs(fn),
+ SelectFromArray(qual, name, erasure(tree.symbol)(qual.tpe)).copyAttrs(fn),
args)
}
case Apply(fn @ Select(qual, _), Nil) if interceptedMethods(fn.symbol) =>
@@ -1064,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 => scalaErasure.eraseNormalClassRef(pre, clazz)
- case tpe => specialErasure(NoSymbol, tpe)
+ case tpe => specialScalaErasure(tpe)
}
treeCopy.Literal(tree, Constant(erased))
@@ -1084,10 +1084,13 @@ abstract class Erasure extends AddInterfaces
val tree1 = preErase(tree)
tree1 match {
case EmptyTree | TypeTree() =>
- tree1 setType specialErasure(NoSymbol, tree1.tpe)
+ tree1 setType specialScalaErasure(tree1.tpe)
+ case ArrayValue(elemtpt, trees) =>
+ treeCopy.ArrayValue(
+ tree1, elemtpt setType specialScalaErasure.applyInArray(elemtpt.tpe), trees map transform) setType null
case DefDef(_, _, _, _, tpt, _) =>
val result = super.transform(tree1) setType null
- tpt.tpe = specialErasure(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/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 064a3dd229..91ea7c7cd9 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -515,7 +515,8 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
!other.isDeferred && other.isJavaDefined && {
// #3622: erasure operates on uncurried types --
// note on passing sym in both cases: only sym.isType is relevant for uncurry.transformInfo
- def uncurryAndErase(tp: Type) = erasure.erasure(sym, uncurry.transformInfo(sym, tp))
+ // !!! erasure.erasure(sym, uncurry.transformInfo(sym, tp)) gives erreneous of inaccessible type - check whether that's still the case!
+ def uncurryAndErase(tp: Type) = erasure.erasure(sym)(uncurry.transformInfo(sym, tp))
val tp1 = uncurryAndErase(clazz.thisType.memberType(sym))
val tp2 = uncurryAndErase(clazz.thisType.memberType(other))
atPhase(currentRun.erasurePhase.next)(tp1 matches tp2)
diff --git a/test/files/run/Meter.scala b/test/files/run/Meter.scala
index 66d35bfc75..da99f81722 100644
--- a/test/files/run/Meter.scala
+++ b/test/files/run/Meter.scala
@@ -59,24 +59,26 @@ object Test extends App {
val b: Any = y
println("a == b: "+(a == b))
- {
- val arr = Array(x, y + x)
- println(arr.deep)
- def foo[T <: Printable](x: Array[T]) {
- for (i <- 0 until x.length) { x(i).print; println(" "+x(i)) }
- }
- val m = arr(0)
- println(m)
- foo(arr)
+ { println("testing native arrays")
+ val arr = Array(x, y + x)
+ println(arr.deep)
+ def foo[T <: Printable](x: Array[T]) {
+ for (i <- 0 until x.length) { x(i).print; println(" "+x(i)) }
+ }
+ val m = arr(0)
+ println(m)
+ foo(arr)
}
- val arr = Meter.FlatArray(x, y + x)
- println(arr)
- def foo(x: Meter.FlatArray) {
- for (i <- 0 until x.length) { x(i).print; println(" "+x(i)) }
+ { println("testing wrapped arrays")
+ val arr = Meter.FlatArray(x, y + x)
+ println(arr)
+ def foo(x: Meter.FlatArray) {
+ for (i <- 0 until x.length) { x(i).print; println(" "+x(i)) }
+ }
+ val m = arr(0)
+ println(m)
+ foo(arr)
}
- val m = arr(0)
- println(m)
- foo(arr)
}