Skip to content

Commit a27ffeb

Browse files
Merge pull request #11329 from dotty-staging/alternative-definition-layout-of-IArray
Alternative definition layout of IArray
2 parents 5b46900 + 12bc226 commit a27ffeb

File tree

6 files changed

+52
-59
lines changed

6 files changed

+52
-59
lines changed

compiler/src/dotty/tools/dotc/Compiler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ class Compiler {
9595
new FunctionXXLForwarders, // Add forwarders for FunctionXXL apply method
9696
new ParamForwarding, // Add forwarders for aliases of superclass parameters
9797
new TupleOptimizations, // Optimize generic operations on tuples
98-
new LetOverApply, // Lift blocks from receivers of applications
98+
new LetOverApply, // Lift blocks from receivers of applications
9999
new ArrayConstructors) :: // Intercept creation of (non-generic) arrays and intrinsify.
100100
List(new Erasure) :: // Rewrite types to JVM model, erasing all type parameters, abstract types and refinements.
101101
List(new ElimErasedValueType, // Expand erased value types to their underlying implmementation types

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,10 @@ class Definitions {
551551
@tu lazy val ArrayConstructor: Symbol = ArrayClass.requiredMethod(nme.CONSTRUCTOR)
552552

553553
@tu lazy val ArrayModule: Symbol = requiredModule("scala.Array")
554+
def ArrayModuleClass: Symbol = ArrayModule.moduleClass
555+
556+
@tu lazy val IArrayModule: Symbol = requiredModule("scala.IArray")
557+
def IArrayModuleClass: Symbol = IArrayModule.moduleClass
554558

555559
@tu lazy val UnitType: TypeRef = valueTypeRef("scala.Unit", java.lang.Void.TYPE, UnitEnc, nme.specializedTypeNames.Void)
556560
def UnitClass(using Context): ClassSymbol = UnitType.symbol.asClass

compiler/src/dotty/tools/dotc/transform/ArrayApply.scala

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import MegaPhase._
66
import Contexts._
77
import Symbols._
88
import Types._
9+
import Flags._
910
import StdNames._
1011
import ast.Trees._
1112
import dotty.tools.dotc.ast.tpd
@@ -23,7 +24,7 @@ class ArrayApply extends MiniPhase {
2324
override def phaseName: String = "arrayApply"
2425

2526
override def transformApply(tree: tpd.Apply)(using Context): tpd.Tree =
26-
if (tree.symbol.name == nme.apply && tree.symbol.owner == defn.ArrayModule.moduleClass) // Is `Array.apply`
27+
if isArrayModuleApply(tree.symbol) then
2728
tree.args match {
2829
case StripAscription(Apply(wrapRefArrayMeth, (seqLit: tpd.JavaSeqLiteral) :: Nil)) :: ct :: Nil
2930
if defn.WrapArrayMethods().contains(wrapRefArrayMeth.symbol) && elideClassTag(ct) =>
@@ -39,6 +40,10 @@ class ArrayApply extends MiniPhase {
3940

4041
else tree
4142

43+
private def isArrayModuleApply(sym: Symbol)(using Context): Boolean =
44+
sym.name == nme.apply
45+
&& (sym.owner == defn.ArrayModuleClass || (sym.owner == defn.IArrayModuleClass && !sym.is(Extension)))
46+
4247
/** Only optimize when classtag if it is one of
4348
* - `ClassTag.apply(classOf[XYZ])`
4449
* - `ClassTag.apply(java.lang.XYZ.Type)` for boxed primitives `XYZ``

compiler/src/dotty/tools/dotc/transform/ArrayConstructors.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class ArrayConstructors extends MiniPhase {
3232
val TypeApply(tycon, targ :: Nil) = tree.fun
3333
expand(targ.tpe, tree.args)
3434
}
35-
else if ((tree.fun.symbol.maybeOwner eq defn.ArrayModule.moduleClass) && (tree.fun.symbol.name eq nme.ofDim) && !tree.tpe.isInstanceOf[MethodicType]) {
35+
else if ((tree.fun.symbol.maybeOwner eq defn.ArrayModuleClass) && (tree.fun.symbol.name eq nme.ofDim) && !tree.tpe.isInstanceOf[MethodicType]) {
3636
val Apply(Apply(TypeApply(_, List(tp)), _), _) = tree
3737
val cs = tp.tpe.classSymbol
3838
tree.fun match {

compiler/test/dotty/tools/backend/jvm/ArrayApplyOptTest.scala

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,18 @@ class ArrayApplyOptTest extends DottyBytecodeTest {
2222
test("Array[Char]()", newArray0Opcodes(T_CHAR))
2323
test("Array[T]()", newArray0Opcodes(T_INT))
2424

25-
test("IArray[String]()", List(Op(ICONST_0), TypeOp(ANEWARRAY, "java/lang/String"), TypeOp(CHECKCAST, "[Ljava/lang/String;"), Op(POP), Op(RETURN)))
26-
test("IArray[Unit]()", List(Op(ICONST_0), TypeOp(ANEWARRAY, "scala/runtime/BoxedUnit"), TypeOp(CHECKCAST, "[Lscala/runtime/BoxedUnit;"), Op(POP), Op(RETURN)))
27-
test("IArray[Object]()", List(Op(ICONST_0), TypeOp(ANEWARRAY, "java/lang/Object"), TypeOp(CHECKCAST, "[Ljava/lang/Object;"), Op(POP), Op(RETURN)))
28-
test("IArray[Boolean]()", newArray0Opcodes(T_BOOLEAN, TypeOp(CHECKCAST, "[Z") :: Nil))
29-
test("IArray[Byte]()", newArray0Opcodes(T_BYTE, TypeOp(CHECKCAST, "[B") :: Nil))
30-
test("IArray[Short]()", newArray0Opcodes(T_SHORT, TypeOp(CHECKCAST, "[S") :: Nil))
31-
test("IArray[Int]()", newArray0Opcodes(T_INT, TypeOp(CHECKCAST, "[I") :: Nil))
32-
test("IArray[Long]()", newArray0Opcodes(T_LONG, TypeOp(CHECKCAST, "[J") :: Nil))
33-
test("IArray[Float]()", newArray0Opcodes(T_FLOAT, TypeOp(CHECKCAST, "[F") :: Nil))
34-
test("IArray[Double]()", newArray0Opcodes(T_DOUBLE, TypeOp(CHECKCAST, "[D") :: Nil))
35-
test("IArray[Char]()", newArray0Opcodes(T_CHAR, TypeOp(CHECKCAST, "[C") :: Nil))
36-
test("IArray[T]()", newArray0Opcodes(T_INT, TypeOp(CHECKCAST, "[I") :: Nil))
25+
test("IArray[String]()", List(Op(ICONST_0), TypeOp(ANEWARRAY, "java/lang/String"), Op(POP), Op(RETURN)))
26+
test("IArray[Unit]()", List(Op(ICONST_0), TypeOp(ANEWARRAY, "scala/runtime/BoxedUnit"), Op(POP), Op(RETURN)))
27+
test("IArray[Object]()", List(Op(ICONST_0), TypeOp(ANEWARRAY, "java/lang/Object"), Op(POP), Op(RETURN)))
28+
test("IArray[Boolean]()", newArray0Opcodes(T_BOOLEAN))
29+
test("IArray[Byte]()", newArray0Opcodes(T_BYTE))
30+
test("IArray[Short]()", newArray0Opcodes(T_SHORT))
31+
test("IArray[Int]()", newArray0Opcodes(T_INT))
32+
test("IArray[Long]()", newArray0Opcodes(T_LONG))
33+
test("IArray[Float]()", newArray0Opcodes(T_FLOAT))
34+
test("IArray[Double]()", newArray0Opcodes(T_DOUBLE))
35+
test("IArray[Char]()", newArray0Opcodes(T_CHAR))
36+
test("IArray[T]()", newArray0Opcodes(T_INT))
3737
}
3838

3939
@Test def testArrayGenericApply = {
@@ -42,10 +42,8 @@ class ArrayApplyOptTest extends DottyBytecodeTest {
4242
test("""Array("a", "b")""", opCodes("java/lang/String"))
4343
test("""Array[Object]("a", "b")""", opCodes("java/lang/Object"))
4444

45-
def opCodes2(tpe: String) =
46-
List(Op(ICONST_2), TypeOp(ANEWARRAY, tpe), Op(DUP), Op(ICONST_0), Ldc(LDC, "a"), Op(AASTORE), Op(DUP), Op(ICONST_1), Ldc(LDC, "b"), Op(AASTORE), TypeOp(CHECKCAST, s"[L$tpe;"), Op(POP), Op(RETURN))
47-
test("""IArray("a", "b")""", opCodes2("java/lang/String"))
48-
test("""IArray[Object]("a", "b")""", opCodes2("java/lang/Object"))
45+
test("""IArray("a", "b")""", opCodes("java/lang/String"))
46+
test("""IArray[Object]("a", "b")""", opCodes("java/lang/Object"))
4947
}
5048

5149
@Test def testArrayApplyBoolean = {
@@ -106,7 +104,7 @@ class ArrayApplyOptTest extends DottyBytecodeTest {
106104
Op(ICONST_1), Field(GETSTATIC, "scala/runtime/BoxedUnit", "UNIT", "Lscala/runtime/BoxedUnit;"), Op(AASTORE), Op(POP), Op(RETURN)))
107105
test("IArray[Unit]((), ())", List(Op(ICONST_2), TypeOp(ANEWARRAY, "scala/runtime/BoxedUnit"), Op(DUP),
108106
Op(ICONST_0), Field(GETSTATIC, "scala/runtime/BoxedUnit", "UNIT", "Lscala/runtime/BoxedUnit;"), Op(AASTORE), Op(DUP),
109-
Op(ICONST_1), Field(GETSTATIC, "scala/runtime/BoxedUnit", "UNIT", "Lscala/runtime/BoxedUnit;"), Op(AASTORE), TypeOp(CHECKCAST, "[Lscala/runtime/BoxedUnit;"), Op(POP), Op(RETURN)))
107+
Op(ICONST_1), Field(GETSTATIC, "scala/runtime/BoxedUnit", "UNIT", "Lscala/runtime/BoxedUnit;"), Op(AASTORE), Op(POP), Op(RETURN)))
110108
}
111109

112110
@Test def testArrayInlined = test(

library/src/scala/IArray.scala

Lines changed: 25 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,12 @@ import reflect.ClassTag
33

44
import scala.collection.immutable
55

6+
opaque type IArray[+T] = Array[_ <: T]
7+
68
/** An immutable array. An `IArray[T]` has the same representation as an `Array[T]`,
79
* but it cannot be updated. Unlike regular arrays, immutable arrays are covariant.
810
*/
9-
object opaques:
10-
opaque type IArray[+T] = Array[_ <: T]
11-
12-
private[scala] type Sub[A] >: Array[A] <: IArray[A]
13-
private[scala] type Sup[A] >: IArray[A] <: Array[_ <: A]
11+
object IArray:
1412

1513
/** The selection operation on an immutable array.
1614
*
@@ -316,17 +314,6 @@ object opaques:
316314
extension (arr: IArray[Unit]) def toSeq: immutable.ArraySeq[Unit] =
317315
immutable.ArraySeq.ofUnit(arr.asInstanceOf[Array[Unit]])
318316

319-
end opaques
320-
321-
type IArray[+T] = opaques.IArray[T]
322-
323-
object IArray {
324-
import opaques.Sub
325-
import opaques.Sup
326-
327-
// A convenience to avoid having to cast everything by hand
328-
private given [A]: Conversion[Array[A], IArray[A]] = identity[Sub[A]]
329-
330317
/** Convert an array into an immutable array without copying, the original array
331318
* must _not_ be mutated after this or the guaranteed immutablity of IArray will
332319
* be violated.
@@ -356,25 +343,25 @@ object IArray {
356343
def emptyObjectIArray: IArray[Object] = Array.emptyObjectArray
357344

358345
/** An immutable array with given elements. */
359-
inline def apply[T](inline xs: T*)(using inline ct: ClassTag[T]): IArray[T] = Array(xs: _*).asInstanceOf
346+
def apply[T](xs: T*)(using ct: ClassTag[T]): IArray[T] = Array(xs: _*)
360347
/** An immutable array with given elements. */
361-
inline def apply(inline x: Boolean, inline xs: Boolean*): IArray[Boolean] = Array(x, xs: _*).asInstanceOf
348+
def apply(x: Boolean, xs: Boolean*): IArray[Boolean] = Array(x, xs: _*)
362349
/** An immutable array with given elements. */
363-
inline def apply(inline x: Byte, inline xs: Byte*): IArray[Byte] = Array(x, xs: _*).asInstanceOf
350+
def apply(x: Byte, xs: Byte*): IArray[Byte] = Array(x, xs: _*)
364351
/** An immutable array with given elements. */
365-
inline def apply(inline x: Short, inline xs: Short*): IArray[Short] = Array(x, xs: _*).asInstanceOf
352+
def apply(x: Short, xs: Short*): IArray[Short] = Array(x, xs: _*)
366353
/** An immutable array with given elements. */
367-
inline def apply(inline x: Char, inline xs: Char*): IArray[Char] = Array(x, xs: _*).asInstanceOf
354+
def apply(x: Char, xs: Char*): IArray[Char] = Array(x, xs: _*)
368355
/** An immutable array with given elements. */
369-
inline def apply(inline x: Int, inline xs: Int*): IArray[Int] = Array(x, xs: _*).asInstanceOf
356+
def apply(x: Int, xs: Int*): IArray[Int] = Array(x, xs: _*)
370357
/** An immutable array with given elements. */
371-
inline def apply(inline x: Long, inline xs: Long*): IArray[Long] = Array(x, xs: _*).asInstanceOf
358+
def apply(x: Long, xs: Long*): IArray[Long] = Array(x, xs: _*)
372359
/** An immutable array with given elements. */
373-
inline def apply(inline x: Float, inline xs: Float*): IArray[Float] = Array(x, xs: _*).asInstanceOf
360+
def apply(x: Float, xs: Float*): IArray[Float] = Array(x, xs: _*)
374361
/** An immutable array with given elements. */
375-
inline def apply(inline x: Double, inline xs: Double*): IArray[Double] = Array(x, xs: _*).asInstanceOf
362+
def apply(x: Double, xs: Double*): IArray[Double] = Array(x, xs: _*)
376363
/** An immutable array with given elements. */
377-
inline def apply(inline x: Unit, inline xs: Unit*): IArray[Unit] = Array(x, xs: _*).asInstanceOf
364+
def apply(x: Unit, xs: Unit*): IArray[Unit] = Array(x, xs: _*)
378365

379366
/** Concatenates all arrays into a single immutable array.
380367
*
@@ -405,7 +392,7 @@ object IArray {
405392
*/
406393
def fill[T: ClassTag](n1: Int, n2: Int)(elem: => T): IArray[IArray[T]] =
407394
// We cannot avoid a cast here as Array.fill creates inner arrays out of our control:
408-
Array.fill(n1, n2)(elem).asInstanceOf
395+
Array.fill(n1, n2)(elem)
409396

410397
/** Returns a three-dimensional immutable array that contains the results of some element computation a number
411398
* of times. Each element is determined by a separate computation.
@@ -416,7 +403,7 @@ object IArray {
416403
* @param elem the element computation
417404
*/
418405
def fill[T: ClassTag](n1: Int, n2: Int, n3: Int)(elem: => T): IArray[IArray[IArray[T]]] =
419-
Array.fill(n1, n2, n3)(elem).asInstanceOf
406+
Array.fill(n1, n2, n3)(elem)
420407

421408
/** Returns a four-dimensional immutable array that contains the results of some element computation a number
422409
* of times. Each element is determined by a separate computation.
@@ -428,7 +415,7 @@ object IArray {
428415
* @param elem the element computation
429416
*/
430417
def fill[T: ClassTag](n1: Int, n2: Int, n3: Int, n4: Int)(elem: => T): IArray[IArray[IArray[IArray[T]]]] =
431-
Array.fill(n1, n2, n3, n4)(elem).asInstanceOf
418+
Array.fill(n1, n2, n3, n4)(elem)
432419

433420
/** Returns a five-dimensional immutable array that contains the results of some element computation a number
434421
* of times. Each element is determined by a separate computation.
@@ -441,7 +428,7 @@ object IArray {
441428
* @param elem the element computation
442429
*/
443430
def fill[T: ClassTag](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int)(elem: => T): IArray[IArray[IArray[IArray[IArray[T]]]]] =
444-
Array.fill(n1, n2, n3, n4, n5)(elem).asInstanceOf
431+
Array.fill(n1, n2, n3, n4, n5)(elem)
445432

446433
/** Returns an immutable array containing values of a given function over a range of integer
447434
* values starting from 0.
@@ -460,7 +447,7 @@ object IArray {
460447
* @param f The function computing element values
461448
*/
462449
def tabulate[T: ClassTag](n1: Int, n2: Int)(f: (Int, Int) => T): IArray[IArray[T]] =
463-
Array.tabulate(n1, n2)(f).asInstanceOf
450+
Array.tabulate(n1, n2)(f)
464451

465452
/** Returns a three-dimensional immutable array containing values of a given function
466453
* over ranges of integer values starting from `0`.
@@ -471,7 +458,7 @@ object IArray {
471458
* @param f The function computing element values
472459
*/
473460
def tabulate[T: ClassTag](n1: Int, n2: Int, n3: Int)(f: (Int, Int, Int) => T): IArray[IArray[IArray[T]]] =
474-
Array.tabulate(n1, n2, n3)(f).asInstanceOf
461+
Array.tabulate(n1, n2, n3)(f)
475462

476463
/** Returns a four-dimensional immutable array containing values of a given function
477464
* over ranges of integer values starting from `0`.
@@ -483,7 +470,7 @@ object IArray {
483470
* @param f The function computing element values
484471
*/
485472
def tabulate[T: ClassTag](n1: Int, n2: Int, n3: Int, n4: Int)(f: (Int, Int, Int, Int) => T): IArray[IArray[IArray[IArray[T]]]] =
486-
Array.tabulate(n1, n2, n3, n4)(f).asInstanceOf
473+
Array.tabulate(n1, n2, n3, n4)(f)
487474

488475
/** Returns a five-dimensional immutable array containing values of a given function
489476
* over ranges of integer values starting from `0`.
@@ -496,7 +483,7 @@ object IArray {
496483
* @param f The function computing element values
497484
*/
498485
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]]]]] =
499-
Array.tabulate(n1, n2, n3, n4, n5)(f).asInstanceOf
486+
Array.tabulate(n1, n2, n3, n4, n5)(f)
500487

501488
/** Returns an immutable array containing a sequence of increasing integers in a range.
502489
*
@@ -531,8 +518,7 @@ object IArray {
531518
* @param x the selector value
532519
* @return sequence wrapped in a [[scala.Some]], if `x` is a Seq, otherwise `None`
533520
*/
534-
def unapplySeq[T](x: IArray[T]) =
535-
// The double type ascription is currently needed,
536-
// for some reason (see: https://scastie.scala-lang.org/sSsmOhKxSKym405MgNRKqQ)
537-
Array.unapplySeq((x: Sup[T]): Array[_ <: T])
538-
}
521+
def unapplySeq[T](x: IArray[T]): Array.UnapplySeqWrapper[_ <: T] =
522+
Array.unapplySeq(x)
523+
524+
end IArray

0 commit comments

Comments
 (0)