I asked a question over here, but after having looked a little more at the syntax summary and playing around a little, it looks like splices inside quoted patterns can be arbitrary blocks, which permit code that can’t be compiled into patterns and also forbids code that can (like bindings). So for example,
import scala.quoted.*
object MyMatcher {
def unapply(expr: Expr[Any])(using Quotes): Option[Expr[Int]] = ???
}
def foo(x: Any): Unit = ???
def f(expr: Expr[Any])(using Quotes): Expr[Int] = expr match
case '{ foo(${MyMatcher(y)}) } => y
compiles but
import scala.quoted.*
object MyMatcher {
def unapply(expr: Expr[Any])(using Quotes): Option[Expr[Int]] = ???
}
def foo(x: Any): Unit = ???
def f(expr: Expr[Any])(using Quotes): Expr[Int] = expr match
case '{ foo(${import scala.Int; MyMatcher(y)}) } => y
does not because there is no apply
method on MyMatcher
. (I added the import there just as something that should be a no-op of sorts). This seems like a big problem to me. Either splices in patterns should be treated as
(1) expressions that always evaluate to Expr
s in the forward direction, so that the semantics of
case '{ foo(${...}) }
should be the same as case '{ foo(bar()) }
if ...
evaluates to the Expr bar()
or
(2) regular patterns, in which case ${y@MyMatcher(_)}
should be (syntactically) permitted inside a pattern but ${import scala.Int; MyMatcher(y)}
should not.
I think the parsing behavior indicates (1), but (2) seems to happen in practice when the splice can be interpreted as a pattern. Am I misunderstanding something here?