diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index ab0e9b3ed9d4..6020df3d9e5b 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1575,6 +1575,17 @@ object SymDenotations { (symbol eq defn.NothingClass) || (symbol eq defn.NullClass) && (base ne defn.NothingClass)) + /** Is it possible that a class inherits both `this` and `that`? + * + * @note The test is based on single-class inheritance and the closed + * hierarchy of final classes. + * + * @return The result may contain false positives, but never false negatives. + */ + final def mayHaveCommonChild(that: ClassSymbol)(implicit ctx: Context): Boolean = + !this.is(Final) && !that.is(Final) && (this.is(Trait) || that.is(Trait)) || + this.derivesFrom(that) || that.derivesFrom(this.symbol) + final override def typeParamCreationFlags: FlagSet = ClassTypeParamCreationFlags /** Hook to do a pre-enter test. Overridden in PackageDenotation */ diff --git a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala index dbd781357c23..b14024e933c5 100644 --- a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala +++ b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala @@ -132,6 +132,7 @@ object TypeTestsCasts { recur(tp1, P) && recur(tp2, P) case _ => // first try withou striping type parameters for performance + X.classSymbol.exists && P.classSymbol.exists && !X.classSymbol.asClass.mayHaveCommonChild(P.classSymbol.asClass) || isClassDetermined(X, tpe)(ctx.fresh.setNewTyperState()) || isClassDetermined(stripTypeParam(X), tpe)(ctx.fresh.setNewTyperState()) } diff --git a/tests/pos-special/fatal-warnings/i5970.scala b/tests/pos-special/fatal-warnings/i5970.scala new file mode 100644 index 000000000000..51adb8cd0535 --- /dev/null +++ b/tests/pos-special/fatal-warnings/i5970.scala @@ -0,0 +1,12 @@ +object Test extends App { + case class Foo[T](t: T) + + def foo[T](ft: Unit|Foo[T]): T = { + ft match { + case Foo(t) => t + case () => ??? + } + } + + foo(Foo(23)) +}