diff options
-rw-r--r-- | src/dotty/DottyPredef.scala | 14 | ||||
-rw-r--r-- | src/dotty/runtime/vc/VCPrototype.scala | 486 | ||||
-rw-r--r-- | src/dotty/tools/dotc/config/ScalaSettings.scala | 1 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/ValueClasses.scala | 1 | ||||
-rw-r--r-- | src/scala/runtime/ScalaRunTime/ScalaRunTime.scala | 371 |
5 files changed, 873 insertions, 0 deletions
diff --git a/src/dotty/DottyPredef.scala b/src/dotty/DottyPredef.scala index 4b68e4029..7c8098bd1 100644 --- a/src/dotty/DottyPredef.scala +++ b/src/dotty/DottyPredef.scala @@ -8,4 +8,18 @@ object DottyPredef { /** implicits for ClassTag and TypeTag. Should be implemented with macros */ implicit def classTag[T]: ClassTag[T] = scala.Predef.??? implicit def typeTag[T]: TypeTag[T] = scala.Predef.??? + + + /** ClassTags for final classes */ + implicit val IntClassTag: ClassTag[Int] = ClassTag.Int + implicit val ByteClassTag: ClassTag[Byte] = ClassTag.Byte + implicit val ShortClassTag: ClassTag[Short] = ClassTag.Short + implicit val CharClassTag: ClassTag[Char] = ClassTag.Char + implicit val LongClassTag: ClassTag[Long] = ClassTag.Long + implicit val FloatClassTag: ClassTag[Float] = ClassTag.Float + implicit val DoubleClassTag: ClassTag[Double] = ClassTag.Double + implicit val BooleanClassTag: ClassTag[Boolean] = ClassTag.Boolean + implicit val UnitClassTag: ClassTag[Unit] = ClassTag.Unit + implicit val NullClassTag: ClassTag[Null] = ClassTag.Null + implicit val NothingClassTag: ClassTag[Nothing] = ClassTag.Nothing } diff --git a/src/dotty/runtime/vc/VCPrototype.scala b/src/dotty/runtime/vc/VCPrototype.scala new file mode 100644 index 000000000..0a3abe5a2 --- /dev/null +++ b/src/dotty/runtime/vc/VCPrototype.scala @@ -0,0 +1,486 @@ +package dotty.runtime.vc + +import scala.reflect.ClassTag + +abstract class VCPrototype { +} + + +abstract class VCArrayPrototype[T <: VCPrototype] extends Object with Cloneable { + def apply(idx: Int): Object + def update(idx: Int, el: T): Unit + def length: Int + override def clone: Object = super.clone() +} + + +abstract class VCFloatPrototype(val underlying: Float) extends VCPrototype {} + +abstract class VCFloatCasePrototype(underlying: Float) extends VCFloatPrototype(underlying) with Product1[Float] { + + final def _1: Float = underlying + + override final def hashCode(): Int = { + underlying.hashCode() + } + + override final def toString: String = { + s"$productPrefix($underlying)" + } +} + +abstract class VCFloatCompanion[T <: VCFloatPrototype] extends ClassTag[T] { + def box(underlying: Float): T + final def unbox(boxed: T) = boxed.underlying + + implicit def classTag: this.type = this + override def newArray(len: Int): Array[T] = + new VCFloatArray(this, len).asInstanceOf[Array[T]] + + + final def _1$extension(underlying: Float) = underlying + final def hashCode$extension(underlying: Float) = underlying.hashCode() + final def toString$extension(underlying: Float) = s"${productPrefix$extension(underlying)}($underlying)" + def productPrefix$extension(underlying: Float): String +} + +final class VCFloatArray[T <: VCFloatPrototype] private (val arr: Array[Float], val ct: VCFloatCompanion[T]) + extends VCArrayPrototype[T] { + def this(ct: VCFloatCompanion[T], sz: Int) = + this(new Array[Float](sz), ct) + + def apply(idx: Int) = + ct.box(arr(idx)) + def update(idx: Int, elem: T) = + arr(idx) = ct.unbox(elem) + def length: Int = arr.length + + override def clone(): VCFloatArray[T] = { + new VCFloatArray[T](arr.clone(), ct) + } + + override def toString: String = { + "[" + ct.runtimeClass + } +} + + +abstract class VCObjectPrototype(val underlying: Object) extends VCPrototype {} + +abstract class VCObjectCasePrototype(underlying: Object) extends VCObjectPrototype(underlying) with Product1[Object] { + + final def _1: Object = underlying + + override final def hashCode(): Int = { + underlying.hashCode() + } + + override final def toString: String = { + s"$productPrefix($underlying)" + } +} + +abstract class VCObjectCompanion[T <: VCObjectPrototype] extends ClassTag[T] { + def box(underlying: Object): T + final def unbox(boxed: T) = boxed.underlying + + implicit def classTag: this.type = this + override def newArray(len: Int): Array[T] = + new VCObjectArray(this, len).asInstanceOf[Array[T]] + + + final def _1$extension(underlying: Object) = underlying + final def hashCode$extension(underlying: Object) = underlying.hashCode() + final def toString$extension(underlying: Object) = s"${productPrefix$extension(underlying)}($underlying)" + def productPrefix$extension(underlying: Object): String +} + +final class VCObjectArray[T <: VCObjectPrototype] private (val arr: Array[Object], val ct: VCObjectCompanion[T]) + extends VCArrayPrototype[T] { + def this(ct: VCObjectCompanion[T], sz: Int) = + this(new Array[Object](sz), ct) + + def apply(idx: Int) = + ct.box(arr(idx)) + + def update(idx: Int, elem: T) = + arr(idx) = ct.unbox(elem) + + def length: Int = arr.length + + override def clone(): VCObjectArray[T] = { + new VCObjectArray[T](arr.clone(), ct) + } + + override def toString: String = { + "[" + ct.runtimeClass + } +} + + +abstract class VCShortPrototype(val underlying: Short) extends VCPrototype {} + +abstract class VCShortCasePrototype(underlying: Short) extends VCShortPrototype(underlying) with Product1[Short] { + + final def _1: Short = underlying + + override final def hashCode(): Int = { + underlying.hashCode() + } + + override final def toString: String = { + s"$productPrefix($underlying)" + } +} + +abstract class VCShortCompanion[T <: VCShortPrototype] extends ClassTag[T] { + def box(underlying: Short): T + final def unbox(boxed: T) = boxed.underlying + + implicit def classTag: this.type = this + override def newArray(len: Int): Array[T] = + new VCShortArray(this, len).asInstanceOf[Array[T]] + + + final def _1$extension(underlying: Short) = underlying + final def hashCode$extension(underlying: Short) = underlying.hashCode() + final def toString$extension(underlying: Short) = s"${productPrefix$extension(underlying)}($underlying)" + def productPrefix$extension(underlying: Short): String +} + +final class VCShortArray[T <: VCShortPrototype] private (val arr: Array[Short], val ct: VCShortCompanion[T]) + extends VCArrayPrototype[T] { + def this(ct: VCShortCompanion[T], sz: Int) = + this(new Array[Short](sz), ct) + + def apply(idx: Int) = + ct.box(arr(idx)) + + def update(idx: Int, elem: T) = + arr(idx) = ct.unbox(elem) + + def length: Int = arr.length + + override def clone(): VCShortArray[T] = { + new VCShortArray[T](arr.clone(), ct) + } + + override def toString: String = { + "[" + ct.runtimeClass + } + +} + + +abstract class VCLongPrototype(val underlying: Long) extends VCPrototype {} + +abstract class VCLongCasePrototype(underlying: Long) extends VCLongPrototype(underlying) with Product1[Long] { + + final def _1: Long = underlying + + override final def hashCode(): Int = { + underlying.hashCode() + } + + override final def toString: String = { + s"$productPrefix($underlying)" + } +} + +abstract class VCLongCompanion[T <: VCLongPrototype] extends ClassTag[T] { + def box(underlying: Long): T + final def unbox(boxed: T) = boxed.underlying + + implicit def classTag: this.type = this + override def newArray(len: Int): Array[T] = + new VCLongArray(this, len).asInstanceOf[Array[T]] + + + final def _1$extension(underlying: Long) = underlying + final def hashCode$extension(underlying: Long) = underlying.hashCode() + final def toString$extension(underlying: Long) = s"${productPrefix$extension(underlying)}($underlying)" + def productPrefix$extension(underlying: Long): String +} + +final class VCLongArray[T <: VCLongPrototype] private (val arr: Array[Long], val ct: VCLongCompanion[T]) + extends VCArrayPrototype[T] { + def this(ct: VCLongCompanion[T], sz: Int) = + this(new Array[Long](sz), ct) + + def apply(idx: Int) = + ct.box(arr(idx)) + + def update(idx: Int, elem: T) = + arr(idx) = ct.unbox(elem) + + def length: Int = arr.length + + override def clone(): VCLongArray[T] = { + new VCLongArray[T](arr.clone(), ct) + } + + override def toString: String = { + "[" + ct.runtimeClass + } +} + + +abstract class VCIntPrototype(val underlying: Int) extends VCPrototype {} + +abstract class VCIntCasePrototype(underlying: Int) extends VCIntPrototype(underlying) with Product1[Int] { + + final def _1: Int = underlying + + override final def hashCode(): Int = { + underlying.hashCode() + } + + override final def toString: String = { + s"$productPrefix($underlying)" + } +} + +abstract class VCIntCompanion[T <: VCIntPrototype] extends ClassTag[T] { + def box(underlying: Int): T + final def unbox(boxed: T) = boxed.underlying + + implicit def classTag: this.type = this + override def newArray(len: Int): Array[T] = + new VCIntArray(this, len).asInstanceOf[Array[T]] + + + final def _1$extension(underlying: Int) = underlying + final def hashCode$extension(underlying: Int) = underlying.hashCode() + final def toString$extension(underlying: Int) = s"${productPrefix$extension(underlying)}($underlying)" + def productPrefix$extension(underlying: Int): String +} + +final class VCIntArray[T <: VCIntPrototype] private (val arr: Array[Int], val ct: VCIntCompanion[T]) + extends VCArrayPrototype[T] { + def this(ct: VCIntCompanion[T], sz: Int) = + this(new Array[Int](sz), ct) + + def apply(idx: Int) = + ct.box(arr(idx)) + def update(idx: Int, elem: T) = + arr(idx) = ct.unbox(elem) + def length: Int = arr.length + + override def clone(): VCIntArray[T] = { + new VCIntArray[T](arr.clone(), ct) + } + + override def toString: String = { + "[" + ct.runtimeClass + } +} + + +abstract class VCDoublePrototype(val underlying: Double) extends VCPrototype {} + +abstract class VCDoubleCasePrototype(underlying: Double) extends VCDoublePrototype(underlying) with Product1[Double] { + + final def _1: Double = underlying + + override final def hashCode(): Int = { + underlying.hashCode() + } + + override final def toString: String = { + s"$productPrefix($underlying)" + } +} + +abstract class VCDoubleCompanion[T <: VCDoublePrototype] extends ClassTag[T] { + def box(underlying: Double): T + final def unbox(boxed: T) = boxed.underlying + + implicit def classTag: this.type = this + override def newArray(len: Int): Array[T] = + new VCDoubleArray(this, len).asInstanceOf[Array[T]] + + + final def _1$extension(underlying: Double) = underlying + final def hashCode$extension(underlying: Double) = underlying.hashCode() + final def toString$extension(underlying: Double) = s"${productPrefix$extension(underlying)}($underlying)" + def productPrefix$extension(underlying: Double): String +} + +final class VCDoubleArray[T <: VCDoublePrototype] private (val arr: Array[Double], val ct: VCDoubleCompanion[T]) + extends VCArrayPrototype[T] { + def this(ct: VCDoubleCompanion[T], sz: Int) = + this(new Array[Double](sz), ct) + + def apply(idx: Int) = + ct.box(arr(idx)) + def update(idx: Int, elem: T) = + arr(idx) = ct.unbox(elem) + def length: Int = arr.length + + override def clone(): VCDoubleArray[T] = { + new VCDoubleArray[T](arr.clone(), ct) + } + + override def toString: String = { + "[" + ct.runtimeClass + } +} + + +abstract class VCBooleanPrototype(val underlying: Boolean) extends VCPrototype {} + +abstract class VCBooleanCasePrototype(underlying: Boolean) extends VCBooleanPrototype(underlying) with Product1[Boolean] { + + final def _1: Boolean = underlying + + override final def hashCode(): Int = { + underlying.hashCode() + } + + override final def toString: String = { + s"$productPrefix($underlying)" + } +} + +abstract class VCBooleanCompanion[T <: VCBooleanPrototype] extends ClassTag[T] { + def box(underlying: Boolean): T + final def unbox(boxed: T) = boxed.underlying + + implicit def classTag: this.type = this + override def newArray(len: Int): Array[T] = + new VCBooleanArray(this, len).asInstanceOf[Array[T]] + + + final def _1$extension(underlying: Boolean) = underlying + final def hashCode$extension(underlying: Boolean) = underlying.hashCode() + final def toString$extension(underlying: Boolean) = s"${productPrefix$extension(underlying)}($underlying)" + def productPrefix$extension(underlying: Boolean): String +} + +final class VCBooleanArray[T <: VCBooleanPrototype] private (val arr: Array[Boolean], val ct: VCBooleanCompanion[T]) + extends VCArrayPrototype[T] { + def this(ct: VCBooleanCompanion[T], sz: Int) = + this(new Array[Boolean](sz), ct) + + def apply(idx: Int) = + ct.box(arr(idx)) + + def update(idx: Int, elem: T) = + arr(idx) = ct.unbox(elem) + + def length: Int = arr.length + + override def clone(): VCBooleanArray[T] = { + new VCBooleanArray[T](arr.clone(), ct) + } + + override def toString: String = { + "[" + ct.runtimeClass + } +} + + +abstract class VCCharPrototype(val underlying: Char) extends VCPrototype {} + +abstract class VCCharCasePrototype(underlying: Char) extends VCCharPrototype(underlying) with Product1[Char] { + + final def _1: Char = underlying + + override final def hashCode(): Int = { + underlying.hashCode() + } + + override final def toString: String = { + s"$productPrefix($underlying)" + } + + // subclasses are expected to implement equals, productPrefix, and canEqual +} + +abstract class VCCharCompanion[T <: VCCharPrototype] extends ClassTag[T] { + def box(underlying: Char): T + final def unbox(boxed: T) = boxed.underlying + + implicit def classTag: this.type = this + override def newArray(len: Int): Array[T] = + new VCCharArray(this, len).asInstanceOf[Array[T]] + + + final def _1$extension(underlying: Char) = underlying + final def hashCode$extension(underlying: Char) = underlying.hashCode() + final def toString$extension(underlying: Char) = s"${productPrefix$extension(underlying)}($underlying)" + def productPrefix$extension(underlying: Char): String +} + +final class VCCharArray[T <: VCCharPrototype] private (val arr: Array[Char], val ct: VCCharCompanion[T]) + extends VCArrayPrototype[T] { + def this(ct: VCCharCompanion[T], sz: Int) = + this(new Array[Char](sz), ct) + + def apply(idx: Int) = + ct.box(arr(idx)) + def update(idx: Int, elem: T) = + arr(idx) = ct.unbox(elem) + def length: Int = arr.length + + override def clone(): VCCharArray[T] = { + new VCCharArray[T](arr.clone(), ct) + } + + override def toString: String = { + "[" + ct.runtimeClass + } +} + + +abstract class VCBytePrototype(val underlying: Byte) extends VCPrototype {} + +abstract class VCByteCasePrototype(underlying: Byte) extends VCBytePrototype(underlying) with Product1[Byte] { + + final def _1: Byte = underlying + + override final def hashCode(): Int = { + underlying.hashCode() + } + + override final def toString: String = { + s"$productPrefix($underlying)" + } +} + +abstract class VCByteCompanion[T <: VCBytePrototype] extends ClassTag[T] { + def box(underlying: Byte): T + final def unbox(boxed: T) = boxed.underlying + + implicit def classTag: this.type = this + override def newArray(len: Int): Array[T] = + new VCByteArray(this, len).asInstanceOf[Array[T]] + + + final def _1$extension(underlying: Byte) = underlying + final def hashCode$extension(underlying: Byte) = underlying.hashCode() + final def toString$extension(underlying: Byte) = s"${productPrefix$extension(underlying)}($underlying)" + def productPrefix$extension(underlying: Byte): String +} + +final class VCByteArray[T <: VCBytePrototype] private (val arr: Array[Byte], val ct: VCByteCompanion[T]) + extends VCArrayPrototype[T] { + def this(ct: VCByteCompanion[T], sz: Int) = + this(new Array[Byte](sz), ct) + + def apply(idx: Int) = + ct.box(arr(idx)) + def update(idx: Int, elem: T) = + arr(idx) = ct.unbox(elem) + def length: Int = arr.length + + override def clone(): VCByteArray[T] = { + new VCByteArray[T](arr.clone(), ct) + } + + override def toString: String = { + "[" + ct.runtimeClass + } + +} + diff --git a/src/dotty/tools/dotc/config/ScalaSettings.scala b/src/dotty/tools/dotc/config/ScalaSettings.scala index 2ad39c3c0..2ba907084 100644 --- a/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -88,6 +88,7 @@ class ScalaSettings extends Settings.SettingGroup { val Xshowobj = StringSetting("-Xshow-object", "object", "Show internal representation of object.", "") val showPhases = BooleanSetting("-Xshow-phases", "Print a synopsis of compiler phases.") val sourceReader = StringSetting("-Xsource-reader", "classname", "Specify a custom method for reading source files.", "") + val XnoValueClasses = BooleanSetting("-Xno-value-classes", "Do not use value classes. Helps debugging.") val XoldPatmat = BooleanSetting("-Xoldpatmat", "Use the pre-2.10 pattern matcher. Otherwise, the 'virtualizing' pattern matcher is used in 2.10.") val XnoPatmatAnalysis = BooleanSetting("-Xno-patmat-analysis", "Don't perform exhaustivity/unreachability analysis. Also, ignore @switch annotation.") diff --git a/src/dotty/tools/dotc/transform/ValueClasses.scala b/src/dotty/tools/dotc/transform/ValueClasses.scala index 30802f426..93005c57a 100644 --- a/src/dotty/tools/dotc/transform/ValueClasses.scala +++ b/src/dotty/tools/dotc/transform/ValueClasses.scala @@ -13,6 +13,7 @@ import StdNames._ object ValueClasses { def isDerivedValueClass(d: SymDenotation)(implicit ctx: Context) = { + !ctx.settings.XnoValueClasses.value && !d.isRefinementClass && d.isValueClass && (d.initial.symbol ne defn.AnyValClass) && // Compare the initial symbol because AnyVal does not exist after erasure diff --git a/src/scala/runtime/ScalaRunTime/ScalaRunTime.scala b/src/scala/runtime/ScalaRunTime/ScalaRunTime.scala new file mode 100644 index 000000000..b875b4d1e --- /dev/null +++ b/src/scala/runtime/ScalaRunTime/ScalaRunTime.scala @@ -0,0 +1,371 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala +package runtime + +import dotty.runtime.vc.VCArrayPrototype + +import scala.collection.{ Seq, IndexedSeq, TraversableView, AbstractIterator } +import scala.collection.mutable.WrappedArray +import scala.collection.immutable.{ StringLike, NumericRange, List, Stream, Nil, :: } +import scala.collection.generic.{ Sorted, IsTraversableLike } +import scala.reflect.{ ClassTag, classTag } +import scala.util.control.ControlThrowable +import java.lang.{ Class => jClass } + +import java.lang.Double.doubleToLongBits +import java.lang.reflect.{ Modifier, Method => JMethod } + +/** The object ScalaRunTime provides support methods required by + * the scala runtime. All these methods should be considered + * outside the API and subject to change or removal without notice. + */ +object ScalaRunTime { + def isArray(x: Any, atLevel: Int = 1): Boolean = + x != null && isArrayClass(x.getClass, atLevel) + + private def isArrayClass(clazz: jClass[_], atLevel: Int): Boolean = + (clazz.isArray || classOf[VCArrayPrototype[_]].isAssignableFrom(clazz)) && + (atLevel == 1 || isArrayClass(clazz.getComponentType, atLevel - 1)) + + def isValueClass(clazz: jClass[_]) = clazz.isPrimitive() + + // includes specialized subclasses and future proofed against hypothetical TupleN (for N > 22) + def isTuple(x: Any) = x != null && x.getClass.getName.startsWith("scala.Tuple") + def isAnyVal(x: Any) = x match { + case _: Byte | _: Short | _: Char | _: Int | _: Long | _: Float | _: Double | _: Boolean | _: Unit => true + case _ => false + } + + // A helper method to make my life in the pattern matcher a lot easier. + def drop[Repr](coll: Repr, num: Int)(implicit traversable: IsTraversableLike[Repr]): Repr = + traversable conversion coll drop num + + /** Return the class object representing an array with element class `clazz`. + */ + def arrayClass(clazz: jClass[_]): jClass[_] = { + ??? // Dmitry: I want to see where this method is used to know how to fix it + // newInstance throws an exception if the erasure is Void.TYPE. see SI-5680 + if (clazz == java.lang.Void.TYPE) classOf[Array[Unit]] + else java.lang.reflect.Array.newInstance(clazz, 0).getClass + } + + /** Return the class object representing elements in arrays described by a given schematic. + */ + def arrayElementClass(schematic: Any): jClass[_] = schematic match { + case cls: jClass[_] => cls.getComponentType + case tag: ClassTag[_] => tag.runtimeClass + case _ => + throw new UnsupportedOperationException(s"unsupported schematic $schematic (${schematic.getClass})") + } + + /** Return the class object representing an unboxed value type, + * e.g., classOf[int], not classOf[java.lang.Integer]. The compiler + * rewrites expressions like 5.getClass to come here. + */ + def anyValClass[T <: AnyVal : ClassTag](value: T): jClass[T] = + classTag[T].runtimeClass.asInstanceOf[jClass[T]] + + /** Retrieve generic array element */ + def array_apply(xs: AnyRef, idx: Int): Any = { + xs match { + case x: Array[AnyRef] => x(idx).asInstanceOf[Any] + case x: Array[Int] => x(idx).asInstanceOf[Any] + case x: Array[Double] => x(idx).asInstanceOf[Any] + case x: Array[Long] => x(idx).asInstanceOf[Any] + case x: Array[Float] => x(idx).asInstanceOf[Any] + case x: Array[Char] => x(idx).asInstanceOf[Any] + case x: Array[Byte] => x(idx).asInstanceOf[Any] + case x: Array[Short] => x(idx).asInstanceOf[Any] + case x: Array[Boolean] => x(idx).asInstanceOf[Any] + case x: Array[Unit] => x(idx).asInstanceOf[Any] + case x: VCArrayPrototype[_] => x.apply(idx) + case null => throw new NullPointerException + } + } + + /** update generic array element */ + def array_update(xs: AnyRef, idx: Int, value: Any): Unit = { + xs match { + case x: Array[AnyRef] => x(idx) = value.asInstanceOf[AnyRef] + case x: Array[Int] => x(idx) = value.asInstanceOf[Int] + case x: Array[Double] => x(idx) = value.asInstanceOf[Double] + case x: Array[Long] => x(idx) = value.asInstanceOf[Long] + case x: Array[Float] => x(idx) = value.asInstanceOf[Float] + case x: Array[Char] => x(idx) = value.asInstanceOf[Char] + case x: Array[Byte] => x(idx) = value.asInstanceOf[Byte] + case x: Array[Short] => x(idx) = value.asInstanceOf[Short] + case x: Array[Boolean] => x(idx) = value.asInstanceOf[Boolean] + case x: Array[Unit] => x(idx) = value.asInstanceOf[Unit] + case x: VCArrayPrototype[t] => x.update(idx, value.asInstanceOf[t]) + case null => throw new NullPointerException + } + } + + /** Get generic array length */ + def array_length(xs: AnyRef): Int = xs match { + case x: Array[AnyRef] => x.length + case x: Array[Int] => x.length + case x: Array[Double] => x.length + case x: Array[Long] => x.length + case x: Array[Float] => x.length + case x: Array[Char] => x.length + case x: Array[Byte] => x.length + case x: Array[Short] => x.length + case x: Array[Boolean] => x.length + case x: Array[Unit] => x.length + case x: VCArrayPrototype[_] => x.length + case null => throw new NullPointerException + } + + def array_clone(xs: AnyRef): AnyRef = xs match { + case x: Array[AnyRef] => ArrayRuntime.cloneArray(x) + case x: Array[Int] => ArrayRuntime.cloneArray(x) + case x: Array[Double] => ArrayRuntime.cloneArray(x) + case x: Array[Long] => ArrayRuntime.cloneArray(x) + case x: Array[Float] => ArrayRuntime.cloneArray(x) + case x: Array[Char] => ArrayRuntime.cloneArray(x) + case x: Array[Byte] => ArrayRuntime.cloneArray(x) + case x: Array[Short] => ArrayRuntime.cloneArray(x) + case x: Array[Boolean] => ArrayRuntime.cloneArray(x) + case x: Array[Unit] => x + case x: VCArrayPrototype[_] => x.clone() + case null => throw new NullPointerException + } + + /** Convert an array to an object array. + * Needed to deal with vararg arguments of primitive types that are passed + * to a generic Java vararg parameter T ... + */ + def toObjectArray(src: AnyRef): Array[Object] = src match { + case x: Array[AnyRef] => x + case _ => + val length = array_length(src) + val dest = new Array[Object](length) + for (i <- 0 until length) + array_update(dest, i, array_apply(src, i)) + dest + } + + def toArray[T](xs: scala.collection.Seq[T]) = { + val arr = new Array[AnyRef](xs.length) + var i = 0 + for (x <- xs) { + arr(i) = x.asInstanceOf[AnyRef] + i += 1 + } + arr + } + + // Java bug: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4071957 + // More background at ticket #2318. + def ensureAccessible(m: JMethod): JMethod = scala.reflect.ensureAccessible(m) + + def checkInitialized[T <: AnyRef](x: T): T = + if (x == null) throw new UninitializedError else x + + def _toString(x: Product): String = + x.productIterator.mkString(x.productPrefix + "(", ",", ")") + + def _hashCode(x: Product): Int = scala.util.hashing.MurmurHash3.productHash(x) + + /** A helper for case classes. */ + def typedProductIterator[T](x: Product): Iterator[T] = { + new AbstractIterator[T] { + private var c: Int = 0 + private val cmax = x.productArity + def hasNext = c < cmax + def next() = { + val result = x.productElement(c) + c += 1 + result.asInstanceOf[T] + } + } + } + + /** Fast path equality method for inlining; used when -optimise is set. + */ + @inline def inlinedEquals(x: Object, y: Object): Boolean = + if (x eq y) true + else if (x eq null) false + else if (x.isInstanceOf[java.lang.Number]) BoxesRunTime.equalsNumObject(x.asInstanceOf[java.lang.Number], y) + else if (x.isInstanceOf[java.lang.Character]) BoxesRunTime.equalsCharObject(x.asInstanceOf[java.lang.Character], y) + else x.equals(y) + + def _equals(x: Product, y: Any): Boolean = y match { + case y: Product if x.productArity == y.productArity => x.productIterator sameElements y.productIterator + case _ => false + } + + // hashcode ----------------------------------------------------------- + // + // Note that these are the implementations called by ##, so they + // must not call ## themselves. + + def hash(x: Any): Int = + if (x == null) 0 + else if (x.isInstanceOf[java.lang.Number]) BoxesRunTime.hashFromNumber(x.asInstanceOf[java.lang.Number]) + else x.hashCode + + def hash(dv: Double): Int = { + val iv = dv.toInt + if (iv == dv) return iv + + val lv = dv.toLong + if (lv == dv) return lv.hashCode + + val fv = dv.toFloat + if (fv == dv) fv.hashCode else dv.hashCode + } + def hash(fv: Float): Int = { + val iv = fv.toInt + if (iv == fv) return iv + + val lv = fv.toLong + if (lv == fv) hash(lv) + else fv.hashCode + } + def hash(lv: Long): Int = { + val low = lv.toInt + val lowSign = low >>> 31 + val high = (lv >>> 32).toInt + low ^ (high + lowSign) + } + def hash(x: Number): Int = runtime.BoxesRunTime.hashFromNumber(x) + + // The remaining overloads are here for completeness, but the compiler + // inlines these definitions directly so they're not generally used. + def hash(x: Int): Int = x + def hash(x: Short): Int = x.toInt + def hash(x: Byte): Int = x.toInt + def hash(x: Char): Int = x.toInt + def hash(x: Boolean): Int = if (x) true.hashCode else false.hashCode + def hash(x: Unit): Int = 0 + + /** A helper method for constructing case class equality methods, + * because existential types get in the way of a clean outcome and + * it's performing a series of Any/Any equals comparisons anyway. + * See ticket #2867 for specifics. + */ + def sameElements(xs1: scala.collection.Seq[Any], xs2: scala.collection.Seq[Any]) = xs1 sameElements xs2 + + /** Given any Scala value, convert it to a String. + * + * The primary motivation for this method is to provide a means for + * correctly obtaining a String representation of a value, while + * avoiding the pitfalls of naïvely calling toString on said value. + * In particular, it addresses the fact that (a) toString cannot be + * called on null and (b) depending on the apparent type of an + * array, toString may or may not print it in a human-readable form. + * + * @param arg the value to stringify + * @return a string representation of arg. + */ + def stringOf(arg: Any): String = stringOf(arg, scala.Int.MaxValue) + def stringOf(arg: Any, maxElements: Int): String = { + def packageOf(x: AnyRef) = x.getClass.getPackage match { + case null => "" + case p => p.getName + } + def isScalaClass(x: AnyRef) = packageOf(x) startsWith "scala." + def isScalaCompilerClass(x: AnyRef) = packageOf(x) startsWith "scala.tools.nsc." + + // We use reflection because the scala.xml package might not be available + def isSubClassOf(potentialSubClass: Class[_], ofClass: String) = + try { + val classLoader = potentialSubClass.getClassLoader + val clazz = Class.forName(ofClass, /*initialize =*/ false, classLoader) + clazz.isAssignableFrom(potentialSubClass) + } catch { + case cnfe: ClassNotFoundException => false + } + def isXmlNode(potentialSubClass: Class[_]) = isSubClassOf(potentialSubClass, "scala.xml.Node") + def isXmlMetaData(potentialSubClass: Class[_]) = isSubClassOf(potentialSubClass, "scala.xml.MetaData") + + // When doing our own iteration is dangerous + def useOwnToString(x: Any) = x match { + // Range/NumericRange have a custom toString to avoid walking a gazillion elements + case _: Range | _: NumericRange[_] => true + // Sorted collections to the wrong thing (for us) on iteration - ticket #3493 + case _: Sorted[_, _] => true + // StringBuilder(a, b, c) and similar not so attractive + case _: StringLike[_] => true + // Don't want to evaluate any elements in a view + case _: TraversableView[_, _] => true + // Node extends NodeSeq extends Seq[Node] and MetaData extends Iterable[MetaData] + // -> catch those by isXmlNode and isXmlMetaData. + // Don't want to a) traverse infinity or b) be overly helpful with peoples' custom + // collections which may have useful toString methods - ticket #3710 + // or c) print AbstractFiles which are somehow also Iterable[AbstractFile]s. + case x: Traversable[_] => !x.hasDefiniteSize || !isScalaClass(x) || isScalaCompilerClass(x) || isXmlNode(x.getClass) || isXmlMetaData(x.getClass) + // Otherwise, nothing could possibly go wrong + case _ => false + } + + // A variation on inner for maps so they print -> instead of bare tuples + def mapInner(arg: Any): String = arg match { + case (k, v) => inner(k) + " -> " + inner(v) + case _ => inner(arg) + } + + // Special casing Unit arrays, the value class which uses a reference array type. + def arrayToString(x: AnyRef) = { + if (x.getClass.getComponentType == classOf[BoxedUnit]) + 0 until (array_length(x) min maxElements) map (_ => "()") mkString ("Array(", ", ", ")") + else + WrappedArray make x take maxElements map inner mkString ("Array(", ", ", ")") + } + + // The recursively applied attempt to prettify Array printing. + // Note that iterator is used if possible and foreach is used as a + // last resort, because the parallel collections "foreach" in a + // random order even on sequences. + def inner(arg: Any): String = arg match { + case null => "null" + case "" => "\"\"" + case x: String => if (x.head.isWhitespace || x.last.isWhitespace) "\"" + x + "\"" else x + case x if useOwnToString(x) => x.toString + case x: AnyRef if isArray(x) => arrayToString(x) + case x: scala.collection.Map[_, _] => x.iterator take maxElements map mapInner mkString (x.stringPrefix + "(", ", ", ")") + case x: Iterable[_] => x.iterator take maxElements map inner mkString (x.stringPrefix + "(", ", ", ")") + case x: Traversable[_] => x take maxElements map inner mkString (x.stringPrefix + "(", ", ", ")") + case x: Product1[_] if isTuple(x) => "(" + inner(x._1) + ",)" // that special trailing comma + case x: Product if isTuple(x) => x.productIterator map inner mkString ("(", ",", ")") + case x => x.toString + } + + // The try/catch is defense against iterables which aren't actually designed + // to be iterated, such as some scala.tools.nsc.io.AbstractFile derived classes. + try inner(arg) + catch { + case _: UnsupportedOperationException | _: AssertionError => "" + arg + } + } + + /** stringOf formatted for use in a repl result. */ + def replStringOf(arg: Any, maxElements: Int): String = { + val s = stringOf(arg, maxElements) + val nl = if (s contains "\n") "\n" else "" + + nl + s + "\n" + } + + def box[T](clazz: jClass[T]): jClass[_] = clazz match { + case java.lang.Byte.TYPE => classOf[java.lang.Byte] + case java.lang.Short.TYPE => classOf[java.lang.Short] + case java.lang.Character.TYPE => classOf[java.lang.Character] + case java.lang.Integer.TYPE => classOf[java.lang.Integer] + case java.lang.Long.TYPE => classOf[java.lang.Long] + case java.lang.Float.TYPE => classOf[java.lang.Float] + case java.lang.Double.TYPE => classOf[java.lang.Double] + case java.lang.Void.TYPE => classOf[scala.runtime.BoxedUnit] + case java.lang.Boolean.TYPE => classOf[java.lang.Boolean] + case _ => clazz + } +} |