Skip to content

pattern matcher generates illegal isInstanceOf[Null] for nullable parameter of unapply #23243

@olhotak

Description

@olhotak
Contributor

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.

Activity

olhotak

olhotak commented on May 22, 2025

@olhotak
ContributorAuthor
removed
stat:needs triageEvery issue needs to have an "area" and "itype" label
on May 23, 2025
Gedochao

Gedochao commented on May 23, 2025

@Gedochao
Contributor
SuperCl4sh

SuperCl4sh commented on May 27, 2025

@SuperCl4sh
Contributor

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.

som-snytt

som-snytt commented on May 30, 2025

@som-snytt
Contributor

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")
            }
        }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

    Participants

    @som-snytt@olhotak@Gedochao@SuperCl4sh

    Issue actions

      pattern matcher generates illegal isInstanceOf[Null] for nullable parameter of unapply · Issue #23243 · scala/scala3