Skip to content

Commit 4a9a526

Browse files
committed
Fix #7458: Refine typevar interpolation
If there are several type variables to instantiate in an interpolation call, instantiate first those type variables that do not tighten the constraint for other instantiatable type variables.
1 parent ca6b1c6 commit 4a9a526

File tree

2 files changed

+24
-3
lines changed

2 files changed

+24
-3
lines changed

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

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ trait Inferencing { this: Typer =>
389389
if ((ownedVars ne locked) && !ownedVars.isEmpty) {
390390
val qualifying = ownedVars -- locked
391391
if (!qualifying.isEmpty) {
392-
typr.println(i"interpolate $tree: ${tree.tpe.widen} in $state, owned vars = ${state.ownedVars.toList}%, %, previous = ${locked.toList}%, % / ${state.constraint}")
392+
typr.println(i"interpolate $tree: ${tree.tpe.widen} in $state, owned vars = ${state.ownedVars.toList}%, %, qualifying = ${qualifying.toList}%, %, previous = ${locked.toList}%, % / ${state.constraint}")
393393
val resultAlreadyConstrained =
394394
tree.isInstanceOf[Apply] || tree.tpe.isInstanceOf[MethodOrPoly]
395395
if (!resultAlreadyConstrained)
@@ -421,22 +421,40 @@ trait Inferencing { this: Typer =>
421421
// val y: List[List[String]] = List(List(1))
422422
val hasUnreportedErrors = state.reporter.hasUnreportedErrors
423423
def constraint = state.constraint
424+
type InstantiateQueue = mutable.ListBuffer[(TypeVar, Boolean)]
425+
val toInstantiate = new InstantiateQueue
424426
for (tvar <- qualifying)
425427
if (!tvar.isInstantiated && state.constraint.contains(tvar)) {
426428
// Needs to be checked again, since previous interpolations could already have
427429
// instantiated `tvar` through unification.
428430
val v = vs(tvar)
429431
if (v == null) {
430432
typr.println(i"interpolate non-occurring $tvar in $state in $tree: $tp, fromBelow = ${tvar.hasLowerBound}, $constraint")
431-
tvar.instantiate(fromBelow = tvar.hasLowerBound)
433+
toInstantiate += ((tvar, tvar.hasLowerBound))
432434
}
433435
else if (!hasUnreportedErrors)
434436
if (v.intValue != 0) {
435437
typr.println(i"interpolate $tvar in $state in $tree: $tp, fromBelow = ${v.intValue == 1}, $constraint")
436-
tvar.instantiate(fromBelow = v.intValue == 1)
438+
toInstantiate += ((tvar, v.intValue == 1))
437439
}
438440
else typr.println(i"no interpolation for nonvariant $tvar in $state")
439441
}
442+
443+
def doInstantiate(buf: InstantiateQueue): Unit =
444+
if buf.nonEmpty then
445+
val suspended = new InstantiateQueue
446+
while buf.nonEmpty do
447+
val first @ (tvar, fromBelow) = buf.head
448+
buf.dropInPlace(1)
449+
val suspend = buf.exists{ (following, _) =>
450+
if fromBelow then constraint.isLess(following.origin, tvar.origin)
451+
else constraint.isLess(following.origin, tvar.origin)
452+
}
453+
if suspend then suspended += first
454+
else tvar.instantiate(fromBelow)
455+
doInstantiate(suspended)
456+
end doInstantiate
457+
doInstantiate(toInstantiate)
440458
}
441459
}
442460
tree

tests/pos/i7458.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
type Tr[+V1, +O1 <: V1]
2+
def [V2, O2 <: V2](tr: Tr[V2, O2]) sl: Tr[V2, O2] = ???
3+
def as[V3, O3 <: V3](tr: Tr[V3, O3]) : Tr[V3, O3] = tr.sl

0 commit comments

Comments
 (0)