Skip to content

Commit

Permalink
Fix #5980
Browse files Browse the repository at this point in the history
  • Loading branch information
anatoliykmetyuk committed Mar 10, 2019
1 parent 51d8cab commit 8f0f13c
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 11 deletions.
31 changes: 20 additions & 11 deletions compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -738,7 +738,9 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
return recur(AndType(tp11, tp121), tp2) && recur(AndType(tp11, tp122), tp2)
case _ =>
}
either(recur(tp11, tp2), recur(tp12, tp2))
val tp1norm = simplifyAndTypeWithFallback(tp11, tp12, tp1)
if (tp1 ne tp1norm) recur(tp1norm, tp2)
else either(recur(tp11, tp2), recur(tp12, tp2))
case tp1: MatchType =>
def compareMatch = tp2 match {
case tp2: MatchType =>
Expand Down Expand Up @@ -1641,6 +1643,18 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
NoType
}

private[this] def andTypeGen(tp1: Type, tp2: Type, op: (Type, Type) => Type
, original: (Type, Type) => Type, isErased: Boolean = ctx.erasedTypes): Type = trace(s"glb(${tp1.show}, ${tp2.show})", subtyping, show = true) {
val t1 = distributeAnd(tp1, tp2)
if (t1.exists) t1
else {
val t2 = distributeAnd(tp2, tp1)
if (t2.exists) t2
else if (isErased) erasedGlb(tp1, tp2, isJava = false)
else liftIfHK(tp1, tp2, op, original)
}
}

/** Form a normalized conjunction of two types.
* Note: For certain types, `&` is distributed inside the type. This holds for
* all types which are not value types (e.g. TypeBounds, ClassInfo,
Expand All @@ -1659,16 +1673,11 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
*
* In these cases, a MergeError is thrown.
*/
final def andType(tp1: Type, tp2: Type, isErased: Boolean = ctx.erasedTypes): Type = trace(s"glb(${tp1.show}, ${tp2.show})", subtyping, show = true) {
val t1 = distributeAnd(tp1, tp2)
if (t1.exists) t1
else {
val t2 = distributeAnd(tp2, tp1)
if (t2.exists) t2
else if (isErased) erasedGlb(tp1, tp2, isJava = false)
else liftIfHK(tp1, tp2, AndType(_, _), _ & _)
}
}
final def andType(tp1: Type, tp2: Type, isErased: Boolean = ctx.erasedTypes): Type =
andTypeGen(tp1, tp2, AndType(_, _), _ & _, isErased)

final def simplifyAndTypeWithFallback(tp1: Type, tp2: Type, fallback: Type): Type =
andTypeGen(tp1, tp2, (_, _) => fallback, _ & _)

/** Form a normalized conjunction of two types.
* Note: For certain types, `|` is distributed inside the type. This holds for
Expand Down
File renamed without changes.
34 changes: 34 additions & 0 deletions tests/pos/i5980.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
trait A
trait B

trait Covariant[F[+_]] {
trait G[+X]

def fx: F[A & B] = fy
def fy: F[A] & F[B] = fx

def gx: G[A & B] = gy
def gy: G[A] & G[B] = gx
}

trait Contravariant[F[-_]] {
trait G[-X]

def fx: F[A | B] = fy
def fy: F[A] & F[B] = fx

def gx: G[A | B] = gy
def gy: G[A] & G[B] = gx
}

trait LiskovViolation[F[+_]] {
trait A { def children: F[A] }
trait B { def children: F[B] }
trait C extends A with B { def children: F[A] & F[B] = ??? }

def fc1: C = new C {}
def fc2: A & B = fc1

def fy1: F[A & B] = fc1.children
def fy2: F[A & B] = fc2.children
}
10 changes: 10 additions & 0 deletions tests/pos/infinite-loop-potential.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
object InfiniteSubtypingLoopPossibility {
trait A[X]
trait B extends A[B]
trait Min[+S <: B with A[S]]

def c: Any = ???
c match {
case pc: Min[_] =>
}
}

0 comments on commit 8f0f13c

Please sign in to comment.