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 ts, concrete ts 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 typetags expected example.apply method. thought of using in() method seems allow transferring typetags 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 typetags you. needs tested, though. try using this:
typeapply(select(reify(example).tree, newtermname("apply")), typetree().settype(childtpe))
Comments
Post a Comment