It seems that the input of Context.eval
can reference only values from different compilation unit:
// project 1
object Z {
val foo = "WOOF"
def impl(c: Context)(x: c.Expr[String]) = {
val x1 = c.Expr[String](c.untypecheck(x.tree.duplicate))
println(s"compile-time value is: ${c.eval(x1)}")
x
}
def test(x: String) = macro impl
}
// project 2
object Y {
val foo = "GOOF"
val boo = Z.test(Z.foo)
}
println(Y.boo)
prints out "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)
...
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.
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-L67Let's modify your macro
Then we'll have
Tree
This
means that it represents a runtime value. JustClassNotFoundException
sometimes happens faster thanToolBoxError
. You subproject with macrosproject 1
doesn't depend on subprojectproject 2
so during compilation of macrosY
is not found.Difference between
Z.foo
andfoo
(akaY.foo
) is thatfoo
is actuallythis.foo
(compiler doesn't care here ifY
is a class or object) and can be overriden in subclasses.Quill doesn't use
eval
. It parses a tree into its own AST if it can or leaveDynamic
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 withQueryMeta
or during compile time + runtime withDecoder
https://github.com/getquill/quill/blob/master/quill-core/src/main/scala/io/getquill/context/QueryMacro.scala#L34-L38
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