diff options
author | Martin Odersky <odersky@gmail.com> | 2012-02-14 18:37:56 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2012-02-14 18:37:56 +0100 |
commit | ea96b48d9274e90b64b66e51507460c004c01643 (patch) | |
tree | 0ee4f7f9f1283c6fa1b510a16e8942ef74e1e08d | |
parent | 5bbc2d089f0f440612d6219479ea8e5cea0f01a4 (diff) | |
download | scala-ea96b48d9274e90b64b66e51507460c004c01643.tar.gz scala-ea96b48d9274e90b64b66e51507460c004c01643.tar.bz2 scala-ea96b48d9274e90b64b66e51507460c004c01643.zip |
Changed erasure behavior of arrays to use always boxed representation.
Conflicts:
test/files/run/Meter.scala
-rw-r--r-- | src/compiler/scala/reflect/internal/transform/Erasure.scala | 98 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Erasure.scala | 2 | ||||
-rwxr-xr-x | src/library/scala/reflect/api/Types.scala | 2 | ||||
-rw-r--r-- | test/files/run/Meter.scala | 41 |
4 files changed, 95 insertions, 48 deletions
diff --git a/src/compiler/scala/reflect/internal/transform/Erasure.scala b/src/compiler/scala/reflect/internal/transform/Erasure.scala index 2be7ec3190..bd6a77fb07 100644 --- a/src/compiler/scala/reflect/internal/transform/Erasure.scala +++ b/src/compiler/scala/reflect/internal/transform/Erasure.scala @@ -71,50 +71,56 @@ trait Erasure { 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 { - case ConstantType(_) => - tp - case st: SubType => - apply(st.supertype) - case TypeRef(pre, sym, args) => - if (sym == ArrayClass) - if (unboundedGenericArrayLevel(tp) == 1) ObjectClass.tpe - else if (args.head.typeSymbol.isBottomClass) ObjectArray - else typeRef(apply(pre), sym, args map this) - else if (sym == AnyClass || sym == AnyValClass || sym == SingletonClass || sym == NotNullClass) erasedTypeRef(ObjectClass) - else if (sym == UnitClass) erasedTypeRef(BoxedUnitClass) - else if (sym.isRefinementClass) apply(mergeParents(tp.parents)) - else if (sym.isInlineClass) eraseInlineClassRef(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) - case ExistentialType(tparams, restpe) => - apply(restpe) - case mt @ MethodType(params, restpe) => - MethodType( - cloneSymbolsAndModify(params, ErasureMap.this), - if (restpe.typeSymbol == UnitClass) erasedTypeRef(UnitClass) - // this replaces each typeref that refers to an argument - // by the type `p.tpe` of the actual argument p (p in params) - else apply(mt.resultType(params map (_.tpe)))) - case RefinedType(parents, decls) => - apply(mergeParents(parents)) - case AnnotatedType(_, atp, _) => - apply(atp) - case ClassInfoType(parents, decls, clazz) => - ClassInfoType( - if (clazz == ObjectClass || isPrimitiveValueClass(clazz)) Nil - else if (clazz == ArrayClass) List(erasedTypeRef(ObjectClass)) - else removeLaterObjects(parents map this), - decls, clazz) - case _ => - mapOver(tp) - } + def apply(tp: Type): Type = tp match { + case ConstantType(_) => + tp + case st: SubType => + apply(st.supertype) + case TypeRef(pre, sym, args) => + if (sym == ArrayClass) + if (unboundedGenericArrayLevel(tp) == 1) ObjectClass.tpe + else if (args.head.typeSymbol.isBottomClass) ObjectArray + else typeRef(apply(pre), sym, args map applyInArray) + else if (sym == AnyClass || sym == AnyValClass || sym == SingletonClass || sym == NotNullClass) erasedTypeRef(ObjectClass) + 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 apply(sym.info) // alias type or abstract type + case PolyType(tparams, restpe) => + apply(restpe) + case ExistentialType(tparams, restpe) => + apply(restpe) + case mt @ MethodType(params, restpe) => + MethodType( + cloneSymbolsAndModify(params, ErasureMap.this), + if (restpe.typeSymbol == UnitClass) erasedTypeRef(UnitClass) + // this replaces each typeref that refers to an argument + // by the type `p.tpe` of the actual argument p (p in params) + else apply(mt.resultType(params map (_.tpe)))) + case RefinedType(parents, decls) => + apply(mergeParents(parents)) + case AnnotatedType(_, atp, _) => + apply(atp) + case ClassInfoType(parents, decls, clazz) => + ClassInfoType( + if (clazz == ObjectClass || isPrimitiveValueClass(clazz)) Nil + else if (clazz == ArrayClass) List(erasedTypeRef(ObjectClass)) + else removeLaterObjects(parents map this), + decls, clazz) + case _ => + mapOver(tp) + } + + private def applyInArray(tp: Type): Type = tp match { + case TypeRef(pre, sym, args) if (sym.isInlineClass) => eraseNormalClassRef(pre, sym) + case _ => apply(tp) } } @@ -159,7 +165,7 @@ trait Erasure { } 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. @@ -172,7 +178,7 @@ trait Erasure { else if (sym.isValue && sym.owner.isMethodWithExtension) specialErasureAvoiding(sym.owner.owner, tp) else - specialErasure(tp) + specialErasure(tp) /** Scala's more precise erasure than java's is problematic as follows: * @@ -193,9 +199,9 @@ trait Erasure { def mergeParents(parents: List[Type]): Type = intersectionDominator(parents) } - + 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. @@ -203,7 +209,7 @@ trait Erasure { 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) => diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 30448b6eaa..5e481f570d 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -1063,7 +1063,7 @@ abstract class Erasure extends AddInterfaces case Literal(ct) if ct.tag == ClassTag && ct.typeValue.typeSymbol != definitions.UnitClass => val erased = ct.typeValue match { - case TypeRef(pre, clazz, args) if clazz.isInlineClass => typeRef(pre, clazz, List()) + case TypeRef(pre, clazz, args) if clazz.isInlineClass => scalaErasure.eraseNormalClassRef(pre, clazz) case tpe => specialErasure(NoSymbol, tpe) } treeCopy.Literal(tree, Constant(erased)) diff --git a/src/library/scala/reflect/api/Types.scala b/src/library/scala/reflect/api/Types.scala index 8a91956320..09ee90355e 100755 --- a/src/library/scala/reflect/api/Types.scala +++ b/src/library/scala/reflect/api/Types.scala @@ -46,7 +46,7 @@ trait Types { self: Universe => /** Substitute types in `to` for corresponding occurrences of references to * symbols `from` in this type. */ - def substituteTypes(from: List[Symbol], to: List[Type]): Type // !!! Too many things with names like "subst" + def substituteTypes(from: List[Symbol], to: List[Type]): Type /** If this is a parameterized types, the type arguments. * Otherwise the empty list diff --git a/test/files/run/Meter.scala b/test/files/run/Meter.scala index 0db917aeee..66d35bfc75 100644 --- a/test/files/run/Meter.scala +++ b/test/files/run/Meter.scala @@ -6,6 +6,28 @@ class Meter(val underlying: Double) extends AnyVal with Printable { def < (other: Meter): Boolean = this.underlying < other.underlying override def toString: String = underlying.toString+"m" } +object Meter extends (Double => Meter) { + + def apply(x: Double): Meter = new Meter(x) + + class FlatArray(underlying: Array[Double]) { + def length = underlying.length + def apply(i: Int): Meter = new Meter(underlying(i)) + def update(i: Int, m: Meter) = underlying(i) = m.underlying + override def toString = underlying.toList map Meter mkString ("Meter.FlatArray(", ", ", ")") + } + + object FlatArray { + + def apply(xs: Meter*) = { + val elems = Array.ofDim[Double](xs.length) + for (i <- 0 until xs.length) + elems(i) = xs(i).asInstanceOf[Double] + new FlatArray(elems) + } + } + +} trait Printable extends Any { def print: Unit = Console.print(this) } object Test extends App { @@ -37,5 +59,24 @@ 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) + } + + 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) + } |