Skip to content

Commit 0f567f4

Browse files
committed
Change type lub behaviour for GADT constraints
1 parent a0dbebb commit 0f567f4

File tree

3 files changed

+15
-20
lines changed

3 files changed

+15
-20
lines changed

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

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

2828
protected def isSubType(tp1: Type, tp2: Type)(implicit actx: AbstractContext): Boolean
2929
protected def isSameType(tp1: Type, tp2: Type)(implicit actx: AbstractContext): Boolean
30+
protected def typeLub(tp1: Type, tp2: Type)(implicit actx: AbstractContext): Type
3031

3132
protected def constraint: Constraint
3233
protected def constraint_=(c: Constraint): Unit
@@ -102,7 +103,7 @@ trait ConstraintHandling[AbstractContext] {
102103
homogenizeArgs = Config.alignArgsInAnd
103104
try
104105
if (isUpper) oldBounds.derivedTypeBounds(lo, hi & bound)
105-
else oldBounds.derivedTypeBounds(lo | bound, hi)
106+
else oldBounds.derivedTypeBounds(typeLub(lo, bound), hi)
106107
finally homogenizeArgs = saved
107108
}
108109
val c1 = constraint.updateEntry(param, narrowedBounds)

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

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,10 @@ object Contexts {
754754
override def isSubType(tp1: Type, tp2: Type)(implicit ctx: Context): Boolean = ctx.typeComparer.isSubType(tp1, tp2)
755755
override def isSameType(tp1: Type, tp2: Type)(implicit ctx: Context): Boolean = ctx.typeComparer.isSameType(tp1, tp2)
756756

757+
override protected def typeLub(tp1: Type, tp2: Type)(implicit ctx: Context): Type = {
758+
ctx.typeComparer.lub(tp1, tp2, admitSingletons = true)
759+
}
760+
757761
override def addEmptyBounds(sym: Symbol)(implicit ctx: Context): Unit = tvar(sym)
758762

759763
override def addBound(sym: Symbol, bound: Type, isUpper: Boolean)(implicit ctx: Context): Boolean = try {
@@ -779,21 +783,6 @@ object Contexts {
779783
}, gadts)
780784
}
781785

782-
// avoid recording skolems in lower bounds
783-
// recording two skolem bounds results in an union, which is then simplified
784-
// T >: Sko(U) | Sko(U) is simplified to T >: U, which is simply wrong
785-
// instead, we only ensure that new bounds would be satisfiable
786-
// TODO: this likely causes unsoundness
787-
// TODO: it should be removed after we added support for singleton type unions
788-
if (!isUpper) bound match {
789-
case _: SkolemType =>
790-
val TypeBounds(lo, hi) = bounds(sym)
791-
val newLo = lo | bound
792-
gadts.println(i"replacing skolem bound $sym <:< $bound with $newLo <:< $hi")
793-
return newLo <:< hi
794-
case _ => ;
795-
}
796-
797786
val symTvar: TypeVar = stripInternalTypeVar(tvar(sym)) match {
798787
case tv: TypeVar => tv
799788
case inst =>

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
3232
def constraint: Constraint = state.constraint
3333
def constraint_=(c: Constraint): Unit = state.constraint = c
3434

35+
override protected def typeLub(tp1: Type, tp2: Type)(implicit actx: AbsentContext): Type =
36+
lub(tp1, tp2)
37+
3538
private[this] var pendingSubTypes: mutable.Set[(Type, Type)] = null
3639
private[this] var recCount = 0
3740
private[this] var monitored = false
@@ -1415,9 +1418,10 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
14151418

14161419
/** The least upper bound of two types
14171420
* @param canConstrain If true, new constraints might be added to simplify the lub.
1418-
* @note We do not admit singleton types in or-types as lubs.
1421+
* @param admitSingletons We only admit singletons as parts of lubs when we must maintain necessary conditions,
1422+
* such as when inferring GADT constraints.
14191423
*/
1420-
def lub(tp1: Type, tp2: Type, canConstrain: Boolean = false): Type = /*>|>*/ trace(s"lub(${tp1.show}, ${tp2.show}, canConstrain=$canConstrain)", subtyping, show = true) /*<|<*/ {
1424+
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) /*<|<*/ {
14211425
if (tp1 eq tp2) tp1
14221426
else if (!tp1.exists) tp1
14231427
else if (!tp2.exists) tp2
@@ -1429,6 +1433,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
14291433
else {
14301434
val t2 = mergeIfSuper(tp2, tp1, canConstrain)
14311435
if (t2.exists) t2
1436+
else if (admitSingletons) orType(tp1.widenExpr, tp2.widenExpr)
14321437
else {
14331438
val tp1w = tp1.widen
14341439
val tp2w = tp2.widen
@@ -1954,8 +1959,8 @@ class ExplainingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
19541959
super.hasMatchingMember(name, tp1, tp2)
19551960
}
19561961

1957-
override def lub(tp1: Type, tp2: Type, canConstrain: Boolean = false): Type =
1958-
traceIndented(s"lub(${show(tp1)}, ${show(tp2)}, canConstrain=$canConstrain)") {
1962+
override def lub(tp1: Type, tp2: Type, canConstrain: Boolean = false, admitSingletons: Boolean = false): Type =
1963+
traceIndented(s"lub(${show(tp1)}, ${show(tp2)}, canConstrain=$canConstrain, admitSingletons=$admitSingletons)") {
19591964
super.lub(tp1, tp2, canConstrain)
19601965
}
19611966

0 commit comments

Comments
 (0)