Closed
Description
The current optimization is unsound:
scala> def foo[T : reflect.ClassTag](t: T) = Array.apply[T](t); foo[String]("")
def foo[T](t: T)(implicit evidence$1: scala.reflect.ClassTag[T]): Array[T]
val res13: Array[String] = Array("")
scala> def foo[T <: AnyRef : reflect.ClassTag](t: T) = Array.apply[T](t); foo[String]("")
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
... 32 elided
This should be fixed by limiting it to Array.apply
applications that had a concrete type. I think this can be done by detecting ApplyImplicitArgs(Array.apply(....)(<implicitly materialed class tag>)
.
In cases when this isn't the case, we could still avoid temporary array by code generating {val arr = classTag.newArray(N); ScalaRunTime.arrayUpdate(arr, N, elemN); ...; arr}
. Then, both variations below could avoid a temporary array and collection wrapper.
import scala.reflect.ClassTag
class OptimusSeq[T]
object OptimusSeq {
private def unsafeFromAnyArray1[T <: AnyRef](ts: Array[T]): OptimusSeq[T] = null;
def apply1[T <: AnyRef : ClassTag](p1: T, p2: T, p3: T, p4: T): OptimusSeq[T] = {
unsafeFromAnyArray2(Array(p1, p2, p3, p4))
}
private def unsafeFromAnyArray2[T](ts: Array[T]): OptimusSeq[T] = null;
def apply2[T : ClassTag](p1: T, p2: T, p3: T, p4: T): OptimusSeq[T] = {
unsafeFromAnyArray2(Array(p1, p2, p3, p4))
}
}
[[syntax trees at end of erasure]] // test.scala
package <empty> {
class OptimusSeq extends Object {
def <init>(): OptimusSeq = {
OptimusSeq.super.<init>();
()
}
};
object OptimusSeq extends Object {
def <init>(): OptimusSeq.type = {
OptimusSeq.super.<init>();
()
};
private def unsafeFromAnyArray1(ts: Array[Object]): OptimusSeq = null;
def apply1(p1: Object, p2: Object, p3: Object, p4: Object, evidence$1: scala.reflect.ClassTag): OptimusSeq = OptimusSeq.this.unsafeFromAnyArray2(scala.Array.apply(scala.Predef.wrapRefArray(Array[Object]{p1, p2, p3, p4}), evidence$1));
private def unsafeFromAnyArray2(ts: Object): OptimusSeq = null;
def apply2(p1: Object, p2: Object, p3: Object, p4: Object, evidence$2: scala.reflect.ClassTag): OptimusSeq = OptimusSeq.this.unsafeFromAnyArray2(scala.Array.apply(scala.Predef.genericWrapArray(Array[Object]{p1, p2, p3, p4}), evidence$2))
}
}
[[syntax trees at end of cleanup]] // test.scala
package <empty> {
class OptimusSeq extends Object {
def <init>(): OptimusSeq = {
OptimusSeq.super.<init>();
()
}
};
object OptimusSeq extends Object {
private def unsafeFromAnyArray1(ts: Array[Object]): OptimusSeq = null;
def apply1(p1: Object, p2: Object, p3: Object, p4: Object, evidence$1: scala.reflect.ClassTag): OptimusSeq = OptimusSeq.this.unsafeFromAnyArray2(Array[Object]{p1, p2, p3, p4});
private def unsafeFromAnyArray2(ts: Object): OptimusSeq = null;
def apply2(p1: Object, p2: Object, p3: Object, p4: Object, evidence$2: scala.reflect.ClassTag): OptimusSeq = OptimusSeq.this.unsafeFromAnyArray2(scala.Array.apply(scala.Predef.genericWrapArray(Array[Object]{p1, p2, p3, p4}), evidence$2));
def <init>(): OptimusSeq.type = {
OptimusSeq.super.<init>();
()
}
}
}