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
extractor macros don't work #5903
Comments
Imported From: https://issues.scala-lang.org/browse/SI-5903?orig=1 |
@xeno-by said: Moreover, with the incoming addition of c.introduceTopLevel it becomes possible to generate arbitrarily complex unappliers, even with heterogeneous types of arguments, varying from expansion to expansion: import language.experimental.macros
import scala.reflect.macros.Context
object Macros {
implicit class ContextExtensions(c: StringContext) {
object q {
def unapply(x: Any): Option[Any] = macro impl
}
}
def impl(c: Context)(x: c.Expr[Any]): c.Expr[Option[Any]] = {
import c.universe._
import Flag._
// parts here will be string literals - static parts of the string interpolation
// e.g. for q"$x, $y" parts will be Literal(Constant("")), Literal(Constant(", ")) and Literal(Constant(""))
val Apply(Select(Select(Apply(_, List(Apply(_, parts))), _), _), _) = c.macroApplication
val nresults = parts.length - 1
def results() =
((1 to (nresults - 1)).toList map (i => Literal(Constant(i)))) :+ // (n - 1) results of type Int
Apply(Ident(TermName("List")), List(Literal(Constant(nresults)))) // and also one result of a different type
def extractorBody() =
if (nresults == 0) Literal(Constant(true))
else if (nresults == 1) Apply(Ident(TermName("Some")), results())
else Apply(Ident(TermName("Some")), List(Apply(Ident(TermName("Tuple" + nresults)), results())))
val name = TermName(java.util.UUID.randomUUID().toString.replace("-", ""))
val mdef = ModuleDef(NoMods, name, Template(List(Select(Ident(TermName("scala")), TypeName("AnyRef"))), emptyValDef, List(
DefDef(Modifiers(), nme.CONSTRUCTOR, List(), List(List()), TypeTree(),
Block(List(pendingSuperCall), Literal(Constant(())))),
DefDef(Modifiers(), TermName("unapply"), List(), List(List(ValDef(Modifiers(PARAM), TermName("x"), Ident(TypeName("Any")), EmptyTree))), TypeTree(),
extractorBody()))))
c.introduceTopLevel(nme.EMPTY_PACKAGE_NAME.toString, mdef)
c.Expr[Option[Any]](Apply(Select(Ident(name), TermName("unapply")), List(x.tree)))
}
} object Test extends App {
import Macros._
def whatever() = null
val q"$x1, $y1" = whatever()
println(x1, y1)
val q"$x2" = whatever()
println(x2)
}
22:27 ~/Projects/Paradise/sandbox (paradise/macros)$ scalac Macros.scala && scalac Test.scala && scala Test
(1,List(2))
List(1) |
@paulp said: |
@jrudolph said: Couldn't an unapply macro be treated in a way that allows to replace |
@jrudolph said: |
@xeno-by said: |
@xeno-by said: |
@adriaanm said: |
@xeno-by said: |
We want some way to perform macro expansion in left-hand side expressions in pattern matches. The most popular request in this area seems to be declaring
StringContext.xxx.unapply
as a macro.=== A naive version ===
Expands unapply into None. Sure thing, it won't work because inside a CaseDef one needs to expand into patterns.
=== A smarter version ===
Expands into a block that returns Option[...], uses the thingie, which stands for a scrutinee, to inspect that scrutinee. Crashes because
extractFormalType
andMatchTranslation
expect expressions involving to be unapply calls.=== A cleaner version ===
The problem with a smarter version is that, even though it's well aligned with the concept of def macros, it leaks implementation details and sacrifices the purity of textual abstraction.
Imagine we have a
Foo(x, y)
pattern, with Foo.unapply being a macro. Before the macro gets a chance to expand, the pattern is translated to UnApply(Foo.unapply(<unapply-selector>)
, List(x
,y
)), so the stuff that is really expanded isFoo.unapply(<unapply-selector>)
, but not the entire pattern. This brings awkwardness and inefficiency (via boxing).The best thing here would be to use untyped macros and expand
Foo(x, y)
before it's desugared. This however requires untyped macros though.The text was updated successfully, but these errors were encountered: