@@ -79,10 +79,11 @@ class TyperState() {
79
79
80
80
private var isCommitted : Boolean = _
81
81
82
- /** The set of uninstantiated type variables which have this state as their owning state
83
- * NOTE: It could be that a variable in `ownedVars` is already instantiated. This is because
84
- * the link between ownedVars and variable instantiation in TypeVar#setInst is made up
85
- * from a weak reference and weak references can have spurious nulls.
82
+ /** The set of uninstantiated type variables which have this state as their owning state.
83
+ *
84
+ * Invariant:
85
+ * if `tstate.isCommittable` then
86
+ * `tstate.ownedVars.contains(tvar)` iff `tvar.owningState.get eq tstate`
86
87
*/
87
88
private var myOwnedVars : TypeVars = _
88
89
def ownedVars : TypeVars = myOwnedVars
@@ -138,6 +139,7 @@ class TyperState() {
138
139
def commit ()(using Context ): Unit = {
139
140
Stats .record(" typerState.commit" )
140
141
assert(isCommittable)
142
+ setCommittable(false )
141
143
val targetState = ctx.typerState
142
144
if constraint ne targetState.constraint then
143
145
Stats .record(" typerState.commit.new constraint" )
@@ -157,12 +159,7 @@ class TyperState() {
157
159
* in this constraint and its predecessors where necessary.
158
160
*/
159
161
def ensureNotConflicting (other : Constraint )(using Context ): Unit =
160
- def hasConflictingTypeVarsFor (tl : TypeLambda ) =
161
- constraint.typeVarOfParam(tl.paramRefs(0 )) ne other.typeVarOfParam(tl.paramRefs(0 ))
162
- // Note: Since TypeVars are allocated in bulk for each type lambda, we only
163
- // have to check the first one to find out if some of them are different.
164
- val conflicting = constraint.domainLambdas.find(tl =>
165
- other.contains(tl) && hasConflictingTypeVarsFor(tl))
162
+ val conflicting = constraint.domainLambdas.filter(constraint.hasConflictingTypeVarsFor(_, other))
166
163
for tl <- conflicting do
167
164
val tl1 = constraint.ensureFresh(tl)
168
165
for case (tvar : TypeVar , pref1) <- tl.paramRefs.map(constraint.typeVarOfParam).lazyZip(tl1.paramRefs) do
@@ -172,15 +169,29 @@ class TyperState() {
172
169
ts.constraint = ts.constraint.subst(tl, tl1)
173
170
ts = ts.previous
174
171
172
+ /** Integrate the constraints from `that` into this TyperState.
173
+ *
174
+ * @pre If `that` is committable, it must not contain any type variable which
175
+ * does not exist in `this` (in other words, all its type variables must
176
+ * be owned by a common parent of `this` and `that`).
177
+ */
175
178
def mergeConstraintWith (that : TyperState )(using Context ): Unit =
176
179
that.ensureNotConflicting(constraint)
177
180
constraint = constraint & (that.constraint, otherHasErrors = that.reporter.errorsReported)
178
181
for tvar <- constraint.uninstVars do
179
- if ! isOwnedAnywhere(this , tvar) then ownedVars += tvar
182
+ if ! isOwnedAnywhere(this , tvar) then includeVar( tvar)
180
183
for tl <- constraint.domainLambdas do
181
184
if constraint.isRemovable(tl) then constraint = constraint.remove(tl)
182
185
186
+ /** Take ownership of `tvar`.
187
+ *
188
+ * @pre `tvar` is not owned by a committable TyperState. This ensures
189
+ * each tvar can only be instantiated by one TyperState.
190
+ */
183
191
private def includeVar (tvar : TypeVar )(using Context ): Unit =
192
+ val oldState = tvar.owningState.get
193
+ assert(oldState == null || ! oldState.isCommittable,
194
+ i " $this attempted to take ownership of $tvar which is already owned by committable $oldState" )
184
195
tvar.owningState = new WeakReference (this )
185
196
ownedVars += tvar
186
197
@@ -196,12 +207,13 @@ class TyperState() {
196
207
Stats .record(" typerState.gc" )
197
208
val toCollect = new mutable.ListBuffer [TypeLambda ]
198
209
for tvar <- ownedVars do
199
- if ! tvar.inst.exists then // See comment of `ownedVars` for why this test is necessary
200
- val inst = constraint.instType(tvar)
201
- if inst.exists then
202
- tvar.setInst(inst)
203
- val tl = tvar.origin.binder
204
- if constraint.isRemovable(tl) then toCollect += tl
210
+ assert(tvar.owningState.get eq this , s " Inconsistent state in $this: it owns $tvar whose owningState is ${tvar.owningState.get}" )
211
+ assert(! tvar.inst.exists, s " Inconsistent state in $this: it owns $tvar which is already instantiated " )
212
+ val inst = constraint.instType(tvar)
213
+ if inst.exists then
214
+ tvar.setInst(inst)
215
+ val tl = tvar.origin.binder
216
+ if constraint.isRemovable(tl) then toCollect += tl
205
217
for tl <- toCollect do
206
218
constraint = constraint.remove(tl)
207
219
0 commit comments