@@ -82,7 +82,7 @@ object Semantic {
82
82
*/
83
83
def updateField (field : Symbol , value : Value )(using Heap , Context ): Unit =
84
84
val obj = objekt
85
- assert(! obj.hasField(field), field.show + " already init, new = " + value + " , old = " + obj.field(field))
85
+ assert(! obj.hasField(field), field.show + " already init, new = " + value + " , old = " + obj.field(field) + " , ref = " + this )
86
86
val obj2 = obj.copy(fields = obj.fields.updated(field, value))
87
87
heap.update(this , obj2)
88
88
@@ -92,7 +92,7 @@ object Semantic {
92
92
*/
93
93
def updateOuter (klass : ClassSymbol , value : Value )(using Heap , Context ): Unit =
94
94
val obj = objekt
95
- assert(! obj.hasOuter(klass), klass.show + " already init , new = " + value + " , old = " + obj.outer(klass))
95
+ assert(! obj.hasOuter(klass), klass.show + " already has outer , new = " + value + " , old = " + obj.outer(klass) + " , ref = " + this )
96
96
val obj2 = obj.copy(outers = obj.outers.updated(klass, value))
97
97
heap.update(this , obj2)
98
98
}
@@ -292,6 +292,7 @@ object Semantic {
292
292
extension (cache : CacheIn | CacheOut )
293
293
def contains (value : Value , expr : Tree ): Boolean = cache.contains(value) && cache(value).contains(expr)
294
294
def get (value : Value , expr : Tree ): Value = cache(value)(expr)
295
+ def remove (value : Value , expr : Tree ) = cache(value).remove(expr)
295
296
def put (value : Value , expr : Tree , result : Value ): Unit = {
296
297
val innerMap = cache.getOrElseUpdate(value, new EqHashMap [Tree , Value ])
297
298
innerMap(expr) = result
@@ -403,7 +404,7 @@ object Semantic {
403
404
if target.is(Flags .Lazy ) then
404
405
given Trace = trace1
405
406
val rhs = target.defTree.asInstanceOf [ValDef ].rhs
406
- eval(rhs, ref, target.owner.asClass)
407
+ eval(rhs, ref, target.owner.asClass, cacheResult = true )
407
408
else
408
409
val obj = ref.objekt
409
410
if obj.hasField(target) then
@@ -417,7 +418,7 @@ object Semantic {
417
418
Result (Hot , Nil )
418
419
else if target.hasSource then
419
420
val rhs = target.defTree.asInstanceOf [ValOrDefDef ].rhs
420
- eval(rhs, ref, target.owner.asClass)
421
+ eval(rhs, ref, target.owner.asClass, cacheResult = true )
421
422
else
422
423
val error = CallUnknown (field, source, trace.toVector)
423
424
Result (Hot , error :: Nil )
@@ -469,7 +470,7 @@ object Semantic {
469
470
val env2 = Env (ddef, args.map(_.value).widenArgs)
470
471
// normal method call
471
472
withEnv(if isLocal then env else Env .empty) {
472
- eval(ddef.rhs, ref, cls) ++ checkArgs
473
+ eval(ddef.rhs, ref, cls, cacheResult = true ) ++ checkArgs
473
474
}
474
475
else if ref.canIgnoreMethodCall(target) then
475
476
Result (Hot , Nil )
@@ -490,7 +491,7 @@ object Semantic {
490
491
if meth.name.toString == " tupled" then Result (value, Nil ) // a call like `fun.tupled`
491
492
else
492
493
withEnv(env) {
493
- eval(body, thisV, klass) ++ checkArgs
494
+ eval(body, thisV, klass, cacheResult = true ) ++ checkArgs
494
495
}
495
496
496
497
case RefSet (refs) =>
@@ -517,11 +518,11 @@ object Semantic {
517
518
if ctor.isPrimaryConstructor then
518
519
given Env = env2
519
520
val tpl = cls.defTree.asInstanceOf [TypeDef ].rhs.asInstanceOf [Template ]
520
- val res = withTrace(trace.add(cls.defTree)) { eval(tpl, ref, cls) }
521
+ val res = withTrace(trace.add(cls.defTree)) { eval(tpl, ref, cls, cacheResult = true ) }
521
522
Result (ref, res.errors)
522
523
else
523
524
given Env = env2
524
- eval(ddef.rhs, ref, cls)
525
+ eval(ddef.rhs, ref, cls, cacheResult = true )
525
526
else if ref.canIgnoreMethodCall(ctor) then
526
527
Result (Hot , Nil )
527
528
else
@@ -770,25 +771,22 @@ object Semantic {
770
771
type Task = ThisRef
771
772
772
773
class WorkList private [Semantic ]() {
773
- private var checkedTasks : Set [Task ] = Set .empty
774
774
private var pendingTasks : List [Task ] = Nil
775
775
776
776
def addTask (task : Task ): Unit =
777
- if ! checkedTasks.contains(task) then pendingTasks = task :: pendingTasks
777
+ pendingTasks = task :: pendingTasks
778
778
779
779
/** Process the worklist until done */
780
780
@ tailrec
781
781
final def work ()(using State , Context ): Unit =
782
782
pendingTasks match
783
783
case task :: rest =>
784
+ val heapBefore = heap.snapshot()
784
785
val res = doTask(task)
785
786
res.errors.foreach(_.issue)
786
787
787
- val heapBefore = heap.snapshot()
788
-
789
- if res.errors.nonEmpty then
788
+ if res.errors.nonEmpty || ! cache.changed then
790
789
pendingTasks = rest
791
- checkedTasks = checkedTasks + task
792
790
else
793
791
// discard heap changes and copy cache.out to cache.in
794
792
cache.update()
@@ -811,7 +809,7 @@ object Semantic {
811
809
given Trace = Trace .empty
812
810
given Env = Env (paramValues)
813
811
814
- init (tpl, thisRef, thisRef.klass)
812
+ eval (tpl, thisRef, thisRef.klass)
815
813
}
816
814
}
817
815
inline def workList (using wl : WorkList ): WorkList = wl
@@ -862,15 +860,17 @@ object Semantic {
862
860
*
863
861
* This method only handles cache logic and delegates the work to `cases`.
864
862
*/
865
- def eval (expr : Tree , thisV : Ref , klass : ClassSymbol ): Contextual [Result ] = log(" evaluating " + expr.show + " , this = " + thisV.show, printer, res => res.asInstanceOf [Result ].show) {
863
+ def eval (expr : Tree , thisV : Ref , klass : ClassSymbol , cacheResult : Boolean = false ): Contextual [Result ] = log(" evaluating " + expr.show + " , this = " + thisV.show, printer, res => res.asInstanceOf [Result ].show) {
866
864
if (cache.out.contains(thisV, expr)) Result (cache.out.get(thisV, expr), Errors .empty)
867
865
else {
868
866
val assumeValue = if (cache.in.contains(thisV, expr)) cache.in.get(thisV, expr) else Hot
869
867
cache.out.put(thisV, expr, assumeValue)
870
868
val res = cases(expr, thisV, klass)
871
869
if res.value != assumeValue then
872
870
cache.changed = true
873
- cache.out.put(thisV, expr, res.value)
871
+ cache.out.put(thisV, expr, res.value) // must put in cache for termination
872
+ else
873
+ if ! cacheResult then cache.out.remove(thisV, expr)
874
874
res
875
875
}
876
876
}
@@ -1058,6 +1058,9 @@ object Semantic {
1058
1058
if tdef.isClassDef then Result (Hot , Errors .empty)
1059
1059
else Result (Hot , checkTermUsage(tdef.rhs, thisV, klass))
1060
1060
1061
+ case tpl : Template =>
1062
+ init(tpl, thisV, klass)
1063
+
1061
1064
case _ : Import | _ : Export =>
1062
1065
Result (Hot , Errors .empty)
1063
1066
@@ -1102,17 +1105,15 @@ object Semantic {
1102
1105
else
1103
1106
thisV match
1104
1107
case Hot => Hot
1105
- case thisRef : ThisRef =>
1106
- val obj = thisRef .objekt
1108
+ case ref : Ref =>
1109
+ val obj = ref .objekt
1107
1110
val outerCls = klass.owner.lexicallyEnclosingClass.asClass
1108
1111
if ! obj.hasOuter(klass) then
1109
1112
val error = PromoteError (" outer not yet initialized, target = " + target + " , klass = " + klass, source, trace.toVector)
1110
1113
report.error(error.show + error.stacktrace, source)
1111
1114
Hot
1112
1115
else
1113
1116
resolveThis(target, obj.outer(klass), outerCls, source)
1114
- case warm : Warm =>
1115
- ???
1116
1117
case RefSet (refs) =>
1117
1118
refs.map(ref => resolveThis(target, ref, klass, source)).join
1118
1119
case fun : Fun =>
@@ -1168,7 +1169,7 @@ object Semantic {
1168
1169
else cases(tref.prefix, thisV, klass, source)
1169
1170
1170
1171
/** Initialize part of an abstract object in `klass` of the inheritance chain */
1171
- def init (tpl : Template , thisV : ThisRef , klass : ClassSymbol ): Contextual [Result ] = log(" init " + klass.show, printer, res => res.asInstanceOf [Result ].show) {
1172
+ def init (tpl : Template , thisV : Ref , klass : ClassSymbol ): Contextual [Result ] = log(" init " + klass.show, printer, res => res.asInstanceOf [Result ].show) {
1172
1173
val errorBuffer = new mutable.ArrayBuffer [Error ]
1173
1174
1174
1175
val paramsMap = tpl.constr.termParamss.flatten.map { vdef =>
@@ -1275,8 +1276,11 @@ object Semantic {
1275
1276
case _ : MemberDef =>
1276
1277
1277
1278
case tree =>
1278
- if fieldsChanged then thisV.tryPromoteCurrentObject
1279
- fieldsChanged = false
1279
+ thisV match
1280
+ case thisRef : ThisRef =>
1281
+ if fieldsChanged then thisRef.tryPromoteCurrentObject
1282
+ fieldsChanged = false
1283
+ case _ =>
1280
1284
1281
1285
given Env = Env .empty
1282
1286
errorBuffer ++= eval(tree, thisV, klass).errors
0 commit comments