Skip to content

Commit 210b2d1

Browse files
committed
Improve warning for wildcard matching non-nullable types (scala#21577)
Adds a more detailed warning message when a wildcard case is unreachable on an non-nullable type to suggest adding a nullable type annotation. Fixes scala#21577
1 parent ba9e59a commit 210b2d1

File tree

6 files changed

+49
-1
lines changed

6 files changed

+49
-1
lines changed

compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe
215215
case TailrecNestedCallID //errorNumber: 199
216216
case FinalLocalDefID // errorNumber: 200
217217
case NonNamedArgumentInJavaAnnotationID // errorNumber: 201
218+
case MatchCaseNonNullableWildcardWarningID // errorNumber: 202
218219

219220
def errorNumber = ordinal - 1
220221

compiler/src/dotty/tools/dotc/reporting/messages.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -935,6 +935,12 @@ extends PatternMatchMsg(MatchCaseOnlyNullWarningID) {
935935
def explain(using Context) = ""
936936
}
937937

938+
class MatchCaseNonNullableWildcardWarning()(using Context)
939+
extends PatternMatchMsg(MatchCaseNonNullableWildcardWarningID) {
940+
def msg(using Context) = i"""Unreachable case (if expression is expected to be nullable, consider giving it a nullable type annotation)."""
941+
def explain(using Context) = ""
942+
}
943+
938944
class MatchableWarning(tp: Type, pattern: Boolean)(using Context)
939945
extends TypeMsg(MatchableWarningID) {
940946
def msg(using Context) =

compiler/src/dotty/tools/dotc/transform/patmat/Space.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -928,7 +928,11 @@ object SpaceEngine {
928928
&& isSubspace(covered, prev)
929929
then {
930930
val nullOnly = isNullable && i == len - 1 && isWildcardArg(pat)
931-
val msg = if nullOnly then MatchCaseOnlyNullWarning() else MatchCaseUnreachable()
931+
val wildcardNotNullable = i == len - 1 && isWildcardArg(pat)
932+
val msg =
933+
if nullOnly then MatchCaseOnlyNullWarning()
934+
else if wildcardNotNullable then MatchCaseNonNullableWildcardWarning()
935+
else MatchCaseUnreachable()
932936
report.warning(msg, pat.srcPos)
933937
}
934938
deferred = Nil

compiler/test/dotty/tools/dotc/CompilationTests.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,11 @@ class CompilationTests {
212212
)
213213
}.checkCompile()
214214

215+
@Test def explicitNullsWarn: Unit = {
216+
implicit val testGroup: TestGroup = TestGroup("explicitNullsWarn")
217+
compileFilesInDir("tests/explicit-nulls/warn", explicitNullsOptions)
218+
}.checkWarnings()
219+
215220
@Test def explicitNullsRun: Unit = {
216221
implicit val testGroup: TestGroup = TestGroup("explicitNullsRun")
217222
compileFilesInDir("tests/explicit-nulls/run", explicitNullsOptions)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-- [E202] Pattern Match Warning: tests/explicit-nulls/warn/i21577.scala:5:9 --------------------------------------------
2+
5 | case _ => println(2) // warn
3+
| ^
4+
| Unreachable case (if expression is expected to be nullable, consider giving it a nullable type annotation).
5+
-- [E202] Pattern Match Warning: tests/explicit-nulls/warn/i21577.scala:12:11 ------------------------------------------
6+
12 | case _ => println(2) // warn
7+
| ^
8+
| Unreachable case (if expression is expected to be nullable, consider giving it a nullable type annotation).
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
def f(s: String) =
2+
val s2 = s.trim()
3+
s2 match
4+
case s3: String => println(1)
5+
case _ => println(2) // warn
6+
7+
8+
def f2(s: String | Null) =
9+
val s2 = s.nn.trim()
10+
s2 match
11+
case s3: String => println(1)
12+
case _ => println(2) // warn
13+
14+
def f3(s: String | Null) =
15+
val s2 = s
16+
s2 match
17+
case s3: String => println(1)
18+
case _ => println(2)
19+
20+
def f4(s: String | Int) =
21+
val s2 = s
22+
s2 match
23+
case s3: String => println(1)
24+
case _ => println(2)

0 commit comments

Comments
 (0)