Skip to content

Fix #5980 #6023

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 = 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[_] =>
}
}