Skip to content

def unapply(implicit ev: T) no longer works in pattern matching #23499

Closed as not planned
@WojciechMazur

Description

@WojciechMazur

Based on OpenCB failure in scalaland/chimney - fyi @MateuszKubuszok

Previously defining extractor using def unapply(implicit value: T) allowed for dual usage:

  • in pattern matching it worked as normal def unapply(value: T) method
  • in user code allowed to summon instance of extacted object if given implicit was in scope.

It was never possible to achive the same with def unapply(using value: T) syntax becouse it requires an explicit using keyword at callsite - it was never handled by the compiler in case of pattern matching.

The hidden feature of def unapply(implicit value: T) works until Scala 3.7.0, in 3.7.1 it crashes (see #23022) and in 3.7.2-RC1 / nightly it fails to compile (see output)

The possible workaround is to define 2 unapply methods variants - taking normal and using arguments and chaning the output name with @targetName, however this solution is not as flexible as previously

Compiler version

Last good release: 3.7.1-RC1-bin-20250411-f4847cc-NIGHTLY
First bad release: 3.7.1-RC1-bin-20250412-e70ea84-NIGHTLY
Bisect points to b4a802a

Related to #23022

Minimized code

def summonsTest = 
  given Type[String] = ???
  val opt1: Option[Wrapper[String]] = Wrapper.unapply[String] // ok
  val opt2 = Wrapper.unapply[String]
  opt2.map(_.getValue) // error when using workaround

def patternMatchTest =
  Type[String] match 
    case Wrapper(v) => v.getValue

type Type[A] = Class[A] // any rhs would work here
object Type:
  def apply[A]: Type[A] = ???

trait Wrapper[T]:
  def getValue: T = ???
object Wrapper:
  def unapply[T](implicit ev: Type[T]): Option[Wrapper[T]] = None
    
  // Workaround: 
  // @annotation.targetName("unapplyValue")
  // def unapply[T](ev: Type[T]): Option[Wrapper[T]] = unapply(using ev)
  
  // @annotation.targetName("unapplySummon")
  // def unapply[T](using Type[T]): Option[Wrapper[T]] = ???

Output

[error] ./my.example.scala:10:10
[error] Wrapper cannot be used as an extractor in a pattern because it lacks an unapply or unapplySeq method with the appropriate signature
[error]     case Wrapper(v) => v.getValue
[error]          ^^^^^^^
[error] ./my.example.scala:10:24
[error] Not found: v
[error]     case Wrapper(v) => v.getValue
[error]                        ^

With workaround:

[error] ./my.example.scala:6:3
[error] value map is not a member of Class[String] => Option[Wrapper[String]]
[error]   opt2.map(_.getValue) // error when using workaround
[error]   ^^^^^^^^

Expectation

To be decided if the old behaviour under unapply(implicit T) should still be supported

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions