@@ -65,44 +65,51 @@ object Semantic {
65
65
sealed abstract class Ref extends Value {
66
66
def klass : ClassSymbol
67
67
def outer : Value
68
- def objekt : Objekt
68
+ def objekt (using Heap ): Objekt = heap(this )
69
+
70
+ def ensureObjectExists ()(using Heap ) =
71
+ if heap.contains(this ) then heap(this )
72
+ else {
73
+ val obj = Objekt (this .klass, fields = Map .empty, outers = Map (this .klass -> this .outer))
74
+ heap.update(this , obj)
75
+ obj
76
+ }
77
+
69
78
70
79
/** Update field value of the abstract object
71
80
*
72
81
* Invariant: fields are immutable and only set once
73
82
*/
74
- def updateField (field : Symbol , value : Value )(using Context ): Unit =
75
- objekt.updateField(field, value)
83
+ def updateField (field : Symbol , value : Value )(using Heap , Context ): Unit =
84
+ val obj = objekt
85
+ assert(! obj.hasField(field), field.show + " already init, new = " + value + " , old = " + obj.field(field))
86
+ val obj2 = obj.copy(fields = obj.fields.updated(field, value))
87
+ heap.update(this , obj2)
76
88
77
89
/** Update the immediate outer of the given `klass` of the abstract object
78
90
*
79
91
* Invariant: outers are immutable and only set once
80
92
*/
81
- def updateOuter (klass : ClassSymbol , value : Value )(using Context ): Unit =
82
- objekt.updateOuter(klass, value)
93
+ def updateOuter (klass : ClassSymbol , value : Value )(using Heap , Context ): Unit =
94
+ val obj = objekt
95
+ assert(! obj.hasOuter(klass), klass.show + " already init, new = " + value + " , old = " + obj.outer(klass))
96
+ val obj2 = obj.copy(outers = obj.outers.updated(klass, value))
97
+ heap.update(this , obj2)
83
98
}
84
99
85
100
/** A reference to the object under initialization pointed by `this` */
86
- case class ThisRef (klass : ClassSymbol ) extends Ref {
101
+ case class ThisRef (klass : ClassSymbol )( using Heap ) extends Ref {
87
102
val outer = Hot
88
- /** Caches initialized fields */
89
- val objekt = Objekt (klass, fields = mutable. Map .empty, outers = mutable. Map (klass -> outer) )
103
+
104
+ ensureObjectExists( )
90
105
}
91
106
92
107
/** An object with all fields initialized but reaches objects under initialization
93
108
*
94
109
* We need to restrict nesting levels of `outer` to finitize the domain.
95
110
*/
96
111
case class Warm (klass : ClassSymbol , outer : Value , ctor : Symbol , args : List [Value ])(using Heap ) extends Ref {
97
- val objekt = getCachedObject()
98
-
99
- private def getCachedObject ()(using Heap ) =
100
- if heap.contains(this ) then heap(this )
101
- else {
102
- val obj = Objekt (this .klass, fields = mutable.Map .empty, outers = mutable.Map (this .klass -> this .outer))
103
- heap.update(this , obj)
104
- obj
105
- }
112
+ ensureObjectExists()
106
113
}
107
114
108
115
/** A function value */
@@ -123,40 +130,33 @@ object Semantic {
123
130
*
124
131
* Note: Object is NOT a value.
125
132
*/
126
- class Objekt (val klass : ClassSymbol , fields : mutable. Map [Symbol , Value ], outers : mutable. Map [ClassSymbol , Value ]) {
133
+ case class Objekt (val klass : ClassSymbol , val fields : Map [Symbol , Value ], val outers : Map [ClassSymbol , Value ]) {
127
134
def field (f : Symbol ): Value = fields(f)
128
135
129
136
def outer (klass : ClassSymbol ) = outers(klass)
130
137
131
138
def hasOuter (klass : ClassSymbol ) = outers.contains(klass)
132
139
133
140
def hasField (f : Symbol ) = fields.contains(f)
134
-
135
- def updateField (field : Symbol , value : Value )(using Context ): Unit =
136
- assert(! fields.contains(field), field.show + " already init, new = " + value + " , old = " + fields(field))
137
- fields(field) = value
138
-
139
- def updateOuter (klass : ClassSymbol , value : Value )(using Context ): Unit =
140
- assert(! outers.contains(klass), klass.show + " already init, new = " + value + " , old = " + outers(klass))
141
- outers(klass) = value
142
141
}
143
142
144
143
/** Abstract heap stores abstract warm objects
145
144
*
146
145
* The heap serves as cache of summaries for warm objects and is shared for checking all classes.
147
146
*/
148
147
object Heap {
149
- opaque type Heap = mutable.Map [Warm , Objekt ]
148
+ class Heap (private var map : Map [Ref , Objekt ]) {
149
+ def contains (ref : Ref ): Boolean = map.contains(ref)
150
+ def apply (ref : Ref ): Objekt = map(ref)
151
+ def update (ref : Ref , obj : Objekt ): Unit =
152
+ map = map.updated(ref, obj)
153
+
154
+ def snapshot (): Heap = new Heap (map)
155
+ def restore (h : Heap ) = this .map = h.map
156
+ }
150
157
151
158
/** Note: don't use `val` to avoid incorrect sharing */
152
- private [Semantic ] def empty : Heap = mutable.Map .empty
153
-
154
- extension (heap : Heap )
155
- def contains (ref : Warm ): Boolean = heap.contains(ref)
156
- def apply (ref : Warm ): Objekt = heap(ref)
157
- def update (ref : Warm , obj : Objekt ): Unit =
158
- heap(ref) = obj
159
- end extension
159
+ private [Semantic ] def empty : Heap = new Heap (Map .empty)
160
160
}
161
161
type Heap = Heap .Heap
162
162
@@ -784,12 +784,15 @@ object Semantic {
784
784
val res = doTask(task)
785
785
res.errors.foreach(_.issue)
786
786
787
+ val heapBefore = heap.snapshot()
788
+
787
789
if res.errors.nonEmpty then
788
790
pendingTasks = rest
789
791
checkedTasks = checkedTasks + task
790
792
else
791
793
// discard heap changes and copy cache.out to cache.in
792
794
cache.update()
795
+ heap.restore(heapBefore)
793
796
794
797
work()
795
798
case _ =>
0 commit comments