@@ -162,7 +162,7 @@ object Objects:
162
162
val joinedTrace = data.pendingTraces.slice(index + 1 , data.checkingObjects.size).foldLeft(pendingTrace) { (a, acc) => acc ++ a }
163
163
val callTrace = Trace .buildStacktrace(joinedTrace, " Calling trace:\n " )
164
164
val cycle = data.checkingObjects.slice(index, data.checkingObjects.size)
165
- val pos = clazz.defTree. asInstanceOf [ TypeDef ].rhs. asInstanceOf [ Template ].constr
165
+ val pos = clazz.defTree
166
166
report.warning(" Cyclic initialization: " + cycle.map(_.show).mkString(" -> " ) + " -> " + clazz.show + " . " + callTrace, pos)
167
167
else if index == - 1 && data.checkedObjects.indexOf(clazz) == - 1 then
168
168
data.pendingTraces += pendingTrace
@@ -186,12 +186,15 @@ object Objects:
186
186
187
187
def show (using Context ): String
188
188
189
- /** Local environments can be deeply nested, therefore we need `outer`. */
190
- private case class LocalEnv (private [Env ] val params : Map [Symbol , Value ], owner : Symbol , outer : Data )(using Context ) extends Data :
189
+ /** Local environments can be deeply nested, therefore we need `outer`.
190
+ *
191
+ * For local variables in rhs of class field definitions, the `meth` is the primary constructor.
192
+ */
193
+ private case class LocalEnv (private [Env ] val params : Map [Symbol , Value ], meth : Symbol , outer : Data )(using Context ) extends Data :
191
194
val level = outer.level + 1
192
195
193
196
if (level > 3 )
194
- report.warning(" [Internal error] Deeply nested environemnt, level = " + level + " , " + owner .show + " in " + owner .enclosingClass.show, owner .defTree)
197
+ report.warning(" [Internal error] Deeply nested environemnt, level = " + level + " , " + meth .show + " in " + meth .enclosingClass.show, meth .defTree)
195
198
196
199
private [Env ] val locals : mutable.Map [Symbol , Value ] = mutable.Map .empty
197
200
@@ -203,10 +206,10 @@ object Objects:
203
206
params.contains(x) || locals.contains(x)
204
207
205
208
def widen (height : Int )(using Context ): Data =
206
- new LocalEnv (params.map(_ -> _.widen(height)), owner , outer.widen(height))
209
+ new LocalEnv (params.map(_ -> _.widen(height)), meth , outer.widen(height))
207
210
208
211
def show (using Context ) =
209
- " owner: " + owner .show + " \n " +
212
+ " owner: " + meth .show + " \n " +
210
213
" params: " + params.map(_.show + " ->" + _.show).mkString(" {" , " , " , " }" ) + " \n " +
211
214
" locals: " + locals.map(_.show + " ->" + _.show).mkString(" {" , " , " , " }" ) + " \n " +
212
215
" outer = {\n " + outer.show + " \n }"
@@ -265,19 +268,19 @@ object Objects:
265
268
* @param thisV The value for `this` of the enclosing class where the local variable is referenced.
266
269
* @param env The local environment where the local variable is referenced.
267
270
*/
268
- def resolveEnv (owner : Symbol , thisV : Value , env : Data )(using Context ): Option [(Value , Data )] =
271
+ def resolveEnv (meth : Symbol , thisV : Value , env : Data )(using Context ): Option [(Value , Data )] = log( " Resolving env for " + meth.show + " , this = " + thisV.show + " , env = " + env.show, printer) {
269
272
env match
270
273
case localEnv : LocalEnv =>
271
- if localEnv.owner == owner then Some (thisV -> env)
272
- else resolveEnv(owner , thisV, localEnv.outer)
274
+ if localEnv.meth == meth then Some (thisV -> env)
275
+ else resolveEnv(meth , thisV, localEnv.outer)
273
276
case NoEnv =>
274
277
// TODO: handle RefSet
275
278
thisV match
276
279
case ref : OfClass =>
277
- resolveEnv(owner , ref.outer, ref.env)
280
+ resolveEnv(meth , ref.outer, ref.env)
278
281
case _ =>
279
282
None
280
- end resolveEnv
283
+ }
281
284
282
285
def withEnv [T ](env : Data )(fn : Data ?=> T ): T = fn(using env)
283
286
end Env
@@ -517,7 +520,8 @@ object Objects:
517
520
else if target.exists then
518
521
if target.isOneOf(Flags .Mutable ) then
519
522
if ref.owner == State .currentObject then
520
- Heap .read(ref, field)
523
+ val isPrimitive = field.info.typeSymbol.isPrimitiveValueClass
524
+ if isPrimitive then Bottom else Heap .read(ref, field)
521
525
else
522
526
report.warning(" Reading mutable state of " + ref.owner.show + " during initialization of " + State .currentObject + " is discouraged as it breaks initialization-time irrelevance. Calling trace: " + Trace .show, Trace .position)
523
527
Bottom
@@ -566,7 +570,9 @@ object Objects:
566
570
if ref.owner != State .currentObject then
567
571
errorMutateOtherStaticObject(State .currentObject, ref.owner)
568
572
else
569
- Heap .write(ref, field, rhs)
573
+ val isPrimitive = field.info.typeSymbol.isPrimitiveValueClass
574
+ if ! isPrimitive then
575
+ Heap .write(ref, field, rhs)
570
576
end match
571
577
572
578
Bottom
@@ -587,7 +593,8 @@ object Objects:
587
593
if klass.owner.isClass then
588
594
(outer.widen(1 ), Env .NoEnv )
589
595
else
590
- Env .resolveEnv(klass.enclosingMethod, outer, summon[Env .Data ]).getOrElse(Cold -> Env .NoEnv )
596
+ // klass.enclosingMethod returns its primary constructor
597
+ Env .resolveEnv(klass.owner.enclosingMethod, outer, summon[Env .Data ]).getOrElse(Cold -> Env .NoEnv )
591
598
592
599
val instance = OfClass (klass, outerWidened, ctor, args.map(_.value), envWidened, State .currentObject)
593
600
callConstructor(instance, ctor, args)
@@ -598,51 +605,58 @@ object Objects:
598
605
}
599
606
600
607
def initLocal (ref : Ref , sym : Symbol , value : Value ): Contextual [Unit ] = log(" initialize local " + sym.show + " with " + value.show, printer) {
601
- if sym.is(Flags .Mutable ) then
602
- val env = summon[Env .Data ]
603
- Heap .writeLocalVar(ref, env, sym, value)
604
- else
605
- Env .setLocalVal(sym, value)
608
+ val isPrimitive = sym.info.typeSymbol.isPrimitiveValueClass
609
+ if ! isPrimitive then
610
+ if sym.is(Flags .Mutable ) then
611
+ val env = summon[Env .Data ]
612
+ Heap .writeLocalVar(ref, env, sym, value)
613
+ else
614
+ Env .setLocalVal(sym, value)
606
615
}
607
616
608
617
def readLocal (thisV : Value , sym : Symbol ): Contextual [Value ] = log(" reading local " + sym.show, printer, (_ : Value ).show) {
609
- Env .resolveEnv(sym.enclosingMethod, thisV, summon[Env .Data ]) match
610
- case Some (thisV -> env) =>
611
- if sym.is(Flags .Mutable ) then
612
- thisV match
613
- case ref : Ref =>
614
- Heap .readLocalVar(ref, env, sym)
615
- case _ =>
618
+ val isPrimitive = sym.info.typeSymbol.isPrimitiveValueClass
619
+ if isPrimitive then
620
+ Bottom
621
+ else
622
+ Env .resolveEnv(sym.enclosingMethod, thisV, summon[Env .Data ]) match
623
+ case Some (thisV -> env) =>
624
+ if sym.is(Flags .Mutable ) then
625
+ thisV match
626
+ case ref : Ref =>
627
+ Heap .readLocalVar(ref, env, sym)
628
+ case _ =>
629
+ Cold
630
+ else if sym.isPatternBound then
631
+ // TODO: handle patterns
616
632
Cold
617
- else if sym.isPatternBound then
618
- // TODO: handle patterns
619
- Cold
620
- else
621
- given Env .Data = env
622
- try
623
- Env (sym)
624
- catch ex =>
625
- report.warning(" [Internal error] Not found " + sym.show + " \n env = " + env.show + " . Calling trace:\n " + Trace .show, Trace .position)
626
- Bottom
633
+ else
634
+ given Env .Data = env
635
+ try
636
+ Env (sym)
637
+ catch ex =>
638
+ report.warning(" [Internal error] Not found " + sym.show + " \n env = " + env.show + " . Calling trace:\n " + Trace .show, Trace .position)
639
+ Bottom
627
640
628
- case _ => Cold
641
+ case _ => Cold
629
642
}
630
643
631
644
def writeLocal (thisV : Value , sym : Symbol , value : Value ): Contextual [Value ] = log(" write local " + sym.show + " with " + value.show, printer, (_ : Value ).show) {
632
645
633
646
assert(sym.is(Flags .Mutable ), " Writing to immutable variable " + sym.show)
647
+ val isPrimitive = sym.info.typeSymbol.isPrimitiveValueClass
648
+ if ! isPrimitive then
649
+ Env .resolveEnv(sym.enclosingMethod, thisV, summon[Env .Data ]) match
650
+ case Some (thisV -> env) =>
651
+ thisV match
652
+ case ref : Ref =>
653
+ Heap .writeLocalVar(ref, summon[Env .Data ], sym, value)
654
+ case _ =>
655
+ report.warning(" Assigning to variables in outer scope" , Trace .position)
634
656
635
- Env .resolveEnv(sym.enclosingMethod, thisV, summon[Env .Data ]) match
636
- case Some (thisV -> env) =>
637
- thisV match
638
- case ref : Ref =>
639
- Heap .writeLocalVar(ref, summon[Env .Data ], sym, value)
640
657
case _ =>
641
658
report.warning(" Assigning to variables in outer scope" , Trace .position)
642
-
643
- case _ =>
644
- report.warning(" Assigning to variables in outer scope" , Trace .position)
645
-
659
+ end if
646
660
Bottom
647
661
}
648
662
@@ -660,7 +674,7 @@ object Objects:
660
674
def iterate ()(using Context ): Unit =
661
675
count += 1
662
676
663
- given Trace = Trace .empty.add(tpl.constr )
677
+ given Trace = Trace .empty.add(classSym.defTree )
664
678
given env : Env .Data = Env .emptyEnv(tpl.constr.symbol)
665
679
666
680
log(" Iteration " + count) {
0 commit comments