Reputation: 3013
def control(x: String): Option[String] = macro controlImpl
def controlImpl(c: Context)(x: c.Expr[String]): c.Expr[Option[String]] = {
import c.universe._
val result = x.tree match {
case Match(expr, cases) =>
val matchz = Match(q"""List("hello")""", cases)
q"Some(List(5)).map{a => $matchz}"
case a => a
}
c.Expr[Option[String]](result)
}
This macro crashes during macro expansion with the following error:
java.lang.IllegalArgumentException: Could not find proxy for val o7: Some in List(value o7, method apply, <$anon: Function1>, value f, method apply, <$anon: Function1>, method apply, <$anon: Function0>, value <local ApplicativeTest>, object ApplicativeTest, package scalaz, package <root>) (currentOwner= value one )
This is the macro application point:
val f = IdiomBracket.control {
a.get match {
case List(one) => one
case _ => ""
}
}
What is odd is that if you substitute q"Some(List(5)).map{a => $matchz}"
with q"Some($matchz)"
then the compiler crash goes away.
Upvotes: 1
Views: 252
Reputation: 39577
"Simple macro" is an oxymoron.
The crash is in lambda lift, which indicates a bad symbol owner.
You can inspect the tree you produce with -Ybrowse:typer
.
Consider what you'd like to produce:
class X {
//def g = List("hello") match { case List(x) => x case _ => "" }
def f = Some(List(5)).map{a => List("hello") match { case List(x) => x case _ => "" } }
}
The var in the case is owned by the anonfun you want to create:
Symbol: [has] value x
Symbol owner: value $anonfun
Your actual result:
Symbol: [has] value x
Symbol owner: value <local Controlled>
where Controlled
is my sample enclosing object for your code.
You might have to rebuild the cases, as opposed to just cases map (_.untypecheck)
.
https://github.com/scala/scala/blob/v2.11.5/src/reflect/scala/reflect/api/Trees.scala#L1100
Upvotes: 2