Skip to content

Commit c137c21

Browse files
committed
Primitive support for arrays
1 parent e5b4f22 commit c137c21

File tree

2 files changed

+70
-19
lines changed

2 files changed

+70
-19
lines changed

compiler/src/dotty/tools/dotc/transform/init/Objects.scala

Lines changed: 64 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import Util.*
2222
import scala.collection.immutable.ListSet
2323
import scala.collection.mutable
2424
import scala.annotation.tailrec
25+
import scala.annotation.constructorOnly
2526

2627
/** Check initialization safety of static objects
2728
*
@@ -119,13 +120,13 @@ object Objects:
119120
def show(using Context) = "ObjectRef(" + klass.show + ")"
120121

121122
/**
122-
* Rerepsents values that are instances of the specified class
123+
* Rerepsents values that are instances of the specified class.
123124
*
125+
* Note that the 2nd parameter block does not take part in the definition of equality.
124126
*/
125127
case class OfClass private (klass: ClassSymbol, outer: Value, ctor: Symbol, args: List[Value], env: Env.Data)
126128
(valsMap: mutable.Map[Symbol, Value], varsMap: mutable.Map[Symbol, Heap.Addr], outersMap: mutable.Map[ClassSymbol, Value])
127129
extends Ref(valsMap, varsMap, outersMap):
128-
129130
def widenedCopy(outer: Value, args: List[Value], env: Env.Data): OfClass =
130131
new OfClass(klass, outer, ctor, args, env)(this.valsMap, this.varsMap, outersMap)
131132

@@ -138,13 +139,31 @@ object Objects:
138139
klass: ClassSymbol, outer: Value, ctor: Symbol, args: List[Value], env: Env.Data)(
139140
using Context
140141
): OfClass =
141-
val instance =
142-
new OfClass(klass, outer, ctor, args, env)(
143-
valsMap = mutable.Map.empty, varsMap = mutable.Map.empty, outersMap = mutable.Map.empty
144-
)
142+
val instance = new OfClass(klass, outer, ctor, args, env)(
143+
valsMap = mutable.Map.empty, varsMap = mutable.Map.empty, outersMap = mutable.Map.empty
144+
)
145145
instance.initOuter(klass, outer)
146146
instance
147147

148+
149+
/**
150+
* Rerepsents arrays.
151+
*
152+
* Note that the 2nd parameter block does not take part in the definition of equality.
153+
*
154+
* Different arrays are distinguished by the context. Currently the default context is the static
155+
* object whose initialization triggers the creation of the array.
156+
*
157+
* In the future, it is possible that we introduce a mechanism for end-users to mark the context.
158+
*
159+
* @param owner The static object whose initialization creates the array.
160+
*/
161+
case class OfArray(owner: ClassSymbol)(using @constructorOnly ctx: Context)
162+
extends Ref(valsMap = mutable.Map.empty, varsMap = mutable.Map.empty, outersMap = mutable.Map.empty):
163+
val klass: ClassSymbol = defn.ArrayClass
164+
val addr: Heap.Addr = Heap.arrayAddr(this, owner)
165+
def show(using Context) = "OfArray(owner = " + owner.show + ")"
166+
148167
/**
149168
* Represents a lambda expression
150169
*/
@@ -426,6 +445,9 @@ object Objects:
426445
def fieldVarAddr(ref: Ref, sym: Symbol, owner: ClassSymbol): Addr =
427446
FieldAddr(ref, sym, owner)
428447

448+
def arrayAddr(ref: Ref, owner: ClassSymbol): Addr =
449+
FieldAddr(ref, NoSymbol, owner)
450+
429451
def getHeapData()(using mutable: MutableData): Data = mutable.heap
430452

431453
/** Cache used to terminate the check */
@@ -502,6 +524,26 @@ object Objects:
502524
case Bottom =>
503525
Bottom
504526

