Skip to content

Commit d7a439e

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 a672e05 commit d7a439e

File tree

4 files changed

+52
-5
lines changed

4 files changed

+52
-5
lines changed

Diff for: compiler/src/dotty/tools/dotc/transform/patmat/Space.scala

+11-5
Original file line numberDiff line numberDiff line change
@@ -903,7 +903,7 @@ object SpaceEngine {
903903
then project(OrType(selTyp, ConstantType(Constant(null)), soft = false))
904904
else project(selTyp)
905905
)
906-
906+
907907
var i = 0
908908
val len = cases.length
909909
var prevs = List.empty[Space]
@@ -925,11 +925,17 @@ object SpaceEngine {
925925
report.warning(MatchCaseUnreachable(), pat.srcPos)
926926
if pat != EmptyTree // rethrow case of catch uses EmptyTree
927927
&& !pat.symbol.isAllOf(SyntheticCase, butNot=Method) // ExpandSAMs default cases use SyntheticCase
928-
&& isSubspace(covered, prev)
928+
&& isSubspace(covered, Or(List(prev, Typ(defn.NullType)))) // for when Null is not subtype of AnyRef under explicit nulls
929929
then {
930-
val nullOnly = isNullable && i == len - 1 && isWildcardArg(pat)
931-
val msg = if nullOnly then MatchCaseOnlyNullWarning() else MatchCaseUnreachable()
932-
report.warning(msg, pat.srcPos)
930+
val nullOnly =
931+
(isNullable || (defn.NullType <:< selTyp))
932+
&& i == len - 1
933+
&& isWildcardArg(pat)
934+
if nullOnly then {
935+
report.warning(MatchCaseOnlyNullWarning(), pat.srcPos)
936+
} else if isSubspace(covered, prev) then {
937+
report.warning(MatchCaseUnreachable(), pat.srcPos)
938+
}
933939
}
934940
deferred = Nil
935941
}

Diff for: compiler/test/dotty/tools/dotc/CompilationTests.scala

+5
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)

Diff for: tests/explicit-nulls/warn/i21577.check

+12
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).

Diff for: tests/explicit-nulls/warn/i21577.scala

+24
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)