The following macro generates a case class Person and returns an instance of this class. It uses whitebox macros so the compiler can infer the type Person. This allows the macro client to call p.name even though this field was generated inside the macro.
import scala.language.experimental.macros
class MacroDefs(val c: scala.reflect.macros.whitebox.Context) {
import c.universe._
def createCaseImpl(): c.Expr[Product] = {
val code: Tree = q""" case class Person(name:String); new Person("Joe") """
c.Expr(code)
}
}
object Macros {
def createCase(): Product = macro MacrosDef.createCaseImpl
}
object Test {
def main(args: Array[String]) {
val p = Macros.createCase()
println("Name: " + p.name)
}
}
The code works, but the compiler is using structural types to access p.name, as you can see from the warning message below (and I confirmed it by decompiling the generated bytecode):
Warning:(5, 54) inferred existential type Person forSome { type Person <: Product with Serializable{val name: String; def copy(name: String): Person; def copy$default$1: String @scala.annotation.unchecked.uncheckedVariance} }, which cannot be expressed by wildcards, should be enabled
by making the implicit value scala.language.existentials visible.
val c = Macros.createCase()
^
Since structural types rely on Java Reflection, I'm concerned about performance.
My question is if there is a better way of doing this so that the compiler will use standard method invocations instead of structural types and reflection. I'm using Scala 2.11.6.
A second minor question: Intellij does not seem to play well with whitebox macros and marks the access to p.name as invalid, saying that the field is not known, even though it will compile and run with scalac. Is there a way of making Intellij aware of whitebox macros?