Skip to content

Commit 29d89ce

Browse files
committed
Tweak lambda/tvar cleanup, to avoid mis-instantiating
1 parent 5dda2a3 commit 29d89ce

File tree

3 files changed

+44
-15
lines changed

3 files changed

+44
-15
lines changed

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

+2-11
Original file line numberDiff line numberDiff line change
@@ -436,17 +436,8 @@ trait ConstraintHandling {
436436

437437
val level1 = nestingLevel(p1)
438438
val level2 = nestingLevel(p2)
439-
val p1Wins = if level1 == level2 then
440-
// If the nesting levels match, then we would prefer to unify to the outer most parameter.
441-
// For instance in pos/i21981, while running `normalizedCompatible` against `.map2`,
442-
// we want to unify to B over K, to allow easily removing K by just instantiating it.
443-
def preferP1(ctx: Context): Boolean =
444-
val c = ctx.typerState.constraint
445-
!c.contains(p2) || c.contains(p1) && preferP1(ctx.outer)
446-
preferP1(ctx)
447-
else level1 <= level2
448-
val pKept = if p1Wins then p1 else p2
449-
val pRemoved = if p1Wins then p2 else p1
439+
val pKept = if level1 <= level2 then p1 else p2
440+
val pRemoved = if level1 <= level2 then p2 else p1
450441

451442
val down = constraint.exclusiveLower(p2, p1)
452443
val up = constraint.exclusiveUpper(p1, p2)

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

+14-4
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,20 @@ object ProtoTypes {
7272
|constraint now: ${newctx.typerState.constraint}""")
7373
if result && (ctx.typerState.constraint ne newctx.typerState.constraint) then
7474
// Remove all type lambdas and tvars introduced by testCompat
75-
for tvar <- newctx.typerState.ownedVars do
76-
inContext(newctx):
77-
if !tvar.isInstantiated then
78-
tvar.instantiate(fromBelow = false) // any direction
75+
inContext(newctx):
76+
val tvars = ctx.typerState.ownedVars
77+
val tvars1 = for tvar <- tvars.toList yield
78+
// Filter out any tvar that instantiating would further constrain the current constraint
79+
val aboveOK = !ctx.typerState.constraint.dependsOn(tvar, tvars, co = true)
80+
val belowOK = !ctx.typerState.constraint.dependsOn(tvar, tvars, co = false)
81+
val fromBelow: Boolean | Null =
82+
if aboveOK then true
83+
else if belowOK then false
84+
else null // don't instantiate
85+
(tvar, fromBelow)
86+
for (tvar, fromBelow) <- tvars1 do
87+
if fromBelow != null && !tvar.isInstantiated then
88+
tvar.instantiate(fromBelow.uncheckedNN)
7989

8090
// commit any remaining changes in typer state
8191
newctx.typerState.commit()

tests/pos/i21981.alt.scala

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
trait Ops[F[_], A]:
2+
def map0[B](f0: A => B): F[B] = ???
3+
4+
trait Functor1[G[_]]
5+
6+
trait Functor2[H[_]]:
7+
extension [C1, C2](hc: H[(C1, C2)])
8+
def map2[D](f1: (C1, C2) => D): H[D]
9+
10+
trait Ref[I[_], +E]
11+
12+
final class Cov[+F]
13+
14+
class Test:
15+
given [J[_]](using J: Functor1[J]): Functor2[J] with
16+
extension [K1, K2](jk: J[(K1, K2)])
17+
def map2[L](f2: (K1, K2) => L): J[L] = ???
18+
19+
def t1[
20+
M[_[t]],
21+
N[_],
22+
](using N: Functor1[N]): Unit =
23+
24+
val x3: Ops[N, M[[t] =>> Ref[N, t]]] = ???
25+
26+
val x2: N[(M[N], M[[t] =>> Ref[N, t]])] = x3
27+
.map0 { refs => (???, refs) }
28+
.map2 { case (not, refs) => (???, refs) }

0 commit comments

Comments
 (0)