Description
import quoted._
import tasty._
def makeMatch[A,T](a : Type[A], b : Type[T], head : Expr[_], parts : List[(Expr[_],Expr[_])])(implicit reflection : Reflection) : Expr[T] = {
implicit val e1 = a
implicit val e2 = b
import reflection._
Match(
head.asInstanceOf[Expr[A]].unseal,
parts.map({
case (l,r) => {
val sacrifice = '{
${ head.asInstanceOf[Expr[A]] } match {
case x if x == ${ l.asInstanceOf[Expr[A]] } => ${ r.asInstanceOf[Expr[T]] }
}
}
sacrifice.unseal match {
case IsInlined(inl) => inl.body match {
case IsMatch(m) => m.cases.head
}
}
}
})).seal.cast[T]
}
def mm(implicit reflection : Reflection) =
makeMatch[Int,Boolean]('[Int],'[Boolean],'{42},List('{1}->'{true},'{2}->'{false},'{42}->'{true}))
inline def f = ${ mm }
Trying to call f
will crash with a ClassCastException, suggesting that this code is causing some kind of misalignment wrt. holes in the tasty. It seems something is assuming some overly strong invariants about where the parts of a .unseal
ed expression can end up.
Removing the call to .unseal
will remove the error, no matter how the result of that call is (or isn't) used.
scala> f
1 |f
|^
|An exception occurred while executing macro expansion
|class scala.internal.quoted.TaggedType cannot be cast to class scala.quoted.Expr
Advice?
The root of the issue is that I can't generate match expressions with a variable number of cases using quotes, so I had to resort to tasty.Reflection
. tasty.Reflection
on the other hand doesn't seem to be able to generate the appropriate name bindings/patterns, so I have to "steal" the appropriate AST fragments from a quoted Expr.
Is there a better way to do this? Any workaround suggestions?