Skip to content

Commit abc11ac

Browse files
Merge pull request #13483 from dotty-staging/fix-13455
Fix #13455: Also consider sealed classes closed sums
2 parents aaac006 + 9d8c161 commit abc11ac

File tree

3 files changed

+22
-15
lines changed

3 files changed

+22
-15
lines changed

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

+10-13
Original file line numberDiff line numberDiff line change
@@ -2526,17 +2526,6 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
25262526
case _ => false
25272527
})
25282528

2529-
/** Can we enumerate all instantiations of this type? */
2530-
def isClosedSum(tp: Symbol): Boolean =
2531-
tp.is(Sealed) && tp.isOneOf(AbstractOrTrait) && !tp.hasAnonymousChild
2532-
2533-
/** Splits a closed type into a disjunction of smaller types.
2534-
* It should hold that `tp` and `decompose(tp).reduce(_ or _)`
2535-
* denote the same set of values.
2536-
*/
2537-
def decompose(sym: Symbol, tp: Type): List[Type] =
2538-
sym.children.map(x => refineUsingParent(tp, x)).filter(_.exists)
2539-
25402529
def fullyInstantiated(tp: Type): Boolean = new TypeAccumulator[Boolean] {
25412530
override def apply(x: Boolean, t: Type) =
25422531
x && {
@@ -2558,6 +2547,10 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
25582547
case (tp1: TypeRef, tp2: TypeRef) if tp1.symbol.isClass && tp2.symbol.isClass =>
25592548
val cls1 = tp1.classSymbol
25602549
val cls2 = tp2.classSymbol
2550+
def isDecomposable(tp: Symbol): Boolean =
2551+
tp.is(Sealed) && !tp.hasAnonymousChild
2552+
def decompose(sym: Symbol, tp: Type): List[Type] =
2553+
sym.children.map(x => refineUsingParent(tp, x)).filter(_.exists)
25612554
if (cls1.derivesFrom(cls2) || cls2.derivesFrom(cls1))
25622555
false
25632556
else
@@ -2570,9 +2563,13 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
25702563
// subtype, so they must be unrelated by single inheritance
25712564
// of classes.
25722565
true
2573-
else if (isClosedSum(cls1))
2566+
else if (isDecomposable(cls1))
2567+
// At this point, !cls1.derivesFrom(cls2): we know that direct
2568+
// instantiations of `cls1` (terms of the form `new cls1`) are not
2569+
// of type `tp2`. Therefore, we can safely decompose `cls1` using
2570+
// `.children`, even if `cls1` is non abstract.
25742571
decompose(cls1, tp1).forall(x => provablyDisjoint(x, tp2))
2575-
else if (isClosedSum(cls2))
2572+
else if (isDecomposable(cls2))
25762573
decompose(cls2, tp2).forall(x => provablyDisjoint(x, tp1))
25772574
else
25782575
false

tests/patmat/andtype-opentype-interaction.check

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
23: Pattern Match Exhaustivity: _: Trait & OpenTrait, _: Clazz & OpenTrait, _: AbstractClass & OpenTrait, _: SealedClass & OpenTrait
2-
27: Pattern Match Exhaustivity: _: Trait & OpenTrait & OpenTrait2, _: Clazz & OpenTrait & OpenTrait2, _: AbstractClass & OpenTrait & OpenTrait2, _: SealedClass & OpenTrait & OpenTrait2
1+
23: Pattern Match Exhaustivity: _: Trait & OpenTrait, _: Clazz & OpenTrait, _: AbstractClass & OpenTrait
2+
27: Pattern Match Exhaustivity: _: Trait & OpenTrait & OpenTrait2, _: Clazz & OpenTrait & OpenTrait2, _: AbstractClass & OpenTrait & OpenTrait2
33
31: Pattern Match Exhaustivity: _: Trait & OpenClass
44
35: Pattern Match Exhaustivity: _: Trait & OpenTrait & OpenClass
55
43: Pattern Match Exhaustivity: _: Trait & OpenAbstractClass

tests/pos/13455.scala

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
sealed class R
2+
3+
type X[T] = T match {
4+
case R => String
5+
case (z => r) => Int
6+
}
7+
def x[T]: X[T] = ???
8+
9+
def i(i0: Int): Unit = ???
10+
val a = i(x[Int => String])

0 commit comments

Comments
 (0)