527+
case arr: OfArray =>
528+
val target = resolve(defn.ArrayClass, meth)
529+
530+
if target == defn.Array_apply || target == defn.Array_clone then
531+
if arr.addr.owner == State.currentObject then
532+
Heap.read(arr.addr)
533+
else
534+
errorReadOtherStaticObject(State.currentObject, arr.addr.owner)
535+
Bottom
536+
else if target == defn.Array_update then
537+
assert(args.size == 2, "Incorrect number of arguments for Array update, found = " + args.size)
538+
if arr.addr.owner != State.currentObject then
539+
errorMutateOtherStaticObject(State.currentObject, arr.addr.owner)
540+
else
541+
Heap.write(arr.addr, args.tail.head.value)
542+
Bottom
543+
else
544+
// Array.length is OK
545+
Bottom
546+
505547
case ref: Ref =>
506548
val isLocal = !meth.owner.isClass
507549
val target =
@@ -669,24 +711,27 @@ object Objects:
669711
def instantiate(outer: Value, klass: ClassSymbol, ctor: Symbol, args: List[ArgInfo]): Contextual[Value] = log("instantiating " + klass.show + ", outer = " + outer + ", args = " + args.map(_.value.show), printer, (_: Value).show) {
670712
outer match
671713

672-
case fun: Fun =>
673-
report.error("[Internal error] unexpected tree in instantiating a function, fun = " + fun.code.show + Trace.show, Trace.position)
714+
case _ : Fun | _: OfArray =>
715+
report.error("[Internal error] unexpected outer in instantiating a class, outer = " + outer.show + ", class = " + klass.show + ", " + Trace.show, Trace.position)
674716
Bottom
675717

676718
case value: (Bottom.type | ObjectRef | OfClass | Cold.type) =>
677719
// The outer can be a bottom value for top-level classes.
678720

679-
// Widen the outer to finitize the domain. Arguments already widened in `evalArgs`.
680-
val (outerWidened, envWidened) =
681-
if klass.owner.isClass then
682-
(outer.widen(1), Env.NoEnv)
683-
else
684-
// klass.enclosingMethod returns its primary constructor
685-
Env.resolveEnv(klass.owner.enclosingMethod, outer, summon[Env.Data]).getOrElse(Cold -> Env.NoEnv)
721+
if klass == defn.ArrayClass then
722+
OfArray(State.currentObject)
723+
else
724+
// Widen the outer to finitize the domain. Arguments already widened in `evalArgs`.
725+
val (outerWidened, envWidened) =
726+
if klass.owner.isClass then
727+
(outer.widen(1), Env.NoEnv)
728+
else
729+
// klass.enclosingMethod returns its primary constructor
730+
Env.resolveEnv(klass.owner.enclosingMethod, outer, summon[Env.Data]).getOrElse(Cold -> Env.NoEnv)
686731

687-
val instance = OfClass(klass, outerWidened, ctor, args.map(_.value), envWidened)
688-
callConstructor(instance, ctor, args)
689-
instance
732+
val instance = OfClass(klass, outerWidened, ctor, args.map(_.value), envWidened)
733+
callConstructor(instance, ctor, args)
734+
instance
690735

691736
case RefSet(refs) =>
692737
refs.map(ref => instantiate(ref, klass, ctor, args)).join
@@ -730,7 +775,7 @@ object Objects:
730775
case Cold =>
731776
report.warning("Calling cold by-name alias. Call trace: \n" + Trace.show, Trace.position)
732777
Bottom
733-
case _: RefSet | _: OfClass | _: ObjectRef =>
778+
case _: RefSet | _: Ref =>
734779
report.warning("[Internal error] Unexpected by-name value " + value.show + ". Calling trace:\n" + Trace.show, Trace.position)
735780
Bottom
736781
else
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
object A:
2+
val array: Array[Int] = new Array(1)
3+
array(0) = 10
4+
5+
object B:
6+
var y = A.array(0) * 2 // error

0 commit comments

Comments
 (0)