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#evalcan'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
Thismeans that it represents a runtime value. JustClassNotFoundExceptionsometimes happens faster thanToolBoxError. You subproject with macrosproject 1doesn't depend on subprojectproject 2so during compilation of macrosYis not found.Difference between
Z.fooandfoo(akaY.foo) is thatfoois actuallythis.foo(compiler doesn't care here ifYis 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 leaveDynamicif 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 withQueryMetaor during compile time + runtime withDecoderhttps://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