diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 45d02ca9538e..15130174f0b5 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -2526,17 +2526,6 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling case _ => false }) - /** Can we enumerate all instantiations of this type? */ - def isClosedSum(tp: Symbol): Boolean = - tp.is(Sealed) && tp.isOneOf(AbstractOrTrait) && !tp.hasAnonymousChild - - /** Splits a closed type into a disjunction of smaller types. - * It should hold that `tp` and `decompose(tp).reduce(_ or _)` - * denote the same set of values. - */ - def decompose(sym: Symbol, tp: Type): List[Type] = - sym.children.map(x => refineUsingParent(tp, x)).filter(_.exists) - def fullyInstantiated(tp: Type): Boolean = new TypeAccumulator[Boolean] { override def apply(x: Boolean, t: Type) = x && { @@ -2558,6 +2547,10 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling case (tp1: TypeRef, tp2: TypeRef) if tp1.symbol.isClass && tp2.symbol.isClass => val cls1 = tp1.classSymbol val cls2 = tp2.classSymbol + def isDecomposable(tp: Symbol): Boolean = + tp.is(Sealed) && !tp.hasAnonymousChild + def decompose(sym: Symbol, tp: Type): List[Type] = + sym.children.map(x => refineUsingParent(tp, x)).filter(_.exists) if (cls1.derivesFrom(cls2) || cls2.derivesFrom(cls1)) false else @@ -2570,9 +2563,13 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling // subtype, so they must be unrelated by single inheritance // of classes. true - else if (isClosedSum(cls1)) + else if (isDecomposable(cls1)) + // At this point, !cls1.derivesFrom(cls2): we know that direct + // instantiations of `cls1` (terms of the form `new cls1`) are not + // of type `tp2`. Therefore, we can safely decompose `cls1` using + // `.children`, even if `cls1` is non abstract. decompose(cls1, tp1).forall(x => provablyDisjoint(x, tp2)) - else if (isClosedSum(cls2)) + else if (isDecomposable(cls2)) decompose(cls2, tp2).forall(x => provablyDisjoint(x, tp1)) else false diff --git a/tests/patmat/andtype-opentype-interaction.check b/tests/patmat/andtype-opentype-interaction.check index a9d8618adad0..b8f9fbc10ac9 100644 --- a/tests/patmat/andtype-opentype-interaction.check +++ b/tests/patmat/andtype-opentype-interaction.check @@ -1,5 +1,5 @@ -23: Pattern Match Exhaustivity: _: Trait & OpenTrait, _: Clazz & OpenTrait, _: AbstractClass & OpenTrait, _: SealedClass & OpenTrait -27: Pattern Match Exhaustivity: _: Trait & OpenTrait & OpenTrait2, _: Clazz & OpenTrait & OpenTrait2, _: AbstractClass & OpenTrait & OpenTrait2, _: SealedClass & OpenTrait & OpenTrait2 +23: Pattern Match Exhaustivity: _: Trait & OpenTrait, _: Clazz & OpenTrait, _: AbstractClass & OpenTrait +27: Pattern Match Exhaustivity: _: Trait & OpenTrait & OpenTrait2, _: Clazz & OpenTrait & OpenTrait2, _: AbstractClass & OpenTrait & OpenTrait2 31: Pattern Match Exhaustivity: _: Trait & OpenClass 35: Pattern Match Exhaustivity: _: Trait & OpenTrait & OpenClass 43: Pattern Match Exhaustivity: _: Trait & OpenAbstractClass diff --git a/tests/pos/13455.scala b/tests/pos/13455.scala new file mode 100644 index 000000000000..62e0dae9c881 --- /dev/null +++ b/tests/pos/13455.scala @@ -0,0 +1,10 @@ +sealed class R + +type X[T] = T match { + case R => String + case (z => r) => Int +} +def x[T]: X[T] = ??? + +def i(i0: Int): Unit = ??? +val a = i(x[Int => String])