Skip to content

Commit 0cf41d0

Browse files
committed
Improve warning for wildcard matching only null under explicit nulls (scala#21577)
Adds a more detailed warning message when a wildcard case is only reachable by null under explict nulls flag. Fixes scala#21577
1 parent f7f51ed commit 0cf41d0

File tree

4 files changed

+52
-5
lines changed

4 files changed

+52
-5
lines changed

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

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -920,7 +920,7 @@ object SpaceEngine {
920920
then project(OrType(selTyp, ConstantType(Constant(null)), soft = false))
921921
else project(selTyp)
922922
)
923-
923+
924924
var i = 0
925925
val len = cases.length
926926
var prevs = List.empty[Space]
@@ -942,11 +942,17 @@ object SpaceEngine {
942942
report.warning(MatchCaseUnreachable(), pat.srcPos)
943943
if pat != EmptyTree // rethrow case of catch uses EmptyTree
944944
&& !pat.symbol.isAllOf(SyntheticCase, butNot=Method) // ExpandSAMs default cases use SyntheticCase
945-
&& isSubspace(covered, prev)
945+
&& isSubspace(covered, Or(List(prev, Typ(defn.NullType)))) // for when Null is not subtype of AnyRef under explicit nulls
946946
then {
947-
val nullOnly = isNullable && i == len - 1 && isWildcardArg(pat)
948-
val msg = if nullOnly then MatchCaseOnlyNullWarning() else MatchCaseUnreachable()
949-
report.warning(msg, pat.srcPos)
947+
val nullOnly =
948+
(isNullable || (defn.NullType <:< selTyp))
949+
&& i == len - 1
950+
&& isWildcardArg(pat)
951+
if nullOnly then {
952+
report.warning(MatchCaseOnlyNullWarning(), pat.srcPos)
953+
} else if isSubspace(covered, prev) then {
954+
report.warning(MatchCaseUnreachable(), pat.srcPos)
955+
}
950956
}
951957
deferred = Nil
952958
}

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

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

216+
@Test def explicitNullsWarn: Unit = {
217+
implicit val testGroup: TestGroup = TestGroup("explicitNullsWarn")
218+
compileFilesInDir("tests/explicit-nulls/warn", explicitNullsOptions)
219+
}.checkWarnings()
220+
216221
@Test def explicitNullsRun: Unit = {
217222
implicit val testGroup: TestGroup = TestGroup("explicitNullsRun")
218223
compileFilesInDir("tests/explicit-nulls/run", explicitNullsOptions)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
-- [E121] Pattern Match Warning: tests/explicit-nulls/warn/i21577.scala:5:9 --------------------------------------------
2+
5 | case _ => println(2) // warn
3+
| ^
4+
| Unreachable case except for null (if this is intentional, consider writing case null => instead).
5+
-- [E121] Pattern Match Warning: tests/explicit-nulls/warn/i21577.scala:12:11 ------------------------------------------
6+
12 | case _ => println(2) // warn
7+
| ^
8+
| Unreachable case except for null (if this is intentional, consider writing case null => instead).
9+
-- [E121] Pattern Match Warning: tests/explicit-nulls/warn/i21577.scala:18:11 ------------------------------------------
10+
18 | case _ => println(2) // warn
11+
| ^
12+
| Unreachable case except for null (if this is intentional, consider writing case null => instead).
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) // warn
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)