reflection - Scala macros: convert Context#TypeTag to JavaUniverse#TypeTag -
i want use macros generate code instantiates objects this:
import scala.reflect.runtime.universe._ case class example[t: typetag] { val tpe = implicitly[typetag[t]].tpe }
this, obviously, translates following:
import scala.reflect.runtime.universe._ case class example[t](implicit ev: typetag[t]) { val tpe = ev.tpe }
then if class instantiated in regular code scala compiler provides typetag
instance automatically.
however, want generate code instantiates several instances of class different t
s, concrete t
s depend on user input, like
sealed trait test case class subtest1 extends test case class subtest2 extends test val examples = generate[test] // want ^^^^^^^^^^^^^^ expand this: val examples = seq(example[subtest1], example[subtest2])
i know how subclasses of sealed trait, can access c.weaktypetag[subtest1]
, c.weaktypetag[subtest2]
in macro code. not know how turn them typetag
s expected example.apply
method. thought of using in()
method seems allow transferring typetag
s between universes, requires destination mirror, , don't know how runtime mirror @ compile time inside macro.
here code have far (i have added several annotations , statements clearer):
object examplemacro { def collect[t] = macro collect_impl def collect_impl[t: c.weaktypetag](c: context): c.expr[seq[example[_]]] = { import c.universe._ val symbol = weaktypeof[t].typesymbol if (symbol.isclass && symbol.asclass.istrait && symbol.asclass.issealed) { val children = symbol.asclass.knowndirectsubclasses.tolist if (!children.forall(c => c.isclass && c.asclass.iscaseclass)) { c.abort(c.enclosingposition, "all children of sealed trait must case classes") } val args: list[c.tree] = children.map { ch: symbol => val childtpe = c.weaktypetag(ch.typesignature) // or c.typetag(ch.typesignature) val runtimechildtpe: c.expr[scala.reflect.runtime.universe.typetag[_]] = ??? // should go here? apply(select(reify(example).tree, newtermname("apply")), runtimechildtpe.tree) } apply(select(reify(seq).tree, newtermname("apply")), args) } else { c.abort(c.enclosingposition, "can construct sequence sealed trait") } } }
you looking this:
c.reifytype(treebuild.mkruntimeuniverseref, emptytree, childtpe)
the above code work assuming import c.universe._
.
it create tree
evaluate desired scala.reflect.runtime.universe.typetag[_]
in runtime.
on second thought, think manual generation of tree may not needed @ all. tree returned macro undergoes more typechecking means compiler may able fill implicit typetag
s you. needs tested, though. try using this:
typeapply(select(reify(example).tree, newtermname("apply")), typetree().settype(childtpe))
Comments
Post a Comment