Skip to content

Commit 3202767

Browse files
committed
fix #10511: compare enumvalues in provably disjoint
1 parent 1ab80f7 commit 3202767

File tree

4 files changed

+72
-0
lines changed

4 files changed

+72
-0
lines changed

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2412,6 +2412,11 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
24122412
*/
24132413
def provablyDisjoint(tp1: Type, tp2: Type)(using Context): Boolean = {
24142414
// println(s"provablyDisjoint(${tp1.show}, ${tp2.show})")
2415+
2416+
def isEnumValueOrModule(ref: TermRef): Boolean =
2417+
val sym = ref.termSymbol
2418+
sym.isAllOf(EnumCase, butNot=JavaDefined) || sym.is(Module)
2419+
24152420
/** Can we enumerate all instantiations of this type? */
24162421
def isClosedSum(tp: Symbol): Boolean =
24172422
tp.is(Sealed) && tp.isOneOf(AbstractOrTrait) && !tp.hasAnonymousChild
@@ -2517,6 +2522,8 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
25172522
provablyDisjoint(gadtBounds(tp1.symbol).hi, tp2) || provablyDisjoint(tp1.superType, tp2)
25182523
case (_, tp2: NamedType) if gadtBounds(tp2.symbol) != null =>
25192524
provablyDisjoint(tp1, gadtBounds(tp2.symbol).hi) || provablyDisjoint(tp1, tp2.superType)
2525+
case (tp1: TermRef, tp2: TermRef) if isEnumValueOrModule(tp1) && isEnumValueOrModule(tp2) =>
2526+
tp1.termSymbol != tp2.termSymbol
25202527
case (tp1: TypeProxy, tp2: TypeProxy) =>
25212528
provablyDisjoint(matchTypeSuperType(tp1), tp2) || provablyDisjoint(tp1, matchTypeSuperType(tp2))
25222529
case (tp1: TypeProxy, _) =>

tests/neg/i10511.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
enum Bool {
2+
case True
3+
case False
4+
}
5+
6+
import Bool._
7+
8+
type Not[B <: Bool] = B match {
9+
case True.type => False.type
10+
case False.type => True.type
11+
}
12+
13+
def not[B <: Bool & Singleton](b: B): Not[B] = b match {
14+
case b: False.type => True // error
15+
case b: True.type => False // error
16+
}
17+
18+
val f: Not[False.type] = False // error: Found: (Bool.False : Bool) Required: (Bool.True : Bool)

tests/pos/i10511.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
enum Bool {
2+
case True
3+
case False
4+
}
5+
6+
import Bool._
7+
8+
type Not[B <: Bool] = B match {
9+
case True.type => False.type
10+
case False.type => True.type
11+
}
12+
13+
val t: True.type = True
14+
val f: False.type = False
15+
16+
val g: Not[False.type] = t

tests/run/i10511.scala

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
enum Bool {
2+
case True
3+
case False
4+
5+
// just to make sure we are using reference equality
6+
override def equals(a: Any) = false
7+
8+
}
9+
10+
import Bool._
11+
12+
type Not[B <: Bool] = B match {
13+
case True.type => False.type
14+
case False.type => True.type
15+
}
16+
17+
def not[B <: Bool & Singleton](b: B): Not[B] = b match {
18+
case b: True.type => False
19+
case b: False.type => True
20+
}
21+
22+
@main def Test =
23+
24+
val t: True.type = True
25+
val f: False.type = False
26+
27+
val t1: Not[False.type] = t
28+
val f1: Not[True.type] = f
29+
30+
assert(not(True).asInstanceOf[AnyRef] eq False)
31+
assert(not(False).asInstanceOf[AnyRef] eq True)

0 commit comments

Comments
 (0)