Scala 如何确定传递给宏的表达式是否总是产生相同的值?
假设我定义了一个宏,如下所示。它本质上是键入一个T类型的表达式并返回一个MyType[T]类型的对象(实际涉及的类型并不重要) 在我的宏中,我想确定传递的表达式是否为常量。我的意思是,我想知道一旦在运行时对表达式求值,它是否会随后求值为不同的值。如果它是常量,我可以应用某些非常有用的优化 我知道表达式是常量,如果它是:Scala 如何确定传递给宏的表达式是否总是产生相同的值?,scala,scala-macros,Scala,Scala Macros,假设我定义了一个宏,如下所示。它本质上是键入一个T类型的表达式并返回一个MyType[T]类型的对象(实际涉及的类型并不重要) 在我的宏中,我想确定传递的表达式是否为常量。我的意思是,我想知道一旦在运行时对表达式求值,它是否会随后求值为不同的值。如果它是常量,我可以应用某些非常有用的优化 我知道表达式是常量,如果它是: 字面表达 “这”一词 对val或参数的引用 一种成员调用,其中对象表达式为常量,被调用的成员为val或lazy val 例如,下面对callMacro的前五次调用中传递的表达
- 字面表达
- “这”一词
- 对val或参数的引用
- 一种成员调用,其中对象表达式为常量,被调用的成员为val或lazy val
class MyClass {
val i = 0
val myLiteral = callMacro("Hi!") //constant - literal expression
val myThis = callMacro(this) //constant - this expression
val myInt = callMacro(i) //constant - reference to a val
def myMethod(p : MyOtherClass) {
val myParameter = callMacro(p) //constant - reference to a 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
}
我已经为前两种情况实现了代码(这相当简单)
但是,我不确定这样的东西是否已经存在,或者是否可以检测对象上被调用的成员是否是val
是否有可能实施第四个标准?或者,API中已经存在类似的东西了吗?我想出了一个解决方案。这基本上归结为我不知道音阶反射系统中的符号 最后,我添加了第五个条件来处理引用隐式参数或对象的情况
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
}
}
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
}
}
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
}
}