diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index 159b3c9a905e..d22470563d38 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -948,11 +948,11 @@ class UncheckedTypePattern(argType: Type, whyNot: String)(using Context) |""" } -class MatchCaseUnreachable()(using Context) +class MatchCaseUnreachable(why: String = "")(using Context) extends Message(MatchCaseUnreachableID) { def kind = MessageKind.MatchCaseUnreachable - def msg(using Context) = "Unreachable case" - def explain(using Context) = "" + override protected def msg(using Context) = "Unreachable case" + override protected def explain(using Context) = why } class MatchCaseOnlyNullWarning()(using Context) diff --git a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala index a8c8ec8ce1d8..0f7692d00e29 100644 --- a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala +++ b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala @@ -205,12 +205,11 @@ object TypeTestsCasts { def testCls = effectiveClass(testType.widen) def unboxedTestCls = effectiveClass(unboxedTestType.widen) - def unreachable(why: => String)(using Context): Boolean = { - if (flagUnrelated) - if (inMatch) report.error(em"this case is unreachable since $why", expr.srcPos) + def unreachable(why: => String)(using Context): false = + if flagUnrelated then + if inMatch then report.error(MatchCaseUnreachable(why), expr.srcPos) else report.warning(em"this will always yield false since $why", expr.srcPos) false - } /** Are `foundCls` and `testCls` classes that allow checks * whether a test would be always false? diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index 8ede7ba831f5..4abf8a88bbd6 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -949,8 +949,8 @@ object SpaceEngine { if prev == Empty && covered == Empty then // defer until a case is reachable recur(rest, prevs, pat :: deferred) else - for pat <- deferred.reverseIterator - do report.warning(MatchCaseUnreachable(), pat.srcPos) + for deferral <- deferred.reverseIterator + do report.warning(MatchCaseUnreachable(), deferral.srcPos) if pat != EmptyTree // rethrow case of catch uses EmptyTree && !pat.symbol.isAllOf(SyntheticCase, butNot=Method) // ExpandSAMs default cases use SyntheticCase diff --git a/tests/neg/i11118.check b/tests/neg/i11118.check index 6c89f8420cbf..63063b6f5d66 100644 --- a/tests/neg/i11118.check +++ b/tests/neg/i11118.check @@ -6,7 +6,9 @@ | If the narrowing is intentional, this can be communicated by adding `.runtimeChecked` after the expression, | which may result in a MatchError at runtime. | This patch can be rewritten automatically under -rewrite -source 3.8-migration. --- Error: tests/neg/i11118.scala:2:4 ----------------------------------------------------------------------------------- +-- [E030] Match case Unreachable Error: tests/neg/i11118.scala:2:4 ----------------------------------------------------- 2 |val (a,b) = (1,2,3) // error // warning | ^ - | this case is unreachable since type (Int, Int, Int) is not a subclass of class Tuple2 + | Unreachable case + | + | longer explanation available when compiling with `-explain` diff --git a/tests/neg/i24789.scala b/tests/neg/i24789.scala new file mode 100644 index 000000000000..24da8a4e8859 --- /dev/null +++ b/tests/neg/i24789.scala @@ -0,0 +1,10 @@ +//> using options -Werror -explain + +case class A(a: Int) +case class B(b: Int) +case class C(c: Int) + +val a = (A(1): A | B) match + case A(_) => "OK" + case B(_) => "OK" + case C(_) => "Not OK" // error // nopos-error for the warning diff --git a/tests/neg/i8711.check b/tests/neg/i8711.check index 492d16dfa1db..30020926614b 100644 --- a/tests/neg/i8711.check +++ b/tests/neg/i8711.check @@ -10,12 +10,22 @@ 19 | case x: (B | C) => x // warn | ^^^^^^^^^^ | Unreachable case --- Error: tests/neg/i8711.scala:9:9 ------------------------------------------------------------------------------------ +-- [E030] Match case Unreachable Error: tests/neg/i8711.scala:9:9 ------------------------------------------------------ 9 | case x: B => x // error: this case is unreachable since class A is not a subclass of class B | ^ - | this case is unreachable since type A and class B are unrelated --- Error: tests/neg/i8711.scala:14:9 ----------------------------------------------------------------------------------- + | Unreachable case + |--------------------------------------------------------------------------------------------------------------------- + | Explanation (enabled by `-explain`) + |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + | type A and class B are unrelated + --------------------------------------------------------------------------------------------------------------------- +-- [E030] Match case Unreachable Error: tests/neg/i8711.scala:14:9 ----------------------------------------------------- 14 | case x: C => x // error | ^ - | this case is unreachable since type A | B and class C are unrelated + | Unreachable case + |-------------------------------------------------------------------------------------------------------------------- + | Explanation (enabled by `-explain`) + |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + | type A | B and class C are unrelated + -------------------------------------------------------------------------------------------------------------------- No warnings can be incurred under -Werror diff --git a/tests/neg/i8711.scala b/tests/neg/i8711.scala index 88b0a39839fd..e1ad454e7c38 100644 --- a/tests/neg/i8711.scala +++ b/tests/neg/i8711.scala @@ -1,4 +1,4 @@ -//> using options -Werror +//> using options -Werror -explain class A class B diff --git a/tests/neg/named-tuples-2.check b/tests/neg/named-tuples-2.check index daa1c0d69069..a82c79e71c6d 100644 --- a/tests/neg/named-tuples-2.check +++ b/tests/neg/named-tuples-2.check @@ -1,8 +1,12 @@ --- Error: tests/neg/named-tuples-2.scala:4:9 --------------------------------------------------------------------------- +-- [E030] Match case Unreachable Error: tests/neg/named-tuples-2.scala:4:9 --------------------------------------------- 4 | case (name, age) => () // error | ^ - | this case is unreachable since type (String, Int, Boolean) is not a subclass of class Tuple2 --- Error: tests/neg/named-tuples-2.scala:5:9 --------------------------------------------------------------------------- + | Unreachable case + | + | longer explanation available when compiling with `-explain` +-- [E030] Match case Unreachable Error: tests/neg/named-tuples-2.scala:5:9 --------------------------------------------- 5 | case (n, a, m, x) => () // error | ^ - | this case is unreachable since type (String, Int, Boolean) is not a subclass of class Tuple4 + | Unreachable case + | + | longer explanation available when compiling with `-explain`