Skip to content

Commit 8606a41

Browse files
committed
Fix hole when resetting a typerstate
Besides the constraint, we also need to reset any instantiated type variables. This is necessary for correctness and also to avoid uncollected garbage in constraints when an entry is never dropped since the associated type variables are no longer owned by the constraint.
1 parent 4c91988 commit 8606a41

File tree

3 files changed

+19
-3
lines changed

3 files changed

+19
-3
lines changed

compiler/src/dotty/tools/dotc/core/TyperState.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,17 @@ object TyperState {
2222
.init(null, OrderingConstraint.empty)
2323
.setReporter(new ConsoleReporter())
2424
.setCommittable(true)
25+
26+
opaque type Snapshot = (Constraint, TypeVars)
27+
28+
extension (ts: TyperState)
29+
def snapshot(): Snapshot = (ts.constraint, ts.ownedVars)
30+
31+
def resetTo(state: Snapshot)(using Context): Unit =
32+
val (c, tvs) = state
33+
for tv <- tvs do if tv.isInstantiated then tv.resetInst(ts)
34+
ts.ownedVars = tvs
35+
ts.constraint = c
2536
}
2637

2738
class TyperState() {

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4404,6 +4404,10 @@ object Types {
44044404
owningState1.ownedVars -= this
44054405
owningState = null // no longer needed; null out to avoid a memory leak
44064406

4407+
private[core] def resetInst(ts: TyperState): Unit =
4408+
myInst = NoType
4409+
owningState = new WeakReference(ts)
4410+
44074411
/** The state owning the variable. This is at first `creatorState`, but it can
44084412
* be changed to an enclosing state on a commit.
44094413
*/

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3247,7 +3247,7 @@ class Typer extends Namer
32473247
replaceSingletons(tp)
32483248
}
32493249
wtp.paramInfos.foreach(instantiate)
3250-
val constr = ctx.typerState.constraint
3250+
val saved = ctx.typerState.snapshot()
32513251

32523252
def dummyArg(tp: Type) = untpd.Ident(nme.???).withTypeUnchecked(tp)
32533253

@@ -3347,8 +3347,9 @@ class Typer extends Namer
33473347
if (propFail.exists) {
33483348
// If there are several arguments, some arguments might already
33493349
// have influenced the context, binding variables, but later ones
3350-
// might fail. In that case the constraint needs to be reset.
3351-
ctx.typerState.constraint = constr
3350+
// might fail. In that case the constraint and instantiated variables
3351+
// need to be reset.
3352+
ctx.typerState.resetTo(saved)
33523353

33533354
// If method has default params, fall back to regular application
33543355
// where all inferred implicits are passed as named args.

0 commit comments

Comments
 (0)