Skip to content

Commit beea2b5

Browse files
authored
Merge pull request #6023 from anatoliykmetyuk/master
Fix #5980
2 parents 79d36c6 + 7cdab92 commit beea2b5

File tree

3 files changed

+64
-11
lines changed

3 files changed

+64
-11
lines changed

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

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,9 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
738738
return recur(AndType(tp11, tp121), tp2) && recur(AndType(tp11, tp122), tp2)
739739
case _ =>
740740
}
741-
either(recur(tp11, tp2), recur(tp12, tp2))
741+
val tp1norm = simplifyAndTypeWithFallback(tp11, tp12, tp1)
742+
if (tp1 ne tp1norm) recur(tp1norm, tp2)
743+
else either(recur(tp11, tp2), recur(tp12, tp2))
742744
case tp1: MatchType =>
743745
def compareMatch = tp2 match {
744746
case tp2: MatchType =>
@@ -1641,6 +1643,18 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
16411643
NoType
16421644
}
16431645

1646+
private[this] def andTypeGen(tp1: Type, tp2: Type, op: (Type, Type) => Type,
1647+
original: (Type, Type) => Type = _ & _, isErased: Boolean = ctx.erasedTypes): Type = trace(s"glb(${tp1.show}, ${tp2.show})", subtyping, show = true) {
1648+
val t1 = distributeAnd(tp1, tp2)
1649+
if (t1.exists) t1
1650+
else {
1651+
val t2 = distributeAnd(tp2, tp1)
1652+
if (t2.exists) t2
1653+
else if (isErased) erasedGlb(tp1, tp2, isJava = false)
1654+
else liftIfHK(tp1, tp2, op, original)
1655+
}
1656+
}
1657+
16441658
/** Form a normalized conjunction of two types.
16451659
* Note: For certain types, `&` is distributed inside the type. This holds for
16461660
* all types which are not value types (e.g. TypeBounds, ClassInfo,
@@ -1659,16 +1673,11 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
16591673
*
16601674
* In these cases, a MergeError is thrown.
16611675
*/
1662-
final def andType(tp1: Type, tp2: Type, isErased: Boolean = ctx.erasedTypes): Type = trace(s"glb(${tp1.show}, ${tp2.show})", subtyping, show = true) {
1663-
val t1 = distributeAnd(tp1, tp2)
1664-
if (t1.exists) t1
1665-
else {
1666-
val t2 = distributeAnd(tp2, tp1)
1667-
if (t2.exists) t2
1668-
else if (isErased) erasedGlb(tp1, tp2, isJava = false)
1669-
else liftIfHK(tp1, tp2, AndType(_, _), _ & _)
1670-
}
1671-
}
1676+
final def andType(tp1: Type, tp2: Type, isErased: Boolean = ctx.erasedTypes): Type =
1677+
andTypeGen(tp1, tp2, AndType(_, _), isErased = isErased)
1678+
1679+
final def simplifyAndTypeWithFallback(tp1: Type, tp2: Type, fallback: Type): Type =
1680+
andTypeGen(tp1, tp2, (_, _) => fallback)
16721681

16731682
/** Form a normalized conjunction of two types.
16741683
* Note: For certain types, `|` is distributed inside the type. This holds for

tests/pos/i5980.scala

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
trait A
2+
trait B
3+
4+
trait Covariant[F[+_]] {
5+
trait G[+X]
6+
7+
def fx: F[A & B] = fy
8+
def fy: F[A] & F[B] = fx
9+
10+
def gx: G[A & B] = gy
11+
def gy: G[A] & G[B] = gx
12+
}
13+
14+
trait Contravariant[F[-_]] {
15+
trait G[-X]
16+
17+
def fx: F[A | B] = fy
18+
def fy: F[A] & F[B] = fx
19+
20+
def gx: G[A | B] = gy
21+
def gy: G[A] & G[B] = gx
22+
}
23+
24+
trait LiskovViolation[F[+_]] {
25+
trait A { def children: F[A] }
26+
trait B { def children: F[B] }
27+
trait C extends A with B { def children: F[A] & F[B] = ??? }
28+
29+
def fc1: C = new C {}
30+
def fc2: A & B = fc1
31+
32+
def fy1: F[A & B] = fc1.children
33+
def fy2: F[A & B] = fc2.children
34+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
object InfiniteSubtypingLoopPossibility {
2+
trait A[X]
3+
trait B extends A[B]
4+
trait Min[+S <: B with A[S]]
5+
6+
def c: Any = ???
7+
c match {
8+
case pc: Min[_] =>
9+
}
10+
}

0 commit comments

Comments
 (0)