Skip to content

Commit

Permalink
Improve warning for wildcard matching non-nullable types (#21577)
Browse files Browse the repository at this point in the history
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 #21577
  • Loading branch information
HarrisL2 committed Sep 21, 2024
1 parent ba9e59a commit 210b2d1
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe
case TailrecNestedCallID //errorNumber: 199
case FinalLocalDefID // errorNumber: 200
case NonNamedArgumentInJavaAnnotationID // errorNumber: 201
case MatchCaseNonNullableWildcardWarningID // errorNumber: 202

def errorNumber = ordinal - 1

Expand Down
6 changes: 6 additions & 0 deletions compiler/src/dotty/tools/dotc/reporting/messages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -935,6 +935,12 @@ extends PatternMatchMsg(MatchCaseOnlyNullWarningID) {
def explain(using Context) = ""
}

class MatchCaseNonNullableWildcardWarning()(using Context)
extends PatternMatchMsg(MatchCaseNonNullableWildcardWarningID) {
def msg(using Context) = i"""Unreachable case (if expression is expected to be nullable, consider giving it a nullable type annotation)."""
def explain(using Context) = ""
}

class MatchableWarning(tp: Type, pattern: Boolean)(using Context)
extends TypeMsg(MatchableWarningID) {
def msg(using Context) =
Expand Down
6 changes: 5 additions & 1 deletion compiler/src/dotty/tools/dotc/transform/patmat/Space.scala
Original file line number Diff line number Diff line change
Expand Up @@ -928,7 +928,11 @@ object SpaceEngine {
&& isSubspace(covered, prev)
then {
val nullOnly = isNullable && i == len - 1 && isWildcardArg(pat)
val msg = if nullOnly then MatchCaseOnlyNullWarning() else MatchCaseUnreachable()
val wildcardNotNullable = i == len - 1 && isWildcardArg(pat)
val msg =
if nullOnly then MatchCaseOnlyNullWarning()
else if wildcardNotNullable then MatchCaseNonNullableWildcardWarning()
else MatchCaseUnreachable()
report.warning(msg, pat.srcPos)
}
deferred = Nil
Expand Down
5 changes: 5 additions & 0 deletions compiler/test/dotty/tools/dotc/CompilationTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,11 @@ class CompilationTests {
)
}.checkCompile()

@Test def explicitNullsWarn: Unit = {
implicit val testGroup: TestGroup = TestGroup("explicitNullsWarn")
compileFilesInDir("tests/explicit-nulls/warn", explicitNullsOptions)
}.checkWarnings()

@Test def explicitNullsRun: Unit = {
implicit val testGroup: TestGroup = TestGroup("explicitNullsRun")
compileFilesInDir("tests/explicit-nulls/run", explicitNullsOptions)
Expand Down
8 changes: 8 additions & 0 deletions tests/explicit-nulls/warn/i21577.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-- [E202] Pattern Match Warning: tests/explicit-nulls/warn/i21577.scala:5:9 --------------------------------------------
5 | case _ => println(2) // warn
| ^
| Unreachable case (if expression is expected to be nullable, consider giving it a nullable type annotation).
-- [E202] Pattern Match Warning: tests/explicit-nulls/warn/i21577.scala:12:11 ------------------------------------------
12 | case _ => println(2) // warn
| ^
| Unreachable case (if expression is expected to be nullable, consider giving it a nullable type annotation).
24 changes: 24 additions & 0 deletions tests/explicit-nulls/warn/i21577.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
def f(s: String) =
val s2 = s.trim()
s2 match
case s3: String => println(1)
case _ => println(2) // warn


def f2(s: String | Null) =
val s2 = s.nn.trim()
s2 match
case s3: String => println(1)
case _ => println(2) // warn

def f3(s: String | Null) =
val s2 = s
s2 match
case s3: String => println(1)
case _ => println(2)

def f4(s: String | Int) =
val s2 = s
s2 match
case s3: String => println(1)
case _ => println(2)

0 comments on commit 210b2d1

Please sign in to comment.