@@ -22,6 +22,7 @@ import Util.*
22
22
import scala .collection .immutable .ListSet
23
23
import scala .collection .mutable
24
24
import scala .annotation .tailrec
25
+ import scala .annotation .constructorOnly
25
26
26
27
/** Check initialization safety of static objects
27
28
*
@@ -119,13 +120,13 @@ object Objects:
119
120
def show (using Context ) = " ObjectRef(" + klass.show + " )"
120
121
121
122
/**
122
- * Rerepsents values that are instances of the specified class
123
+ * Rerepsents values that are instances of the specified class.
123
124
*
125
+ * Note that the 2nd parameter block does not take part in the definition of equality.
124
126
*/
125
127
case class OfClass private (klass : ClassSymbol , outer : Value , ctor : Symbol , args : List [Value ], env : Env .Data )
126
128
(valsMap : mutable.Map [Symbol , Value ], varsMap : mutable.Map [Symbol , Heap .Addr ], outersMap : mutable.Map [ClassSymbol , Value ])
127
129
extends Ref (valsMap, varsMap, outersMap):
128
-
129
130
def widenedCopy (outer : Value , args : List [Value ], env : Env .Data ): OfClass =
130
131
new OfClass (klass, outer, ctor, args, env)(this .valsMap, this .varsMap, outersMap)
131
132
@@ -138,13 +139,31 @@ object Objects:
138
139
klass : ClassSymbol , outer : Value , ctor : Symbol , args : List [Value ], env : Env .Data )(
139
140
using Context
140
141
): 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
+ )
145
145
instance.initOuter(klass, outer)
146
146
instance
147
147
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
+
148
167
/**
149
168
* Represents a lambda expression
150
169
*/
@@ -426,6 +445,9 @@ object Objects:
426
445
def fieldVarAddr (ref : Ref , sym : Symbol , owner : ClassSymbol ): Addr =
427
446
FieldAddr (ref, sym, owner)
428
447
448
+ def arrayAddr (ref : Ref , owner : ClassSymbol ): Addr =
449
+ FieldAddr (ref, NoSymbol , owner)
450
+
429
451
def getHeapData ()(using mutable : MutableData ): Data = mutable.heap
430
452
431
453
/** Cache used to terminate the check */
@@ -502,6 +524,26 @@ object Objects:
502
524
case Bottom =>
503
525
Bottom
504
526
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
+
505
547
case ref : Ref =>
506
548
val isLocal = ! meth.owner.isClass
507
549
val target =
@@ -669,24 +711,27 @@ object Objects:
669
711
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) {
670
712
outer match
671
713
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)
674
716
Bottom
675
717
676
718
case value : (Bottom .type | ObjectRef | OfClass | Cold .type ) =>
677
719
// The outer can be a bottom value for top-level classes.
678
720
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 )
686
731
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
690
735
691
736
case RefSet (refs) =>
692
737
refs.map(ref => instantiate(ref, klass, ctor, args)).join
@@ -730,7 +775,7 @@ object Objects:
730
775
case Cold =>
731
776
report.warning(" Calling cold by-name alias. Call trace: \n " + Trace .show, Trace .position)
732
777
Bottom
733
- case _ : RefSet | _ : OfClass | _ : ObjectRef =>
778
+ case _ : RefSet | _ : Ref =>
734
779
report.warning(" [Internal error] Unexpected by-name value " + value.show + " . Calling trace:\n " + Trace .show, Trace .position)
735
780
Bottom
736
781
else
0 commit comments