Skip to content

Commit b1fa658

Browse files
committed
Wrap SeqLiteral of value classes using custom wrapper instead of wrapRefArray
wrapRefArray is defined as: def wrapRefArray[T <: AnyRef](xs: Array[T]): WrappedArray[T] After erasure this becomes: def wrapRefArray(xs: Object[]): WrappedArray This is fine for value classes as long as arrays are boxed, but once we change the representation this will result in ClassCastException. Therefore we introduce a wrapper just for value classes: def wrapVCArray[T <: AnyVal](xs: Array[T]): WrappedArray[T] Which is erased to: def wrapVCArray(xs: Object): WrappedArray Which lets us represent arrays of value classes using any reference type.
1 parent bb1d746 commit b1fa658

File tree

2 files changed

+29
-9
lines changed

2 files changed

+29
-9
lines changed

src/dotty/DottyPredef.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package dotty
22

3+
import scala.collection.mutable.WrappedArray
34
import scala.reflect.ClassTag
45
import scala.reflect.runtime.universe.TypeTag
6+
import scala.runtime.ScalaRunTime.arrayElementClass
57
import scala.Predef.??? // this is currently ineffective, because of #530
68

79
abstract class I1 {
@@ -34,4 +36,15 @@ object DottyPredef extends I6 {
3436

3537
/** ClassTags for final classes */
3638
implicit val NothingClassTag: ClassTag[Nothing] = ClassTag.Nothing
39+
40+
// This implicit will never be used for arrays of primitives because
41+
// the wrap*Array in scala.Predef have a higher priority.
42+
implicit def wrapVCArray[T <: AnyVal](xs: Array[T]): WrappedArray[T] =
43+
new WrappedArray[T] {
44+
val array = xs
45+
lazy val elemTag = ClassTag[T](arrayElementClass(array.getClass))
46+
def length: Int = array.length
47+
def apply(index: Int): T = array(index)
48+
def update(index: Int, elem: T) { array(index) = elem }
49+
}
3750
}

src/dotty/tools/dotc/transform/SeqLiterals.scala

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import dotty.tools.dotc.transform.TreeTransforms._
77
import Contexts.Context
88
import Symbols._
99
import Phases._
10-
import Decorators._
10+
import Decorators._, ValueClasses._
1111

1212
/** A transformer that eliminates SeqLiteral's, transforming `SeqLiteral(elems)` to an operation
1313
* equivalent to
@@ -36,13 +36,20 @@ class SeqLiterals extends MiniPhaseTransform {
3636
//println(i"trans seq $tree, arr = $arr: ${arr.tpe} ${arr.tpe.elemType}")
3737
val elemtp = arr.tpe.elemType.bounds.hi
3838
val elemCls = elemtp.classSymbol
39-
val (wrapMethStr, targs) =
40-
if (elemCls.isPrimitiveValueClass) (s"wrap${elemCls.name}Array", Nil)
41-
else if (elemtp derivesFrom defn.ObjectClass) ("wrapRefArray", elemtp :: Nil)
42-
else ("genericWrapArray", elemtp :: Nil)
43-
ref(defn.ScalaPredefModule)
44-
.select(wrapMethStr.toTermName)
45-
.appliedToTypes(targs)
46-
.appliedTo(arr)
39+
if (isDerivedValueClass(elemCls)) {
40+
ref(defn.DottyPredefModule)
41+
.select("wrapVCArray".toTermName)
42+
.appliedToTypes(List(elemtp))
43+
.appliedTo(arr)
44+
} else {
45+
val (wrapMethStr, targs) =
46+
if (elemCls.isPrimitiveValueClass) (s"wrap${elemCls.name}Array", Nil)
47+
else if (elemtp derivesFrom defn.ObjectClass) ("wrapRefArray", elemtp :: Nil)
48+
else ("genericWrapArray", elemtp :: Nil)
49+
ref(defn.ScalaPredefModule)
50+
.select(wrapMethStr.toTermName)
51+
.appliedToTypes(targs)
52+
.appliedTo(arr)
53+
}
4754
}
4855
}

0 commit comments

Comments
 (0)