diff --git a/src/dotty/DottyPredef.scala b/src/dotty/DottyPredef.scala index cd90c4882b77..8e8d912328ab 100644 --- a/src/dotty/DottyPredef.scala +++ b/src/dotty/DottyPredef.scala @@ -1,7 +1,10 @@ package dotty +import scala.collection.generic.CanBuildFrom import scala.reflect.runtime.universe.TypeTag import scala.reflect.ClassTag +import scala.collection.mutable.{ArrayBuilder, ArrayOps, WrappedArray} +import dotty.runtime.vc._ import scala.Predef.??? import scala.collection.Seq @@ -42,4 +45,10 @@ object DottyPredef { implicit def eqNumFloat : Eq[Number, Float] = Eq implicit def eqDoubleNum: Eq[Double, Number] = Eq implicit def eqNumDouble: Eq[Number, Double] = Eq + + def wrapVCArray[T](xs: Array[T]): WrappedArray[T] = + new VCWrappedArray[T](xs) + + def opsVCArray[T /*<: AnyVal*/](xs: Array[T]): ArrayOps[T] = + new VCArrayOps[T](xs) } diff --git a/src/dotty/runtime/vc/VCArrayBuilder.scala b/src/dotty/runtime/vc/VCArrayBuilder.scala new file mode 100644 index 000000000000..b26f192be7f9 --- /dev/null +++ b/src/dotty/runtime/vc/VCArrayBuilder.scala @@ -0,0 +1,69 @@ +package dotty.runtime.vc + +import scala.collection.TraversableOnce +import scala.collection.mutable.ArrayBuilder +import scala.reflect.ClassTag + +class VCArrayBuilder[T](implicit ct: ClassTag[T]) extends ArrayBuilder[T] { + + private var elems: Array[T] = _ + private var capacity: Int = 0 + private var size: Int = 0 + + private def mkArray(size: Int): Array[T] = { + val newelems = new Array[T](size) + if (this.size > 0) Array.copy(elems, 0, newelems, 0, this.size) + newelems + } + + private def resize(size: Int) = { + elems = mkArray(size) + capacity = size + } + + override def sizeHint(size: Int) = { + if (capacity < size) resize(size) + } + + private def ensureSize(size: Int) = { + if (capacity < size || capacity == 0) { + var newsize = if (capacity == 0) 16 else capacity * 2 + while (newsize < size) newsize *= 2 + resize(newsize) + } + } + + def +=(elem: T): this.type = { + ensureSize(size + 1) + elems(size) = elem + size += 1 + this + } + + //use impl from Growable +// override def ++=(xs: TraversableOnce[T]): this.type = (xs.asInstanceOf[AnyRef]) match { +// case xs: VCWrappedArray[_] => +// ensureSize(this.size + xs.length) +// Array.copy(xs.array, 0, elems, this.size, xs.length) +// size += xs.length +// this +// case _ => +// super.++=(xs) +// } + + def clear() = { + size = 0 + } + + def result() = { + if (capacity != 0 && capacity == size) elems + else mkArray(size) + } + + override def equals(other: Any): Boolean = other match { + case x: VCArrayBuilder[_] => (size == x.size) && (elems == x.elems) + case _ => false + } + + override def toString = "ArrayBuilder.ofVC" +} \ No newline at end of file diff --git a/src/dotty/runtime/vc/VCArrayOps.scala b/src/dotty/runtime/vc/VCArrayOps.scala new file mode 100644 index 000000000000..f13210793019 --- /dev/null +++ b/src/dotty/runtime/vc/VCArrayOps.scala @@ -0,0 +1,46 @@ +package dotty.runtime.vc + +import scala.collection.mutable.{Builder, WrappedArray, ArrayBuilder, ArrayOps} +import scala.reflect.ClassTag +import dotty.DottyPredef._ + +import scala.runtime.ScalaRunTime._ + +class VCArrayOps[T](xs: Array[T]) extends ArrayOps[T] { + val array = xs + def length: Int = array.length + def apply(index: Int): T = array(index) + def update(index: Int, elem: T) = { + array(index) = elem + } + + lazy val elemTag = (xs.asInstanceOf[Object]: @unchecked) match { + case vc: VCIntArray[_] => vc.ct.asInstanceOf[ClassTag[T]] + case vc: VCShortArray[_] => vc.ct.asInstanceOf[ClassTag[T]] + case vc: VCLongArray[_] => vc.ct.asInstanceOf[ClassTag[T]] + case vc: VCFloatArray[_] => vc.ct.asInstanceOf[ClassTag[T]] + case vc: VCDoubleArray[_] => vc.ct.asInstanceOf[ClassTag[T]] + case vc: VCByteArray[_] => vc.ct.asInstanceOf[ClassTag[T]] + case vc: VCBooleanArray[_] => vc.ct.asInstanceOf[ClassTag[T]] + case vc: VCCharArray[_] => vc.ct.asInstanceOf[ClassTag[T]] + case vc: VCObjectArray[_] => vc.ct.asInstanceOf[ClassTag[T]] + } + + override def repr = xs + + override protected[this] def newBuilder = new VCArrayBuilder[T]()(elemTag).asInstanceOf[ArrayBuilder[T]] + //override protected[this] def newBuilder = new ArrayBuilder.ofRef[T]()(ClassTag[T](arrayElementClass(repr.getClass))) + + override protected[this] def thisCollection: WrappedArray[T] = wrapVCArray(xs) + override protected[this] def toCollection(repr: Array[T]): WrappedArray[T] = wrapVCArray(xs) + + final def vcElementClass: Class[_] = arrayElementClass(elemTag) + + override def toArray[U >: T : ClassTag]: Array[U] = { + val thatElementClass = arrayElementClass(implicitly[ClassTag[U]]) + if (vcElementClass eq thatElementClass) + repr.asInstanceOf[Array[U]] + else + super.toArray[U] + } +} \ No newline at end of file diff --git a/src/dotty/runtime/vc/VCPrototype.scala b/src/dotty/runtime/vc/VCPrototype.scala index 212046ef8922..f04a0fa387bb 100644 --- a/src/dotty/runtime/vc/VCPrototype.scala +++ b/src/dotty/runtime/vc/VCPrototype.scala @@ -14,7 +14,11 @@ abstract class VCArrayPrototype[T <: VCPrototype] extends Object with Cloneable } -abstract class VCFloatPrototype(val underlying: Float) extends VCPrototype {} +abstract class VCFloatPrototype(val underlying: Float) extends VCPrototype { + override def hashCode(): Int = { + underlying.hashCode() + } +} abstract class VCFloatCasePrototype(underlying: Float) extends VCFloatPrototype(underlying) with Product1[Float] { @@ -29,27 +33,41 @@ abstract class VCFloatCasePrototype(underlying: Float) extends VCFloatPrototype( } } -abstract class VCFloatCompanion[T <: VCFloatPrototype] extends ClassTag[T] { +// NOTE for all VCXCompanion: The type parameter T should be bounded like this: +// abstract class VCXCompanion[T <: VCXPrototype] extends ClassTag[T] +// But this affects erasure: it means that Array[T] is erased to [VCIntPrototype; +// instead of Object, but we really need it to erase to Object if we want +// VCXArray to be a valid array. We work around this by adding casts where +// we need to assume that T is a subtype of VCXPrototype. + +// Final modifier is removed from defs _1$extension and hashCode$extension +// to fix VerifyError at runtime (running 'case class X(x: Int) extends AnyVal; val x = X(5)') + +// VCObjectCompanion's def box(underlying: Object): Object +// returns Object instead of T in order not to cause the bridge generation + +abstract class VCFloatCompanion[T /*<: VCFloatPrototype*/] extends ClassTag[T] { def box(underlying: Float): T - final def unbox(boxed: T) = boxed.underlying + final def unbox(boxed: T) = boxed.asInstanceOf[VCFloatPrototype].underlying implicit def classTag: this.type = this override def newArray(len: Int): Array[T] = - new VCFloatArray(this, len).asInstanceOf[Array[T]] + new VCFloatArray(this.asInstanceOf[VCFloatCompanion[VCFloatPrototype]], len).asInstanceOf[Array[T]] + override def wrap: ClassTag[Array[T]] = ClassTag[Array[T]](this.newArray(0).getClass) - 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 _1$extension(underlying: Float) = underlying + def hashCode$extension(underlying: Float) = underlying.hashCode() + 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]) +final class VCFloatArray[T <: VCFloatPrototype] (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) = + def apply(idx: Int): T = ct.box(arr(idx)) def update(idx: Int, elem: T) = arr(idx) = ct.unbox(elem) @@ -60,48 +78,53 @@ final class VCFloatArray[T <: VCFloatPrototype] private (val arr: Array[Float], } override def toString: String = { - "[" + ct.runtimeClass + "[" + ct.toString } } -abstract class VCObjectPrototype(val underlying: Object) extends VCPrototype {} +abstract class VCObjectPrototype(val underlying: Object) extends VCPrototype { + override def hashCode(): Int = { + if (underlying == null) 0 else underlying.hashCode() + } +} abstract class VCObjectCasePrototype(underlying: Object) extends VCObjectPrototype(underlying) with Product1[Object] { final def _1: Object = underlying override final def hashCode(): Int = { - underlying.hashCode() + if (underlying == null) 0 else underlying.hashCode() } - override final def toString: String = { + override 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 +abstract class VCObjectCompanion[T /*<: VCObjectPrototype*/] extends ClassTag[T] { + def box(underlying: Object): Object + final def unbox(boxed: T) = boxed.asInstanceOf[VCObjectPrototype].underlying implicit def classTag: this.type = this override def newArray(len: Int): Array[T] = - new VCObjectArray(this, len).asInstanceOf[Array[T]] + new VCObjectArray(this.asInstanceOf[VCObjectCompanion[VCObjectPrototype]], len).asInstanceOf[Array[T]] + override def wrap: ClassTag[Array[T]] = ClassTag[Array[T]](this.newArray(0).getClass) - 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 _1$extension(underlying: Object) = underlying + def hashCode$extension(underlying: Object) = underlying.hashCode() + 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]) +final class VCObjectArray[T <: VCObjectPrototype] (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 apply(idx: Int): T = + ct.box(arr(idx)).asInstanceOf[T] def update(idx: Int, elem: T) = arr(idx) = ct.unbox(elem) @@ -113,12 +136,16 @@ final class VCObjectArray[T <: VCObjectPrototype] private (val arr: Array[Object } override def toString: String = { - "[" + ct.runtimeClass + "[" + ct.toString } } -abstract class VCShortPrototype(val underlying: Short) extends VCPrototype {} +abstract class VCShortPrototype(val underlying: Short) extends VCPrototype { + override def hashCode(): Int = { + underlying.hashCode() + } +} abstract class VCShortCasePrototype(underlying: Short) extends VCShortPrototype(underlying) with Product1[Short] { @@ -128,32 +155,33 @@ abstract class VCShortCasePrototype(underlying: Short) extends VCShortPrototype( underlying.hashCode() } - override final def toString: String = { + override def toString: String = { s"$productPrefix($underlying)" } } -abstract class VCShortCompanion[T <: VCShortPrototype] extends ClassTag[T] { +abstract class VCShortCompanion[T /*<: VCShortPrototype*/] extends ClassTag[T] { def box(underlying: Short): T - final def unbox(boxed: T) = boxed.underlying + final def unbox(boxed: T) = boxed.asInstanceOf[VCShortPrototype].underlying implicit def classTag: this.type = this override def newArray(len: Int): Array[T] = - new VCShortArray(this, len).asInstanceOf[Array[T]] + new VCShortArray(this.asInstanceOf[VCShortCompanion[VCShortPrototype]], len).asInstanceOf[Array[T]] + override def wrap: ClassTag[Array[T]] = ClassTag[Array[T]](this.newArray(0).getClass) - 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 _1$extension(underlying: Short) = underlying + def hashCode$extension(underlying: Short) = underlying.hashCode() + 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]) +final class VCShortArray[T <: VCShortPrototype] (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) = + def apply(idx: Int): T = ct.box(arr(idx)) def update(idx: Int, elem: T) = @@ -166,13 +194,17 @@ final class VCShortArray[T <: VCShortPrototype] private (val arr: Array[Short], } override def toString: String = { - "[" + ct.runtimeClass + "[" + ct.toString } } -abstract class VCLongPrototype(val underlying: Long) extends VCPrototype {} +abstract class VCLongPrototype(val underlying: Long) extends VCPrototype { + override def hashCode(): Int = { + underlying.hashCode() + } +} abstract class VCLongCasePrototype(underlying: Long) extends VCLongPrototype(underlying) with Product1[Long] { @@ -182,32 +214,33 @@ abstract class VCLongCasePrototype(underlying: Long) extends VCLongPrototype(und underlying.hashCode() } - override final def toString: String = { + override def toString: String = { s"$productPrefix($underlying)" } } -abstract class VCLongCompanion[T <: VCLongPrototype] extends ClassTag[T] { +abstract class VCLongCompanion[T /*<: VCLongPrototype*/] extends ClassTag[T] { def box(underlying: Long): T - final def unbox(boxed: T) = boxed.underlying + final def unbox(boxed: T) = boxed.asInstanceOf[VCLongPrototype].underlying implicit def classTag: this.type = this override def newArray(len: Int): Array[T] = - new VCLongArray(this, len).asInstanceOf[Array[T]] + new VCLongArray(this.asInstanceOf[VCLongCompanion[VCLongPrototype]], len).asInstanceOf[Array[T]] + override def wrap: ClassTag[Array[T]] = ClassTag[Array[T]](this.newArray(0).getClass) - 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 _1$extension(underlying: Long) = underlying + def hashCode$extension(underlying: Long) = underlying.hashCode() + 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]) +final class VCLongArray[T <: VCLongPrototype] (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) = + def apply(idx: Int): T = ct.box(arr(idx)) def update(idx: Int, elem: T) = @@ -220,47 +253,50 @@ final class VCLongArray[T <: VCLongPrototype] private (val arr: Array[Long], val } override def toString: String = { - "[" + ct.runtimeClass + "[" + ct.toString } } -abstract class VCIntPrototype(val underlying: Int) extends VCPrototype {} +abstract class VCIntPrototype(val underlying: Int) extends VCPrototype { + override def hashCode(): Int = { + underlying.hashCode() + } +} 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 = { + override def toString: String = { s"$productPrefix($underlying)" } } -abstract class VCIntCompanion[T <: VCIntPrototype] extends ClassTag[T] { +abstract class VCIntCompanion[T /*<: VCIntPrototype*/] extends ClassTag[T] { def box(underlying: Int): T - final def unbox(boxed: T) = boxed.underlying + final def unbox(boxed: T) = boxed.asInstanceOf[VCIntPrototype].underlying implicit def classTag: this.type = this override def newArray(len: Int): Array[T] = - new VCIntArray(this, len).asInstanceOf[Array[T]] + new VCIntArray(this.asInstanceOf[VCIntCompanion[VCIntPrototype]], len).asInstanceOf[Array[T]] + override def wrap: ClassTag[Array[T]] = ClassTag[Array[T]](this.newArray(0).getClass) - - 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 _1$extension(underlying: Int) = underlying + def hashCode$extension(underlying: Int) = underlying.hashCode() + 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]) +final class VCIntArray[T <: VCIntPrototype] (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) = + def apply(idx: Int): T = ct.box(arr(idx)) def update(idx: Int, elem: T) = arr(idx) = ct.unbox(elem) @@ -271,12 +307,16 @@ final class VCIntArray[T <: VCIntPrototype] private (val arr: Array[Int], val ct } override def toString: String = { - "[" + ct.runtimeClass + "[" + ct.toString } } -abstract class VCDoublePrototype(val underlying: Double) extends VCPrototype {} +abstract class VCDoublePrototype(val underlying: Double) extends VCPrototype { + override def hashCode(): Int = { + underlying.hashCode() + } +} abstract class VCDoubleCasePrototype(underlying: Double) extends VCDoublePrototype(underlying) with Product1[Double] { @@ -286,32 +326,33 @@ abstract class VCDoubleCasePrototype(underlying: Double) extends VCDoublePrototy underlying.hashCode() } - override final def toString: String = { + override def toString: String = { s"$productPrefix($underlying)" } } -abstract class VCDoubleCompanion[T <: VCDoublePrototype] extends ClassTag[T] { +abstract class VCDoubleCompanion[T /*<: VCDoublePrototype*/] extends ClassTag[T] { def box(underlying: Double): T - final def unbox(boxed: T) = boxed.underlying + final def unbox(boxed: T) = boxed.asInstanceOf[VCDoublePrototype].underlying implicit def classTag: this.type = this override def newArray(len: Int): Array[T] = - new VCDoubleArray(this, len).asInstanceOf[Array[T]] + new VCDoubleArray(this.asInstanceOf[VCDoubleCompanion[VCDoublePrototype]], len).asInstanceOf[Array[T]] + override def wrap: ClassTag[Array[T]] = ClassTag[Array[T]](this.newArray(0).getClass) - 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 _1$extension(underlying: Double) = underlying + def hashCode$extension(underlying: Double) = underlying.hashCode() + 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]) +final class VCDoubleArray[T <: VCDoublePrototype] (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) = + def apply(idx: Int): T = ct.box(arr(idx)) def update(idx: Int, elem: T) = arr(idx) = ct.unbox(elem) @@ -322,12 +363,16 @@ final class VCDoubleArray[T <: VCDoublePrototype] private (val arr: Array[Double } override def toString: String = { - "[" + ct.runtimeClass + "[" + ct.toString } } -abstract class VCBooleanPrototype(val underlying: Boolean) extends VCPrototype {} +abstract class VCBooleanPrototype(val underlying: Boolean) extends VCPrototype { + override def hashCode(): Int = { + underlying.hashCode() + } +} abstract class VCBooleanCasePrototype(underlying: Boolean) extends VCBooleanPrototype(underlying) with Product1[Boolean] { @@ -337,32 +382,33 @@ abstract class VCBooleanCasePrototype(underlying: Boolean) extends VCBooleanProt underlying.hashCode() } - override final def toString: String = { + override def toString: String = { s"$productPrefix($underlying)" } } -abstract class VCBooleanCompanion[T <: VCBooleanPrototype] extends ClassTag[T] { +abstract class VCBooleanCompanion[T /*<: VCBooleanPrototype*/] extends ClassTag[T] { def box(underlying: Boolean): T - final def unbox(boxed: T) = boxed.underlying + final def unbox(boxed: T) = boxed.asInstanceOf[VCBooleanPrototype].underlying implicit def classTag: this.type = this override def newArray(len: Int): Array[T] = - new VCBooleanArray(this, len).asInstanceOf[Array[T]] + new VCBooleanArray(this.asInstanceOf[VCBooleanCompanion[VCBooleanPrototype]], len).asInstanceOf[Array[T]] + override def wrap: ClassTag[Array[T]] = ClassTag[Array[T]](this.newArray(0).getClass) - 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 _1$extension(underlying: Boolean) = underlying + def hashCode$extension(underlying: Boolean) = underlying.hashCode() + 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]) +final class VCBooleanArray[T <: VCBooleanPrototype] (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) = + def apply(idx: Int): T = ct.box(arr(idx)) def update(idx: Int, elem: T) = @@ -375,12 +421,16 @@ final class VCBooleanArray[T <: VCBooleanPrototype] private (val arr: Array[Bool } override def toString: String = { - "[" + ct.runtimeClass + "[" + ct.toString } } -abstract class VCCharPrototype(val underlying: Char) extends VCPrototype {} +abstract class VCCharPrototype(val underlying: Char) extends VCPrototype { + override def hashCode(): Int = { + underlying.hashCode() + } +} abstract class VCCharCasePrototype(underlying: Char) extends VCCharPrototype(underlying) with Product1[Char] { @@ -390,34 +440,35 @@ abstract class VCCharCasePrototype(underlying: Char) extends VCCharPrototype(und underlying.hashCode() } - override final def toString: String = { + override def toString: String = { s"$productPrefix($underlying)" } // subclasses are expected to implement equals, productPrefix, and canEqual } -abstract class VCCharCompanion[T <: VCCharPrototype] extends ClassTag[T] { +abstract class VCCharCompanion[T /*<: VCCharPrototype*/] extends ClassTag[T] { def box(underlying: Char): T - final def unbox(boxed: T) = boxed.underlying + final def unbox(boxed: T) = boxed.asInstanceOf[VCCharPrototype].underlying implicit def classTag: this.type = this override def newArray(len: Int): Array[T] = - new VCCharArray(this, len).asInstanceOf[Array[T]] + new VCCharArray(this.asInstanceOf[VCCharCompanion[VCCharPrototype]], len).asInstanceOf[Array[T]] + override def wrap: ClassTag[Array[T]] = ClassTag[Array[T]](this.newArray(0).getClass) - 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 _1$extension(underlying: Char) = underlying + def hashCode$extension(underlying: Char) = underlying.hashCode() + 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]) +final class VCCharArray[T <: VCCharPrototype] (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) = + def apply(idx: Int): T = ct.box(arr(idx)) def update(idx: Int, elem: T) = arr(idx) = ct.unbox(elem) @@ -428,12 +479,16 @@ final class VCCharArray[T <: VCCharPrototype] private (val arr: Array[Char], val } override def toString: String = { - "[" + ct.runtimeClass + "[" + ct.toString } } -abstract class VCBytePrototype(val underlying: Byte) extends VCPrototype {} +abstract class VCBytePrototype(val underlying: Byte) extends VCPrototype { + override def hashCode(): Int = { + underlying.hashCode() + } +} abstract class VCByteCasePrototype(underlying: Byte) extends VCBytePrototype(underlying) with Product1[Byte] { @@ -443,32 +498,33 @@ abstract class VCByteCasePrototype(underlying: Byte) extends VCBytePrototype(und underlying.hashCode() } - override final def toString: String = { + override def toString: String = { s"$productPrefix($underlying)" } } -abstract class VCByteCompanion[T <: VCBytePrototype] extends ClassTag[T] { +abstract class VCByteCompanion[T /*<: VCBytePrototype*/] extends ClassTag[T] { def box(underlying: Byte): T - final def unbox(boxed: T) = boxed.underlying + final def unbox(boxed: T) = boxed.asInstanceOf[VCBytePrototype].underlying implicit def classTag: this.type = this override def newArray(len: Int): Array[T] = - new VCByteArray(this, len).asInstanceOf[Array[T]] + new VCByteArray(this.asInstanceOf[VCByteCompanion[VCBytePrototype]], len).asInstanceOf[Array[T]] + override def wrap: ClassTag[Array[T]] = ClassTag[Array[T]](this.newArray(0).getClass) - 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 _1$extension(underlying: Byte) = underlying + def hashCode$extension(underlying: Byte) = underlying.hashCode() + 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]) +final class VCByteArray[T <: VCBytePrototype] (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) = + def apply(idx: Int): T = ct.box(arr(idx)) def update(idx: Int, elem: T) = arr(idx) = ct.unbox(elem) @@ -479,7 +535,7 @@ final class VCByteArray[T <: VCBytePrototype] private (val arr: Array[Byte], val } override def toString: String = { - "[" + ct.runtimeClass + "[" + ct.toString } } diff --git a/src/dotty/runtime/vc/VCWrappedArray.scala b/src/dotty/runtime/vc/VCWrappedArray.scala new file mode 100644 index 000000000000..3b4d7dd9b69c --- /dev/null +++ b/src/dotty/runtime/vc/VCWrappedArray.scala @@ -0,0 +1,26 @@ +package dotty.runtime.vc + +import scala.collection.mutable.WrappedArray +import scala.reflect.ClassTag + +class VCWrappedArray[T](xs: Array[T]) extends WrappedArray[T] { + val array = xs + lazy val elemTag = (xs.asInstanceOf[Object]: @unchecked) match { + case vc: VCIntArray[_] => vc.ct.asInstanceOf[ClassTag[T]] + case vc: VCShortArray[_] => vc.ct.asInstanceOf[ClassTag[T]] + case vc: VCLongArray[_] => vc.ct.asInstanceOf[ClassTag[T]] + case vc: VCFloatArray[_] => vc.ct.asInstanceOf[ClassTag[T]] + case vc: VCDoubleArray[_] => vc.ct.asInstanceOf[ClassTag[T]] + case vc: VCByteArray[_] => vc.ct.asInstanceOf[ClassTag[T]] + case vc: VCBooleanArray[_] => vc.ct.asInstanceOf[ClassTag[T]] + case vc: VCCharArray[_] => vc.ct.asInstanceOf[ClassTag[T]] + case vc: VCObjectArray[_] => vc.ct.asInstanceOf[ClassTag[T]] + } + //lazy val elemTag = ClassTag[T](arrayElementClass(array.getClass)) + + def length: Int = array.length + def apply(index: Int): T = array(index) + def update(index: Int, elem: T) = { + array(index) = elem + } +} \ No newline at end of file diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala index 2ddd817185d2..a7d6fbc9f914 100644 --- a/src/dotty/tools/dotc/Compiler.scala +++ b/src/dotty/tools/dotc/Compiler.scala @@ -54,6 +54,7 @@ class Compiler { new NormalizeFlags, // Rewrite some definition flags new ExtensionMethods, // Expand methods of value classes with extension methods new ExpandSAMs, // Expand single abstract method closures to anonymous classes + new VCParents, // Inherit value classes from VCXPrototype new TailRec, // Rewrite tail recursion to loops new LiftTry, // Put try expressions that might execute on non-empty stacks into their own methods new ClassOf), // Expand `Predef.classOf` calls. @@ -72,6 +73,7 @@ class Compiler { new ResolveSuper, // Implement super accessors and add forwarders to trait methods new ArrayConstructors), // Intercept creation of (non-generic) arrays and intrinsify. List(new Erasure), // Rewrite types to JVM model, erasing all type parameters, abstract types and refinements. + List(new VCArrays), // Rewrite arrays of value classes. TODO: change to mini phase List(new ElimErasedValueType, // Expand erased value types to their underlying implmementation types new VCElideAllocations, // Peep-hole optimization to eliminate unnecessary value class allocations new Mixin, // Expand trait fields and trait initializers diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala index 5cb373cfd0a1..ba5fd523e88c 100644 --- a/src/dotty/tools/dotc/core/Definitions.scala +++ b/src/dotty/tools/dotc/core/Definitions.scala @@ -4,6 +4,7 @@ package core import Types._, Contexts._, Symbols._, Denotations._, SymDenotations._, StdNames._, Names._ import Flags._, Scopes._, Decorators._, NameOps._, util.Positions._, Periods._ +import transform.ValueClasses import unpickleScala2.Scala2Unpickler.ensureConstructor import scala.annotation.{ switch, meta } import scala.collection.{ mutable, immutable } @@ -774,6 +775,50 @@ class Definitions { /** The type of the boxed class corresponding to primitive value type `tp`. */ def boxedType(tp: Type)(implicit ctx: Context): TypeRef = boxedTypes(scalaClassName(tp)) + lazy val vcPrototypeTypeKeys: collection.Set[TypeRef] = + defn.ScalaNumericValueTypes + defn.BooleanType + defn.ObjectType + + lazy val vcPrototypeTypes: Map[TypeName, TypeRef] = + vcPrototypeTypeKeys.map(vc => vc.name -> ctx.requiredClassRef(s"dotty.runtime.vc.VC${vc.name}Prototype")).toMap + lazy val vcCompanionTypes: Map[TypeName, TypeRef] = + vcPrototypeTypeKeys.map(vc => vc.name -> ctx.requiredClassRef(s"dotty.runtime.vc.VC${vc.name}Companion")).toMap + lazy val vcArrayTypes: Map[TypeName, TypeRef] = + vcPrototypeTypeKeys.map(vc => vc.name -> ctx.requiredClassRef(s"dotty.runtime.vc.VC${vc.name}Array")).toMap + + //TODO: rewrite + def vcPrototypeValues(implicit ctx: Context): Set[Symbol] = vcPrototypeTypes.values.toSet map {tr: TypeRef => tr.classSymbol} + + lazy val VCArrayPrototypeType = ctx.requiredClassRef(s"dotty.runtime.vc.VCArrayPrototype") + def VCArrayPrototypeClass(implicit ctx: Context) = VCArrayPrototypeType.classSymbol + + lazy val VCPrototypeType = ctx.requiredClassRef(s"dotty.runtime.vc.VCPrototype") + def VCPrototypeClass(implicit ctx: Context) = VCPrototypeType.classSymbol + + def vcRepresentationOf (vcReprs: Map[TypeName, TypeRef], vc: ClassDenotation)( + undFn: ClassDenotation => Symbol)(implicit ctx: Context): Symbol = { + val underlying = undFn(vc) + (if (underlying.isPrimitiveValueClass && vcReprs.isDefinedAt(underlying.name.asTypeName)) + vcReprs(underlying.name.asTypeName) else vcReprs(defn.ObjectType.name)).classSymbol + } + + def vcPrototypeOf(vc: ClassDenotation)(implicit ctx: Context) = vcRepresentationOf(vcPrototypeTypes, vc)( + ValueClasses.underlyingOfValueClass(_).classSymbol) + + def vcDeepPrototypeOf(vc: ClassDenotation)(implicit ctx: Context) = vcRepresentationOf(vcPrototypeTypes, vc)( + ValueClasses.deepUnderlyingOfValueClass(_).classSymbol) + + def vcCompanionOf(vc: ClassDenotation)(implicit ctx: Context) = vcRepresentationOf(vcCompanionTypes, vc)( + ValueClasses.underlyingOfValueClass(_).classSymbol) + + def vcDeepCompanionOf(vc: ClassDenotation)(implicit ctx: Context) = vcRepresentationOf(vcCompanionTypes, vc)( + ValueClasses.deepUnderlyingOfValueClass(_).classSymbol) + + def vcArrayOf(vc: ClassDenotation)(implicit ctx: Context) = vcRepresentationOf(vcArrayTypes, vc)( + ValueClasses.underlyingOfValueClass(_).classSymbol) + + def vcDeepArrayOf(vc: ClassDenotation)(implicit ctx: Context) = vcRepresentationOf(vcArrayTypes, vc)( + ValueClasses.deepUnderlyingOfValueClass(_).classSymbol) + def wrapArrayMethodName(elemtp: Type): TermName = { val cls = elemtp.classSymbol if (cls.isPrimitiveValueClass) nme.wrapXArray(cls.name) diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala index 81f6da0e2c57..39b269f935cf 100644 --- a/src/dotty/tools/dotc/core/StdNames.scala +++ b/src/dotty/tools/dotc/core/StdNames.scala @@ -228,6 +228,7 @@ object StdNames { // Compiler-internal val ANYname: N = "" + val ARR: N = "arr" val CONSTRUCTOR: N = Names.CONSTRUCTOR.toString val DEFAULT_CASE: N = "defaultCase$" val EVT2U: N = "evt2u$" @@ -305,6 +306,9 @@ object StdNames { val ??? = encode("???") val genericWrapArray: N = "genericWrapArray" + val genericWrapArray2: N = "genericWrapArray2" + val genericArrayOps2: N = "genericArrayOps2" + val wrapVCArray: N = "wrapVCArray" def wrapRefArray: N = "wrapRefArray" def wrapXArray(clsName: Name): N = "wrap" + clsName + "Array" diff --git a/src/dotty/tools/dotc/core/TypeErasure.scala b/src/dotty/tools/dotc/core/TypeErasure.scala index 39d02e069ca7..907fd9d90ef9 100644 --- a/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/src/dotty/tools/dotc/core/TypeErasure.scala @@ -386,8 +386,10 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean private def eraseArray(tp: RefinedType)(implicit ctx: Context) = { val defn.ArrayOf(elemtp) = tp + // Arrays are semi-erased to ErasedValueType(V, U)[] and fully erased in + // VCArrays def arrayErasure(tpToErase: Type) = - erasureFn(isJava, semiEraseVCs = false, isConstructor, wildcardOK)(tpToErase) + erasureFn(isJava, semiEraseVCs = true, isConstructor, wildcardOK)(tpToErase) if (elemtp derivesFrom defn.NullClass) JavaArrayType(defn.ObjectType) else if (isUnboundedGeneric(elemtp)) defn.ObjectType else JavaArrayType(arrayErasure(elemtp)) diff --git a/src/dotty/tools/dotc/transform/ElimErasedValueType.scala b/src/dotty/tools/dotc/transform/ElimErasedValueType.scala index a3f8b56ff3b5..ceed26e9c170 100644 --- a/src/dotty/tools/dotc/transform/ElimErasedValueType.scala +++ b/src/dotty/tools/dotc/transform/ElimErasedValueType.scala @@ -15,6 +15,7 @@ import TypeErasure.ErasedValueType, ValueClasses._ class ElimErasedValueType extends MiniPhaseTransform with InfoTransformer { import tpd._ + import ElimErasedValueType._ override def phaseName: String = "elimErasedValueType" @@ -40,17 +41,6 @@ class ElimErasedValueType extends MiniPhaseTransform with InfoTransformer { elimEVT(tp) } - def elimEVT(tp: Type)(implicit ctx: Context): Type = tp match { - case ErasedValueType(_, underlying) => - elimEVT(underlying) - case tp: MethodType => - val paramTypes = tp.paramTypes.mapConserve(elimEVT) - val retType = elimEVT(tp.resultType) - tp.derivedMethodType(tp.paramNames, paramTypes, retType) - case _ => - tp - } - def transformTypeOfTree(tree: Tree)(implicit ctx: Context): Tree = tree.withType(elimEVT(tree.tpe)) @@ -79,3 +69,16 @@ class ElimErasedValueType extends MiniPhaseTransform with InfoTransformer { override def transformTypeTree(tree: TypeTree)(implicit ctx: Context, info: TransformerInfo): Tree = transformTypeOfTree(tree) } + +object ElimErasedValueType { + def elimEVT(tp: Type)(implicit ctx: Context): Type = tp match { + case ErasedValueType(_, underlying) => + elimEVT(underlying) + case tp: MethodType => + val paramTypes = tp.paramTypes.mapConserve(elimEVT) + val retType = elimEVT(tp.resultType) + tp.derivedMethodType(tp.paramNames, paramTypes, retType) + case _ => + tp + } +} diff --git a/src/dotty/tools/dotc/transform/ExtensionMethods.scala b/src/dotty/tools/dotc/transform/ExtensionMethods.scala index 8d61cef42173..117d0e751b3e 100644 --- a/src/dotty/tools/dotc/transform/ExtensionMethods.scala +++ b/src/dotty/tools/dotc/transform/ExtensionMethods.scala @@ -72,27 +72,12 @@ class ExtensionMethods extends MiniPhaseTransform with DenotTransformer with Ful val evt2uSym = ctx.newSymbol(moduleSym, nme.EVT2U, Synthetic | Method, MethodType(List(nme.x_0), List(evt), underlying)) - val defn = ctx.definitions - - val underlyingCls = underlying.classSymbol - val underlyingClsName = - if (underlyingCls.isNumericValueClass || underlyingCls == defn.BooleanClass) underlyingCls.name - else nme.Object - - val syp = ctx.requiredClass(s"dotty.runtime.vc.VC${underlyingClsName}Companion").asClass - - newSuperClass = tpd.ref(syp).select(nme.CONSTRUCTOR).appliedToType(valueClass.typeRef).tpe.resultType - decls1.enter(u2evtSym) decls1.enter(evt2uSym) } - // Add the extension methods, the cast methods u2evt$ and evt2u$, and a VC*Companion superclass - moduleClassSym.copySymDenotation(info = - cinfo.derivedClassInfo( - // FIXME: use of VC*Companion superclasses is disabled until the conflicts with SyntheticMethods are solved. - //classParents = ctx.normalizeToClassRefs(List(newSuperClass), moduleSym, decls1), - decls = decls1)) + // Add the extension methods, the cast methods u2evt$ and evt2u$ + moduleClassSym.copySymDenotation(info = cinfo.derivedClassInfo(decls = decls1)) case _ => moduleClassSym } diff --git a/src/dotty/tools/dotc/transform/SeqLiterals.scala b/src/dotty/tools/dotc/transform/SeqLiterals.scala index 49ea695300bb..3575e64dbc29 100644 --- a/src/dotty/tools/dotc/transform/SeqLiterals.scala +++ b/src/dotty/tools/dotc/transform/SeqLiterals.scala @@ -7,7 +7,7 @@ import dotty.tools.dotc.transform.TreeTransforms._ import Contexts.Context import Symbols._ import Phases._ -import Decorators._ +import Decorators._, ValueClasses._ /** A transformer that eliminates SeqLiteral's, transforming `SeqLiteral(elems)` to an operation * equivalent to @@ -36,13 +36,20 @@ class SeqLiterals extends MiniPhaseTransform { //println(i"trans seq $tree, arr = $arr: ${arr.tpe} ${arr.tpe.elemType}") val elemtp = tree.elemtpt.tpe val elemCls = elemtp.classSymbol - val (wrapMethStr, targs) = - if (elemCls.isPrimitiveValueClass) (s"wrap${elemCls.name}Array", Nil) - else if (elemtp derivesFrom defn.ObjectClass) ("wrapRefArray", elemtp :: Nil) - else ("genericWrapArray", elemtp :: Nil) - ref(defn.ScalaPredefModule) - .select(wrapMethStr.toTermName) - .appliedToTypes(targs) - .appliedTo(arr) + if (isDerivedValueClass(elemCls)) { + ref(defn.DottyPredefModule) + .select("wrapVCArray".toTermName) + .appliedToTypes(List(elemtp)) + .appliedTo(arr) + } else { + val (wrapMethStr, targs) = + if (elemCls.isPrimitiveValueClass) (s"wrap${elemCls.name}Array", Nil) + else if (elemtp derivesFrom defn.ObjectClass) ("wrapRefArray", elemtp :: Nil) + else ("genericWrapArray", elemtp :: Nil) + ref(defn.ScalaPredefModule) + .select(wrapMethStr.toTermName) + .appliedToTypes(targs) + .appliedTo(arr) + } } } diff --git a/src/dotty/tools/dotc/transform/SyntheticMethods.scala b/src/dotty/tools/dotc/transform/SyntheticMethods.scala index 9dfd92fe9f2c..d5a50149b24d 100644 --- a/src/dotty/tools/dotc/transform/SyntheticMethods.scala +++ b/src/dotty/tools/dotc/transform/SyntheticMethods.scala @@ -32,7 +32,6 @@ import scala.language.postfixOps * implementation already exists: * * def equals(other: Any): Boolean - * def hashCode(): Int */ class SyntheticMethods(thisTransformer: DenotTransformer) { import ast.tpd._ @@ -42,8 +41,9 @@ class SyntheticMethods(thisTransformer: DenotTransformer) { private def initSymbols(implicit ctx: Context) = if (myValueSymbols.isEmpty) { - myValueSymbols = List(defn.Any_hashCode, defn.Any_equals) - myCaseSymbols = myValueSymbols ++ List(defn.Any_toString, defn.Product_canEqual, + myValueSymbols = List(defn.Any_equals) + //Any_hashCode should be in myCaseSymbols + myCaseSymbols = myValueSymbols ++ List(defn.Any_toString, defn.Any_hashCode, defn.Product_canEqual, defn.Product_productArity, defn.Product_productPrefix) } diff --git a/src/dotty/tools/dotc/transform/VCArrays.scala b/src/dotty/tools/dotc/transform/VCArrays.scala new file mode 100644 index 000000000000..fa9c8455f796 --- /dev/null +++ b/src/dotty/tools/dotc/transform/VCArrays.scala @@ -0,0 +1,190 @@ +package dotty.tools.dotc +package transform + +import ast.{Trees, tpd} +import core._, core.Decorators._ +import Contexts._, Trees._, Types._, StdNames._, Symbols._ +import Constants.Constant +import DenotTransformers._, TreeTransforms._, Phases.Phase +import TypeErasure.ErasedValueType, ValueClasses._ +import dotty.tools.dotc.core.SymDenotations.ClassDenotation +import ElimErasedValueType.elimEVT + +/** This phase erases arrays of value classes to their runtime representation. + * + * For a value class V whose erased underlying type is U, an array of V has type + * Array[V] before Erasure and Array[ErasedValueType(V, U)] afterwards. This phase + * replaces this type by VCXArray where X is "U" if U is a primitive type and is "Object" + * otherwise. + */ +class VCArrays extends MiniPhaseTransform with InfoTransformer { + import tpd._ + + override def phaseName: String = "vcArrays" + + override def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type = eraseVCArrays(tp) + + private def eraseVCArrays(tp: Type)(implicit ctx: Context): Type = { + val transform = new TypeMap { + //TODO: rewrite, don't create new TypeMap for each invocation of eraseVCArrays + def apply(tp: Type) = mapOver { + tp match { + case JavaArrayType(ErasedValueType(tr, eund)) => + val cls = tr.symbol.asClass + defn.vcDeepArrayOf(cls).typeRef + //case tp: MethodType => + //val paramTypes = tp.paramTypes.mapConserve(eraseVCArrays) + //val retType = eraseVCArrays(tp.resultType) + //tp.derivedMethodType(tp.paramNames, paramTypes, retType) + case ErasedValueType(tr, und) => + ErasedValueType(tr, eraseVCArrays(und)) + case _ => + tp + } + } + } + transform(tp) + } + + private def transformTypeOfTree(tree: Tree)(implicit ctx: Context): Tree = + tree.withType(eraseVCArrays(tree.tpe)) + + override def transformValDef(tree: ValDef)(implicit ctx: Context, info: TransformerInfo): Tree = { + val tpt1 = transformTypeOfTree(tree.tpt) + cpy.ValDef(tree)(tpt = tpt1) + } + + override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = { + val vc = tree.symbol.owner.companionClass + val newRhs = tree.name match { + //box body implementation + case _ if tree.name == nme.box && ValueClasses.isDerivedValueClass(tree.symbol.owner.companionClass) && !tree.symbol.is(Flags.Bridge) => + val List(List(param)) = tree.vparamss + val newParam = ref(param.symbol) + val newRhs: Tree = if (param.tpt.symbol.isPrimitiveValueClass) newParam + else New(vc.typeRef, newParam.ensureConforms(elimEVT(ValueClasses.deepUnderlyingOfValueClass(vc.asClass))) :: Nil) + newRhs + case _ => tree.rhs + } + val tpt1 = transformTypeOfTree(tree.tpt) + val newRhs2 = transformTypeOfTree(newRhs) + cpy.DefDef(tree)(tpt = tpt1, rhs = newRhs2) + } + + override def transformTypeApply(tree: TypeApply)(implicit ctx: Context, info: TransformerInfo): Tree = + tree match { +// case TypeApply(sel @ Select(_, _), _) if (sel.symbol == defn.newRefArrayMethod) => +// // Preserve the semi-erased type of the array so that we can properly transform +// // it in transformApply +// tree + case TypeApply(fun, args) => + val tree1 = cpy.TypeApply(tree)(fun, args.map(transformTypeOfTree(_))) + transformTypeOfTree(tree1) + } + + override def transformSeqLiteral(tree: SeqLiteral)(implicit ctx: Context, info: TransformerInfo): Tree = + tree.tpe match { + // [arg1, arg2, ...] => new VCXArray([V.evt2u$(arg1), V.evt2u$(arg2), ...]) + case JavaArrayType(ErasedValueType(tr, tund)) => + val tund2 = elimEVT(tund) + val cls = tr.symbol.asClass + val evt2uMethod = ref(evt2u(cls)) + //[V.evt2u$(arg1), V.evt2u$(arg2), ...] + val underlyingArray = JavaSeqLiteral(tree.elems.map(evt2uMethod.appliedTo(_)), TypeTree(tund2)) + val mod = cls.companionModule + //new VCXArray([V.evt2u$(arg1), V.evt2u$(arg2), ...], VCXCompanion) + New(defn.vcDeepArrayOf(cls).typeRef, List(underlyingArray, ref(mod))) + case _ => + tree match { + case SeqLiteral(elems, tptr) => + cpy.SeqLiteral(tree)(elems, TypeTree(transformTypeOfTree(tptr))) + case _ => tree + } + } + + override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo): Tree = + transformTypeOfTree(tree) + + override def transformTypeTree(tree: TypeTree)(implicit ctx: Context, info: TransformerInfo): Tree = + transformTypeOfTree(tree) + + override def transformBlock(tree: Block)(implicit ctx: Context, info: TransformerInfo): Tree = + transformTypeOfTree(tree) + + override def transformIf(tree: If)(implicit ctx: Context, info: TransformerInfo): Tree = + transformTypeOfTree(tree) + + override def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo): Tree = + transformTypeOfTree(tree) + + override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree = { + def isArrayWithEVT(tpe: Any): Option[ErasedValueType] = + tpe match { + case JavaArrayType(evt@ErasedValueType(tr, underlying)) => Some(evt) + case JavaArrayType(ijat: JavaArrayType) => isArrayWithEVT(ijat) + case _ => None + } + tree match { + // newArray(args) => New VCXArray(newXArray(args'), V) + case ap@Apply(fun, List(compTpt, retTpt, dims @SeqLiteral(elems, elemtpt))) + if (fun.symbol == defn.newArrayMethod) => + val Literal(Constant(ins)) = retTpt + ins match { + case jat@JavaArrayType(ErasedValueType(tr, underlying)) => + val cls = tr.symbol.asClass + val mod = cls.companionModule + val und2 = elimEVT(underlying) + //TODO: und1 should be processed in case of EVT + val und1 = eraseVCArrays(und2) + val arTpe = jat.derivedJavaArrayType(und1) + New(defn.vcDeepArrayOf(cls).typeRef, + List(newArray(und1, arTpe, tree.pos, dims.asInstanceOf[JavaSeqLiteral]).ensureConforms(arTpe), + ref(mod))) + case _: Type => + val evtOpt = isArrayWithEVT(ins) + evtOpt match { + case Some(evt1@ErasedValueType(tr1, und1)) => + val cls = tr1.symbol.asClass + val mod = cls.companionModule + val retTpt2 = eraseVCArrays(ins.asInstanceOf[Type]) + val Literal(Constant(compTptType)) = compTpt + val compTpt2 = eraseVCArrays((elimEVT(compTptType.asInstanceOf[Type]))) + newArray(compTpt2, retTpt2, tree.pos, dims.asInstanceOf[JavaSeqLiteral]) + case _ => + transformTypeOfTree(tree) + } + } + // array.[]update(idx, elem) => array.arr().[]update(idx, elem) + case Apply(Select(array, nme.primitive.arrayUpdate), List(idx, elem)) => + elem.tpe.widen match { + case ErasedValueType(tr, _) => + val cls = tr.symbol.asClass + array.select(nme.ARR).appliedToNone + .select(nme.primitive.arrayUpdate).appliedTo(idx, ref(evt2u(cls)).appliedTo(elem)) + case _ => + tree + } + // array.[]apply(idx) => array.arr().[]apply(idx) + case t@Apply(Select(array, nme.primitive.arrayApply), List(idx)) => + tree.tpe.widen match { + case ErasedValueType(tr, undType) => + val cls = tr.symbol.asClass + if (undType.classSymbol.isPrimitiveValueClass) + ref(u2evt(cls)).appliedTo(array.select(nme.ARR).appliedToNone + .select(nme.primitive.arrayApply).appliedTo(idx)) + else + ref(u2evt(cls)).appliedTo(array.select(nme.ARR).appliedToNone + .select(nme.primitive.arrayApply).appliedTo(idx).ensureConforms(undType)) + case _ => + transformTypeOfTree(tree) + } + // array.[]length() => array.arr().[]length() + case Apply(Select(array, nme.primitive.arrayLength), Nil) + if (array.tpe <:< defn.VCArrayPrototypeType) => + array.select(nme.ARR).appliedToNone + .select(nme.primitive.arrayLength).appliedToNone + case _ => + transformTypeOfTree(tree) + } + } +} \ No newline at end of file diff --git a/src/dotty/tools/dotc/transform/VCParents.scala b/src/dotty/tools/dotc/transform/VCParents.scala new file mode 100644 index 000000000000..e550094958fc --- /dev/null +++ b/src/dotty/tools/dotc/transform/VCParents.scala @@ -0,0 +1,172 @@ +package dotty.tools.dotc +package transform + +import ast.{Trees, tpd} +import core._, core.Decorators._ +import Contexts._, Flags._, Trees._, Types._, StdNames._, Symbols._ +import Constants.Constant +import Denotations._, SymDenotations._ +import DenotTransformers._, TreeTransforms._, Phases.Phase +import ValueClasses._ + +/** This phase makes value classes extend VCXPrototype and make their companions extend VCXCompanion. + * + * (For a value class class V whose erased underlying type is U, X is "U" if U is a primitive + * type and is "Object" otherwise). + * + * Furthermore, this phase also make VCPrototype extend AnyVal instead of AnyRef to preserve the + * invariant that value classes should always extend AnyVal. + */ +class VCParents extends MiniPhaseTransform with DenotTransformer { + import tpd._ + + override def phaseName: String = "vcParents" + + override def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = + ref match { + case moduleClass: ClassDenotation if moduleClass.is(ModuleClass) => + moduleClass.linkedClass match { + case valueClass: ClassSymbol if isDerivedValueClass(valueClass) => + val moduleSym = moduleClass.symbol.asClass + val cinfo = moduleClass.classInfo + val decls1 = cinfo.decls.cloneScope + + val underlying = deepUnderlyingOfValueClass(valueClass) + // TODO: what should we do if these symbols already exist (box and runtimeClassSym)? + val boxParamTpe = if (underlying.classSymbol.isPrimitiveValueClass) underlying else defn.ObjectType + val boxSymTpe = if (underlying.classSymbol.isPrimitiveValueClass) valueClass.typeRef else defn.ObjectType + val boxSym = ctx.newSymbol(moduleClass.symbol, nme.box, + Synthetic | Override | Method, MethodType(List(nme.x_0), List(boxParamTpe), boxSymTpe)) + val runtimeClassSym = ctx.newSymbol(moduleClass.symbol, nme.runtimeClass, + Synthetic | Override | Method, MethodType(Nil, defn.ClassClass.typeRef)) + decls1.enter(boxSym) + decls1.enter(runtimeClassSym) + + val superType = tpd.ref(defn.vcDeepCompanionOf(valueClass)) + .select(nme.CONSTRUCTOR) + .appliedToType(valueClass.typeRef) + .tpe + .resultType + + moduleClass.copySymDenotation(info = + cinfo.derivedClassInfo(decls = decls1, classParents = + ctx.normalizeToClassRefs(List(superType), moduleSym, decls1))) + case _ => + moduleClass + } + case valueClass: ClassDenotation if isDerivedValueClass(valueClass) => + val cinfo = valueClass.classInfo + val superType = defn.vcDeepPrototypeOf(valueClass).typeRef + + val (p :: ps) = cinfo.classParents + //TODO: remove assert to fix issue with i705-inner-value-class.scala + assert(p.isRef(defn.AnyValClass)) + val parents = superType :: ps + valueClass.copySymDenotation(info = cinfo.derivedClassInfo(classParents = parents)) + // This rewiring is required for cases: + // case class Meter(x: Int) extends AnyVal + // val x: AnyVal = Meter(3) //-Ycheck:all + case proto: ClassDenotation if proto.symbol eq defn.VCPrototypeClass => + // After this phase, value classes extend VCXPrototype which extends VCPrototype, + // so we make VCPrototype extend AnyVal to preserve existing subtyping relations. + // We could make VCPrototype extend AnyVal earlier than this phase, but then we + // would need to be careful to not treat it like a real value class. + val cinfo = proto.classInfo + val (p :: ps) = cinfo.classParents + assert(p.isRef(defn.ObjectClass)) + proto.copySymDenotation(info = + cinfo.derivedClassInfo(classParents = defn.AnyValClass.typeRef :: ps)) + case proto: ClassDenotation if defn.vcPrototypeValues.contains(proto.symbol) => + // We need to copy the ClassDenotations of the VCXPrototype classes to reset + // their cache of base classes, the cache is no longer valid because these + // classes extend VCPrototype and we changed the superclass of VCPrototype + // in this phase. + proto.copySymDenotation(info = proto.info) + case _ => + ref + } + + private def boxDefDef(vc: ClassDenotation)(implicit ctx: Context) = { + val sym = vc.linkedClass.info.decl(nme.box).symbol.asTerm + DefDef(sym, ref(defn.ScalaPredefModule).select(nme.???)) + } + + private def runtimeClassDefDef(vc: ClassDenotation)(implicit ctx: Context) = { + val vctp = vc.typeRef + val sym = vc.linkedClass.info.decl(nme.runtimeClass).symbol.asTerm + DefDef(sym, { _ => + Literal(Constant(TypeErasure.erasure(vctp))) + }) + } + + override def transformTemplate(tree: tpd.Template)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = + ctx.owner.denot match { + case moduleClass: ClassDenotation if moduleClass.is(ModuleClass) => + moduleClass.linkedClass match { + case valueClass: ClassSymbol if isDerivedValueClass(valueClass) => + val rcDef = runtimeClassDefDef(valueClass) + val boxDef = boxDefDef(valueClass) + + val superCall = New(defn.vcDeepCompanionOf(valueClass).typeRef) + .select(nme.CONSTRUCTOR) + .appliedToType(valueClass.typeRef) + .appliedToNone + + val (p :: ps) = tree.parents + // TODO: We shouldn't disallow extending companion objects of value classes + // with classes other than AnyRef + assert(p.tpe.isRef(defn.ObjectClass)) + cpy.Template(tree)(parents = superCall :: ps, body = boxDef :: rcDef :: tree.body) + case _ => + tree + } + case valueClass: ClassDenotation if isDerivedValueClass(valueClass) => + val prototype = defn.vcDeepPrototypeOf(valueClass).typeRef + val underlyingSym = valueClassUnbox(valueClass) + + def deepUndExpr(valueClass: Symbol): List[Symbol] = { + val vcMethod = valueClassUnbox(valueClass.asClass) + valueClass match { + case _ if isDerivedValueClass(vcMethod.info.resultType.classSymbol) => + vcMethod :: deepUndExpr(vcMethod.info.resultType.classSymbol) + case _ => List(vcMethod) + } + } + val deepUnderlyingSyms = deepUndExpr(valueClass.symbol) + //TODO: add null checkings + val deepExpr = deepUnderlyingSyms.tail.foldLeft(ref(deepUnderlyingSyms.head))(_.select(_)) + val superCallExpr = if (deepUnderlyingSyms.last.info.classSymbol.isPrimitiveValueClass) deepExpr + else deepExpr.ensureConforms(defn.ObjectType) //ensureConforms is required in case of Any is underlying type (-Ycheck) + val superCall = New(prototype, List(superCallExpr)) + // TODO: manually do parameter forwarding: the prototype has a local field + // so we don't need a field inside the value class + + val (p :: ps) = tree.parents + assert(p.tpe.isRef(defn.AnyValClass)) + cpy.Template(tree)(parents = superCall :: ps) + case _ => + tree + } + + private var scala2ClassTagModule: Symbol = null + private var scala2ClassTagApplyMethod: Symbol = null + + override def prepareForUnit(tree: tpd.Tree)(implicit ctx: Context): TreeTransform = { + scala2ClassTagModule = ctx.requiredModule("scala.reflect.ClassTag") + scala2ClassTagApplyMethod = scala2ClassTagModule.requiredMethod(nme.apply) + this + } + + //change class tag for derived value class, companion is class tag + override def transformApply(tree: tpd.Apply)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = { + tree match { + case Apply(TypeApply(_, tptr :: _), _) if (tree.fun.symbol eq scala2ClassTagApplyMethod) => { + val claz = tptr.tpe.classSymbol + if (ValueClasses.isDerivedValueClass (claz) ) + //TODO: add ensureConforms to fix -Ycheck:all for array of instances of case class X[T](val x: T) extends AnyVal + ref(claz.companionModule).ensureConforms(tree.tpe) else tree + } + case _ => tree + } + } +} \ No newline at end of file diff --git a/src/dotty/tools/dotc/transform/ValueClasses.scala b/src/dotty/tools/dotc/transform/ValueClasses.scala index 93005c57ae26..38956090e7b5 100644 --- a/src/dotty/tools/dotc/transform/ValueClasses.scala +++ b/src/dotty/tools/dotc/transform/ValueClasses.scala @@ -8,6 +8,9 @@ import SymDenotations._ import Contexts._ import Flags._ import StdNames._ +import dotty.runtime.vc._ + +import scala.reflect.ClassTag /** Methods that apply to user-defined value classes */ object ValueClasses { @@ -53,4 +56,23 @@ object ValueClasses { def underlyingOfValueClass(d: ClassDenotation)(implicit ctx: Context): Type = valueClassUnbox(d).info.resultType + def deepUnderlyingOfValueClass(d: ClassDenotation)(implicit ctx: Context): Type = { + import TypeErasure.ErasedValueType + val und = underlyingOfValueClass(d) + und match { + case _ if isDerivedValueClass(und.classSymbol) => deepUnderlyingOfValueClass(und.classSymbol.asClass) + case ErasedValueType(t, und) => + deepUnderlyingOfValueClass(t.classSymbol.asClass) + case _ => und + } + } + + def isVCCompanion[T](ct: ClassTag[T]) = ct match { + case _: VCIntCompanion[_] | _: VCShortCompanion[_] | + _: VCLongCompanion[_] | _: VCByteCompanion[_] | + _: VCBooleanCompanion[_] | _: VCCharCompanion[_] | + _: VCFloatCompanion[_] | _: VCDoubleCompanion[_] | + _: VCObjectCompanion[_] => true + case _ => false + } } diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 4f27912f115d..9fe00ba138d2 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -24,6 +24,7 @@ import ErrorReporting._ import Checking._ import Inferencing._ import EtaExpansion.etaExpand +import dotty.tools.dotc.core.TypeErasure.ErasedValueType import dotty.tools.dotc.transform.Erasure.Boxing import util.Positions._ import util.common._ @@ -845,7 +846,9 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit val proto1 = pt.elemType orElse WildcardType val elems1 = tree.elems mapconserve (typed(_, proto1)) val proto2 = // the computed type of the `elemtpt` field - if (!tree.elemtpt.isEmpty) WildcardType + //ErasedValueType should be elemtpt for SeqLiteral (in case of arrays of value classes) + if (ctx.erasedTypes && proto1.isInstanceOf[ErasedValueType]) proto1 + else if (!tree.elemtpt.isEmpty) WildcardType else if (isFullyDefined(proto1, ForceDegree.none)) proto1 else if (tree.elems.isEmpty && tree.isInstanceOf[Trees.JavaSeqLiteral[_]]) defn.ObjectType // generic empty Java varargs are of type Object[] diff --git a/src/scala/Array.scala b/src/scala/Array.scala new file mode 100644 index 000000000000..39eb758248b2 --- /dev/null +++ b/src/scala/Array.scala @@ -0,0 +1,578 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala + +import scala.collection.generic._ +import scala.collection.{ mutable, immutable } +import mutable.{ ArrayBuilder, ArraySeq } +import scala.compat.Platform.arraycopy +import scala.reflect.ClassTag +import scala.runtime.ScalaRunTime.{ array_apply, array_update } +import dotty.runtime.vc._ + +/** Contains a fallback builder for arrays when the element type + * does not have a class tag. In that case a generic array is built. + */ +class FallbackArrayBuilding { + + /** A builder factory that generates a generic array. + * Called instead of `Array.newBuilder` if the element type of an array + * does not have a class tag. Note that fallbackBuilder factory + * needs an implicit parameter (otherwise it would not be dominated in + * implicit search by `Array.canBuildFrom`). We make sure that + * implicit search is always successful. + */ + implicit def fallbackCanBuildFrom[T](implicit m: DummyImplicit): CanBuildFrom[Array[_], T, ArraySeq[T]] = + new CanBuildFrom[Array[_], T, ArraySeq[T]] { + def apply(from: Array[_]) = ArraySeq.newBuilder[T] + def apply() = ArraySeq.newBuilder[T] + } +} + +/** Utility methods for operating on arrays. + * For example: + * {{{ + * val a = Array(1, 2) + * val b = Array.ofDim[Int](2) + * val c = Array.concat(a, b) + * }}} + * where the array objects `a`, `b` and `c` have respectively the values + * `Array(1, 2)`, `Array(0, 0)` and `Array(1, 2, 0, 0)`. + * + * @author Martin Odersky + * @version 1.0 + */ +object Array extends FallbackArrayBuilding { + val emptyBooleanArray = new Array[Boolean](0) + val emptyByteArray = new Array[Byte](0) + val emptyCharArray = new Array[Char](0) + val emptyDoubleArray = new Array[Double](0) + val emptyFloatArray = new Array[Float](0) + val emptyIntArray = new Array[Int](0) + val emptyLongArray = new Array[Long](0) + val emptyShortArray = new Array[Short](0) + val emptyObjectArray = new Array[Object](0) + + implicit def canBuildFrom[T](implicit t: ClassTag[T]): CanBuildFrom[Array[_], T, Array[T]] = + new CanBuildFrom[Array[_], T, Array[T]] { + def apply(from: Array[_]) = ArrayBuilder.make[T]()(t) + def apply() = ArrayBuilder.make[T]()(t) + } + + /** + * Returns a new [[scala.collection.mutable.ArrayBuilder]]. + */ + def newBuilder[T](implicit t: ClassTag[T]): ArrayBuilder[T] = ArrayBuilder.make[T]()(t) + + private def slowcopy(src : AnyRef, + srcPos : Int, + dest : AnyRef, + destPos : Int, + length : Int): Unit = { + var i = srcPos + var j = destPos + val srcUntil = srcPos + length + while (i < srcUntil) { + array_update(dest, j, array_apply(src, i)) + i += 1 + j += 1 + } + } + + /** Copy one array to another. + * Equivalent to Java's + * `System.arraycopy(src, srcPos, dest, destPos, length)`, + * except that this also works for polymorphic and boxed arrays. + * + * Note that the passed-in `dest` array will be modified by this call. + * + * @param src the source array. + * @param srcPos starting position in the source array. + * @param dest destination array. + * @param destPos starting position in the destination array. + * @param length the number of array elements to be copied. + * + * @see `java.lang.System#arraycopy` + */ + def copy(src: AnyRef, srcPos: Int, dest: AnyRef, destPos: Int, length: Int): Unit = { + val srcClass = src.getClass + if (srcClass.isArray && dest.getClass.isAssignableFrom(srcClass)) + arraycopy(src, srcPos, dest, destPos, length) + else + slowcopy(src, srcPos, dest, destPos, length) + } + + /** Returns an array of length 0 */ + def empty[T: ClassTag]: Array[T] = new Array[T](0) + + /** Creates an array with given elements. + * + * @param xs the elements to put in the array + * @return an array containing all elements from xs. + */ + def apply[T](xs: T*)(implicit ct: ClassTag[T]): Array[T] = { + var i = 0 + val array = new Array[T](xs.length) + xs match { + case vcwra: VCWrappedArray[T] => + (vcwra.array: Object) match { + case vcia: VCIntArray[_] => + val oldUndArr = vcia.arr + val newUndArr = array.asInstanceOf[VCIntArray[_]].arr + for (x <- oldUndArr.iterator) { newUndArr(i) = x; i += 1 } + case vcoa: VCObjectArray[_] => + val oldUndArr = vcoa.arr + val newUndArr = array.asInstanceOf[VCObjectArray[_]].arr + for (x <- oldUndArr.iterator) { newUndArr(i) = x; i += 1 } + case vcba: VCByteArray[_] => + val oldUndArr = vcba.arr + val newUndArr = array.asInstanceOf[VCByteArray[_]].arr + for (x <- oldUndArr.iterator) { newUndArr(i) = x; i += 1 } + case vcboola: VCBooleanArray[_] => + val oldUndArr = vcboola.arr + val newUndArr = array.asInstanceOf[VCBooleanArray[_]].arr + for (x <- oldUndArr.iterator) { newUndArr(i) = x; i += 1 } + case vcla: VCLongArray[_] => + val oldUndArr = vcla.arr + val newUndArr = array.asInstanceOf[VCLongArray[_]].arr + for (x <- oldUndArr.iterator) { newUndArr(i) = x; i += 1 } + case vcfa: VCFloatArray[_] => + val oldUndArr = vcfa.arr + val newUndArr = array.asInstanceOf[VCFloatArray[_]].arr + for (x <- oldUndArr.iterator) { newUndArr(i) = x; i += 1 } + case vcda: VCDoubleArray[_] => + val oldUndArr = vcda.arr + val newUndArr = array.asInstanceOf[VCDoubleArray[_]].arr + for (x <- oldUndArr.iterator) { newUndArr(i) = x; i += 1 } + case vcca: VCCharArray[_] => + val oldUndArr = vcca.arr + val newUndArr = array.asInstanceOf[VCCharArray[_]].arr + for (x <- oldUndArr.iterator) { newUndArr(i) = x; i += 1 } + case vcsa: VCShortArray[_] => + val oldUndArr = vcsa.arr + val newUndArr = array.asInstanceOf[VCShortArray[_]].arr + for (x <- oldUndArr.iterator) { newUndArr(i) = x; i += 1 } + } + case _ => + // Subject to a compiler optimization in Cleanup. + // Array(e0, ..., en) is translated to { val a = new Array(3); a(i) = ei; a } + for (x <- xs.iterator) { array(i) = x; i += 1 } + } + array + } + + /** Creates an array of `Boolean` objects */ + // Subject to a compiler optimization in Cleanup, see above. + def apply(x: Boolean, xs: Boolean*): Array[Boolean] = { + val array = new Array[Boolean](xs.length + 1) + array(0) = x + var i = 1 + for (x <- xs.iterator) { array(i) = x; i += 1 } + array + } + + /** Creates an array of `Byte` objects */ + // Subject to a compiler optimization in Cleanup, see above. + def apply(x: Byte, xs: Byte*): Array[Byte] = { + val array = new Array[Byte](xs.length + 1) + array(0) = x + var i = 1 + for (x <- xs.iterator) { array(i) = x; i += 1 } + array + } + + /** Creates an array of `Short` objects */ + // Subject to a compiler optimization in Cleanup, see above. + def apply(x: Short, xs: Short*): Array[Short] = { + val array = new Array[Short](xs.length + 1) + array(0) = x + var i = 1 + for (x <- xs.iterator) { array(i) = x; i += 1 } + array + } + + /** Creates an array of `Char` objects */ + // Subject to a compiler optimization in Cleanup, see above. + def apply(x: Char, xs: Char*): Array[Char] = { + val array = new Array[Char](xs.length + 1) + array(0) = x + var i = 1 + for (x <- xs.iterator) { array(i) = x; i += 1 } + array + } + + /** Creates an array of `Int` objects */ + // Subject to a compiler optimization in Cleanup, see above. + def apply(x: Int, xs: Int*): Array[Int] = { + val array = new Array[Int](xs.length + 1) + array(0) = x + var i = 1 + for (x <- xs.iterator) { array(i) = x; i += 1 } + array + } + + /** Creates an array of `Long` objects */ + // Subject to a compiler optimization in Cleanup, see above. + def apply(x: Long, xs: Long*): Array[Long] = { + val array = new Array[Long](xs.length + 1) + array(0) = x + var i = 1 + for (x <- xs.iterator) { array(i) = x; i += 1 } + array + } + + /** Creates an array of `Float` objects */ + // Subject to a compiler optimization in Cleanup, see above. + def apply(x: Float, xs: Float*): Array[Float] = { + val array = new Array[Float](xs.length + 1) + array(0) = x + var i = 1 + for (x <- xs.iterator) { array(i) = x; i += 1 } + array + } + + /** Creates an array of `Double` objects */ + // Subject to a compiler optimization in Cleanup, see above. + def apply(x: Double, xs: Double*): Array[Double] = { + val array = new Array[Double](xs.length + 1) + array(0) = x + var i = 1 + for (x <- xs.iterator) { array(i) = x; i += 1 } + array + } + + /** Creates an array of `Unit` objects */ + def apply(x: Unit, xs: Unit*): Array[Unit] = { + val array = new Array[Unit](xs.length + 1) + array(0) = x + var i = 1 + for (x <- xs.iterator) { array(i) = x; i += 1 } + array + } + + /** Creates array with given dimensions */ + def ofDim[T: ClassTag](n1: Int): Array[T] = + new Array[T](n1) + /** Creates a 2-dimensional array */ + def ofDim[T: ClassTag](n1: Int, n2: Int): Array[Array[T]] = { + val arr: Array[Array[T]] = (new Array[Array[T]](n1): Array[Array[T]]) + for (i <- 0 until n1) arr(i) = new Array[T](n2) + arr + // tabulate(n1)(_ => ofDim[T](n2)) + } + /** Creates a 3-dimensional array */ + def ofDim[T: ClassTag](n1: Int, n2: Int, n3: Int): Array[Array[Array[T]]] = + tabulate(n1)(_ => ofDim[T](n2, n3)) + /** Creates a 4-dimensional array */ + def ofDim[T: ClassTag](n1: Int, n2: Int, n3: Int, n4: Int): Array[Array[Array[Array[T]]]] = + tabulate(n1)(_ => ofDim[T](n2, n3, n4)) + /** Creates a 5-dimensional array */ + def ofDim[T: ClassTag](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int): Array[Array[Array[Array[Array[T]]]]] = + tabulate(n1)(_ => ofDim[T](n2, n3, n4, n5)) + + /** Concatenates all arrays into a single array. + * + * @param xss the given arrays + * @return the array created from concatenating `xss` + */ + def concat[T: ClassTag](xss: Array[T]*): Array[T] = { + val b = newBuilder[T] + b.sizeHint(xss.map(_.length).sum) + for (xs <- xss) b ++= xs + b.result() + } + + /** Returns an array that contains the results of some element computation a number + * of times. + * + * Note that this means that `elem` is computed a total of n times: + * {{{ + * scala> Array.fill(3){ math.random } + * res3: Array[Double] = Array(0.365461167592537, 1.550395944913685E-4, 0.7907242137333306) + * }}} + * + * @param n the number of elements desired + * @param elem the element computation + * @return an Array of size n, where each element contains the result of computing + * `elem`. + */ + def fill[T: ClassTag](n: Int)(elem: => T): Array[T] = { + val b = newBuilder[T] + b.sizeHint(n) + var i = 0 + while (i < n) { + b += elem + i += 1 + } + b.result() + } + + /** Returns a two-dimensional array that contains the results of some element + * computation a number of times. + * + * @param n1 the number of elements in the 1st dimension + * @param n2 the number of elements in the 2nd dimension + * @param elem the element computation + */ + def fill[T: ClassTag](n1: Int, n2: Int)(elem: => T): Array[Array[T]] = + tabulate(n1)(_ => fill(n2)(elem)) + + /** Returns a three-dimensional array that contains the results of some element + * computation a number of times. + * + * @param n1 the number of elements in the 1st dimension + * @param n2 the number of elements in the 2nd dimension + * @param n3 the number of elements in the 3nd dimension + * @param elem the element computation + */ + def fill[T: ClassTag](n1: Int, n2: Int, n3: Int)(elem: => T): Array[Array[Array[T]]] = + tabulate(n1)(_ => fill(n2, n3)(elem)) + + /** Returns a four-dimensional array that contains the results of some element + * computation a number of times. + * + * @param n1 the number of elements in the 1st dimension + * @param n2 the number of elements in the 2nd dimension + * @param n3 the number of elements in the 3nd dimension + * @param n4 the number of elements in the 4th dimension + * @param elem the element computation + */ + def fill[T: ClassTag](n1: Int, n2: Int, n3: Int, n4: Int)(elem: => T): Array[Array[Array[Array[T]]]] = + tabulate(n1)(_ => fill(n2, n3, n4)(elem)) + + /** Returns a five-dimensional array that contains the results of some element + * computation a number of times. + * + * @param n1 the number of elements in the 1st dimension + * @param n2 the number of elements in the 2nd dimension + * @param n3 the number of elements in the 3nd dimension + * @param n4 the number of elements in the 4th dimension + * @param n5 the number of elements in the 5th dimension + * @param elem the element computation + */ + def fill[T: ClassTag](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int)(elem: => T): Array[Array[Array[Array[Array[T]]]]] = + tabulate(n1)(_ => fill(n2, n3, n4, n5)(elem)) + + /** Returns an array containing values of a given function over a range of integer + * values starting from 0. + * + * @param n The number of elements in the array + * @param f The function computing element values + * @return A traversable consisting of elements `f(0),f(1), ..., f(n - 1)` + */ + def tabulate[T: ClassTag](n: Int)(f: Int => T): Array[T] = { + val b = newBuilder[T] + b.sizeHint(n) + var i = 0 + while (i < n) { + b += f(i) + i += 1 + } + b.result() + } + + /** Returns a two-dimensional array containing values of a given function + * over ranges of integer values starting from `0`. + * + * @param n1 the number of elements in the 1st dimension + * @param n2 the number of elements in the 2nd dimension + * @param f The function computing element values + */ + def tabulate[T: ClassTag](n1: Int, n2: Int)(f: (Int, Int) => T): Array[Array[T]] = + tabulate(n1)(i1 => tabulate(n2)(f(i1, _))) + + /** Returns a three-dimensional array containing values of a given function + * over ranges of integer values starting from `0`. + * + * @param n1 the number of elements in the 1st dimension + * @param n2 the number of elements in the 2nd dimension + * @param n3 the number of elements in the 3rd dimension + * @param f The function computing element values + */ + def tabulate[T: ClassTag](n1: Int, n2: Int, n3: Int)(f: (Int, Int, Int) => T): Array[Array[Array[T]]] = + tabulate(n1)(i1 => tabulate(n2, n3)(f(i1, _, _))) + + /** Returns a four-dimensional array containing values of a given function + * over ranges of integer values starting from `0`. + * + * @param n1 the number of elements in the 1st dimension + * @param n2 the number of elements in the 2nd dimension + * @param n3 the number of elements in the 3rd dimension + * @param n4 the number of elements in the 4th dimension + * @param f The function computing element values + */ + def tabulate[T: ClassTag](n1: Int, n2: Int, n3: Int, n4: Int)(f: (Int, Int, Int, Int) => T): Array[Array[Array[Array[T]]]] = + tabulate(n1)(i1 => tabulate(n2, n3, n4)(f(i1, _, _, _))) + + /** Returns a five-dimensional array containing values of a given function + * over ranges of integer values starting from `0`. + * + * @param n1 the number of elements in the 1st dimension + * @param n2 the number of elements in the 2nd dimension + * @param n3 the number of elements in the 3rd dimension + * @param n4 the number of elements in the 4th dimension + * @param n5 the number of elements in the 5th dimension + * @param f The function computing element values + */ + def tabulate[T: ClassTag](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int)(f: (Int, Int, Int, Int, Int) => T): Array[Array[Array[Array[Array[T]]]]] = + tabulate(n1)(i1 => tabulate(n2, n3, n4, n5)(f(i1, _, _, _, _))) + + /** Returns an array containing a sequence of increasing integers in a range. + * + * @param start the start value of the array + * @param end the end value of the array, exclusive (in other words, this is the first value '''not''' returned) + * @return the array with values in range `start, start + 1, ..., end - 1` + * up to, but excluding, `end`. + */ + def range(start: Int, end: Int): Array[Int] = range(start, end, 1) + + /** Returns an array containing equally spaced values in some integer interval. + * + * @param start the start value of the array + * @param end the end value of the array, exclusive (in other words, this is the first value '''not''' returned) + * @param step the increment value of the array (may not be zero) + * @return the array with values in `start, start + step, ...` up to, but excluding `end` + */ + def range(start: Int, end: Int, step: Int): Array[Int] = { + if (step == 0) throw new IllegalArgumentException("zero step") + val b = newBuilder[Int] + b.sizeHint(immutable.Range.count(start, end, step, isInclusive = false)) + + var i = start + while (if (step < 0) end < i else i < end) { + b += i + i += step + } + b.result() + } + + /** Returns an array containing repeated applications of a function to a start value. + * + * @param start the start value of the array + * @param len the number of elements returned by the array + * @param f the function that is repeatedly applied + * @return the array returning `len` values in the sequence `start, f(start), f(f(start)), ...` + */ + def iterate[T: ClassTag](start: T, len: Int)(f: T => T): Array[T] = { + val b = newBuilder[T] + + if (len > 0) { + b.sizeHint(len) + var acc = start + var i = 1 + b += acc + + while (i < len) { + acc = f(acc) + i += 1 + b += acc + } + } + b.result() + } + + /** Called in a pattern match like `{ case Array(x,y,z) => println('3 elements')}`. + * + * @param x the selector value + * @return sequence wrapped in a [[scala.Some]], if `x` is a Seq, otherwise `None` + */ + def unapplySeq[T](x: Array[T]): Option[IndexedSeq[T]] = + if (x == null) None else Some(x.toIndexedSeq) + // !!! the null check should to be necessary, but without it 2241 fails. Seems to be a bug + // in pattern matcher. @PP: I noted in #4364 I think the behavior is correct. +} + +/** Arrays are mutable, indexed collections of values. `Array[T]` is Scala's representation + * for Java's `T[]`. + * + * {{{ + * val numbers = Array(1, 2, 3, 4) + * val first = numbers(0) // read the first element + * numbers(3) = 100 // replace the 4th array element with 100 + * val biggerNumbers = numbers.map(_ * 2) // multiply all numbers by two + * }}} + * + * Arrays make use of two common pieces of Scala syntactic sugar, shown on lines 2 and 3 of the above + * example code. + * Line 2 is translated into a call to `apply(Int)`, while line 3 is translated into a call to + * `update(Int, T)`. + * + * Two implicit conversions exist in [[scala.Predef]] that are frequently applied to arrays: a conversion + * to [[scala.collection.mutable.ArrayOps]] (shown on line 4 of the example above) and a conversion + * to [[scala.collection.mutable.WrappedArray]] (a subtype of [[scala.collection.Seq]]). + * Both types make available many of the standard operations found in the Scala collections API. + * The conversion to `ArrayOps` is temporary, as all operations defined on `ArrayOps` return an `Array`, + * while the conversion to `WrappedArray` is permanent as all operations return a `WrappedArray`. + * + * The conversion to `ArrayOps` takes priority over the conversion to `WrappedArray`. For instance, + * consider the following code: + * + * {{{ + * val arr = Array(1, 2, 3) + * val arrReversed = arr.reverse + * val seqReversed : Seq[Int] = arr.reverse + * }}} + * + * Value `arrReversed` will be of type `Array[Int]`, with an implicit conversion to `ArrayOps` occurring + * to perform the `reverse` operation. The value of `seqReversed`, on the other hand, will be computed + * by converting to `WrappedArray` first and invoking the variant of `reverse` that returns another + * `WrappedArray`. + * + * @author Martin Odersky + * @version 1.0 + * @see [[http://www.scala-lang.org/docu/files/ScalaReference.pdf Scala Language Specification]], for in-depth information on the transformations the Scala compiler makes on Arrays (Sections 6.6 and 6.15 respectively.) + * @see [[http://docs.scala-lang.org/sips/completed/scala-2-8-arrays.html "Scala 2.8 Arrays"]] the Scala Improvement Document detailing arrays since Scala 2.8. + * @see [[http://docs.scala-lang.org/overviews/collections/arrays.html "The Scala 2.8 Collections' API"]] section on `Array` by Martin Odersky for more information. + * @define coll array + * @define Coll `Array` + * @define orderDependent + * @define orderDependentFold + * @define mayNotTerminateInf + * @define willNotTerminateInf + * @define collectExample + * @define undefinedorder + * @define thatinfo the class of the returned collection. In the standard library configuration, + * `That` is either `Array[B]` if an ClassTag is available for B or `ArraySeq[B]` otherwise. + * @define zipthatinfo $thatinfo + * @define bfinfo an implicit value of class `CanBuildFrom` which determines the result class `That` from the current + * representation type `Repr` and the new element type `B`. + */ +final class Array[T](_length: Int) extends java.io.Serializable with java.lang.Cloneable { + + /** The length of the array */ + def length: Int = throw new Error() + + /** The element at given index. + * + * Indices start at `0`; `xs.apply(0)` is the first element of array `xs`. + * Note the indexing syntax `xs(i)` is a shorthand for `xs.apply(i)`. + * + * @param i the index + * @return the element at the given index + * @throws ArrayIndexOutOfBoundsException if `i < 0` or `length <= i` + */ + def apply(i: Int): T = throw new Error() + + /** Update the element at given index. + * + * Indices start at `0`; `xs.update(i, x)` replaces the i^th^ element in the array. + * Note the syntax `xs(i) = x` is a shorthand for `xs.update(i, x)`. + * + * @param i the index + * @param x the value to be written at index `i` + * @throws ArrayIndexOutOfBoundsException if `i < 0` or `length <= i` + */ + def update(i: Int, x: T): Unit = { throw new Error() } + + /** Clone the Array. + * + * @return A clone of the Array. + */ + override def clone(): Array[T] = throw new Error() +} diff --git a/src/scala/Predef.scala b/src/scala/Predef.scala new file mode 100644 index 000000000000..82e078022caa --- /dev/null +++ b/src/scala/Predef.scala @@ -0,0 +1,512 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala + +import scala.collection.{ mutable, immutable, generic } +import immutable.StringOps +import mutable.ArrayOps +import generic.CanBuildFrom +import scala.annotation.{ elidable, implicitNotFound } +import scala.annotation.elidable.ASSERTION +import scala.language.{implicitConversions, existentials} +import scala.io.StdIn +import dotty.runtime.vc.VCArrayPrototype + +/** The `Predef` object provides definitions that are accessible in all Scala + * compilation units without explicit qualification. + * + * === Commonly Used Types === + * Predef provides type aliases for types which are commonly used, such as + * the immutable collection types [[scala.collection.immutable.Map]], + * [[scala.collection.immutable.Set]], and the [[scala.collection.immutable.List]] + * constructors ([[scala.collection.immutable.::]] and + * [[scala.collection.immutable.Nil]]). + * + * === Console I/O === + * Predef provides a number of simple functions for console I/O, such as + * `print`, `println`, `readLine`, `readInt`, etc. These functions are all + * aliases of the functions provided by [[scala.Console]]. + * + * === Assertions === + * + * A set of `assert` functions are provided for use as a way to document + * and dynamically check invariants in code. `assert` statements can be elided + * at runtime by providing the command line argument `-Xdisable-assertions` to + * the `scala` command. + * + * Variants of `assert` intended for use with static analysis tools are also + * provided: `assume`, `require` and `ensuring`. `require` and `ensuring` are + * intended for use as a means of design-by-contract style specification + * of pre- and post-conditions on functions, with the intention that these + * specifications could be consumed by a static analysis tool. For instance, + * + * {{{ + * def addNaturals(nats: List[Int]): Int = { + * require(nats forall (_ >= 0), "List contains negative numbers") + * nats.foldLeft(0)(_ + _) + * } ensuring(_ >= 0) + * }}} + * + * The declaration of `addNaturals` states that the list of integers passed should + * only contain natural numbers (i.e. non-negative), and that the result returned + * will also be natural. `require` is distinct from `assert` in that if the + * condition fails, then the caller of the function is to blame rather than a + * logical error having been made within `addNaturals` itself. `ensures` is a + * form of `assert` that declares the guarantee the function is providing with + * regards to it's return value. + * + * === Implicit Conversions === + * A number of commonly applied implicit conversions are also defined here, and + * in the parent type [[scala.LowPriorityImplicits]]. Implicit conversions + * are provided for the "widening" of numeric values, for instance, converting a + * Short value to a Long value as required, and to add additional higher-order + * functions to Array values. These are described in more detail in the documentation of [[scala.Array]]. + */ +object Predef extends LowPriorityImplicits with DeprecatedPredef { + /** + * Retrieve the runtime representation of a class type. `classOf[T]` is equivalent to + * the class literal `T.class` in Java. + * + * @example {{{ + * val listClass = classOf[List[_]] + * // listClass is java.lang.Class[List[_]] = class scala.collection.immutable.List + * + * val mapIntString = classOf[Map[Int,String]] + * // mapIntString is java.lang.Class[Map[Int,String]] = interface scala.collection.immutable.Map + * }}} + */ + def classOf[T]: Class[T] = null // This is a stub method. The actual implementation is filled in by the compiler. + + type String = java.lang.String + type Class[T] = java.lang.Class[T] + + // miscelleaneous ----------------------------------------------------- + scala.`package` // to force scala package object to be seen. + scala.collection.immutable.List // to force Nil, :: to be seen. + + type Function[-A, +B] = Function1[A, B] + + type Map[A, +B] = immutable.Map[A, B] + type Set[A] = immutable.Set[A] + val Map = immutable.Map + val Set = immutable.Set + + // Manifest types, companions, and incantations for summoning + @annotation.implicitNotFound(msg = "No ClassManifest available for ${T}.") + @deprecated("Use `scala.reflect.ClassTag` instead", "2.10.0") + type ClassManifest[T] = scala.reflect.ClassManifest[T] + // TODO undeprecated until Scala reflection becomes non-experimental + // @deprecated("This notion doesn't have a corresponding concept in 2.10, because scala.reflect.runtime.universe.TypeTag can capture arbitrary types. Use type tags instead of manifests, and there will be no need in opt manifests.", "2.10.0") + type OptManifest[T] = scala.reflect.OptManifest[T] + @annotation.implicitNotFound(msg = "No Manifest available for ${T}.") + // TODO undeprecated until Scala reflection becomes non-experimental + // @deprecated("Use `scala.reflect.ClassTag` (to capture erasures) or scala.reflect.runtime.universe.TypeTag (to capture types) or both instead", "2.10.0") + type Manifest[T] = scala.reflect.Manifest[T] + @deprecated("Use `scala.reflect.ClassTag` instead", "2.10.0") + val ClassManifest = scala.reflect.ClassManifest + // TODO undeprecated until Scala reflection becomes non-experimental + // @deprecated("Use `scala.reflect.ClassTag` (to capture erasures) or scala.reflect.runtime.universe.TypeTag (to capture types) or both instead", "2.10.0") + val Manifest = scala.reflect.Manifest + // TODO undeprecated until Scala reflection becomes non-experimental + // @deprecated("This notion doesn't have a corresponding concept in 2.10, because scala.reflect.runtime.universe.TypeTag can capture arbitrary types. Use type tags instead of manifests, and there will be no need in opt manifests.", "2.10.0") + val NoManifest = scala.reflect.NoManifest + + // TODO undeprecated until Scala reflection becomes non-experimental + // @deprecated("Use scala.reflect.classTag[T] and scala.reflect.runtime.universe.typeTag[T] instead", "2.10.0") + def manifest[T](implicit m: Manifest[T]) = m + @deprecated("Use scala.reflect.classTag[T] instead", "2.10.0") + def classManifest[T](implicit m: ClassManifest[T]) = m + // TODO undeprecated until Scala reflection becomes non-experimental + // @deprecated("This notion doesn't have a corresponding concept in 2.10, because scala.reflect.runtime.universe.TypeTag can capture arbitrary types. Use type tags instead of manifests, and there will be no need in opt manifests.", "2.10.0") + def optManifest[T](implicit m: OptManifest[T]) = m + + // Minor variations on identity functions + def identity[A](x: A): A = x // @see `conforms` for the implicit version + @inline def implicitly[T](implicit e: T) = e // for summoning implicit values from the nether world -- TODO: when dependent method types are on by default, give this result type `e.type`, so that inliner has better chance of knowing which method to inline in calls like `implicitly[MatchingStrategy[Option]].zero` + @inline def locally[T](x: T): T = x // to communicate intent and avoid unmoored statements + + // errors and asserts ------------------------------------------------- + + // !!! Remove this when possible - ideally for 2.11. + // We are stuck with it a while longer because sbt's compiler interface + // still calls it as of 0.12.2. + @deprecated("Use `sys.error(message)` instead", "2.9.0") + def error(message: String): Nothing = sys.error(message) + + /** Tests an expression, throwing an `AssertionError` if false. + * Calls to this method will not be generated if `-Xelide-below` + * is at least `ASSERTION`. + * + * @see elidable + * @param assertion the expression to test + */ + @elidable(ASSERTION) + def assert(assertion: Boolean) { + if (!assertion) + throw new java.lang.AssertionError("assertion failed") + } + + /** Tests an expression, throwing an `AssertionError` if false. + * Calls to this method will not be generated if `-Xelide-below` + * is at least `ASSERTION`. + * + * @see elidable + * @param assertion the expression to test + * @param message a String to include in the failure message + */ + @elidable(ASSERTION) @inline + final def assert(assertion: Boolean, message: => Any) { + if (!assertion) + throw new java.lang.AssertionError("assertion failed: "+ message) + } + + /** Tests an expression, throwing an `AssertionError` if false. + * This method differs from assert only in the intent expressed: + * assert contains a predicate which needs to be proven, while + * assume contains an axiom for a static checker. Calls to this method + * will not be generated if `-Xelide-below` is at least `ASSERTION`. + * + * @see elidable + * @param assumption the expression to test + */ + @elidable(ASSERTION) + def assume(assumption: Boolean) { + if (!assumption) + throw new java.lang.AssertionError("assumption failed") + } + + /** Tests an expression, throwing an `AssertionError` if false. + * This method differs from assert only in the intent expressed: + * assert contains a predicate which needs to be proven, while + * assume contains an axiom for a static checker. Calls to this method + * will not be generated if `-Xelide-below` is at least `ASSERTION`. + * + * @see elidable + * @param assumption the expression to test + * @param message a String to include in the failure message + */ + @elidable(ASSERTION) @inline + final def assume(assumption: Boolean, message: => Any) { + if (!assumption) + throw new java.lang.AssertionError("assumption failed: "+ message) + } + + /** Tests an expression, throwing an `IllegalArgumentException` if false. + * This method is similar to `assert`, but blames the caller of the method + * for violating the condition. + * + * @param requirement the expression to test + */ + def require(requirement: Boolean) { + if (!requirement) + throw new IllegalArgumentException("requirement failed") + } + + /** Tests an expression, throwing an `IllegalArgumentException` if false. + * This method is similar to `assert`, but blames the caller of the method + * for violating the condition. + * + * @param requirement the expression to test + * @param message a String to include in the failure message + */ + @inline final def require(requirement: Boolean, message: => Any) { + if (!requirement) + throw new IllegalArgumentException("requirement failed: "+ message) + } + + /** `???` can be used for marking methods that remain to be implemented. + * @throws NotImplementedError + */ + def ??? : Nothing = throw new NotImplementedError + + // tupling ------------------------------------------------------------ + + @deprecated("Use built-in tuple syntax or Tuple2 instead", "2.11.0") + type Pair[+A, +B] = Tuple2[A, B] + @deprecated("Use built-in tuple syntax or Tuple2 instead", "2.11.0") + object Pair { + def apply[A, B](x: A, y: B) = Tuple2(x, y) + def unapply[A, B](x: Tuple2[A, B]): Option[Tuple2[A, B]] = Some(x) + } + + @deprecated("Use built-in tuple syntax or Tuple3 instead", "2.11.0") + type Triple[+A, +B, +C] = Tuple3[A, B, C] + @deprecated("Use built-in tuple syntax or Tuple3 instead", "2.11.0") + object Triple { + def apply[A, B, C](x: A, y: B, z: C) = Tuple3(x, y, z) + def unapply[A, B, C](x: Tuple3[A, B, C]): Option[Tuple3[A, B, C]] = Some(x) + } + + // implicit classes ----------------------------------------------------- + + implicit final class ArrowAssoc[A](private val self: A) extends AnyVal { + @inline def -> [B](y: B): Tuple2[A, B] = Tuple2(self, y) + def →[B](y: B): Tuple2[A, B] = ->(y) + } + + implicit final class Ensuring[A](private val self: A) extends AnyVal { + def ensuring(cond: Boolean): A = { assert(cond); self } + def ensuring(cond: Boolean, msg: => Any): A = { assert(cond, msg); self } + def ensuring(cond: A => Boolean): A = { assert(cond(self)); self } + def ensuring(cond: A => Boolean, msg: => Any): A = { assert(cond(self), msg); self } + } + + implicit final class StringFormat[A](private val self: A) extends AnyVal { + /** Returns string formatted according to given `format` string. + * Format strings are as for `String.format` + * (@see java.lang.String.format). + */ + @inline def formatted(fmtstr: String): String = fmtstr format self + } + + // TODO: remove, only needed for binary compatibility of 2.11.0-RC1 with 2.11.0-M8 + // note that `private[scala]` becomes `public` in bytecode + private[scala] final class StringAdd[A](private val self: A) extends AnyVal { + def +(other: String): String = String.valueOf(self) + other + } + private[scala] def StringAdd(x: Any): Any = new StringAdd(x) + + // SI-8229 retaining the pre 2.11 name for source compatibility in shadowing this implicit + implicit final class any2stringadd[A](private val self: A) extends AnyVal { + def +(other: String): String = String.valueOf(self) + other + } + + implicit final class RichException(private val self: Throwable) extends AnyVal { + import scala.compat.Platform.EOL + @deprecated("Use Throwable#getStackTrace", "2.11.0") def getStackTraceString = self.getStackTrace().mkString("", EOL, EOL) + } + + implicit final class SeqCharSequence(val __sequenceOfChars: scala.collection.IndexedSeq[Char]) extends CharSequence { + def length: Int = __sequenceOfChars.length + def charAt(index: Int): Char = __sequenceOfChars(index) + def subSequence(start: Int, end: Int): CharSequence = new SeqCharSequence(__sequenceOfChars.slice(start, end)) + override def toString = __sequenceOfChars mkString "" + } + + implicit final class ArrayCharSequence(val __arrayOfChars: Array[Char]) extends CharSequence { + def length: Int = __arrayOfChars.length + def charAt(index: Int): Char = __arrayOfChars(index) + def subSequence(start: Int, end: Int): CharSequence = new runtime.ArrayCharSequence(__arrayOfChars, start, end) + override def toString = __arrayOfChars mkString "" + } + + implicit val StringCanBuildFrom: CanBuildFrom[String, Char, String] = new CanBuildFrom[String, Char, String] { + def apply(from: String) = apply() + def apply() = mutable.StringBuilder.newBuilder + } + + @inline implicit def augmentString(x: String): StringOps = new StringOps(x) + @inline implicit def unaugmentString(x: StringOps): String = x.repr + + // printing ----------------------------------------------------------- + + def print(x: Any) = Console.print(x) + def println() = Console.println() + def println(x: Any) = Console.println(x) + def printf(text: String, xs: Any*) = Console.print(text.format(xs: _*)) + + // views -------------------------------------------------------------- + + implicit def tuple2ToZippedOps[T1, T2](x: (T1, T2)) = new runtime.Tuple2Zipped.Ops(x) + implicit def tuple3ToZippedOps[T1, T2, T3](x: (T1, T2, T3)) = new runtime.Tuple3Zipped.Ops(x) + + implicit def genericArrayOps[T](xs: Array[T]): ArrayOps[T] = (xs match { + case _ if xs.isInstanceOf[VCArrayPrototype[_]] => dotty.DottyPredef.opsVCArray(xs) + case x: Array[AnyRef] => refArrayOps[AnyRef](x) + case x: Array[Boolean] => booleanArrayOps(x) + case x: Array[Byte] => byteArrayOps(x) + case x: Array[Char] => charArrayOps(x) + case x: Array[Double] => doubleArrayOps(x) + case x: Array[Float] => floatArrayOps(x) + case x: Array[Int] => intArrayOps(x) + case x: Array[Long] => longArrayOps(x) + case x: Array[Short] => shortArrayOps(x) + case x: Array[Unit] => unitArrayOps(x) + case null => null + }).asInstanceOf[ArrayOps[T]] + + implicit def booleanArrayOps(xs: Array[Boolean]): ArrayOps[Boolean] = new ArrayOps.ofBoolean(xs) + implicit def byteArrayOps(xs: Array[Byte]): ArrayOps[Byte] = new ArrayOps.ofByte(xs) + implicit def charArrayOps(xs: Array[Char]): ArrayOps[Char] = new ArrayOps.ofChar(xs) + implicit def doubleArrayOps(xs: Array[Double]): ArrayOps[Double] = new ArrayOps.ofDouble(xs) + implicit def floatArrayOps(xs: Array[Float]): ArrayOps[Float] = new ArrayOps.ofFloat(xs) + implicit def intArrayOps(xs: Array[Int]): ArrayOps[Int] = new ArrayOps.ofInt(xs) + implicit def longArrayOps(xs: Array[Long]): ArrayOps[Long] = new ArrayOps.ofLong(xs) + implicit def refArrayOps[T <: AnyRef](xs: Array[T]): ArrayOps[T] = new ArrayOps.ofRef[T](xs) + implicit def shortArrayOps(xs: Array[Short]): ArrayOps[Short] = new ArrayOps.ofShort(xs) + implicit def unitArrayOps(xs: Array[Unit]): ArrayOps[Unit] = new ArrayOps.ofUnit(xs) + + // "Autoboxing" and "Autounboxing" --------------------------------------------------- + + implicit def byte2Byte(x: Byte) = java.lang.Byte.valueOf(x) + implicit def short2Short(x: Short) = java.lang.Short.valueOf(x) + implicit def char2Character(x: Char) = java.lang.Character.valueOf(x) + implicit def int2Integer(x: Int) = java.lang.Integer.valueOf(x) + implicit def long2Long(x: Long) = java.lang.Long.valueOf(x) + implicit def float2Float(x: Float) = java.lang.Float.valueOf(x) + implicit def double2Double(x: Double) = java.lang.Double.valueOf(x) + implicit def boolean2Boolean(x: Boolean) = java.lang.Boolean.valueOf(x) + + implicit def Byte2byte(x: java.lang.Byte): Byte = x.byteValue + implicit def Short2short(x: java.lang.Short): Short = x.shortValue + implicit def Character2char(x: java.lang.Character): Char = x.charValue + implicit def Integer2int(x: java.lang.Integer): Int = x.intValue + implicit def Long2long(x: java.lang.Long): Long = x.longValue + implicit def Float2float(x: java.lang.Float): Float = x.floatValue + implicit def Double2double(x: java.lang.Double): Double = x.doubleValue + implicit def Boolean2boolean(x: java.lang.Boolean): Boolean = x.booleanValue + + // Type Constraints -------------------------------------------------------------- + + /** + * An instance of `A <:< B` witnesses that `A` is a subtype of `B`. + * Requiring an implicit argument of the type `A <:< B` encodes + * the generalized constraint `A <: B`. + * + * @note we need a new type constructor `<:<` and evidence `conforms`, + * as reusing `Function1` and `identity` leads to ambiguities in + * case of type errors (`any2stringadd` is inferred) + * + * To constrain any abstract type T that's in scope in a method's + * argument list (not just the method's own type parameters) simply + * add an implicit argument of type `T <:< U`, where `U` is the required + * upper bound; or for lower-bounds, use: `L <:< T`, where `L` is the + * required lower bound. + * + * In part contributed by Jason Zaugg. + */ + @implicitNotFound(msg = "Cannot prove that ${From} <:< ${To}.") + sealed abstract class <:<[-From, +To] extends (From => To) with Serializable + private[this] final val singleton_<:< = new <:<[Any,Any] { def apply(x: Any): Any = x } + // The dollar prefix is to dodge accidental shadowing of this method + // by a user-defined method of the same name (SI-7788). + // The collections rely on this method. + implicit def $conforms[A]: A <:< A = singleton_<:<.asInstanceOf[A <:< A] + + @deprecated("Use `implicitly[T <:< U]` or `identity` instead.", "2.11.0") + def conforms[A]: A <:< A = $conforms[A] + + /** An instance of `A =:= B` witnesses that the types `A` and `B` are equal. + * + * @see `<:<` for expressing subtyping constraints + */ + @implicitNotFound(msg = "Cannot prove that ${From} =:= ${To}.") + sealed abstract class =:=[From, To] extends (From => To) with Serializable + private[this] final val singleton_=:= = new =:=[Any,Any] { def apply(x: Any): Any = x } + object =:= { + implicit def tpEquals[A]: A =:= A = singleton_=:=.asInstanceOf[A =:= A] + } + + /** A type for which there is always an implicit value. + * @see [[scala.Array$]], method `fallbackCanBuildFrom` + */ + class DummyImplicit + + object DummyImplicit { + + /** An implicit value yielding a `DummyImplicit`. + * @see [[scala.Array$]], method `fallbackCanBuildFrom` + */ + implicit def dummyImplicit: DummyImplicit = new DummyImplicit + } +} + +private[scala] trait DeprecatedPredef { + self: Predef.type => + + // Deprecated stubs for any who may have been calling these methods directly. + @deprecated("Use `ArrowAssoc`", "2.11.0") def any2ArrowAssoc[A](x: A): ArrowAssoc[A] = new ArrowAssoc(x) + @deprecated("Use `Ensuring`", "2.11.0") def any2Ensuring[A](x: A): Ensuring[A] = new Ensuring(x) + @deprecated("Use `StringFormat`", "2.11.0") def any2stringfmt(x: Any): StringFormat[Any] = new StringFormat(x) + @deprecated("Use `Throwable` directly", "2.11.0") def exceptionWrapper(exc: Throwable) = new RichException(exc) + @deprecated("Use `SeqCharSequence`", "2.11.0") def seqToCharSequence(xs: scala.collection.IndexedSeq[Char]): CharSequence = new SeqCharSequence(xs) + @deprecated("Use `ArrayCharSequence`", "2.11.0") def arrayToCharSequence(xs: Array[Char]): CharSequence = new ArrayCharSequence(xs) + + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readLine(): String = StdIn.readLine() + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readLine(text: String, args: Any*) = StdIn.readLine(text, args: _*) + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readBoolean() = StdIn.readBoolean() + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readByte() = StdIn.readByte() + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readShort() = StdIn.readShort() + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readChar() = StdIn.readChar() + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readInt() = StdIn.readInt() + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readLong() = StdIn.readLong() + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readFloat() = StdIn.readFloat() + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readDouble() = StdIn.readDouble() + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readf(format: String) = StdIn.readf(format) + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readf1(format: String) = StdIn.readf1(format) + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readf2(format: String) = StdIn.readf2(format) + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readf3(format: String) = StdIn.readf3(format) +} + +/** The `LowPriorityImplicits` class provides implicit values that + * are valid in all Scala compilation units without explicit qualification, + * but that are partially overridden by higher-priority conversions in object + * `Predef`. + * + * @author Martin Odersky + * @since 2.8 + */ +// SI-7335 Parents of Predef are defined in the same compilation unit to avoid +// cyclic reference errors compiling the standard library *without* a previously +// compiled copy on the classpath. +private[scala] abstract class LowPriorityImplicits { + import mutable.WrappedArray + import immutable.WrappedString + + /** We prefer the java.lang.* boxed types to these wrappers in + * any potential conflicts. Conflicts do exist because the wrappers + * need to implement ScalaNumber in order to have a symmetric equals + * method, but that implies implementing java.lang.Number as well. + * + * Note - these are inlined because they are value classes, but + * the call to xxxWrapper is not eliminated even though it does nothing. + * Even inlined, every call site does a no-op retrieval of Predef's MODULE$ + * because maybe loading Predef has side effects! + */ + @inline implicit def byteWrapper(x: Byte) = new runtime.RichByte(x) + @inline implicit def shortWrapper(x: Short) = new runtime.RichShort(x) + @inline implicit def intWrapper(x: Int) = new runtime.RichInt(x) + @inline implicit def charWrapper(c: Char) = new runtime.RichChar(c) + @inline implicit def longWrapper(x: Long) = new runtime.RichLong(x) + @inline implicit def floatWrapper(x: Float) = new runtime.RichFloat(x) + @inline implicit def doubleWrapper(x: Double) = new runtime.RichDouble(x) + @inline implicit def booleanWrapper(x: Boolean) = new runtime.RichBoolean(x) + + implicit def genericWrapArray[T](xs: Array[T]): WrappedArray[T] = + if (xs eq null) null + else WrappedArray.make(xs) + + // Since the JVM thinks arrays are covariant, one 0-length Array[AnyRef] + // is as good as another for all T <: AnyRef. Instead of creating 100,000,000 + // unique ones by way of this implicit, let's share one. + implicit def wrapRefArray[T <: AnyRef](xs: Array[T]): WrappedArray[T] = { + if (xs eq null) null + else if (xs.length == 0) WrappedArray.empty[T] + else new WrappedArray.ofRef[T](xs) + } + + implicit def wrapIntArray(xs: Array[Int]): WrappedArray[Int] = if (xs ne null) new WrappedArray.ofInt(xs) else null + implicit def wrapDoubleArray(xs: Array[Double]): WrappedArray[Double] = if (xs ne null) new WrappedArray.ofDouble(xs) else null + implicit def wrapLongArray(xs: Array[Long]): WrappedArray[Long] = if (xs ne null) new WrappedArray.ofLong(xs) else null + implicit def wrapFloatArray(xs: Array[Float]): WrappedArray[Float] = if (xs ne null) new WrappedArray.ofFloat(xs) else null + implicit def wrapCharArray(xs: Array[Char]): WrappedArray[Char] = if (xs ne null) new WrappedArray.ofChar(xs) else null + implicit def wrapByteArray(xs: Array[Byte]): WrappedArray[Byte] = if (xs ne null) new WrappedArray.ofByte(xs) else null + implicit def wrapShortArray(xs: Array[Short]): WrappedArray[Short] = if (xs ne null) new WrappedArray.ofShort(xs) else null + implicit def wrapBooleanArray(xs: Array[Boolean]): WrappedArray[Boolean] = if (xs ne null) new WrappedArray.ofBoolean(xs) else null + implicit def wrapUnitArray(xs: Array[Unit]): WrappedArray[Unit] = if (xs ne null) new WrappedArray.ofUnit(xs) else null + + implicit def wrapString(s: String): WrappedString = if (s ne null) new WrappedString(s) else null + implicit def unwrapString(ws: WrappedString): String = if (ws ne null) ws.self else null + + implicit def fallbackStringCanBuildFrom[T]: CanBuildFrom[String, T, immutable.IndexedSeq[T]] = + new CanBuildFrom[String, T, immutable.IndexedSeq[T]] { + def apply(from: String) = immutable.IndexedSeq.newBuilder[T] + def apply() = immutable.IndexedSeq.newBuilder[T] + } +} diff --git a/src/scala/collection/mutable/ArrayBuilder.scala b/src/scala/collection/mutable/ArrayBuilder.scala new file mode 100644 index 000000000000..b2f5e5fb1af8 --- /dev/null +++ b/src/scala/collection/mutable/ArrayBuilder.scala @@ -0,0 +1,704 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala +package collection +package mutable + +import scala.reflect.ClassTag +import scala.runtime.ScalaRunTime +import dotty.runtime.vc.VCArrayBuilder +import dotty.tools.dotc.transform.ValueClasses + +/** A builder class for arrays. + * + * @since 2.8 + * @tparam T the type of the elements for the builder. + */ +abstract class ArrayBuilder[T] extends Builder[T, Array[T]] with Serializable + +/** A companion object for array builders. + * + * @since 2.8 + */ +object ArrayBuilder { + + /** Creates a new arraybuilder of type `T`. + * + * @tparam T type of the elements for the array builder, with a `ClassTag` context bound. + * @return a new empty array builder. + */ + def make[T: ClassTag](): ArrayBuilder[T] = { + val tag = implicitly[ClassTag[T]] + tag.runtimeClass match { + case java.lang.Byte.TYPE => new ArrayBuilder.ofByte().asInstanceOf[ArrayBuilder[T]] + case java.lang.Short.TYPE => new ArrayBuilder.ofShort().asInstanceOf[ArrayBuilder[T]] + case java.lang.Character.TYPE => new ArrayBuilder.ofChar().asInstanceOf[ArrayBuilder[T]] + case java.lang.Integer.TYPE => new ArrayBuilder.ofInt().asInstanceOf[ArrayBuilder[T]] + case java.lang.Long.TYPE => new ArrayBuilder.ofLong().asInstanceOf[ArrayBuilder[T]] + case java.lang.Float.TYPE => new ArrayBuilder.ofFloat().asInstanceOf[ArrayBuilder[T]] + case java.lang.Double.TYPE => new ArrayBuilder.ofDouble().asInstanceOf[ArrayBuilder[T]] + case java.lang.Boolean.TYPE => new ArrayBuilder.ofBoolean().asInstanceOf[ArrayBuilder[T]] + case java.lang.Void.TYPE => new ArrayBuilder.ofUnit().asInstanceOf[ArrayBuilder[T]] + case _ if ValueClasses.isVCCompanion(tag) => new VCArrayBuilder[T]()(tag).asInstanceOf[ArrayBuilder[T]] + case _ => new ArrayBuilder.ofRef[T with AnyRef]()(tag.asInstanceOf[ClassTag[T with AnyRef]]).asInstanceOf[ArrayBuilder[T]] + } + } + + /** A class for array builders for arrays of reference types. + * + * @tparam T type of elements for the array builder, subtype of `AnyRef` with a `ClassTag` context bound. + */ + @deprecatedInheritance("ArrayBuilder.ofRef is an internal implementation not intended for subclassing.", "2.11.0") + class ofRef[T <: AnyRef : ClassTag] extends ArrayBuilder[T] { + + private var elems: Array[T] = _ + private var capacity: Int = 0 + private var size: Int = 0 + + private def mkArray(size: Int): Array[T] = { + val newelems = new Array[T](size) + if (this.size > 0) Array.copy(elems, 0, newelems, 0, this.size) + newelems + } + + private def resize(size: Int) { + elems = mkArray(size) + capacity = size + } + + override def sizeHint(size: Int) { + if (capacity < size) resize(size) + } + + private def ensureSize(size: Int) { + if (capacity < size || capacity == 0) { + var newsize = if (capacity == 0) 16 else capacity * 2 + while (newsize < size) newsize *= 2 + resize(newsize) + } + } + + def +=(elem: T): this.type = { + ensureSize(size + 1) + elems(size) = elem + size += 1 + this + } + + override def ++=(xs: TraversableOnce[T]): this.type = (xs.asInstanceOf[AnyRef]) match { + case xs: WrappedArray.ofRef[_] => + ensureSize(this.size + xs.length) + Array.copy(xs.array, 0, elems, this.size, xs.length) + size += xs.length + this + case _ => + super.++=(xs) + } + + def clear() { + size = 0 + } + + def result() = { + if (capacity != 0 && capacity == size) elems + else mkArray(size) + } + + override def equals(other: Any): Boolean = other match { + case x: ofRef[_] => (size == x.size) && (elems == x.elems) + case _ => false + } + + override def toString = "ArrayBuilder.ofRef" + } + + /** A class for array builders for arrays of `byte`s. */ + @deprecatedInheritance("ArrayBuilder.ofByte is an internal implementation not intended for subclassing.", "2.11.0") + class ofByte extends ArrayBuilder[Byte] { + + private var elems: Array[Byte] = _ + private var capacity: Int = 0 + private var size: Int = 0 + + private def mkArray(size: Int): Array[Byte] = { + val newelems = new Array[Byte](size) + if (this.size > 0) Array.copy(elems, 0, newelems, 0, this.size) + newelems + } + + private def resize(size: Int) { + elems = mkArray(size) + capacity = size + } + + override def sizeHint(size: Int) { + if (capacity < size) resize(size) + } + + private def ensureSize(size: Int) { + if (capacity < size || capacity == 0) { + var newsize = if (capacity == 0) 16 else capacity * 2 + while (newsize < size) newsize *= 2 + resize(newsize) + } + } + + def +=(elem: Byte): this.type = { + ensureSize(size + 1) + elems(size) = elem + size += 1 + this + } + + override def ++=(xs: TraversableOnce[Byte]): this.type = xs match { + case xs: WrappedArray.ofByte => + ensureSize(this.size + xs.length) + Array.copy(xs.array, 0, elems, this.size, xs.length) + size += xs.length + this + case _ => + super.++=(xs) + } + + def clear() { + size = 0 + } + + def result() = { + if (capacity != 0 && capacity == size) elems + else mkArray(size) + } + + override def equals(other: Any): Boolean = other match { + case x: ofByte => (size == x.size) && (elems == x.elems) + case _ => false + } + + override def toString = "ArrayBuilder.ofByte" + } + + /** A class for array builders for arrays of `short`s. */ + @deprecatedInheritance("ArrayBuilder.ofShort is an internal implementation not intended for subclassing.", "2.11.0") + class ofShort extends ArrayBuilder[Short] { + + private var elems: Array[Short] = _ + private var capacity: Int = 0 + private var size: Int = 0 + + private def mkArray(size: Int): Array[Short] = { + val newelems = new Array[Short](size) + if (this.size > 0) Array.copy(elems, 0, newelems, 0, this.size) + newelems + } + + private def resize(size: Int) { + elems = mkArray(size) + capacity = size + } + + override def sizeHint(size: Int) { + if (capacity < size) resize(size) + } + + private def ensureSize(size: Int) { + if (capacity < size || capacity == 0) { + var newsize = if (capacity == 0) 16 else capacity * 2 + while (newsize < size) newsize *= 2 + resize(newsize) + } + } + + def +=(elem: Short): this.type = { + ensureSize(size + 1) + elems(size) = elem + size += 1 + this + } + + override def ++=(xs: TraversableOnce[Short]): this.type = xs match { + case xs: WrappedArray.ofShort => + ensureSize(this.size + xs.length) + Array.copy(xs.array, 0, elems, this.size, xs.length) + size += xs.length + this + case _ => + super.++=(xs) + } + + def clear() { + size = 0 + } + + def result() = { + if (capacity != 0 && capacity == size) elems + else mkArray(size) + } + + override def equals(other: Any): Boolean = other match { + case x: ofShort => (size == x.size) && (elems == x.elems) + case _ => false + } + + override def toString = "ArrayBuilder.ofShort" + } + + /** A class for array builders for arrays of `char`s. */ + @deprecatedInheritance("ArrayBuilder.ofChar is an internal implementation not intended for subclassing.", "2.11.0") + class ofChar extends ArrayBuilder[Char] { + + private var elems: Array[Char] = _ + private var capacity: Int = 0 + private var size: Int = 0 + + private def mkArray(size: Int): Array[Char] = { + val newelems = new Array[Char](size) + if (this.size > 0) Array.copy(elems, 0, newelems, 0, this.size) + newelems + } + + private def resize(size: Int) { + elems = mkArray(size) + capacity = size + } + + override def sizeHint(size: Int) { + if (capacity < size) resize(size) + } + + private def ensureSize(size: Int) { + if (capacity < size || capacity == 0) { + var newsize = if (capacity == 0) 16 else capacity * 2 + while (newsize < size) newsize *= 2 + resize(newsize) + } + } + + def +=(elem: Char): this.type = { + ensureSize(size + 1) + elems(size) = elem + size += 1 + this + } + + override def ++=(xs: TraversableOnce[Char]): this.type = xs match { + case xs: WrappedArray.ofChar => + ensureSize(this.size + xs.length) + Array.copy(xs.array, 0, elems, this.size, xs.length) + size += xs.length + this + case _ => + super.++=(xs) + } + + def clear() { + size = 0 + } + + def result() = { + if (capacity != 0 && capacity == size) elems + else mkArray(size) + } + + override def equals(other: Any): Boolean = other match { + case x: ofChar => (size == x.size) && (elems == x.elems) + case _ => false + } + + override def toString = "ArrayBuilder.ofChar" + } + + /** A class for array builders for arrays of `int`s. */ + @deprecatedInheritance("ArrayBuilder.ofInt is an internal implementation not intended for subclassing.", "2.11.0") + class ofInt extends ArrayBuilder[Int] { + + private var elems: Array[Int] = _ + private var capacity: Int = 0 + private var size: Int = 0 + + private def mkArray(size: Int): Array[Int] = { + val newelems = new Array[Int](size) + if (this.size > 0) Array.copy(elems, 0, newelems, 0, this.size) + newelems + } + + private def resize(size: Int) { + elems = mkArray(size) + capacity = size + } + + override def sizeHint(size: Int) { + if (capacity < size) resize(size) + } + + private def ensureSize(size: Int) { + if (capacity < size || capacity == 0) { + var newsize = if (capacity == 0) 16 else capacity * 2 + while (newsize < size) newsize *= 2 + resize(newsize) + } + } + + def +=(elem: Int): this.type = { + ensureSize(size + 1) + elems(size) = elem + size += 1 + this + } + + override def ++=(xs: TraversableOnce[Int]): this.type = xs match { + case xs: WrappedArray.ofInt => + ensureSize(this.size + xs.length) + Array.copy(xs.array, 0, elems, this.size, xs.length) + size += xs.length + this + case _ => + super.++=(xs) + } + + def clear() { + size = 0 + } + + def result() = { + if (capacity != 0 && capacity == size) elems + else mkArray(size) + } + + override def equals(other: Any): Boolean = other match { + case x: ofInt => (size == x.size) && (elems == x.elems) + case _ => false + } + + override def toString = "ArrayBuilder.ofInt" + } + + /** A class for array builders for arrays of `long`s. */ + @deprecatedInheritance("ArrayBuilder.ofLong is an internal implementation not intended for subclassing.", "2.11.0") + class ofLong extends ArrayBuilder[Long] { + + private var elems: Array[Long] = _ + private var capacity: Int = 0 + private var size: Int = 0 + + private def mkArray(size: Int): Array[Long] = { + val newelems = new Array[Long](size) + if (this.size > 0) Array.copy(elems, 0, newelems, 0, this.size) + newelems + } + + private def resize(size: Int) { + elems = mkArray(size) + capacity = size + } + + override def sizeHint(size: Int) { + if (capacity < size) resize(size) + } + + private def ensureSize(size: Int) { + if (capacity < size || capacity == 0) { + var newsize = if (capacity == 0) 16 else capacity * 2 + while (newsize < size) newsize *= 2 + resize(newsize) + } + } + + def +=(elem: Long): this.type = { + ensureSize(size + 1) + elems(size) = elem + size += 1 + this + } + + override def ++=(xs: TraversableOnce[Long]): this.type = xs match { + case xs: WrappedArray.ofLong => + ensureSize(this.size + xs.length) + Array.copy(xs.array, 0, elems, this.size, xs.length) + size += xs.length + this + case _ => + super.++=(xs) + } + + def clear() { + size = 0 + } + + def result() = { + if (capacity != 0 && capacity == size) elems + else mkArray(size) + } + + override def equals(other: Any): Boolean = other match { + case x: ofLong => (size == x.size) && (elems == x.elems) + case _ => false + } + + override def toString = "ArrayBuilder.ofLong" + } + + /** A class for array builders for arrays of `float`s. */ + @deprecatedInheritance("ArrayBuilder.ofFloat is an internal implementation not intended for subclassing.", "2.11.0") + class ofFloat extends ArrayBuilder[Float] { + + private var elems: Array[Float] = _ + private var capacity: Int = 0 + private var size: Int = 0 + + private def mkArray(size: Int): Array[Float] = { + val newelems = new Array[Float](size) + if (this.size > 0) Array.copy(elems, 0, newelems, 0, this.size) + newelems + } + + private def resize(size: Int) { + elems = mkArray(size) + capacity = size + } + + override def sizeHint(size: Int) { + if (capacity < size) resize(size) + } + + private def ensureSize(size: Int) { + if (capacity < size || capacity == 0) { + var newsize = if (capacity == 0) 16 else capacity * 2 + while (newsize < size) newsize *= 2 + resize(newsize) + } + } + + def +=(elem: Float): this.type = { + ensureSize(size + 1) + elems(size) = elem + size += 1 + this + } + + override def ++=(xs: TraversableOnce[Float]): this.type = xs match { + case xs: WrappedArray.ofFloat => + ensureSize(this.size + xs.length) + Array.copy(xs.array, 0, elems, this.size, xs.length) + size += xs.length + this + case _ => + super.++=(xs) + } + + def clear() { + size = 0 + } + + def result() = { + if (capacity != 0 && capacity == size) elems + else mkArray(size) + } + + override def equals(other: Any): Boolean = other match { + case x: ofFloat => (size == x.size) && (elems == x.elems) + case _ => false + } + + override def toString = "ArrayBuilder.ofFloat" + } + + /** A class for array builders for arrays of `double`s. */ + @deprecatedInheritance("ArrayBuilder.ofDouble is an internal implementation not intended for subclassing.", "2.11.0") + class ofDouble extends ArrayBuilder[Double] { + + private var elems: Array[Double] = _ + private var capacity: Int = 0 + private var size: Int = 0 + + private def mkArray(size: Int): Array[Double] = { + val newelems = new Array[Double](size) + if (this.size > 0) Array.copy(elems, 0, newelems, 0, this.size) + newelems + } + + private def resize(size: Int) { + elems = mkArray(size) + capacity = size + } + + override def sizeHint(size: Int) { + if (capacity < size) resize(size) + } + + private def ensureSize(size: Int) { + if (capacity < size || capacity == 0) { + var newsize = if (capacity == 0) 16 else capacity * 2 + while (newsize < size) newsize *= 2 + resize(newsize) + } + } + + def +=(elem: Double): this.type = { + ensureSize(size + 1) + elems(size) = elem + size += 1 + this + } + + override def ++=(xs: TraversableOnce[Double]): this.type = xs match { + case xs: WrappedArray.ofDouble => + ensureSize(this.size + xs.length) + Array.copy(xs.array, 0, elems, this.size, xs.length) + size += xs.length + this + case _ => + super.++=(xs) + } + + def clear() { + size = 0 + } + + def result() = { + if (capacity != 0 && capacity == size) elems + else mkArray(size) + } + + override def equals(other: Any): Boolean = other match { + case x: ofDouble => (size == x.size) && (elems == x.elems) + case _ => false + } + + override def toString = "ArrayBuilder.ofDouble" + } + + /** A class for array builders for arrays of `boolean`s. */ + class ofBoolean extends ArrayBuilder[Boolean] { + + private var elems: Array[Boolean] = _ + private var capacity: Int = 0 + private var size: Int = 0 + + private def mkArray(size: Int): Array[Boolean] = { + val newelems = new Array[Boolean](size) + if (this.size > 0) Array.copy(elems, 0, newelems, 0, this.size) + newelems + } + + private def resize(size: Int) { + elems = mkArray(size) + capacity = size + } + + override def sizeHint(size: Int) { + if (capacity < size) resize(size) + } + + private def ensureSize(size: Int) { + if (capacity < size || capacity == 0) { + var newsize = if (capacity == 0) 16 else capacity * 2 + while (newsize < size) newsize *= 2 + resize(newsize) + } + } + + def +=(elem: Boolean): this.type = { + ensureSize(size + 1) + elems(size) = elem + size += 1 + this + } + + override def ++=(xs: TraversableOnce[Boolean]): this.type = xs match { + case xs: WrappedArray.ofBoolean => + ensureSize(this.size + xs.length) + Array.copy(xs.array, 0, elems, this.size, xs.length) + size += xs.length + this + case _ => + super.++=(xs) + } + + def clear() { + size = 0 + } + + def result() = { + if (capacity != 0 && capacity == size) elems + else mkArray(size) + } + + override def equals(other: Any): Boolean = other match { + case x: ofBoolean => (size == x.size) && (elems == x.elems) + case _ => false + } + + override def toString = "ArrayBuilder.ofBoolean" + } + + /** A class for array builders for arrays of `Unit` type. */ + @deprecatedInheritance("ArrayBuilder.ofUnit is an internal implementation not intended for subclassing.", "2.11.0") + class ofUnit extends ArrayBuilder[Unit] { + + private var elems: Array[Unit] = _ + private var capacity: Int = 0 + private var size: Int = 0 + + private def mkArray(size: Int): Array[Unit] = { + val newelems = new Array[Unit](size) + if (this.size > 0) Array.copy(elems, 0, newelems, 0, this.size) + newelems + } + + private def resize(size: Int) { + elems = mkArray(size) + capacity = size + } + + override def sizeHint(size: Int) { + if (capacity < size) resize(size) + } + + private def ensureSize(size: Int) { + if (capacity < size || capacity == 0) { + var newsize = if (capacity == 0) 16 else capacity * 2 + while (newsize < size) newsize *= 2 + resize(newsize) + } + } + + def +=(elem: Unit): this.type = { + ensureSize(size + 1) + elems(size) = elem + size += 1 + this + } + + override def ++=(xs: TraversableOnce[Unit]): this.type = xs match { + case xs: WrappedArray.ofUnit => + ensureSize(this.size + xs.length) + Array.copy(xs.array, 0, elems, this.size, xs.length) + size += xs.length + this + case _ => + super.++=(xs) + } + + def clear() { + size = 0 + } + + def result() = { + if (capacity != 0 && capacity == size) elems + else mkArray(size) + } + + override def equals(other: Any): Boolean = other match { + case x: ofUnit => (size == x.size) && (elems == x.elems) + case _ => false + } + + override def toString = "ArrayBuilder.ofUnit" + } +} diff --git a/src/scala/collection/mutable/ArrayOps.scala b/src/scala/collection/mutable/ArrayOps.scala new file mode 100644 index 000000000000..652680ec8830 --- /dev/null +++ b/src/scala/collection/mutable/ArrayOps.scala @@ -0,0 +1,313 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala +package collection +package mutable + +import scala.compat.Platform.arraycopy +import scala.reflect.ClassTag +import scala.runtime.ScalaRunTime._ +import parallel.mutable.ParArray + +/** This class serves as a wrapper for `Array`s with all the operations found in + * indexed sequences. Where needed, instances of arrays are implicitly converted + * into this class. + * + * The difference between this class and `WrappedArray` is that calling transformer + * methods such as `filter` and `map` will yield an array, whereas a `WrappedArray` + * will remain a `WrappedArray`. + * + * @since 2.8 + * + * @tparam T type of the elements contained in this array. + * + * @define Coll `Array` + * @define orderDependent + * @define orderDependentFold + * @define mayNotTerminateInf + * @define willNotTerminateInf + */ +@deprecatedInheritance("ArrayOps will be sealed to facilitate greater flexibility with array/collections integration in future releases.", "2.11.0") +trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParallelizable[T, ParArray[T]] { + + private def elementClass: Class[_] = + arrayElementClass(repr.getClass) + + override def copyToArray[U >: T](xs: Array[U], start: Int, len: Int) { + var l = math.min(len, repr.length) + if (xs.length - start < l) l = xs.length - start max 0 + Array.copy(repr, 0, xs, start, l) + } + + override def toArray[U >: T : ClassTag]: Array[U] = { + val thatElementClass = arrayElementClass(implicitly[ClassTag[U]]) + if (elementClass eq thatElementClass) + repr.asInstanceOf[Array[U]] + else + super.toArray[U] + } + + def :+[B >: T: ClassTag](elem: B): Array[B] = { + val result = Array.ofDim[B](repr.length + 1) + Array.copy(repr, 0, result, 0, repr.length) + result(repr.length) = elem + result + } + + def +:[B >: T: ClassTag](elem: B): Array[B] = { + val result = Array.ofDim[B](repr.length + 1) + result(0) = elem + Array.copy(repr, 0, result, 1, repr.length) + result + } + + override def par = ParArray.handoff(repr) + + /** Flattens a two-dimensional array by concatenating all its rows + * into a single array. + * + * @tparam U Type of row elements. + * @param asTrav A function that converts elements of this array to rows - arrays of type `U`. + * @return An array obtained by concatenating rows of this array. + */ + def flatten[U](implicit asTrav: T => scala.collection.Traversable[U], m: ClassTag[U]): Array[U] = { + val b = Array.newBuilder[U] + b.sizeHint(map{case is: scala.collection.IndexedSeq[_] => is.size case _ => 0}.sum) + for (xs <- this) + b ++= asTrav(xs) + b.result() + } + + //TODO: rewrite this method + /** Transposes a two dimensional array. + * + * @tparam U Type of row elements. + * @param asArray A function that converts elements of this array to rows - arrays of type `U`. + * @return An array obtained by replacing elements of this arrays with rows the represent. + */ + def transpose[U](implicit asArray: T => Array[U]): Array[Array[U]] = { + val bb: Builder[Array[U], Array[Array[U]]] = Array.newBuilder(ClassTag[Array[U]](elementClass)) + if (isEmpty) bb.result() + else { + val checkHead = asArray(head) + val ct = if (classOf[dotty.runtime.vc.VCArrayPrototype[_]].isAssignableFrom(elementClass)) { + if (checkHead.nonEmpty) + ClassTag(checkHead(0).getClass).asInstanceOf[ClassTag[U]] + //TODO: this ClassTag shouldn't be used in code below (checkHead is empty and mkRowBuilder can't be invoded) + else ClassTag.Object //change to null + } else ClassTag[U](arrayElementClass(elementClass)) + //TODO: move ct generation inside mkRowBuilder + def mkRowBuilder() = Array.newBuilder(ct).asInstanceOf[ArrayBuilder[U]] + val bs = checkHead map (_ => mkRowBuilder()) + for (xs <- this) { + var i = 0 + for (x <- asArray(xs)) { + bs(i) += x + i += 1 + } + } + for (b <- bs) bb += b.result().asInstanceOf[Array[U]] + bb.result() + } + } + + /** Converts an array of pairs into an array of first elements and an array of second elements. + * + * @tparam T1 the type of the first half of the element pairs + * @tparam T2 the type of the second half of the element pairs + * @param asPair an implicit conversion which asserts that the element type + * of this Array is a pair. + * @param ct1 a class tag for T1 type parameter that is required to create an instance + * of Array[T1] + * @param ct2 a class tag for T2 type parameter that is required to create an instance + * of Array[T2] + * @return a pair of Arrays, containing, respectively, the first and second half + * of each element pair of this Array. + */ + // implementation NOTE: ct1 and ct2 can't be written as context bounds because desugared + // implicits are put in front of asPair parameter that is supposed to guide type inference + def unzip[T1, T2](implicit asPair: T => (T1, T2), ct1: ClassTag[T1], ct2: ClassTag[T2]): (Array[T1], Array[T2]) = { + val a1 = new Array[T1](length) + val a2 = new Array[T2](length) + var i = 0 + while (i < length) { + val e = apply(i) + a1(i) = e._1 + a2(i) = e._2 + i += 1 + } + (a1, a2) + } + + /** Converts an array of triples into three arrays, one containing the elements from each position of the triple. + * + * @tparam T1 the type of the first of three elements in the triple + * @tparam T2 the type of the second of three elements in the triple + * @tparam T3 the type of the third of three elements in the triple + * @param asTriple an implicit conversion which asserts that the element type + * of this Array is a triple. + * @param ct1 a class tag for T1 type parameter that is required to create an instance + * of Array[T1] + * @param ct2 a class tag for T2 type parameter that is required to create an instance + * of Array[T2] + * @param ct3 a class tag for T3 type parameter that is required to create an instance + * of Array[T3] + * @return a triple of Arrays, containing, respectively, the first, second, and third + * elements from each element triple of this Array. + */ + // implementation NOTE: ct1, ct2, ct3 can't be written as context bounds because desugared + // implicits are put in front of asPair parameter that is supposed to guide type inference + def unzip3[T1, T2, T3](implicit asTriple: T => (T1, T2, T3), ct1: ClassTag[T1], ct2: ClassTag[T2], + ct3: ClassTag[T3]): (Array[T1], Array[T2], Array[T3]) = { + val a1 = new Array[T1](length) + val a2 = new Array[T2](length) + val a3 = new Array[T3](length) + var i = 0 + while (i < length) { + val e = apply(i) + a1(i) = e._1 + a2(i) = e._2 + a3(i) = e._3 + i += 1 + } + (a1, a2, a3) + } + + + def seq = thisCollection + +} + +/** + * A companion object for `ArrayOps`. + * + * @since 2.8 + */ +object ArrayOps { + + /** A class of `ArrayOps` for arrays containing reference types. */ + final class ofRef[T <: AnyRef](override val repr: Array[T]) extends AnyVal with ArrayOps[T] with ArrayLike[T, Array[T]] { + + override protected[this] def thisCollection: WrappedArray[T] = new WrappedArray.ofRef[T](repr) + override protected[this] def toCollection(repr: Array[T]): WrappedArray[T] = new WrappedArray.ofRef[T](repr) + override protected[this] def newBuilder = new ArrayBuilder.ofRef[T]()(ClassTag[T](arrayElementClass(repr.getClass))) + + def length: Int = repr.length + def apply(index: Int): T = repr(index) + def update(index: Int, elem: T) { repr(index) = elem } + } + + /** A class of `ArrayOps` for arrays containing `byte`s. */ + final class ofByte(override val repr: Array[Byte]) extends AnyVal with ArrayOps[Byte] with ArrayLike[Byte, Array[Byte]] { + + override protected[this] def thisCollection: WrappedArray[Byte] = new WrappedArray.ofByte(repr) + override protected[this] def toCollection(repr: Array[Byte]): WrappedArray[Byte] = new WrappedArray.ofByte(repr) + override protected[this] def newBuilder = new ArrayBuilder.ofByte + + def length: Int = repr.length + def apply(index: Int): Byte = repr(index) + def update(index: Int, elem: Byte) { repr(index) = elem } + } + + /** A class of `ArrayOps` for arrays containing `short`s. */ + final class ofShort(override val repr: Array[Short]) extends AnyVal with ArrayOps[Short] with ArrayLike[Short, Array[Short]] { + + override protected[this] def thisCollection: WrappedArray[Short] = new WrappedArray.ofShort(repr) + override protected[this] def toCollection(repr: Array[Short]): WrappedArray[Short] = new WrappedArray.ofShort(repr) + override protected[this] def newBuilder = new ArrayBuilder.ofShort + + def length: Int = repr.length + def apply(index: Int): Short = repr(index) + def update(index: Int, elem: Short) { repr(index) = elem } + } + + /** A class of `ArrayOps` for arrays containing `char`s. */ + final class ofChar(override val repr: Array[Char]) extends AnyVal with ArrayOps[Char] with ArrayLike[Char, Array[Char]] { + + override protected[this] def thisCollection: WrappedArray[Char] = new WrappedArray.ofChar(repr) + override protected[this] def toCollection(repr: Array[Char]): WrappedArray[Char] = new WrappedArray.ofChar(repr) + override protected[this] def newBuilder = new ArrayBuilder.ofChar + + def length: Int = repr.length + def apply(index: Int): Char = repr(index) + def update(index: Int, elem: Char) { repr(index) = elem } + } + + /** A class of `ArrayOps` for arrays containing `int`s. */ + final class ofInt(override val repr: Array[Int]) extends AnyVal with ArrayOps[Int] with ArrayLike[Int, Array[Int]] { + + override protected[this] def thisCollection: WrappedArray[Int] = new WrappedArray.ofInt(repr) + override protected[this] def toCollection(repr: Array[Int]): WrappedArray[Int] = new WrappedArray.ofInt(repr) + override protected[this] def newBuilder = new ArrayBuilder.ofInt + + def length: Int = repr.length + def apply(index: Int): Int = repr(index) + def update(index: Int, elem: Int) { repr(index) = elem } + } + + /** A class of `ArrayOps` for arrays containing `long`s. */ + final class ofLong(override val repr: Array[Long]) extends AnyVal with ArrayOps[Long] with ArrayLike[Long, Array[Long]] { + + override protected[this] def thisCollection: WrappedArray[Long] = new WrappedArray.ofLong(repr) + override protected[this] def toCollection(repr: Array[Long]): WrappedArray[Long] = new WrappedArray.ofLong(repr) + override protected[this] def newBuilder = new ArrayBuilder.ofLong + + def length: Int = repr.length + def apply(index: Int): Long = repr(index) + def update(index: Int, elem: Long) { repr(index) = elem } + } + + /** A class of `ArrayOps` for arrays containing `float`s. */ + final class ofFloat(override val repr: Array[Float]) extends AnyVal with ArrayOps[Float] with ArrayLike[Float, Array[Float]] { + + override protected[this] def thisCollection: WrappedArray[Float] = new WrappedArray.ofFloat(repr) + override protected[this] def toCollection(repr: Array[Float]): WrappedArray[Float] = new WrappedArray.ofFloat(repr) + override protected[this] def newBuilder = new ArrayBuilder.ofFloat + + def length: Int = repr.length + def apply(index: Int): Float = repr(index) + def update(index: Int, elem: Float) { repr(index) = elem } + } + + /** A class of `ArrayOps` for arrays containing `double`s. */ + final class ofDouble(override val repr: Array[Double]) extends AnyVal with ArrayOps[Double] with ArrayLike[Double, Array[Double]] { + + override protected[this] def thisCollection: WrappedArray[Double] = new WrappedArray.ofDouble(repr) + override protected[this] def toCollection(repr: Array[Double]): WrappedArray[Double] = new WrappedArray.ofDouble(repr) + override protected[this] def newBuilder = new ArrayBuilder.ofDouble + + def length: Int = repr.length + def apply(index: Int): Double = repr(index) + def update(index: Int, elem: Double) { repr(index) = elem } + } + + /** A class of `ArrayOps` for arrays containing `boolean`s. */ + final class ofBoolean(override val repr: Array[Boolean]) extends AnyVal with ArrayOps[Boolean] with ArrayLike[Boolean, Array[Boolean]] { + + override protected[this] def thisCollection: WrappedArray[Boolean] = new WrappedArray.ofBoolean(repr) + override protected[this] def toCollection(repr: Array[Boolean]): WrappedArray[Boolean] = new WrappedArray.ofBoolean(repr) + override protected[this] def newBuilder = new ArrayBuilder.ofBoolean + + def length: Int = repr.length + def apply(index: Int): Boolean = repr(index) + def update(index: Int, elem: Boolean) { repr(index) = elem } + } + + /** A class of `ArrayOps` for arrays of `Unit` types. */ + final class ofUnit(override val repr: Array[Unit]) extends AnyVal with ArrayOps[Unit] with ArrayLike[Unit, Array[Unit]] { + + override protected[this] def thisCollection: WrappedArray[Unit] = new WrappedArray.ofUnit(repr) + override protected[this] def toCollection(repr: Array[Unit]): WrappedArray[Unit] = new WrappedArray.ofUnit(repr) + override protected[this] def newBuilder = new ArrayBuilder.ofUnit + + def length: Int = repr.length + def apply(index: Int): Unit = repr(index) + def update(index: Int, elem: Unit) { repr(index) = elem } + } +} diff --git a/src/scala/collection/mutable/WrappedArray.scala b/src/scala/collection/mutable/WrappedArray.scala new file mode 100644 index 000000000000..19158b710e24 --- /dev/null +++ b/src/scala/collection/mutable/WrappedArray.scala @@ -0,0 +1,196 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + + + +package scala +package collection +package mutable + +import scala.reflect.ClassTag +import scala.runtime.ScalaRunTime._ +import scala.collection.generic._ +import scala.collection.parallel.mutable.ParArray +import dotty.runtime.vc.VCArrayPrototype + +/** + * A class representing `Array[T]`. + * + * @tparam T type of the elements in this wrapped array. + * + * @author Martin Odersky, Stephane Micheloud + * @version 1.0 + * @since 2.8 + * @define Coll `WrappedArray` + * @define coll wrapped array + * @define orderDependent + * @define orderDependentFold + * @define mayNotTerminateInf + * @define willNotTerminateInf + */ +abstract class WrappedArray[T] + extends AbstractSeq[T] + with IndexedSeq[T] + with ArrayLike[T, WrappedArray[T]] + with CustomParallelizable[T, ParArray[T]] +{ + + override protected[this] def thisCollection: WrappedArray[T] = this + override protected[this] def toCollection(repr: WrappedArray[T]): WrappedArray[T] = repr + + /** The tag of the element type */ + def elemTag: ClassTag[T] + + @deprecated("use elemTag instead", "2.10.0") + def elemManifest: ClassManifest[T] = ClassManifest.fromClass[T](arrayElementClass(elemTag).asInstanceOf[Class[T]]) + + /** The length of the array */ + def length: Int + + /** The element at given index */ + def apply(index: Int): T + + /** Update element at given index */ + def update(index: Int, elem: T): Unit + + /** The underlying array */ + def array: Array[T] + + override def par = ParArray.handoff(array) + + private def elementClass: Class[_] = + arrayElementClass(array.getClass) + + override def toArray[U >: T : ClassTag]: Array[U] = { + val thatElementClass = arrayElementClass(implicitly[ClassTag[U]]) + if (elementClass eq thatElementClass) + array.asInstanceOf[Array[U]] + else + super.toArray[U] + } + + override def stringPrefix = "WrappedArray" + + /** Clones this object, including the underlying Array. */ + override def clone(): WrappedArray[T] = WrappedArray make array.clone() + + /** Creates new builder for this collection ==> move to subclasses + */ + override protected[this] def newBuilder: Builder[T, WrappedArray[T]] = + new WrappedArrayBuilder[T](elemTag) + +} + +/** A companion object used to create instances of `WrappedArray`. + */ +object WrappedArray { + // This is reused for all calls to empty. + private val EmptyWrappedArray = new ofRef[AnyRef](new Array[AnyRef](0)) + def empty[T <: AnyRef]: WrappedArray[T] = EmptyWrappedArray.asInstanceOf[WrappedArray[T]] + + // If make is called explicitly we use whatever we're given, even if it's + // empty. This may be unnecesssary (if WrappedArray is to honor the collections + // contract all empty ones must be equal, so discriminating based on the reference + // equality of an empty array should not come up) but we may as well be + // conservative since wrapRefArray contributes most of the unnecessary allocations. + def make[T](x: AnyRef): WrappedArray[T] = (x match { + case null => null + case x: VCArrayPrototype[_] => dotty.DottyPredef.wrapVCArray(x.asInstanceOf[Array[T]]) + case x: Array[AnyRef] => new ofRef[AnyRef](x) + case x: Array[Int] => new ofInt(x) + case x: Array[Double] => new ofDouble(x) + case x: Array[Long] => new ofLong(x) + case x: Array[Float] => new ofFloat(x) + case x: Array[Char] => new ofChar(x) + case x: Array[Byte] => new ofByte(x) + case x: Array[Short] => new ofShort(x) + case x: Array[Boolean] => new ofBoolean(x) + case x: Array[Unit] => new ofUnit(x) + }).asInstanceOf[WrappedArray[T]] + + implicit def canBuildFrom[T](implicit m: ClassTag[T]): CanBuildFrom[WrappedArray[_], T, WrappedArray[T]] = + new CanBuildFrom[WrappedArray[_], T, WrappedArray[T]] { + def apply(from: WrappedArray[_]): Builder[T, WrappedArray[T]] = + ArrayBuilder.make[T]()(m) mapResult WrappedArray.make[T] + def apply: Builder[T, WrappedArray[T]] = + ArrayBuilder.make[T]()(m) mapResult WrappedArray.make[T] + } + + //TODO: check for vc arrays + def newBuilder[A]: Builder[A, IndexedSeq[A]] = new ArrayBuffer + + final class ofRef[T <: AnyRef](val array: Array[T]) extends WrappedArray[T] with Serializable { + lazy val elemTag = ClassTag[T](arrayElementClass(array.getClass)) + def length: Int = array.length + def apply(index: Int): T = array(index).asInstanceOf[T] + def update(index: Int, elem: T) { array(index) = elem } + } + + final class ofByte(val array: Array[Byte]) extends WrappedArray[Byte] with Serializable { + def elemTag = ClassTag.Byte + def length: Int = array.length + def apply(index: Int): Byte = array(index) + def update(index: Int, elem: Byte) { array(index) = elem } + } + + final class ofShort(val array: Array[Short]) extends WrappedArray[Short] with Serializable { + def elemTag = ClassTag.Short + def length: Int = array.length + def apply(index: Int): Short = array(index) + def update(index: Int, elem: Short) { array(index) = elem } + } + + final class ofChar(val array: Array[Char]) extends WrappedArray[Char] with Serializable { + def elemTag = ClassTag.Char + def length: Int = array.length + def apply(index: Int): Char = array(index) + def update(index: Int, elem: Char) { array(index) = elem } + } + + final class ofInt(val array: Array[Int]) extends WrappedArray[Int] with Serializable { + def elemTag = ClassTag.Int + def length: Int = array.length + def apply(index: Int): Int = array(index) + def update(index: Int, elem: Int) { array(index) = elem } + } + + final class ofLong(val array: Array[Long]) extends WrappedArray[Long] with Serializable { + def elemTag = ClassTag.Long + def length: Int = array.length + def apply(index: Int): Long = array(index) + def update(index: Int, elem: Long) { array(index) = elem } + } + + final class ofFloat(val array: Array[Float]) extends WrappedArray[Float] with Serializable { + def elemTag = ClassTag.Float + def length: Int = array.length + def apply(index: Int): Float = array(index) + def update(index: Int, elem: Float) { array(index) = elem } + } + + final class ofDouble(val array: Array[Double]) extends WrappedArray[Double] with Serializable { + def elemTag = ClassTag.Double + def length: Int = array.length + def apply(index: Int): Double = array(index) + def update(index: Int, elem: Double) { array(index) = elem } + } + + final class ofBoolean(val array: Array[Boolean]) extends WrappedArray[Boolean] with Serializable { + def elemTag = ClassTag.Boolean + def length: Int = array.length + def apply(index: Int): Boolean = array(index) + def update(index: Int, elem: Boolean) { array(index) = elem } + } + + final class ofUnit(val array: Array[Unit]) extends WrappedArray[Unit] with Serializable { + def elemTag = ClassTag.Unit + def length: Int = array.length + def apply(index: Int): Unit = array(index) + def update(index: Int, elem: Unit) { array(index) = elem } + } +} diff --git a/src/scala/reflect/ClassTag.scala b/src/scala/reflect/ClassTag.scala new file mode 100644 index 000000000000..d364a2b2cf99 --- /dev/null +++ b/src/scala/reflect/ClassTag.scala @@ -0,0 +1,159 @@ +package scala +package reflect + +import java.lang.{ Class => jClass } +import scala.runtime.ScalaRunTime.arrayElementClass + +/** + * + * A `ClassTag[T]` stores the erased class of a given type `T`, accessible via the `runtimeClass` + * field. This is particularly useful for instantiating `Array`s whose element types are unknown + * at compile time. + * + * `ClassTag`s are a weaker special case of [[scala.reflect.api.TypeTags#TypeTag]]s, in that they + * wrap only the runtime class of a given type, whereas a `TypeTag` contains all static type + * information. That is, `ClassTag`s are constructed from knowing only the top-level class of a + * type, without necessarily knowing all of its argument types. This runtime information is enough + * for runtime `Array` creation. + * + * For example: + * {{{ + * scala> def mkArray[T : ClassTag](elems: T*) = Array[T](elems: _*) + * mkArray: [T](elems: T*)(implicit evidence$1: scala.reflect.ClassTag[T])Array[T] + * + * scala> mkArray(42, 13) + * res0: Array[Int] = Array(42, 13) + * + * scala> mkArray("Japan","Brazil","Germany") + * res1: Array[String] = Array(Japan, Brazil, Germany) + * }}} + * + * See [[scala.reflect.api.TypeTags]] for more examples, or the + * [[http://docs.scala-lang.org/overviews/reflection/typetags-manifests.html Reflection Guide: TypeTags]] + * for more details. + * + */ +@scala.annotation.implicitNotFound(msg = "No ClassTag available for ${T}") +trait ClassTag[T] extends ClassManifestDeprecatedApis[T] with Equals with Serializable { + // please, don't add any APIs here, like it was with `newWrappedArray` and `newArrayBuilder` + // class tags, and all tags in general, should be as minimalistic as possible + + /** A class representing the type `U` to which `T` would be erased. + * Note that there is no subtyping relationship between `T` and `U`. + */ + def runtimeClass: jClass[_] + + /** Produces a `ClassTag` that knows how to instantiate an `Array[Array[T]]` */ + def wrap: ClassTag[Array[T]] = ClassTag[Array[T]](arrayClass(runtimeClass)) + + /** Produces a new array with element type `T` and length `len` */ + override def newArray(len: Int): Array[T] = + runtimeClass match { + case java.lang.Byte.TYPE => new Array[Byte](len).asInstanceOf[Array[T]] + case java.lang.Short.TYPE => new Array[Short](len).asInstanceOf[Array[T]] + case java.lang.Character.TYPE => new Array[Char](len).asInstanceOf[Array[T]] + case java.lang.Integer.TYPE => new Array[Int](len).asInstanceOf[Array[T]] + case java.lang.Long.TYPE => new Array[Long](len).asInstanceOf[Array[T]] + case java.lang.Float.TYPE => new Array[Float](len).asInstanceOf[Array[T]] + case java.lang.Double.TYPE => new Array[Double](len).asInstanceOf[Array[T]] + case java.lang.Boolean.TYPE => new Array[Boolean](len).asInstanceOf[Array[T]] + case java.lang.Void.TYPE => new Array[Unit](len).asInstanceOf[Array[T]] + case _ => java.lang.reflect.Array.newInstance(runtimeClass, len).asInstanceOf[Array[T]] + } + + /** A ClassTag[T] can serve as an extractor that matches only objects of type T. + * + * The compiler tries to turn unchecked type tests in pattern matches into checked ones + * by wrapping a `(_: T)` type pattern as `ct(_: T)`, where `ct` is the `ClassTag[T]` instance. + * Type tests necessary before calling other extractors are treated similarly. + * `SomeExtractor(...)` is turned into `ct(SomeExtractor(...))` if `T` in `SomeExtractor.unapply(x: T)` + * is uncheckable, but we have an instance of `ClassTag[T]`. + */ + def unapply(x: Any): Option[T] = x match { + case null => None + case b: Byte => unapply(b) + case s: Short => unapply(s) + case c: Char => unapply(c) + case i: Int => unapply(i) + case l: Long => unapply(l) + case f: Float => unapply(f) + case d: Double => unapply(d) + case b: Boolean => unapply(b) + case u: Unit => unapply(u) + case a: Any => unapplyImpl(a) + } + + // TODO: Inline the bodies of these into the Any-accepting unapply overload above and delete them. + // This cannot be done until at least 2.12.0 for reasons of binary compatibility + def unapply(x: Byte) : Option[T] = unapplyImpl(x, classOf[Byte]) + def unapply(x: Short) : Option[T] = unapplyImpl(x, classOf[Short]) + def unapply(x: Char) : Option[T] = unapplyImpl(x, classOf[Char]) + def unapply(x: Int) : Option[T] = unapplyImpl(x, classOf[Int]) + def unapply(x: Long) : Option[T] = unapplyImpl(x, classOf[Long]) + def unapply(x: Float) : Option[T] = unapplyImpl(x, classOf[Float]) + def unapply(x: Double) : Option[T] = unapplyImpl(x, classOf[Double]) + def unapply(x: Boolean) : Option[T] = unapplyImpl(x, classOf[Boolean]) + def unapply(x: Unit) : Option[T] = unapplyImpl(x, classOf[Unit]) + + private[this] def unapplyImpl(x: Any, alternative: jClass[_] = null): Option[T] = { + val conforms = runtimeClass.isAssignableFrom(x.getClass) || (alternative != null && runtimeClass.isAssignableFrom(alternative)) + if (conforms) Some(x.asInstanceOf[T]) else None + } + + // case class accessories + override def canEqual(x: Any) = x.isInstanceOf[ClassTag[_]] + override def equals(x: Any) = x.isInstanceOf[ClassTag[_]] && this.runtimeClass == x.asInstanceOf[ClassTag[_]].runtimeClass + override def hashCode = scala.runtime.ScalaRunTime.hash(runtimeClass) + override def toString = { + def prettyprint(clazz: jClass[_]): String = + if (clazz.isArray) s"Array[${prettyprint(arrayElementClass(clazz))}]" else + clazz.getName + prettyprint(runtimeClass) + } +} + +/** + * Class tags corresponding to primitive types and constructor/extractor for ClassTags. + */ +object ClassTag { + private val ObjectTYPE = classOf[java.lang.Object] + private val NothingTYPE = classOf[scala.runtime.Nothing$] + private val NullTYPE = classOf[scala.runtime.Null$] + + val Byte : ClassTag[scala.Byte] = Manifest.Byte + val Short : ClassTag[scala.Short] = Manifest.Short + val Char : ClassTag[scala.Char] = Manifest.Char + val Int : ClassTag[scala.Int] = Manifest.Int + val Long : ClassTag[scala.Long] = Manifest.Long + val Float : ClassTag[scala.Float] = Manifest.Float + val Double : ClassTag[scala.Double] = Manifest.Double + val Boolean : ClassTag[scala.Boolean] = Manifest.Boolean + val Unit : ClassTag[scala.Unit] = Manifest.Unit + val Any : ClassTag[scala.Any] = Manifest.Any + val Object : ClassTag[java.lang.Object] = Manifest.Object + val AnyVal : ClassTag[scala.AnyVal] = Manifest.AnyVal + val AnyRef : ClassTag[scala.AnyRef] = Manifest.AnyRef + val Nothing : ClassTag[scala.Nothing] = Manifest.Nothing + val Null : ClassTag[scala.Null] = Manifest.Null + + def apply[T](runtimeClass1: jClass[_]): ClassTag[T] = + runtimeClass1 match { + case java.lang.Byte.TYPE => ClassTag.Byte.asInstanceOf[ClassTag[T]] + case java.lang.Short.TYPE => ClassTag.Short.asInstanceOf[ClassTag[T]] + case java.lang.Character.TYPE => ClassTag.Char.asInstanceOf[ClassTag[T]] + case java.lang.Integer.TYPE => ClassTag.Int.asInstanceOf[ClassTag[T]] + case java.lang.Long.TYPE => ClassTag.Long.asInstanceOf[ClassTag[T]] + case java.lang.Float.TYPE => ClassTag.Float.asInstanceOf[ClassTag[T]] + case java.lang.Double.TYPE => ClassTag.Double.asInstanceOf[ClassTag[T]] + case java.lang.Boolean.TYPE => ClassTag.Boolean.asInstanceOf[ClassTag[T]] + case java.lang.Void.TYPE => ClassTag.Unit.asInstanceOf[ClassTag[T]] + case ObjectTYPE => ClassTag.Object.asInstanceOf[ClassTag[T]] + case NothingTYPE => ClassTag.Nothing.asInstanceOf[ClassTag[T]] + case NullTYPE => ClassTag.Null.asInstanceOf[ClassTag[T]] + case _ if classOf[dotty.runtime.vc.VCPrototype].isAssignableFrom(runtimeClass1) => + Class.forName(s"${runtimeClass1.getName()}$$").newInstance().asInstanceOf[ClassTag[T]] + case _ => new ClassTag[T]{ def runtimeClass = runtimeClass1 } + } + + def unapply[T](ctag: ClassTag[T]): Option[Class[_]] = Some(ctag.runtimeClass) +} diff --git a/src/scala/runtime/ScalaRunTime.scala b/src/scala/runtime/ScalaRunTime.scala index ed1eb82b1b10..194562819cba 100644 --- a/src/scala/runtime/ScalaRunTime.scala +++ b/src/scala/runtime/ScalaRunTime.scala @@ -58,7 +58,11 @@ object ScalaRunTime { // at scala.Array$.fill(Array.scala:281) // at dotty.tools.dotc.core.Flags$.(Flags.scala:139) // newInstance throws an exception if the erasure is Void.TYPE. see SI-5680 + // TODO: update comment + // Vladimir: this method is used in the process of ClassTag generation in several methods of scala.Array + // ClassTag..MODULE$.apply(ScalaRunTime..MODULE$.arrayClass(ScalaRunTime..MODULE$.arrayClass(evidence$5.runtimeClass())))); if (clazz == java.lang.Void.TYPE) classOf[Array[Unit]] + else if (classOf[dotty.runtime.vc.VCPrototype].isAssignableFrom(clazz)) ClassTag(clazz).wrap.runtimeClass else java.lang.reflect.Array.newInstance(clazz, 0).getClass } diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index d43c5059b9b2..ddb1658bb8e5 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -47,6 +47,7 @@ class tests extends CompilerTest { val runDir = testsDir + "run/" val newDir = testsDir + "new/" val replDir = testsDir + "repl/" + val vcArraysDir = posDir + "vc-arrays/" val sourceDir = "./src/" val dottyDir = sourceDir + "dotty/" @@ -103,6 +104,20 @@ class tests extends CompilerTest { @Test def pos_anonClassSubtyping = compileFile(posDir, "anonClassSubtyping", twice) @Test def pos_extmethods = compileFile(posDir, "extmethods", twice) @Test def pos_companions = compileFile(posDir, "companions", twice) + @Test def pos_vc_proto_any_val = compileFile(vcArraysDir, "prototypeAnyVal", args = "-Ycheck:all" :: Nil) + @Test def pos_vc_array_functions = compileFile(runDir, "valueclasses-array-functions", args = "-Ycheck:all" :: Nil) + @Test def pos_vc_array_functions2 = compileFile(runDir, "valueclasses-array-functions2", args = "-Ycheck:all" :: Nil) + @Test def pos_vc_array_usage = compileFile(runDir, "valueclasses-array-usage", args = "-Ycheck:all" :: Nil) + @Test def pos_vc_array_gen = compileFile(runDir, "valueclasses-array-gen", args = "-Ycheck:all" :: Nil) + @Test def pos_vc_array_int = compileFile(runDir, "valueclasses-array-int", args = "-Ycheck:all" :: Nil) + @Test def pos_vc_array_object = compileFile(runDir, "valueclasses-array-object", args = "-Ycheck:all" :: Nil) + @Test def pos_vc_array_newarray = compileFile(runDir, "valueclasses-array-newarray", args = "-Ycheck:all" :: Nil) + @Test def pos_vc_underlying_null = compileFile(runDir, "valueclasses-underlying-null", args = "-Ycheck:all" :: Nil) + @Test def pos_vc_array_creation = compileFile(runDir, "valueclasses-array-creation", args = "-Ycheck:all" :: Nil) + @Test def pos_vc_array_caseclasses = compileFile(runDir, "valueclasses-array-caseclasses", args = "-Ycheck:all" :: Nil) + @Test def pos_vc_array_arrayops = compileFile(runDir, "valueclasses-array-arrayops", args = "-Ycheck:all" :: Nil) + @Test def pos_vc_array_array = compileFile(runDir, "valueclasses-array-array", args = "-Ycheck:all" :: Nil) + @Test def pos_vc_array_und_array = compileFile(runDir, "valueclasses-array-und-array", args = "-Ycheck:all" :: Nil) @Test def pos_all = compileFiles(posDir) // twice omitted to make tests run faster diff --git a/tests/neg/i705-inner-value-class.scala b/tests/neg/i705-inner-value-class.scala index 82ac962b57be..ab9dbfc9e873 100644 --- a/tests/neg/i705-inner-value-class.scala +++ b/tests/neg/i705-inner-value-class.scala @@ -15,7 +15,7 @@ object Test { class C(val a: Int) extends AnyVal // error: value class may not be a local class new C(1) } - class B1(val b: Int) extends B(b) // error: cannot extend final class B +// class B1(val b: Int) extends B(b) // removeerror: cannot extend final class B // class D extends B( { class E(val a: Int) extends AnyVal; new E(1) } ) } diff --git a/tests/pos/vc-arrays/prototypeAnyVal.scala b/tests/pos/vc-arrays/prototypeAnyVal.scala new file mode 100644 index 000000000000..6fce98b92307 --- /dev/null +++ b/tests/pos/vc-arrays/prototypeAnyVal.scala @@ -0,0 +1,5 @@ +case class Meter(x: Int) extends AnyVal +class Test { + //prototypes and companions should be rewired to pass -Ycheck:all + val x: AnyVal = Meter(1) +} \ No newline at end of file diff --git a/tests/pos/vc-arrays/vcSimple.scala b/tests/pos/vc-arrays/vcSimple.scala new file mode 100644 index 000000000000..d008cd972048 --- /dev/null +++ b/tests/pos/vc-arrays/vcSimple.scala @@ -0,0 +1,14 @@ +case class X(val x: Int) extends AnyVal +case class Y(val y: Any) extends AnyVal +object Test2 { + def t: AnyVal = new X(5) + def t2 = X(5) + def w: AnyVal = new Y(7) + def w2 = Y(7) + def main(args: Array[String]) = { + println(t) + println(t2) + println(w) + println(w2) + } +} \ No newline at end of file diff --git a/tests/run/valueclasses-array-array.check b/tests/run/valueclasses-array-array.check new file mode 100644 index 000000000000..f5ea97879149 --- /dev/null +++ b/tests/run/valueclasses-array-array.check @@ -0,0 +1,9 @@ +List(X@0, X@0, X@0, X@0) +List([X, [X, [X, [X) +List(X@1, X@2, X@3, X@4) +List(X@1, X@1, X@1, X@1, X@1) +List([X, [X, [X, [X, [X) +List(X@0, X@1, X@2, X@3, X@4) +List([X, [X, [X, [X) +List(X@5, X@a, X@14) +Some(Vector(X@1, X@2, X@3)) \ No newline at end of file diff --git a/tests/run/valueclasses-array-array.scala b/tests/run/valueclasses-array-array.scala new file mode 100644 index 000000000000..0987b34e5754 --- /dev/null +++ b/tests/run/valueclasses-array-array.scala @@ -0,0 +1,32 @@ +class X[T](val x: T) extends AnyVal +object Test { + def main(args: Array[String]) = { + def pl(xs: Array[_]) = println(xs.toList) + pl(Array.ofDim[X](4)) + pl(Array.ofDim[X](4,3)) + Array.ofDim[X](4,3,2) + Array.ofDim[X](4,3,2,5) + Array.ofDim[X](4,3,2,5,6) + pl(Array.concat(Array[X](new X(1), new X(2)), Array[X](new X(3), new X(4)))) + import scala.collection.mutable.{ WrappedArray, ArrayBuilder } + val ar: WrappedArray[X] = Array[X](new X(1), new X(2)) + ar.toArray + val ar0: WrappedArray[X] = Array[X](new X(1), new X(2)) + val ar1: ArrayBuilder[X] = ArrayBuilder.make[X]() + val ar2 = ar1.++=(ar0) + pl(Array.fill(5)(new X(1))) + pl(Array.fill(5,6)(new X(1))) + Array.fill(5,6,7)(new X(1)) + Array.fill(5,6,7,8)(new X(1)) + Array.fill(5,6,7,8,9)(new X(1)) + + pl(Array.tabulate(5)(x => new X(x))) + pl(Array.tabulate(4,5)((x,y) => new X(x + y))) + Array.tabulate(4,5,6)((x,y,z) => new X(x + y + z)) + Array.tabulate(4,5,6,7)((x,y,z,q) => new X(x + y + z + q)) + Array.tabulate(4,5,6,7,8)((x,y,z,q,w) => new X(x + y + z + q + w)) + + pl(Array.iterate(new X(5), 3)(xx => new X(2*xx.x))) + println(Array.unapplySeq(Array[X](new X(1), new X(2), new X(3)))) + } +} \ No newline at end of file diff --git a/tests/run/valueclasses-array-arrayops.check b/tests/run/valueclasses-array-arrayops.check new file mode 100644 index 000000000000..f6408d19f588 --- /dev/null +++ b/tests/run/valueclasses-array-arrayops.check @@ -0,0 +1,14 @@ +Array(X@1, X@2) +SeqView(...) +SeqViewS(...) +List(X@1, X@2) +List() +non-empty iterator +ArrayBuffer(X@1, X@2) +X@1 +WrappedArray(X@1, X@2) +List(X@1, X@2) +Set(X@1, X@2) +Set(ArrayBuffer(X@1, X@4), ArrayBuffer(X@2, X@5), ArrayBuffer(X@3, X@6)) +t4.transpose: List([X, [X, [X) +t21.transpose: List() \ No newline at end of file diff --git a/tests/run/valueclasses-array-arrayops.scala b/tests/run/valueclasses-array-arrayops.scala new file mode 100644 index 000000000000..c32283b4b7c4 --- /dev/null +++ b/tests/run/valueclasses-array-arrayops.scala @@ -0,0 +1,33 @@ +import scala.collection.mutable._ +class X(val x: Int) extends AnyVal +object Test { + def main(args: Array[String]) = { + val ar3 = Array(Array(new X(1)), Array(new X(2))) + val ar = Array(new X(1), new X(2)) + println(ar.deep) //ArrayLike + println(ar.view) //IndexedSeqLike + println(ar.view(0,1)) + println(ar.drop(0).toList) + println(ar.take(0).toList) + println(ar.iterator) + println(ar.toBuffer) + println(ar.head) + println(ar.seq) + println(ar3.flatten.toList) + + val ar2: WrappedArray[X] = ar + println(ar2.toArray.toSet) + ar2.companion + + val t = Array((1, new X(3)), (2, new X(4))) + t.unzip + + val t2: Array[Array[X]] = Array(Array(new X(1), new X(2), new X(3)), Array(new X(4), new X(5), new X(6))) + val t3: WrappedArray[Array[X]] = t2 + println(t3.transpose.toSet) + val t4: ArrayOps[Array[X]] = t2 + println(s"t4.transpose: ${t4.transpose.toList}") + val t21: Array[Array[X]] = Array(Array[X](), Array[X]()) + println(s"t21.transpose: ${t21.transpose.toList}") + } +} \ No newline at end of file diff --git a/tests/run/valueclasses-array-caseclasses.check b/tests/run/valueclasses-array-caseclasses.check new file mode 100644 index 000000000000..f5bcfd70072e --- /dev/null +++ b/tests/run/valueclasses-array-caseclasses.check @@ -0,0 +1,6 @@ +List([Y) +List(Y(null), Y(null)) +List(Y(null), Y(null), Y(null), Y(null), Y(null)) +List(Y(Z()), Y(Z()), Y(Z())) +List(Y(Z()), Y(Z()), Y(Z())) +List(Y(Z()), Y(Z()), Y(Z())) \ No newline at end of file diff --git a/tests/run/valueclasses-array-caseclasses.scala b/tests/run/valueclasses-array-caseclasses.scala new file mode 100644 index 000000000000..5e97ceee68a1 --- /dev/null +++ b/tests/run/valueclasses-array-caseclasses.scala @@ -0,0 +1,18 @@ +case class Y[T](val y: T) extends AnyVal +case class Z() + +object Test { + def main(args: Array[String]) = { + val a1 = Array(Array[Y[Z]]()) + val a2 = Array.ofDim[Y[Z]](2) + val a3 = new Array[Y[Z]](5) + val a4: Array[Y[Z]] = Array(Y[Z](Z()), Y[Z](Z()), Y[Z](Z())) + + println(a1.toList) + println(a2.toList) + println(a3.toList) + println(a4.toArray.toList) + println(a4.par.toList) + println(a4.map(x => a4(0)).toList) + } +} \ No newline at end of file diff --git a/tests/run/valueclasses-array-creation.check b/tests/run/valueclasses-array-creation.check new file mode 100644 index 000000000000..638199c47e8e --- /dev/null +++ b/tests/run/valueclasses-array-creation.check @@ -0,0 +1,12 @@ +List(X@b, X@16) +List([X, [X) +List(X@7, X@2) +X@1 +X@1 +List([X, [X) +List(X@7, X@2) +List(X@0, X@0, X@0) +List(null, null, null) +List(null, null, null) +List(X@6, X@6) +List(X@e) \ No newline at end of file diff --git a/tests/run/valueclasses-array-creation.scala b/tests/run/valueclasses-array-creation.scala new file mode 100644 index 000000000000..390e8966618e --- /dev/null +++ b/tests/run/valueclasses-array-creation.scala @@ -0,0 +1,52 @@ +class X(val x: Int) extends AnyVal +object Test { + def main(args: Array[String]) = { + val simple = Array(new X(11), new X(22)) + val a = Array(Array(new X(1), new X(2)), Array(new X(3))) + val b = a(0) + val c = b(0) + val d = a(0)(0) + a(0)(0) = new X(7) + def test(x: Array[Array[X]]) = { + x(0) = Array(new X(5)); + x + } + def test2(x: Array[X]) = x + def test3[T](y: Array[T]) = { + val a = y(0); + y(0) = y(1); + y(1) = a; + y match { + case ar@Array(el1: X, el2: X) => (ar.asInstanceOf[Array[X]]) filter (_.x > 1) map { t => new X(el2.x * 2) } + case _ => y + } + } + def test4(y: Array[X]) = { + y match { + case ar@Array(el1, el2) => ar filter (_.x > 1) map { t => new X(el2.x * 2) } + case _ => y + } + } + + + val x = new Array[X](3) + val y = new Array[Array[X]](3) + val z = new Array[Array[Array[X]]](3) + + println(simple.toList) + + println(a.toList) + println(b.toList) + println(c) + println(d) + println(test(a).toList) + println(test2(b).toList) + + println(x.toList) + println(y.toList) + println(z.toList) + + println(test3(Array(new X(3), new X(5))).toList) + println(test4(Array(new X(0), new X(7))).toList) + } +} \ No newline at end of file diff --git a/tests/run/valueclasses-array-functions.check b/tests/run/valueclasses-array-functions.check new file mode 100644 index 000000000000..c25a1d76feac --- /dev/null +++ b/tests/run/valueclasses-array-functions.check @@ -0,0 +1,14 @@ +X-7 +X-9 +X-11 +X-7 +X-9 +X-11 +X-32 +List(X-11) +r7: List(X-7, X-9, X-11) +List(X-3, X-4, X-5) +List(X-3, X-4, X-5, X-6) +List(X-7, X-3, X-4, X-5) +List(X-3, X-4, X-5) +List(X-3, X-3) diff --git a/tests/run/valueclasses-array-functions.scala b/tests/run/valueclasses-array-functions.scala new file mode 100644 index 000000000000..81904c27b180 --- /dev/null +++ b/tests/run/valueclasses-array-functions.scala @@ -0,0 +1,36 @@ +import scala.collection.mutable._ + +class X(val a: Int) extends AnyVal { + override def toString = s"X-$a" +} +object Test { + def prettyPrintArray3(x: Array[_]) = { println(x.toString); println(x(0)) } + + def main(args: Array[String]): Unit = { + val r1 = for (y <- test) { println(y) } + val r2 = test foreach ( x => println(x.toString) ) + val r3 = test.foldLeft(new X(5))((x, y) => new X(x.a + y.a)) + val r4 = test filter ( x => x.toString.contains("1") ) + val r5 = r4.toList + println(r3) + println(r5) + val r6 = test.toSet + val r7 = test.toList + println(s"r7: $r7") + + val t1: ArrayOps[X] = Array(new X(7)) + //def a1 = Array(Array[X]()) + def a2 = Array.ofDim[X](2) + def a3 = new Array[X](5) + def a4: Array[X] = Array(new X(3), new X(4), new X(5)) + println(a4.toArray.toList) + println(a4.:+(new X(6)).toList) + println(a4.+:(new X(7)).toList) + println(a4.par.toList) + val a5 = Array(new X(1), new X(2)) + val a6 = Array(new X(3), new X(4)) + println(a5.map(x => a6(0)).toList) + } + + def test: Array[X] = Array(new X(7), new X(9), new X(11)) +} \ No newline at end of file diff --git a/tests/run/valueclasses-array-functions2.check b/tests/run/valueclasses-array-functions2.check new file mode 100644 index 000000000000..f3b9b065dec2 --- /dev/null +++ b/tests/run/valueclasses-array-functions2.check @@ -0,0 +1,6 @@ +r: List(X(6), X(8), X(10)) +r3: List(X(1), X(2), X(3)) +r4: List(X(1), X(2), X(3)) +r5: List(X(3), X(6), X(9)) +r6: List(Z(1), Z(2), Z(3)) +v7: List(Z(X(3)), Z(X(4)), Z(X(5))) \ No newline at end of file diff --git a/tests/run/valueclasses-array-functions2.scala b/tests/run/valueclasses-array-functions2.scala new file mode 100644 index 000000000000..0e18efce03fe --- /dev/null +++ b/tests/run/valueclasses-array-functions2.scala @@ -0,0 +1,27 @@ +class X(val x: Int) extends AnyVal { + override def toString = s"X($x)" +} +class Y(val y: Int) +class Z(val z: String) extends AnyVal { + override def toString = s"Z($z)" +} + +object Test { + def main(args: Array[String]) = { + val r = test map { v1 => new X(v1.x*2) } + println(s"r: ${r.toList}") + val r3 = Array(1,2,3).map(v3 => new X(v3)) + println(s"r3: ${r3.toList}") + val r4 = test2 map (v4 => new X(v4.y)) + println(s"r4: ${r4.toList}") + val r5 = test3 map {x => new X(x.asInstanceOf[X].x*3)} + println(s"r5: ${r5.toList}") + val r6 = test2 map (v6 => new Z(v6.y.toString)) + println(s"r6: ${r6.toList}") + val r7 = test map (v7 => new Z(v7.toString)) + println(s"v7: ${r7.toList}") + } + def test = Array(new X(3), new X(4), new X(5)) + def test2 = Array(new Y(1), new Y(2), new Y(3)) + def test3: Array[_] = Array(new X(1), new X(2), new X(3)) +} \ No newline at end of file diff --git a/tests/run/valueclasses-array-functions3.check b/tests/run/valueclasses-array-functions3.check new file mode 100644 index 000000000000..25b7264713c1 --- /dev/null +++ b/tests/run/valueclasses-array-functions3.check @@ -0,0 +1,5 @@ +List(Y(Z()), Y(Z()), Y(Z())) +List(Y(Z()), Y(Z()), Y(Z()), Y(Z())) +List(Y(Z()), Y(Z()), Y(Z()), Y(Z())) +List(Y(Z()), Y(Z()), Y(Z())) +List(Y(Z()), Y(Z())) \ No newline at end of file diff --git a/tests/run/valueclasses-array-functions3.scala b/tests/run/valueclasses-array-functions3.scala new file mode 100644 index 000000000000..caf84065fecd --- /dev/null +++ b/tests/run/valueclasses-array-functions3.scala @@ -0,0 +1,17 @@ +case class Y(val y: Object) extends AnyVal +case class Z() +object Test { + def main(args: Array[String]) = { + //def a1 = Array(Array[Y]()) + def a2 = Array.ofDim[Y](2) + def a3 = new Array[Y](5) + def a4: Array[Y] = Array(Y(Z()), Y(Z()), Y(Z())) + println(a4.toArray.toList) + println(a4.:+(Y(Z())).toList) + println(a4.+:(Y(Z())).toList) + println(a4.par.toList) + val a5 = Array(Y(Z()), Y(Z())) + val a6 = Array(Y(Z()), Y(Z())) + println(a5.map(x => a6(0)).toList) + } +} \ No newline at end of file diff --git a/tests/run/valueclasses-array-gen.check b/tests/run/valueclasses-array-gen.check new file mode 100644 index 000000000000..8dbbce5364a9 --- /dev/null +++ b/tests/run/valueclasses-array-gen.check @@ -0,0 +1,36 @@ +[Meter1 +Meter1(1) +1 +Meter1(2) +2 +Meter1(3) +1 +Meter1(4) +2 +[Meter2 +Meter2(m2-1) +1 +Meter2(m2-2) +2 +Meter2(m2-3) +1 +Meter2(m2-4) +2 +[Meter3 +Meter3(1) +1 +Meter3(2) +2 +Meter3(3) +1 +Meter3(4) +2 +[Meter4 +Meter4(List(1)) +1 +Meter4(List(2)) +2 +Meter4(List(3)) +1 +Meter4(List(4)) +2 \ No newline at end of file diff --git a/tests/run/valueclasses-array-gen.scala b/tests/run/valueclasses-array-gen.scala new file mode 100644 index 000000000000..838137083179 --- /dev/null +++ b/tests/run/valueclasses-array-gen.scala @@ -0,0 +1,105 @@ +class Meter1[T](x: T) extends AnyVal { + override def toString = "Meter1(" + x + ")" +} +class Meter2[T >: Null <: String](x: T) extends AnyVal { + override def toString = "Meter2(" + x + ")" +} +class Meter3[T](x: Int) extends AnyVal { + override def toString = "Meter3(" + x + ")" +} +class Meter4[C[T], Y](x: C[Y]) extends AnyVal { + override def toString = "Meter4(" + x + ")" +} + +object Test { + def genAccess[T](genArray: Array[T]) = genArray(0) + def genUpdated[T](genArray: Array[T], elem: T) = genArray(0) = elem + def genLength[T](genArray: Array[T]) = genArray.length + + def foo1(myArray: Array[Meter1], elem: Meter1) = { + val update = myArray(0) = elem + val access = myArray(0) + val length: Int = myArray.length + + println(access) + println(length) + } + + def foo2(myArray: Array[Meter2], elem: Meter2) = { + val update = myArray(0) = elem + val access = myArray(0) + val length: Int = myArray.length + + println(access) + println(length) + } + + def foo3(myArray: Array[Meter3], elem: Meter3) = { + val update = myArray(0) = elem + val access = myArray(0) + val length: Int = myArray.length + + println(access) + println(length) + } + + def foo4(myArray: Array[Meter4], elem: Meter4) = { + val update = myArray(0) = elem + val access = myArray(0) + val length: Int = myArray.length + + println(access) + println(length) + } + + def genFoo[T](genArray: Array[T], elem: T) = { + val update = genArray(0) = elem + val access = genArray(0) + val length: Int = genArray.length + + println(access) + println(length) + } + + def main(args: Array[String]) = { + val meter1Array = new Array[Meter1](1) + val meter1Array2 = Array[Meter1](new Meter1(1), new Meter1(2)) + assert(meter1Array.getClass eq meter1Array2.getClass) + + println(meter1Array.toString) + foo1(meter1Array, new Meter1(1)) + foo1(meter1Array2, new Meter1(2)) + genFoo(meter1Array, new Meter1(3)) + genFoo(meter1Array2, new Meter1(4)) + + val meter2Array = new Array[Meter2](1) + val meter2Array2 = Array[Meter2](new Meter2("m2-1"), new Meter2("m2-2")) + assert(meter2Array.getClass eq meter2Array2.getClass) + + println(meter2Array.toString) + foo2(meter2Array, new Meter2("m2-1")) + foo2(meter2Array2, new Meter2("m2-2")) + genFoo(meter2Array, new Meter2("m2-3")) + genFoo(meter2Array2, new Meter2("m2-4")) + + val meter3Array = new Array[Meter3](1) + val meter3Array2 = Array[Meter3](new Meter3(1), new Meter3(2)) + assert(meter3Array.getClass eq meter3Array2.getClass) + + println(meter3Array.toString) + foo3(meter3Array, new Meter3(1)) + foo3(meter3Array2, new Meter3(2)) + genFoo(meter3Array, new Meter3(3)) + genFoo(meter3Array2, new Meter3(4)) + + val meter4Array = new Array[Meter4](1) + val meter4Array2 = Array[Meter4](new Meter4(List(1)), new Meter4(List(2))) + assert(meter4Array.getClass eq meter4Array2.getClass) + + println(meter4Array.toString) + foo4(meter4Array, new Meter4(List(1))) + foo4(meter4Array2, new Meter4(List(2))) + genFoo(meter4Array, new Meter4(List(3))) + genFoo(meter4Array2, new Meter4(List(4))) + } +} diff --git a/tests/run/valueclasses-array-int.check b/tests/run/valueclasses-array-int.check new file mode 100644 index 000000000000..2ded70ffad9f --- /dev/null +++ b/tests/run/valueclasses-array-int.check @@ -0,0 +1,9 @@ +[Meter +Meter(1) +1 +Meter(2) +2 +Meter(3) +1 +Meter(4) +2 \ No newline at end of file diff --git a/tests/run/valueclasses-array-int.scala b/tests/run/valueclasses-array-int.scala new file mode 100644 index 000000000000..233d7e2705b0 --- /dev/null +++ b/tests/run/valueclasses-array-int.scala @@ -0,0 +1,42 @@ +class Meter(val underlying: Int) extends AnyVal { + def plus(other: Meter): Meter = + new Meter(underlying + other.underlying) + + override def toString = "Meter(" + underlying + ")" +} + +object Test { + def genAccess[T](genArray: Array[T]) = genArray(0) + def genUpdated[T](genArray: Array[T], elem: T) = genArray(0) = elem + def genLength[T](genArray: Array[T]) = genArray.length + + def foo(myArray: Array[Meter], elem: Meter) = { + val update = myArray(0) = elem + val access = myArray(0) + val length: Int = myArray.length + + println(access) + println(length) + } + + def genFoo[T](genArray: Array[T], elem: T) = { + val update = genArray(0) = elem + val access = genArray(0) + val length: Int = genArray.length + + println(access) + println(length) + } + + def main(args: Array[String]) = { + val myArray = new Array[Meter](1) + val myArray2 = Array[Meter](new Meter(1), new Meter(2)) + assert(myArray.getClass eq myArray2.getClass) + + println(myArray.toString) + foo(myArray, new Meter(1)) + foo(myArray2, new Meter(2)) + genFoo(myArray, new Meter(3)) + genFoo(myArray2, new Meter(4)) + } +} \ No newline at end of file diff --git a/tests/run/valueclasses-array-newarray.check b/tests/run/valueclasses-array-newarray.check new file mode 100644 index 000000000000..2004651cc8b2 --- /dev/null +++ b/tests/run/valueclasses-array-newarray.check @@ -0,0 +1,3 @@ +Set(X@0) +Set(Y(null)) +Set(Z(null)) \ No newline at end of file diff --git a/tests/run/valueclasses-array-newarray.scala b/tests/run/valueclasses-array-newarray.scala new file mode 100644 index 000000000000..9d22dd7cda68 --- /dev/null +++ b/tests/run/valueclasses-array-newarray.scala @@ -0,0 +1,18 @@ +class X(val x: Int) extends AnyVal +class Y(val y: Object) extends AnyVal { + override def toString = s"Y($y)" +} +class Z(val z: String) extends AnyVal { + override def toString = s"Z($z)" +} +object Test { + def main(args: Array[String]) = { + println(a.toSet) + println(b.toSet) + println(c.toSet) + } + + def a = new Array[X](2) + def b = new Array[Y](3) + def c = new Array[Z](4) +} \ No newline at end of file diff --git a/tests/run/valueclasses-array-object.check b/tests/run/valueclasses-array-object.check new file mode 100644 index 000000000000..304b062425ed --- /dev/null +++ b/tests/run/valueclasses-array-object.check @@ -0,0 +1,18 @@ +[MeterObj +Meter(obj1) +1 +Meter(obj2) +2 +Meter(obj3) +1 +Meter(obj4) +2 +[MeterStr +Meter(str1) +1 +Meter(str2) +2 +Meter(str3) +1 +Meter(str4) +2 \ No newline at end of file diff --git a/tests/run/valueclasses-array-object.scala b/tests/run/valueclasses-array-object.scala new file mode 100644 index 000000000000..055e59b1409c --- /dev/null +++ b/tests/run/valueclasses-array-object.scala @@ -0,0 +1,67 @@ +class MeterObj(val underlying: Object) extends AnyVal { + def plus(other: MeterObj): MeterObj = + new MeterObj("plus-object: " + underlying.toString + other.underlying.toString) + + override def toString = "Meter(" + underlying + ")" +} +class MeterStr(val value: String) extends AnyVal { + def plus(other: MeterStr): MeterStr = + new MeterStr("plus-object: " + value + other.value) + + override def toString = "Meter(" + value + ")" +} + +object Test { + def genAccess[T](genArray: Array[T]) = genArray(0) + def genUpdated[T](genArray: Array[T], elem: T) = genArray(0) = elem + def genLength[T](genArray: Array[T]) = genArray.length + + def fooObj(myArray: Array[MeterObj], elem: MeterObj) = { + val update = myArray(0) = elem + val access = myArray(0) + val length: Int = myArray.length + + println(access) + println(length) + } + + def fooStr(myArray: Array[MeterStr], elem: MeterStr) = { + val update = myArray(0) = elem + val access = myArray(0) + val length: Int = myArray.length + + println(access) + println(length) + } + + def genFoo[T](genArray: Array[T], elem: T) = { + val update = genArray(0) = elem + val access = genArray(0) + val length: Int = genArray.length + + println(access) + println(length) + } + + def main(args: Array[String]) = { + val objArray = new Array[MeterObj](1) + val objArray2 = Array[MeterObj](new MeterObj("obj1"), new MeterObj("obj2")) + assert(objArray.getClass eq objArray2.getClass) + + println(objArray.toString) + fooObj(objArray, new MeterObj("obj1")) + fooObj(objArray2, new MeterObj("obj2")) + genFoo(objArray, new MeterObj("obj3")) + genFoo(objArray2, new MeterObj("obj4")) + + val strArray = new Array[MeterStr](1) + val strArray2 = Array[MeterStr](new MeterStr("str1"), new MeterStr("str2")) + assert(strArray.getClass eq strArray2.getClass) + + println(strArray.toString) + fooStr(strArray, new MeterStr("str1")) + fooStr(strArray2, new MeterStr("str2")) + genFoo(strArray, new MeterStr("str3")) + genFoo(strArray2, new MeterStr("str4")) + } +} \ No newline at end of file diff --git a/tests/run/valueclasses-array-und-array.check b/tests/run/valueclasses-array-und-array.check new file mode 100644 index 000000000000..0bc999a3e6aa --- /dev/null +++ b/tests/run/valueclasses-array-und-array.check @@ -0,0 +1,2 @@ +1 +1 \ No newline at end of file diff --git a/tests/run/valueclasses-array-und-array.scala b/tests/run/valueclasses-array-und-array.scala new file mode 100644 index 000000000000..7bb8a1a41b31 --- /dev/null +++ b/tests/run/valueclasses-array-und-array.scala @@ -0,0 +1,56 @@ +import scala.collection.mutable._ +class X(val x: Array[Y]) extends AnyVal +class X0(val x: Array[Y0]) extends AnyVal +class X00(val x: Array[Array[Y0]]) extends AnyVal +class X2(val x: Array[Y2]) extends AnyVal +class X3(val x: Array[Y3]) extends AnyVal +class Y3(val x: Int) extends AnyVal +class Y0(val a: Int) extends AnyVal +class Y(val a: Array[X]) +class Y2(val a: Int) extends AnyVal +class Z(val y: Y) extends AnyVal + +object Test { + def main(args: Array[String]) = { + val ar0 = new Array[X](3) + ar0(0) = new X(Array(new Y(Array(new X(Array()))))) + ar0(1) = new X(new Array[Y](4)) + val ar01 = new Array[X00](5) + val ar011: Array[X00] = null + val ar02 = Array(new X00(Array(Array(new Y0(7))))) + + val y1 = Array(new Y(Array(new X(Array(new Y(new Array[X](2)), new Y(Array(new X(new Array[Y](4))))))))) + val y2 = y1(0) + + val z1 = Array(Array(new Y(Array(new X(Array(new Y(new Array[X](2)), new Y(Array(new X(new Array[Y](4)))))))))) + val z2 = z1(0) + val z3 = z1(0)(0) + val z4 = z2(0) + println(z1.size) + println(z2.size) + + val y10 = Array(new X0(Array(new Y0(4), new Y0(3)))) + val y11 = Array(new X0(new Array[Y0](5))) + val y20 = y10(0) + + val z10 = Array(Array(new X0(Array(new Y0(4), new Y0(3))))) + val z11 = Array(Array(new X0(new Array[Y0](5)))) + val z20 = z10(0) + val z30 = z10(0)(0) + val z40 = z20(0) + + z10 map (x => Array(x(0))) + y10 map (x => x) + + val ar = Array(new X0(Array(new Y0(1)))) + + val ar2 = Array(new X(Array(new Y(Array[X](new X( new Array[Y](5))))))) + + val t = new X3(Array(new Y3(1))) + t.toString + val t2 = new X3(new Array[Y3](4)) + + val ar3 = Array(new X2(new Array[Y2](3))) + val ar4 = Array(new X2(Array(new Y2(3)))) + } +} \ No newline at end of file diff --git a/tests/run/valueclasses-array-usage.check b/tests/run/valueclasses-array-usage.check new file mode 100644 index 000000000000..5f5fbe759f10 --- /dev/null +++ b/tests/run/valueclasses-array-usage.check @@ -0,0 +1,3 @@ +1 +2 +3 \ No newline at end of file diff --git a/tests/run/valueclasses-array-usage.scala b/tests/run/valueclasses-array-usage.scala new file mode 100644 index 000000000000..0c9a6227958a --- /dev/null +++ b/tests/run/valueclasses-array-usage.scala @@ -0,0 +1,21 @@ +class X(val a: Int) extends AnyVal { + override def toString = s"X-$a" +} +class Y(val b: Int) +object Test { + def main(args: Array[String]) = { + val t: Array[X] = Array(new X(5)) + val t2 = new Array[X](2) + t2(0) = new X(1) + t2(1) = new X(2) + println(t.size) + println(t2.size) + println(test.size) + t: Array[X] + t2: Array[X] + } + def test = { + val a = Array(new X(5), new X(6), new X(7)) + a + } +} \ No newline at end of file diff --git a/tests/run/valueclasses-array-wrapped-vc.check b/tests/run/valueclasses-array-wrapped-vc.check new file mode 100644 index 000000000000..044b6c22b52a --- /dev/null +++ b/tests/run/valueclasses-array-wrapped-vc.check @@ -0,0 +1,5 @@ +List(X@37, null) +2 +List(X@0, X@0, X@0, X@0, X@0) +List(X@37, X@4d) +X@37 diff --git a/tests/run/valueclasses-array-wrapped-vc.scala b/tests/run/valueclasses-array-wrapped-vc.scala new file mode 100644 index 000000000000..95dd4bd89028 --- /dev/null +++ b/tests/run/valueclasses-array-wrapped-vc.scala @@ -0,0 +1,17 @@ +class X(val y: Y) extends AnyVal +class Y(val z: Z) extends AnyVal +class Z(val x: Int) extends AnyVal +object Test { + def main(args: Array[String]) = { + val arr = Array(new X(new Y(new Z(55))), null) + println(arr.toList) + val arr2 = Array.ofDim[X](2,3,4) + println(arr2.toList.size) + val arr3 = new Array[X](5) + println(arr3.toList) + arr(1) = new X(new Y(new Z(77))) + println(arr.toList) + val e = arr(0) + println(e) + } +} diff --git a/tests/run/valueclasses-array-wrappers.check b/tests/run/valueclasses-array-wrappers.check new file mode 100644 index 000000000000..5d464ef86431 --- /dev/null +++ b/tests/run/valueclasses-array-wrappers.check @@ -0,0 +1,10 @@ +Array(X-7, X-9, X-11) +Array(X-5) +Array(1) +X-7, X-9, X-11 +[X +[X +[X +X-7 +class X +class Y \ No newline at end of file diff --git a/tests/run/valueclasses-array-wrappers.scala b/tests/run/valueclasses-array-wrappers.scala new file mode 100644 index 000000000000..3468a29ab146 --- /dev/null +++ b/tests/run/valueclasses-array-wrappers.scala @@ -0,0 +1,46 @@ +import scala.collection.mutable._ + +class X(val a: Int) extends AnyVal { + override def toString = s"X-$a" +} +class Y(val y: String) extends AnyVal +class A +object Test { + def prettyPrintArray(x: Array[_]) = println("Array(" + x.mkString(", ") + ")") + def prettyPrintArray2(x: Array[X]) = { + val x0 = x(0) + x.toString + println(x.mkString(", ")) + } + def prettyPrintArray3(x: Array[_]) = { println(x.toString); println(x(0)) } + + def main(args: Array[String]): Unit = { + prettyPrintArray(test) + prettyPrintArray(Array(new X(5))) + + prettyPrintArray(Array() :+ 1) + prettyPrintArray2(test) + + println(test3) + val a = test3(0) + + println(test4) + prettyPrintArray3(test) + + test10 + test11(Array(1,2,3)) + + val b: ArrayOps[X] = Array(new X(11)) + println(s"${b.asInstanceOf[dotty.runtime.vc.VCArrayOps[_]].vcElementClass}") + val c: ArrayOps[Y] = Array(new Y("yyy")) + println(s"${c.asInstanceOf[dotty.runtime.vc.VCArrayOps[_]].vcElementClass}") + } + + def test: Array[X] = Array(new X(7), new X(9), new X(11)) + def test2: WrappedArray[X] = test + def test3: Array[X] = Array() :+ (new X(7)) + def test4: Array[X] = Array() + def test9: Array[Int] = Array(1,2,3) + def test10: ArrayOps[Int] = test9 + def test11(x: Array[_]): ArrayOps[_] = x +} \ No newline at end of file diff --git a/tests/run/valueclasses-array.check b/tests/run/valueclasses-array.check new file mode 100644 index 000000000000..14140012b68c --- /dev/null +++ b/tests/run/valueclasses-array.check @@ -0,0 +1,9 @@ +[Meter +Meter(1) +1 +Meter(2) +2 +Meter(3) +1 +Meter(4) +2 diff --git a/tests/run/valueclasses-underlying-null.check b/tests/run/valueclasses-underlying-null.check new file mode 100644 index 000000000000..34d9e51110df --- /dev/null +++ b/tests/run/valueclasses-underlying-null.check @@ -0,0 +1,3 @@ +0 +0 +Set(Y@0) \ No newline at end of file diff --git a/tests/run/valueclasses-underlying-null.scala b/tests/run/valueclasses-underlying-null.scala new file mode 100644 index 000000000000..f85fe8d30e07 --- /dev/null +++ b/tests/run/valueclasses-underlying-null.scala @@ -0,0 +1,13 @@ +class X(val x: Object) extends AnyVal +class Y(val y: String) extends AnyVal +object Test { + def main(args: Array[String]) = { + val x = new X(null) + val y = new Y(null) + println(x.hashCode()) + println(y.hashCode()) + + val r = Set(new Y(null)) + println(r.toString) + } +} \ No newline at end of file