From d6e9efd563c434a39c96161cd9cb2d0e7f82b860 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Wed, 2 Aug 2023 10:52:38 +0100 Subject: [PATCH] Fix missing case in isSubspace, which broke reachablility --- .../tools/dotc/transform/patmat/Space.scala | 6 ++- tests/patmat/i18118.check | 4 ++ tests/patmat/i18118.scala | 41 +++++++++++++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 tests/patmat/i18118.check create mode 100644 tests/patmat/i18118.scala diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index 45c1444879db..301f80960d8f 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -193,10 +193,11 @@ object SpaceEngine { || canDecompose(b) && isSubspace(a, Or(decompose(b))) case (Prod(tp1, _, _), Typ(tp2, _)) => isSubType(tp1, tp2) - case (Typ(tp1, _), Prod(tp2, fun, ss)) => + case (a @ Typ(tp1, _), Prod(tp2, fun, ss)) => isSubType(tp1, tp2) && covers(fun, tp1, ss.length) && isSubspace(Prod(tp2, fun, signature(fun, tp1, ss.length).map(Typ(_, false))), b) + || canDecompose(a) && isSubspace(Or(decompose(a)), b) case (Prod(_, fun1, ss1), Prod(_, fun2, ss2)) => isSameUnapply(fun1, fun2) && ss1.lazyZip(ss2).forall(isSubspace) } @@ -597,7 +598,7 @@ object SpaceEngine { } /** Whether the extractor covers the given type */ - def covers(unapp: TermRef, scrutineeTp: Type, argLen: Int)(using Context): Boolean = + def covers(unapp: TermRef, scrutineeTp: Type, argLen: Int)(using Context): Boolean = trace(i"covers($unapp, $scrutineeTp, $argLen)") { SpaceEngine.isIrrefutable(unapp, argLen) || unapp.symbol == defn.TypeTest_unapply && { val AppliedType(_, _ :: tp :: Nil) = unapp.prefix.widen.dealias: @unchecked @@ -607,6 +608,7 @@ object SpaceEngine { val AppliedType(_, tp :: Nil) = unapp.prefix.widen.dealias: @unchecked scrutineeTp <:< tp } + } /** Decompose a type into subspaces -- assume the type can be decomposed */ def decompose(tp: Type)(using Context): List[Type] = trace(i"decompose($tp)", debug) { diff --git a/tests/patmat/i18118.check b/tests/patmat/i18118.check new file mode 100644 index 000000000000..8861eb273fb9 --- /dev/null +++ b/tests/patmat/i18118.check @@ -0,0 +1,4 @@ +12: Pattern Match +21: Pattern Match +32: Pattern Match +41: Pattern Match diff --git a/tests/patmat/i18118.scala b/tests/patmat/i18118.scala new file mode 100644 index 000000000000..c51d736d3db3 --- /dev/null +++ b/tests/patmat/i18118.scala @@ -0,0 +1,41 @@ +// scalac: -Werror + +object O1: + sealed trait A + case class B() extends A + case class C() extends A + + + def bigMatch(x: A) = x match + case B() => + case C() => + case _ => // error + +object O2: + sealed trait A + case class B() extends A + + + def bigMatch(x: A) = x match + case B() => + case _ => // error // was: no "unreachable but for null" warning + +object O3: + sealed trait A + case class B() extends A + case class C() extends A + + + def bigMatch(x: A) = x match + case _: B => + case _: C => + case _ => // error + +object O4: + sealed trait A + case class B() extends A + + + def bigMatch(x: A) = x match + case _: B => + case _ => // error