I am trying to write a type provider macro that uses the vampiric methods trick described in this gist; this is a minimal model of my implementation:
object DeriveFamily {
def minimal: Any = macro DeriveFamilyMacros.minimal
}
object DeriveFamilyMacros {
class body(tree: Any) extends StaticAnnotation
def bodyImpl(c: Context) = {
import c.universe._
val field = c.macroApplication.symbol
val bodyAnn = field.annotations.filter(_.tree.tpe <:< typeOf[body]).head
bodyAnn.tree.children.tail.head
}
def minimal(c: Context): c.Tree = {
import c.universe._
q"""object Foobar { val _x = "X"; @DeriveFamilyMacros.body(Foobar._x) def x: String = macro DeriveFamilyMacros.bodyImpl }; Foobar"""
}
}
This is a dumb example, the real implementation tries to use this trick to create bundles of derived typeclass instances that are accessible without reflective calls. The issue that both the real version and this one have is that they work fine if I use them in a function but they crash the compiler if I try to use them at the root of a class
or object
definition:
object Working {
def x = {
val foobar = DeriveFamily.minimal
println(foobar.x)
}
x // Prints "X"
}
object NotWorking {
val foobar = DeriveFamily.minimal
println(foobar.x)
/*
[trace] Stack trace suppressed: run last common/test:compileIncremental for the full output.
[error] (common/test:compileIncremental) java.lang.IllegalArgumentException: Could not find proxy for var Foobar$module: runtime.VolatileObjectRef in List(variable Foobar$module, value foobar, Object NotWorking, package <root>) (currentOwner= value <local NotWorking> )
*/
}
Any help in fixing this will be very welcome, thanks.