Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve warning for wildcard matching non-nullable types (scala#21577) #21623

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need another error?


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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this will work. It will catch other cases which are not related to null. You may want to modify isNullable, since a flexible type is considered "nullable" in terms of values.

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)
Loading