Scala:Context.eval参考中可以编码什么? [英] Scala: what can code in Context.eval reference?
问题描述
Context.eval
的输入似乎只能引用来自不同编译单元的值:
//项目1物体Z {val foo ="WOOF"def impl(c:Context)(x:c.Expr [String])= {val x1 = c.Expr [String](c.untypecheck(x.tree.duplicate))println(s的编译时值为:$ {c.eval(x1)}")X}def test(x:字符串)=宏展示}//专案2物体Y {val foo ="GOOF"val boo = Z.test(Z.foo)}println(Y.boo)
打印出"WOOF"
,但是如果我将boo替换为 val boo = Z.test(Y.foo)
,则会收到以下编译错误:>
错误:(32,29)宏扩展期间发生异常:java.lang.ClassNotFoundException:Y $在scala.reflect.internal.util.AbstractFileClassLoader.findClass(AbstractFileClassLoader.scala:72)...
有什么办法可以解决这个问题?我知道用 quill.io 定义的查询可以引用来自同一范围的方法,但我无法找到他们用来允许它的技巧.
那我们就拥有 树 Quill不使用 因此解决方法是在运行时使用运行时值. 这类似于 prints out Is there any way around this problem? I know that the queries defined with quill.io can reference methods from the same scope, but I wasn't able to find the trick they use to allow it. Let's modify your macro Then we'll have Tree Difference between Quill doesn't use So the workaround is to work with runtime values at runtime. This is similar to https://github.com/getquill/quill/blob/master/quill-core/src/main/scala/io/getquill/context/ContextMacro.scala#L66-L68 这篇关于Scala:Context.eval参考中可以编码什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋! Context#eval
无法评估运行时值.它写在其scaladoc中:
对象应用{/* class */对象Y {val foo ="GOOF";val boo = Z.test(Z.foo)//警告:scalac:输入:Select(Select(Ident(Macros),Macros.Z),TermName("foo"))//警告:scalac:编译时值为:WOOF//val boo1 = Z.test(Y.foo)//Warning:scalac:输入:Select(Select(This(TypeName("App";)),App.Y),TermName("foo"))//错误:宏扩展期间发生异常://java.lang.ClassNotFoundException:App $ Y $//val boo2 = Z.test((new Y).foo)//Warning:scalac:input:Select(Apply(Select(New(Select(This(TypeName(" App"))),App.Y)),termNames.CONSTRUCTOR),List()),TermName("foo")))//错误:宏扩展期间发生异常://java.lang.ClassNotFoundException:App $ Y//val boo3 = Z.test(foo)//警告:scalac:输入:Select(This(TypeName("Y"))),TermName("foo"))//错误:宏扩展期间发生异常://scala.tools.reflect.ToolBoxError:反射编译失败://内部错误:无法找到对象__wrapper $ 1 $ fd3cb1297ce8421e809ee5e821c2f708的外部访问器符号//或者//错误:宏扩展期间发生异常://java.lang.ClassNotFoundException:App $ Y $val boo4 = Z.test("abc")//Warning:scalac:input:Literal(Constant("abc")))//警告:scalac:编译时值为:abcval boo5 = Z.test("abc" +"DEF")//警告:scalac:输入:Literal(Constant("abcDEF"))//警告:scalac:编译时值为:abcDEF}}
此
表示它表示运行时值.只是 ClassNotFoundException
有时会比 ToolBoxError
发生得更快.您使用宏 project 1
的子项目不依赖于子项目 project 2
,因此在宏编译期间未找到 Y
. Z.foo
和 foo
(又名 Y.foo
)之间的区别是 foo
实际上是 this.foo
(如果 Y
是类或对象,编译器不在乎),并且可以在子类中覆盖它. eval
.它将一棵树解析成自己的 AST (如果可以)或 https://github.com/getquill/quill/blob/master/quill-core/src/main/scala/io/getquill/context/QueryMacro.scala#L34-L38 >
def impl(c:blackbox.Context)(x:c.Expr [String]):c.Expr [String] = {导入c.universe._println(s输入:$ {showRaw(x.tree)}"))尝试 {val x1 = c.Expr [String](c.untypecheck(x.tree.duplicate))值x2 = c.eval(x1)println(s编译时值是:$ x2")c.Expr [String](q"$ x2")} 抓住 {例如:Throwable =>println(ex.getMessage)X}}
"WOOF"
, but if I replace boo with val boo = Z.test(Y.foo)
, I get the following compilation error:Error:(32, 29) exception during macro expansion:
java.lang.ClassNotFoundException: Y$
at scala.reflect.internal.util.AbstractFileClassLoader.findClass(AbstractFileClassLoader.scala:72)
...
Context#eval
can't evaluate runtime values. It's written in its scaladoc: https://github.com/scala/scala/blob/2.13.x/src/reflect/scala/reflect/macros/Evals.scala#L61-L67def impl(c: blackbox.Context)(x: c.Expr[String]): c.Expr[String] = {
import c.universe._
println(s"input: ${showRaw(x.tree)}") // added
val x1 = c.Expr[String](c.untypecheck(x.tree.duplicate))
println(s"compile-time value is: ${c.eval(x1)}")
x
}
object App {
/*class*/ object Y {
val foo = "GOOF"
val boo = Z.test(Z.foo)//Warning:scalac: input: Select(Select(Ident(Macros), Macros.Z), TermName("foo"))
//Warning:scalac: compile-time value is: WOOF
// val boo1 = Z.test(Y.foo)//Warning:scalac: input: Select(Select(This(TypeName("App")), App.Y), TermName("foo"))
//Error: exception during macro expansion:
// java.lang.ClassNotFoundException: App$Y$
// val boo2 = Z.test((new Y).foo)//Warning:scalac: input: Select(Apply(Select(New(Select(This(TypeName("App")), App.Y)), termNames.CONSTRUCTOR), List()), TermName("foo"))
//Error: exception during macro expansion:
// java.lang.ClassNotFoundException: App$Y
// val boo3 = Z.test(foo) //Warning:scalac: input: Select(This(TypeName("Y")), TermName("foo"))
//Error: exception during macro expansion:
// scala.tools.reflect.ToolBoxError: reflective compilation has failed:
// Internal error: unable to find the outer accessor symbol of object __wrapper$1$fd3cb1297ce8421e809ee5e821c2f708
// or
//Error: exception during macro expansion:
// java.lang.ClassNotFoundException: App$Y$
val boo4 = Z.test("abc")//Warning:scalac: input: Literal(Constant("abc"))
//Warning:scalac: compile-time value is: abc
val boo5 = Z.test("abc" + "DEF")//Warning:scalac: input: Literal(Constant("abcDEF"))
//Warning:scalac: compile-time value is: abcDEF
}
}
This
means that it represents a runtime value. Just ClassNotFoundException
sometimes happens faster than ToolBoxError
. You subproject with macros project 1
doesn't depend on subproject project 2
so during compilation of macros Y
is not found.Z.foo
and foo
(aka Y.foo
) is that foo
is actually this.foo
(compiler doesn't care here if Y
is a class or object) and can be overriden in subclasses.eval
. It parses a tree into its own AST if it can or leave Dynamic
if it can't (i.e. if the tree corresponds to runtime value). And then it works with these two case differently: either during macros expansion with QueryMeta
or during compile time + runtime with Decoder
def impl(c: blackbox.Context)(x: c.Expr[String]): c.Expr[String] = {
import c.universe._
println(s"input: ${showRaw(x.tree)}")
try {
val x1 = c.Expr[String](c.untypecheck(x.tree.duplicate))
val x2 = c.eval(x1)
println(s"compile-time value is: $x2")
c.Expr[String](q"$x2")
} catch {
case ex: Throwable =>
println(ex.getMessage)
x
}
}