From a64c7cdb23df6ed497c29ac88a4b0de7fb4dd71a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 9 Feb 2019 11:45:40 +0100 Subject: [PATCH 01/13] Handle @uncheckedVariance in hk-types --- compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala b/compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala index 76be55f9cc9d..a36848d62c4b 100644 --- a/compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala +++ b/compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala @@ -48,6 +48,8 @@ object VarianceChecker { case tref: TypeParamRef if tref.binder `eq` tl => val v = tl.typeParams(tref.paramNum).paramVariance varianceConforms(variance, v) || { error(tref); false } + case AnnotatedType(_, annot) if annot.symbol == defn.UncheckedVarianceAnnot => + x case _ => foldOver(x, t) } From 408cec18b428fd787be9ae843496b9ed714f4a94 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 9 Feb 2019 11:56:22 +0100 Subject: [PATCH 02/13] Fix bug related to inlined unary extension methods Unary extension methods are inlined before the end of `extMethodApply`. Have to take this into account when checking that the call is to an extension method. --- compiler/src/dotty/tools/dotc/typer/Applications.scala | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index f513d2ba10d3..43ed31572723 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -1737,7 +1737,12 @@ trait Applications extends Compatibility { self: Typer with Dynamic => val app = typed(untpd.Apply(core, untpd.TypedSplice(receiver) :: Nil), pt1, ctx.typerState.ownedVars)( ctx.addMode(Mode.SynthesizeExtMethodReceiver)) - if (!app.symbol.is(Extension)) + val appSym = + app match { + case Inlined(call, _, _) => call.symbol + case _ => app.symbol + } + if (!appSym.is(Extension)) ctx.error(em"not an extension method: $methodRef", receiver.sourcePos) app } From da2c0de7614faca74b53ff30403c9f09bc07af20 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 9 Feb 2019 12:58:16 +0100 Subject: [PATCH 03/13] Add immutable array type IArray[T] is an opaque alias for Array[T] --- library/src-bootstrapped/scala/IArray.scala | 60 +++++++++++++++++++++ tests/run/iarrays.scala | 53 ++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 library/src-bootstrapped/scala/IArray.scala create mode 100644 tests/run/iarrays.scala diff --git a/library/src-bootstrapped/scala/IArray.scala b/library/src-bootstrapped/scala/IArray.scala new file mode 100644 index 000000000000..280c0557740d --- /dev/null +++ b/library/src-bootstrapped/scala/IArray.scala @@ -0,0 +1,60 @@ +package scala +import reflect.ClassTag + +/** It would be nice it IArray could be covariant, but unfortunately that's not + * possible. The problem is the preculiar behavior of `Array[Any]`. + * `Array[Any]` erases to `Object[]`. So, `IArray[Any]` also erases to `Object[]`. + * Bit this means `IArray[Int]`, which erases to `Int[]`, cannot be a subtype of + * `IArray[Any]`. + */ +opaque type IArray[T] = Array[T] + +object IArray { + + implied arrayOps { + inline def (arr: IArray[T]) apply[T] (n: Int): T = (arr: Array[T]).apply(n) + inline def (arr: IArray[T]) length[T] : Int = (arr: Array[T]).length + } + def apply[T: ClassTag](xs: T*): IArray[T] = Array(xs: _*) + + def apply(x: Boolean, xs: Boolean*): IArray[Boolean] = Array(x, xs: _*) + def apply(x: Byte, xs: Byte*): IArray[Byte] = Array(x, xs: _*) + def apply(x: Short, xs: Short*): IArray[Short] = Array(x, xs: _*) + def apply(x: Char, xs: Char*): IArray[Char] = Array(x, xs: _*) + def apply(x: Int, xs: Int*): IArray[Int] = Array(x, xs: _*) + def apply(x: Long, xs: Long*): IArray[Long] = Array(x, xs: _*) + def apply(x: Float, xs: Float*): IArray[Float] = Array(x, xs: _*) + def apply(x: Double, xs: Double*): IArray[Double] = Array(x, xs: _*) + def apply(x: Unit, xs: Unit*): IArray[Unit] = Array(x, xs: _*) + + def concat[T: ClassTag](xss: IArray[T]*): IArray[T] = Array.concat(xss: _*) + + def fill[T: ClassTag](n: Int)(elem: => T): IArray[T] = + Array.fill(n)(elem) + def fill[T: ClassTag](n1: Int, n2: Int)(elem: => T): IArray[IArray[T]] = + Array.fill(n1, n2)(elem) + def fill[T: ClassTag](n1: Int, n2: Int, n3: Int)(elem: => T): IArray[IArray[IArray[T]]] = + Array.fill(n1, n2, n3)(elem) + def fill[T: ClassTag](n1: Int, n2: Int, n3: Int, n4: Int)(elem: => T): IArray[IArray[IArray[IArray[T]]]] = + Array.fill(n1, n2, n3, n4)(elem) + def fill[T: ClassTag](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int)(elem: => T): IArray[IArray[IArray[IArray[IArray[T]]]]] = + Array.fill(n1, n2, n3, n4, n5)(elem) + + def tabulate[T: ClassTag](n: Int)(f: Int => T): IArray[T] = + Array.tabulate(n)(f) + def tabulate[T: ClassTag](n1: Int, n2: Int)(f: (Int, Int) => T): IArray[IArray[T]] = + Array.tabulate(n1, n2)(f) + def tabulate[T: ClassTag](n1: Int, n2: Int, n3: Int)(f: (Int, Int, Int) => T): IArray[IArray[IArray[T]]] = + Array.tabulate(n1, n2, n3)(f) + def tabulate[T: ClassTag](n1: Int, n2: Int, n3: Int, n4: Int)(f: (Int, Int, Int, Int) => T): IArray[IArray[IArray[IArray[T]]]] = + Array.tabulate(n1, n2, n3, n4)(f) + def tabulate[T: ClassTag](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int)(f: (Int, Int, Int, Int, Int) => T): IArray[IArray[IArray[IArray[IArray[T]]]]] = + Array.tabulate(n1, n2, n3, n4, n5)(f) + + def range(start: Int, end: Int): IArray[Int] = Array.range(start, end) + def range(start: Int, end: Int, step: Int): IArray[Int] = Array.range(start, end, step) + + def iterate[T: ClassTag](start: T, len: Int)(f: T => T): IArray[T] = Array.iterate(start, len)(f) + + def unapplySeq[T](x: IArray[T]): Option[IndexedSeq[T]] = Array.unapplySeq(x) +} \ No newline at end of file diff --git a/tests/run/iarrays.scala b/tests/run/iarrays.scala new file mode 100644 index 000000000000..a8d2b6dbfb9b --- /dev/null +++ b/tests/run/iarrays.scala @@ -0,0 +1,53 @@ +import reflect.ClassTag +object Test extends App { + + val xs = IArray(1, 2, 3) + + def f[T](ys: IArray[T]) = { + assert(ys.length == 3) + var sum = 0 + for (i <- 0 until ys.length) + sum += xs(i) + assert(sum == 6) + } + + f(xs) + + var sum = 0 + for (i <- 0 until xs.length) + sum += xs(i) + assert(sum == 6) + + def reduce[T](xs: IArray[T], z: T, op: (T, T) => T) = { + var acc = z + for (i <- 0 until xs.length) + acc = op(acc, xs(i)) + acc + } + + def flatten[T: ClassTag](ys: IArray[IArray[T]]) = { + var len = 0 + for (i <- 0 until ys.length) len += ys(i).length + val flat = new Array[T](len) + var k = 0 + for (i <- 0 until ys.length) { + for (j <- 0 until ys(i).length) { + flat(k) = ys(i)(j) + k += 1 + } + } + IArray(flat: _*) + } + + val ys = IArray.concat(xs, xs, xs) + assert(reduce(ys, 0, _ + _) == 18) + + val zss = IArray.fill(2, 3)(1) + val zs = flatten(zss) + assert(reduce(zs, 0, _ + _) == 6) + + val is = IArray.iterate(0, 4)(_ + 1) + assert(reduce(is, 0, _ + _) == 6) + + val IArray(1, 2, 3) = xs +} \ No newline at end of file From f1645d4b756b8adecd91c9d309cbd29228270ef2 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 9 Feb 2019 13:26:49 +0100 Subject: [PATCH 04/13] Add test for `uncheckedVariance` in hk types --- library/src-bootstrapped/scala/IArray.scala | 2 +- tests/pos/covaraint-opqaue.scala | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 tests/pos/covaraint-opqaue.scala diff --git a/library/src-bootstrapped/scala/IArray.scala b/library/src-bootstrapped/scala/IArray.scala index 280c0557740d..0c4bbe0bcb52 100644 --- a/library/src-bootstrapped/scala/IArray.scala +++ b/library/src-bootstrapped/scala/IArray.scala @@ -4,7 +4,7 @@ import reflect.ClassTag /** It would be nice it IArray could be covariant, but unfortunately that's not * possible. The problem is the preculiar behavior of `Array[Any]`. * `Array[Any]` erases to `Object[]`. So, `IArray[Any]` also erases to `Object[]`. - * Bit this means `IArray[Int]`, which erases to `Int[]`, cannot be a subtype of + * But this means `IArray[Int]`, which erases to `Int[]`, cannot be a subtype of * `IArray[Any]`. */ opaque type IArray[T] = Array[T] diff --git a/tests/pos/covaraint-opqaue.scala b/tests/pos/covaraint-opqaue.scala new file mode 100644 index 000000000000..9a9e0328ced9 --- /dev/null +++ b/tests/pos/covaraint-opqaue.scala @@ -0,0 +1,3 @@ +import annotation.unchecked.uncheckedVariance + +opaque type O[+T] = Array[T @uncheckedVariance] From 44f614211f3d4e9552c1ca69e3359f43d0184854 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 14 Feb 2019 14:06:50 +0100 Subject: [PATCH 05/13] Make IArray covariant --- library/src-bootstrapped/scala/IArray.scala | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/src-bootstrapped/scala/IArray.scala b/library/src-bootstrapped/scala/IArray.scala index 0c4bbe0bcb52..41322885776e 100644 --- a/library/src-bootstrapped/scala/IArray.scala +++ b/library/src-bootstrapped/scala/IArray.scala @@ -7,13 +7,13 @@ import reflect.ClassTag * But this means `IArray[Int]`, which erases to `Int[]`, cannot be a subtype of * `IArray[Any]`. */ -opaque type IArray[T] = Array[T] +opaque type IArray[+T] = Array[_ <: T] object IArray { implied arrayOps { - inline def (arr: IArray[T]) apply[T] (n: Int): T = (arr: Array[T]).apply(n) - inline def (arr: IArray[T]) length[T] : Int = (arr: Array[T]).length + inline def (arr: IArray[T]) apply[T] (n: Int): T = arr.asInstanceOf[Array[T]].apply(n) + inline def (arr: IArray[T]) length[T] : Int = arr.asInstanceOf[Array[T]].length } def apply[T: ClassTag](xs: T*): IArray[T] = Array(xs: _*) @@ -27,7 +27,7 @@ object IArray { def apply(x: Double, xs: Double*): IArray[Double] = Array(x, xs: _*) def apply(x: Unit, xs: Unit*): IArray[Unit] = Array(x, xs: _*) - def concat[T: ClassTag](xss: IArray[T]*): IArray[T] = Array.concat(xss: _*) + def concat[T: ClassTag](xss: IArray[T]*): IArray[T] = Array.concat[T](xss.asInstanceOf[Seq[Array[T]]]: _*) def fill[T: ClassTag](n: Int)(elem: => T): IArray[T] = Array.fill(n)(elem) @@ -56,5 +56,5 @@ object IArray { def iterate[T: ClassTag](start: T, len: Int)(f: T => T): IArray[T] = Array.iterate(start, len)(f) - def unapplySeq[T](x: IArray[T]): Option[IndexedSeq[T]] = Array.unapplySeq(x) + def unapplySeq[T](x: IArray[T]): Option[IndexedSeq[T]] = Array.unapplySeq[T](x.asInstanceOf[Array[T]]) } \ No newline at end of file From 0dcb5e8dd7bde04b62b8b4ccff16a17622f76bf4 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 14 Feb 2019 14:08:13 +0100 Subject: [PATCH 06/13] Fix underlyingClassRef for hk types This gives us the right error message if we try to instantiate an hk opaque type with `new`. --- compiler/src/dotty/tools/dotc/core/Types.scala | 3 ++- tests/neg/alloc-abstract.scala | 15 +++++++++++++++ tests/neg/parser-stability-21.scala | 2 +- 3 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 tests/neg/alloc-abstract.scala diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 39a503cecee3..0f640f0a6b07 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1166,7 +1166,8 @@ object Types { else if (tp.symbol.isAliasType) tp.underlying.underlyingClassRef(refinementOK) else NoType case tp: AppliedType => - tp.superType.underlyingClassRef(refinementOK) + if (tp.tycon.isLambdaSub) NoType + else tp.superType.underlyingClassRef(refinementOK) case tp: AnnotatedType => tp.underlying.underlyingClassRef(refinementOK) case tp: RefinedType => diff --git a/tests/neg/alloc-abstract.scala b/tests/neg/alloc-abstract.scala new file mode 100644 index 000000000000..e0bcef133d67 --- /dev/null +++ b/tests/neg/alloc-abstract.scala @@ -0,0 +1,15 @@ +class Test[T] { + type U <: T + + type Foo[T] = Array[T] + + new T // error: not a class type + new T() // error: not a class type + new U // error: not a class type + new U() // error: not a class type + new IArray[String] // error: not a class type + new IArray[String]() // error: not a class type + new IArray[String](10) // error: not a class type // error: too mamy arguments + + new Foo[String](10) // ok +} \ No newline at end of file diff --git a/tests/neg/parser-stability-21.scala b/tests/neg/parser-stability-21.scala index 908e2b9bb12f..350e80caae2c 100644 --- a/tests/neg/parser-stability-21.scala +++ b/tests/neg/parser-stability-21.scala @@ -1,3 +1,3 @@ class x0[x1[]] // error - extends x1[ // error + extends x1[ // error \ No newline at end of file From a0104fd8c3515ddd2b2e39a7467e1b51e0554abc Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 14 Feb 2019 14:08:59 +0100 Subject: [PATCH 07/13] Test IArray[Any] --- tests/run/iarrays.scala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/run/iarrays.scala b/tests/run/iarrays.scala index a8d2b6dbfb9b..60091aac2641 100644 --- a/tests/run/iarrays.scala +++ b/tests/run/iarrays.scala @@ -50,4 +50,8 @@ object Test extends App { assert(reduce(is, 0, _ + _) == 6) val IArray(1, 2, 3) = xs + + val as: IArray[Any] = IArray(1, "hello") + assert(as(as.length - 1) == "hello") + } \ No newline at end of file From ea4ba34c31c3ed802871725d38ff632cfcf52b16 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 15 Feb 2019 16:32:20 +0100 Subject: [PATCH 08/13] More tests --- tests/neg/iarrays.scala | 15 +++++++++++++++ tests/neg/iarrays1.scala | 10 ++++++++++ tests/run/iarrays.scala | 11 +++++++++++ 3 files changed, 36 insertions(+) create mode 100644 tests/neg/iarrays.scala create mode 100644 tests/neg/iarrays1.scala diff --git a/tests/neg/iarrays.scala b/tests/neg/iarrays.scala new file mode 100644 index 000000000000..88e77085972d --- /dev/null +++ b/tests/neg/iarrays.scala @@ -0,0 +1,15 @@ +object Test { + + // Can't allocate an IArray + new IArray[String](10) // error: not a class type // error: too many arguments + + val xs = IArray(1, 2, 3) + + // Can't have a wildcard IArray + val ys: IArray[_] = xs + + // Can't update an IArray + xs(0) = 1 // error: value update is not a member + xs(1) += 1 // error: value += is not a member + +} \ No newline at end of file diff --git a/tests/neg/iarrays1.scala b/tests/neg/iarrays1.scala new file mode 100644 index 000000000000..9c38c2452618 --- /dev/null +++ b/tests/neg/iarrays1.scala @@ -0,0 +1,10 @@ +object Test { + + // Can't allocate an IArray + + val xs = IArray(1, 2, 3) + + // Can't have a wildcard IArray + val ys: IArray[_] = xs // error: unreducible application + +} \ No newline at end of file diff --git a/tests/run/iarrays.scala b/tests/run/iarrays.scala index 60091aac2641..25ff2dbc2969 100644 --- a/tests/run/iarrays.scala +++ b/tests/run/iarrays.scala @@ -25,6 +25,13 @@ object Test extends App { acc } + def reduce2[T <: AnyRef](xs: IArray[T], z: T, op: (T, T) => T) = { + var acc = z + for (i <- 0 until xs.length) + acc = op(acc, xs(i)) + acc + } + def flatten[T: ClassTag](ys: IArray[IArray[T]]) = { var len = 0 for (i <- 0 until ys.length) len += ys(i).length @@ -42,6 +49,9 @@ object Test extends App { val ys = IArray.concat(xs, xs, xs) assert(reduce(ys, 0, _ + _) == 18) + val ss = IArray("a", "b", "c") + assert(reduce2(ss, "", _ ++ _) == "abc") + val zss = IArray.fill(2, 3)(1) val zs = flatten(zss) assert(reduce(zs, 0, _ + _) == 6) @@ -53,5 +63,6 @@ object Test extends App { val as: IArray[Any] = IArray(1, "hello") assert(as(as.length - 1) == "hello") + assert(reduce(as, 0, (x, y) => x.toString ++ y.toString) == "01hello") } \ No newline at end of file From 36e3b0f03a9d783c9bec575ff6d5037e6b3d9633 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 18 Feb 2019 19:04:54 +0100 Subject: [PATCH 09/13] Fix and add comments Also, add `empty` method. --- library/src-bootstrapped/scala/IArray.scala | 150 +++++++++++++++++++- 1 file changed, 143 insertions(+), 7 deletions(-) diff --git a/library/src-bootstrapped/scala/IArray.scala b/library/src-bootstrapped/scala/IArray.scala index 41322885776e..099ae68bb672 100644 --- a/library/src-bootstrapped/scala/IArray.scala +++ b/library/src-bootstrapped/scala/IArray.scala @@ -1,22 +1,37 @@ package scala import reflect.ClassTag -/** It would be nice it IArray could be covariant, but unfortunately that's not - * possible. The problem is the preculiar behavior of `Array[Any]`. - * `Array[Any]` erases to `Object[]`. So, `IArray[Any]` also erases to `Object[]`. - * But this means `IArray[Int]`, which erases to `Int[]`, cannot be a subtype of - * `IArray[Any]`. +/** An immutable array. An `IArray[T]` has the same representation as an `Array[T]`, + * but it cannot be updated. Unlike regular arrays, immutable arrays are covariant. */ opaque type IArray[+T] = Array[_ <: T] object IArray { + /** Defines extension methods for immutable arrays */ implied arrayOps { + + /** The selection operatiom on an immutable array. + * + * @param arr the immutable array + * @param n the index of the element to select + * @return the element of the array at the given index + */ inline def (arr: IArray[T]) apply[T] (n: Int): T = arr.asInstanceOf[Array[T]].apply(n) + + /** The number of elements in an immutable array + * @param arr the immutable array + */ inline def (arr: IArray[T]) length[T] : Int = arr.asInstanceOf[Array[T]].length } - def apply[T: ClassTag](xs: T*): IArray[T] = Array(xs: _*) + /** An immutable array of length 0. + */ + def empty[T: ClassTag]: IArray[T] = new Array[T](0) + + /** An immutable array with given elements. + */ + def apply[T: ClassTag](xs: T*): IArray[T] = Array(xs: _*) def apply(x: Boolean, xs: Boolean*): IArray[Boolean] = Array(x, xs: _*) def apply(x: Byte, xs: Byte*): IArray[Byte] = Array(x, xs: _*) def apply(x: Short, xs: Short*): IArray[Short] = Array(x, xs: _*) @@ -27,34 +42,155 @@ object IArray { def apply(x: Double, xs: Double*): IArray[Double] = Array(x, xs: _*) def apply(x: Unit, xs: Unit*): IArray[Unit] = Array(x, xs: _*) + /** Concatenates all arrays into a single immutable array. + * + * @param xss the given immutable arrays + * @return the array created from concatenating `xss` + */ def concat[T: ClassTag](xss: IArray[T]*): IArray[T] = Array.concat[T](xss.asInstanceOf[Seq[Array[T]]]: _*) + /** Returns an immutable array that contains the results of some element computation a number + * of times. Each element is determined by a separate computation. + * + * @param n the number of elements in the array + * @param elem the element computation + */ def fill[T: ClassTag](n: Int)(elem: => T): IArray[T] = Array.fill(n)(elem) + + /** Returns a two-dimensional immutable array that contains the results of some element computation a number + * of times. Each element is determined by a separate computation. + * + * @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): IArray[IArray[T]] = Array.fill(n1, n2)(elem) + + /** Returns a three-dimensional immutable array that contains the results of some element computation a number + * of times. Each element is determined by a separate computation. + * + * @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): IArray[IArray[IArray[T]]] = Array.fill(n1, n2, n3)(elem) + + /** Returns a four-dimensional immutable array that contains the results of some element computation a number + * of times. Each element is determined by a separate computation. + * + * @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): IArray[IArray[IArray[IArray[T]]]] = Array.fill(n1, n2, n3, n4)(elem) + + /** Returns a five-dimensional immutable array that contains the results of some element computation a number + * of times. Each element is determined by a separate computation. + * + * @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): IArray[IArray[IArray[IArray[IArray[T]]]]] = Array.fill(n1, n2, n3, n4, n5)(elem) + /** Returns an immutable 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 + */ def tabulate[T: ClassTag](n: Int)(f: Int => T): IArray[T] = Array.tabulate(n)(f) + + /** Returns a two-dimensional immutable 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): IArray[IArray[T]] = Array.tabulate(n1, n2)(f) + + /** Returns a three-dimensional immutable 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): IArray[IArray[IArray[T]]] = Array.tabulate(n1, n2, n3)(f) + + /** Returns a four-dimensional immutable 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): IArray[IArray[IArray[IArray[T]]]] = Array.tabulate(n1, n2, n3, n4)(f) + + /** Returns a five-dimensional immutable 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): IArray[IArray[IArray[IArray[IArray[T]]]]] = Array.tabulate(n1, n2, n3, n4, n5)(f) + /** Returns an immutable 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 immutable array with values in range `start, start + 1, ..., end - 1` + * up to, but excluding, `end`. + */ def range(start: Int, end: Int): IArray[Int] = Array.range(start, end) + + /** Returns an immutable 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 immutable array with values in `start, start + step, ...` up to, but excluding `end` + */ def range(start: Int, end: Int, step: Int): IArray[Int] = Array.range(start, end, step) + /** Returns an immutable 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 immutable array returning `len` values in the sequence `start, f(start), f(f(start)), ...` + */ def iterate[T: ClassTag](start: T, len: Int)(f: T => T): IArray[T] = Array.iterate(start, len)(f) - def unapplySeq[T](x: IArray[T]): Option[IndexedSeq[T]] = Array.unapplySeq[T](x.asInstanceOf[Array[T]]) + /** Returns a decomposition of the array into a sequence. This supports + * a pattern match like `{ case IArray(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: IArray[T]): Option[IndexedSeq[T]] = Array.unapplySeq[T](x.asInstanceOf[Array[T]]) } \ No newline at end of file From c2a3ccd5b26848c51845c9a31f57c61950b3ff48 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 19 Feb 2019 13:40:26 +0100 Subject: [PATCH 10/13] Add representation test --- tests/run/iarrays.scala | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/run/iarrays.scala b/tests/run/iarrays.scala index 25ff2dbc2969..26a189c08eaa 100644 --- a/tests/run/iarrays.scala +++ b/tests/run/iarrays.scala @@ -65,4 +65,9 @@ object Test extends App { assert(as(as.length - 1) == "hello") assert(reduce(as, 0, (x, y) => x.toString ++ y.toString) == "01hello") + // Check that representation of IArray and Array is the same + val bs: IArray[Double] = IArray(1.0, 2.0) + val cs: Array[Double] = bs.asInstanceOf[Array[Double]] + cs(1) = 3.0 + assert(bs(1) == 3.0) } \ No newline at end of file From 6bf73a9ecb1e79f212229db3eea46199b43d344a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 21 Feb 2019 16:13:29 +0100 Subject: [PATCH 11/13] fix typo in file name --- tests/pos/{covaraint-opqaue.scala => covariant-opaque.scala} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/pos/{covaraint-opqaue.scala => covariant-opaque.scala} (100%) diff --git a/tests/pos/covaraint-opqaue.scala b/tests/pos/covariant-opaque.scala similarity index 100% rename from tests/pos/covaraint-opqaue.scala rename to tests/pos/covariant-opaque.scala From c532d3e90de9655cdb061c7c419206e764d67013 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 22 Feb 2019 17:15:11 +0100 Subject: [PATCH 12/13] Fix typo --- library/src-bootstrapped/scala/IArray.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src-bootstrapped/scala/IArray.scala b/library/src-bootstrapped/scala/IArray.scala index 099ae68bb672..8dad7690699e 100644 --- a/library/src-bootstrapped/scala/IArray.scala +++ b/library/src-bootstrapped/scala/IArray.scala @@ -11,7 +11,7 @@ object IArray { /** Defines extension methods for immutable arrays */ implied arrayOps { - /** The selection operatiom on an immutable array. + /** The selection operation on an immutable array. * * @param arr the immutable array * @param n the index of the element to select From b9decdcaca62469d4bf15acadbea5b76d1ca9803 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 23 Feb 2019 09:46:35 +0100 Subject: [PATCH 13/13] Make IArray.unapplySeq cross build for 2.12/2.13. Need to drop the explicit result type since apparently Array's unapplySeq type is different between 2.12 and 2.13. --- library/src-bootstrapped/scala/IArray.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src-bootstrapped/scala/IArray.scala b/library/src-bootstrapped/scala/IArray.scala index 8dad7690699e..7cae3d163fb0 100644 --- a/library/src-bootstrapped/scala/IArray.scala +++ b/library/src-bootstrapped/scala/IArray.scala @@ -192,5 +192,5 @@ object IArray { * @param x the selector value * @return sequence wrapped in a [[scala.Some]], if `x` is a Seq, otherwise `None` */ - def unapplySeq[T](x: IArray[T]): Option[IndexedSeq[T]] = Array.unapplySeq[T](x.asInstanceOf[Array[T]]) + def unapplySeq[T](x: IArray[T]) = Array.unapplySeq[T](x.asInstanceOf[Array[T]]) } \ No newline at end of file