@@ -121,16 +121,25 @@ class Constraints(
121
121
* Unification variables which are not in scope anymore, but also haven't been solved, yet.
122
122
*/
123
123
private var pendingInactive : Set [CNode ] = Set .empty
124
-
125
124
)(using C : ErrorReporter ) {
126
125
126
+ /**
127
+ * Caches type substitutions, which are only invalidated if the mapping from node to typevar changes.
128
+ *
129
+ * This significantly improves the performance of Typer (see https://github.com/effekt-lang/effekt/pull/954)
130
+ */
131
+ private var _typeSubstitution : Map [TypeVar , ValueType ] = _
132
+ private def invalidate (): Unit = _typeSubstitution = null
133
+
127
134
/**
128
135
* The currently known substitutions
129
136
*/
130
137
def subst : Substitutions =
131
- val types = classes.flatMap[TypeVar , ValueType ] { case (k, v) => typeSubstitution.get(v).map { k -> _ } }
138
+ if _typeSubstitution == null then {
139
+ _typeSubstitution = classes.flatMap[TypeVar , ValueType ] { case (k, v) => typeSubstitution.get(v).map { k -> _ } }
140
+ }
132
141
val captures = captSubstitution.asInstanceOf [Map [CaptVar , Captures ]]
133
- Substitutions (types , captures)
142
+ Substitutions (_typeSubstitution , captures)
134
143
135
144
/**
136
145
* Should only be called on unification variables where we do not know any types, yet
@@ -308,16 +317,18 @@ class Constraints(
308
317
private [typer] def upperNodes : Map [CNode , Filter ] = getData(x).upperNodes
309
318
private def lower_= (bounds : Set [Capture ]): Unit =
310
319
captureConstraints = captureConstraints.updated(x, getData(x).copy(lower = Some (bounds)))
320
+
311
321
private def upper_= (bounds : Set [Capture ]): Unit =
312
322
captureConstraints = captureConstraints.updated(x, getData(x).copy(upper = Some (bounds)))
323
+
313
324
private def addLower (other : CNode , exclude : Filter ): Unit =
314
325
val oldData = getData(x)
315
326
316
327
// compute the intersection of filters
317
328
val oldFilter = oldData.lowerNodes.get(other)
318
329
val newFilter = oldFilter.map { _ intersect exclude }.getOrElse { exclude }
319
-
320
330
captureConstraints = captureConstraints.updated(x, oldData.copy(lowerNodes = oldData.lowerNodes + (other -> newFilter)))
331
+
321
332
private def addUpper (other : CNode , exclude : Filter ): Unit =
322
333
val oldData = getData(x)
323
334
@@ -462,6 +473,7 @@ class Constraints(
462
473
*/
463
474
private def updateSubstitution (): Unit =
464
475
val substitution = subst
476
+ invalidate()
465
477
typeSubstitution = typeSubstitution.map { case (node, tpe) => node -> substitution.substitute(tpe) }
466
478
467
479
private def getNode (x : UnificationVar ): Node =
0 commit comments