scala - How to determine if an expression passed to a macro will always result in the same value? -
let's suppose i've defined macro below. types expression of type t , returns object of type mytype[t] (the actual types involved don't matter).
object mymacro { def macroimpl[t : context.weaktypetag, u : context.weaktypetag](context : scala.reflect.macros.blackbox.context) (expression : context.expr[t]) : context.expr[u] = } object myobj { def callmacro[t](expression : t) : mytype[t] = macro mymacro.macroimpl[t, mytype[t]] }
in macro, i'd determine if expression passed constant or not. mean, want know if expression, once evaluated @ runtime, ever subsequently evaluate different value. if constant, can apply optimizations useful.
i know expression constant if is:
- a literal expression.
- a 'this' expression.
- a reference val or parameter.
- a member invocation object expression constant, , member being invoked val or lazy val.
for example, expressions passed in first 5 calls callmacro below should considered constant:
class myclass { val = 0 val myliteral = callmacro("hi!") //constant - literal expression val mythis = callmacro(this) //constant - expression val myint = callmacro(i) //constant - reference val def mymethod(p : myotherclass) { val myparameter = callmacro(p) //constant - reference parameter val myvalmember = callmacro(p.x) //constant - invocation of val member val myvarmember = vallmacro(p.y) //not constant - invocation of var member val myvarmember = vallmacro(p.z) //not constant - invocation of def member } } class myotherclass(val x : int, var y : int) { def z = x + y }
i've implemented code first 2 cases (which rather trivial).
def isconstant[t](context : scala.reflect.macros.blackbox.context) (expression : context.expr[t]) = { import context.universe._ expression.tree match { case this(_) => true case literal(_) => true /*...put additional cases here...*/ case _ => false } }
however, i'm not sure whether exists, or if possible detect whether member being called on object val or not.
is possible implement fourth criteria? or, exist in api?
i figured out solution. boiled down me not knowing symbols in scale's reflection system.
i ended adding fifth criteria handle case in implicit parameter or object referenced.
implicit class extendsymbol(symbol : scala.reflect.macros.blackbox.context#symbol) { def isstable = (symbol.isterm && symbol.asterm.isstable) || (symbol.ismethod && symbol.asmethod.isstable) } def isconstant[t](context : scala.reflect.macros.blackbox.context) (tree : context.tree) : boolean = { import context.universe._ tree match { case this(_) => true case literal(_) => true case ident @ ident(_) => ident.symbol.isstable case select @ select(objexpr, term) => isconstant(context) (objexpr) && select.symbol.isstable //for implicit values case apply(typeapply(select(select(this(typename("scala")), termname("predef")), termname("implicitly")), _), _) => true case _ => false } }
Comments
Post a Comment