Skip to content

Commit fe93ddc

Browse files
committed
Avoid direct Skolem types in lower GADT bounds
By constraining T s.t. T >: Sko(U) and T >: Sko(U), we end up with T >: Sko(U) | Sko(U), which is a singleton type union and is simplified to T >: U, which is wrong for this case. To avoid this, we record only the _consequence_ of having a Skolem type in a bound. This is a temporary workaround while we cannot take unions and intersections of singleton types and should be removed in the future.
1 parent dad8088 commit fe93ddc

File tree

5 files changed

+38
-6
lines changed

5 files changed

+38
-6
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ trait ConstraintHandling[AbstractContext] {
3030

3131
protected def isSubType(tp1: Type, tp2: Type)(implicit actx: AbstractContext): Boolean
3232
protected def isSameType(tp1: Type, tp2: Type)(implicit actx: AbstractContext): Boolean
33+
protected def typeLub(tp1: Type, tp2: Type)(implicit actx: AbstractContext): Type
3334

3435
protected def constraint: Constraint
3536
protected def constraint_=(c: Constraint): Unit
@@ -126,7 +127,7 @@ trait ConstraintHandling[AbstractContext] {
126127
homogenizeArgs = Config.alignArgsInAnd
127128
try
128129
if (isUpper) oldBounds.derivedTypeBounds(lo, hi & bound)
129-
else oldBounds.derivedTypeBounds(lo | bound, hi)
130+
else oldBounds.derivedTypeBounds(typeLub(lo, bound), hi)
130131
finally homogenizeArgs = saved
131132
}
132133
val c1 = constraint.updateEntry(param, narrowedBounds)

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,10 @@ object Contexts {
803803
override def isSubType(tp1: Type, tp2: Type)(implicit ctx: Context): Boolean = ctx.typeComparer.isSubType(tp1, tp2)
804804
override def isSameType(tp1: Type, tp2: Type)(implicit ctx: Context): Boolean = ctx.typeComparer.isSameType(tp1, tp2)
805805

806+
override protected def typeLub(tp1: Type, tp2: Type)(implicit ctx: Context): Type = {
807+
ctx.typeComparer.lub(tp1, tp2, admitSingletons = true)
808+
}
809+
806810
override def addEmptyBounds(sym: Symbol)(implicit ctx: Context): Unit = tvar(sym)
807811

808812
override def addBound(sym: Symbol, bound: Type, isUpper: Boolean)(implicit ctx: Context): Boolean = {

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

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
3434

3535
override protected def externalize(param: TypeParamRef)(implicit ctx: Context): Type = param
3636

37+
override protected def typeLub(tp1: Type, tp2: Type)(implicit actx: AbsentContext): Type =
38+
lub(tp1, tp2)
39+
40+
3741
private[this] var pendingSubTypes: mutable.Set[(Type, Type)] = null
3842
private[this] var recCount = 0
3943
private[this] var monitored = false
@@ -1429,9 +1433,10 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
14291433

14301434
/** The least upper bound of two types
14311435
* @param canConstrain If true, new constraints might be added to simplify the lub.
1432-
* @note We do not admit singleton types in or-types as lubs.
1436+
* @param admitSingletons We only admit singletons as parts of lubs when we must maintain necessary conditions,
1437+
* such as when inferring GADT constraints.
14331438
*/
1434-
def lub(tp1: Type, tp2: Type, canConstrain: Boolean = false): Type = /*>|>*/ trace(s"lub(${tp1.show}, ${tp2.show}, canConstrain=$canConstrain)", subtyping, show = true) /*<|<*/ {
1439+
def lub(tp1: Type, tp2: Type, canConstrain: Boolean = false, admitSingletons: Boolean = false): Type = /*>|>*/ trace(s"lub(${tp1.show}, ${tp2.show}, canConstrain=$canConstrain)", subtyping, show = true) /*<|<*/ {
14351440
if (tp1 eq tp2) tp1
14361441
else if (!tp1.exists) tp1
14371442
else if (!tp2.exists) tp2
@@ -1443,6 +1448,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
14431448
else {
14441449
val t2 = mergeIfSuper(tp2, tp1, canConstrain)
14451450
if (t2.exists) t2
1451+
else if (admitSingletons) orType(tp1.widenExpr, tp2.widenExpr)
14461452
else {
14471453
val tp1w = tp1.widen
14481454
val tp2w = tp2.widen
@@ -1968,9 +1974,9 @@ class ExplainingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
19681974
super.hasMatchingMember(name, tp1, tp2)
19691975
}
19701976

1971-
override def lub(tp1: Type, tp2: Type, canConstrain: Boolean = false): Type =
1972-
traceIndented(s"lub(${show(tp1)}, ${show(tp2)}, canConstrain=$canConstrain)") {
1973-
super.lub(tp1, tp2, canConstrain)
1977+
override def lub(tp1: Type, tp2: Type, canConstrain: Boolean = false, admitSingletons: Boolean = false): Type =
1978+
traceIndented(s"lub(${show(tp1)}, ${show(tp2)}, canConstrain=$canConstrain, admitSingletons=$admitSingletons)") {
1979+
super.lub(tp1, tp2, canConstrain, admitSingletons)
19741980
}
19751981

19761982
override def glb(tp1: Type, tp2: Type): Type =

tests/neg/int-extractor.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,24 @@ object Test {
88
0 // error
99
}
1010

11+
def foo2[T](t: T): T = t match {
12+
case EssaInt(_) => t match {
13+
case EssaInt(_) =>
14+
0 // error
15+
}
16+
}
17+
1118
case class Inv[T](t: T)
1219

1320
def bar1[T](t: T): T = Inv(t) match {
1421
case Inv(EssaInt(_)) =>
1522
0 // error
1623
}
24+
25+
def bar2[T](t: T): T = t match {
26+
case Inv(EssaInt(_)) => t match {
27+
case Inv(EssaInt(_)) =>
28+
0 // error
29+
}
30+
}
1731
}

tests/neg/invariant-gadt.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,11 @@ object `invariant-gadt` {
1717
0 // error
1818
}
1919
}
20+
21+
def unsoundTwice[T](t: T): T = Invariant(t) match {
22+
case Invariant(_: Int) => Invariant(t) match {
23+
case Invariant(_: Int) =>
24+
0 // error
25+
}
26+
}
2027
}

0 commit comments

Comments
 (0)