scala3
scala3 copied to clipboard
pattern matcher generates illegal isInstanceOf[Null] for nullable parameter of unapply
Compiler version
Scala 3.7.2-RC1-bin-20250520-baac46c-NIGHTLY, JVM (8)
Minimized code
object Extractor:
def unapply(s: String|Null): Boolean = true
class A
def main =
("foo": (A|String)) match
case Extractor() => println("foo matched")
case _ => println("foo didn't match")
Output
$ scala-cli -S 3.nightly patmat.scala
Compiling project (Scala 3.7.2-RC1-bin-20250520-baac46c-NIGHTLY, JVM (8))
[error] ./patmat.scala:9:10
[error] class Null cannot be used in runtime type tests
[error] case Extractor() => println("foo matched")
[error] ^^^^^^^^^^^
Error compiling project (Scala 3.7.2-RC1-bin-20250520-baac46c-NIGHTLY, JVM (8))
Expectation
Is a nullable type parameter of unapply even allowed?
If not, the error message should point out the unapply method.
If yes, the pattern matcher should not generate an illegal isInstanceOf[Null] and the example should compile.
Note: the issue happens both with and without -Yexplicit-nulls.
Note: a similar unapply appears in the compiler source in dotty.tools.backend.jvm.DottyBackendInterface.DeconstructorCommon.
cc @HarrisL2 @SuperCl4sh
cc @noti0na1
Hi, would it possible for me to get assigned to this? I believe I've located the cause, but I haven't produced a fix yet.
An extractor pattern cannot match the value null. The implementation ensures that the unapply/unapplySeq method is not applied to null.
per spec.
The extractor is fine, but patmat should always do a null check or correct instanceof:
def f[T <: String | Null](x: T): Unit =
matchResult2[Unit]:
{
case val x3: (x : T) = x
if (x3 ne null) && X.unapply(x3) then
return[matchResult2]
{
println("foo matched")
}
else ()
return[matchResult2]
{
println("foo didn\'t match")
}
}
def g[T <: String | A](x: T): Unit =
matchResult3[Unit]:
{
case val x4: (x : T) = x
if x4.$isInstanceOf[String] && X.unapply(x4.$asInstanceOf[String])
then
return[matchResult3]
{
println("foo matched")
}
else ()
return[matchResult3]
{
println("foo didn\'t match")
}
}