When I try to add a macro annotation to my case class:
@macid case class CC[A: T](val x: A)
I get the error:
private[this] not allowed for case class parameters
@macid
is just the identity function, defined as a whitebox StaticAnnotation:
import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context
import scala.annotation.StaticAnnotation
class macid extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro macidMacro.impl
}
object macidMacro {
def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
new Macros[c.type](c).macidMacroImpl(annottees.toList)
}
}
class Macros[C <: Context](val c: C) {
import c.universe._
def macidMacroImpl(annottees: List[c.Expr[Any]]): c.Expr[Any] =
annottees(0)
}
The unannotated code works:
case class CC[A: T](val x: A)
It works if I remove the context bound:
@macid case class CC[A](val x: A)
What's happening is the context bound is desugared into a private parameter. The following desugared code gets the same error:
@macid case class CC[A](val x: A)(implicit aIsT: T[A])
To get working code I make the implicit parameter public with val
:
@macid case class CC[A](val x: A)(implicit val aIsT: T[A])
So my questions are: What's the right way for a macro annotation to support context bounds? Why does the compiler perform a no-private-parameters-of-case-classes check for code that's generated by a macro annotation, but doesn't perform the check for ordinary code?
Scala versions 2.11.7 and 2.12.0-M3 both report the error. All the above code examples compile and run as expected in 2.11.3.
Seems like a bug. Here is the tree as seen by the macro:
case class CC[A] extends scala.Product with scala.Serializable {
<caseaccessor> <paramaccessor> val x: A = _;
implicit <synthetic> <caseaccessor> <paramaccessor> private[this] val evidence$1: T[A] = _;
def <init>(x: A)(implicit evidence$1: T[A]) = {
super.<init>();
()
}
}
And through the runtime reflection API:
case class CC[A] extends Product with Serializable {
<caseaccessor> <paramaccessor> val x: A = _;
implicit <synthetic> <paramaccessor> private[this] val evidence$1: $read.T[A] = _;
def <init>(x: A)(implicit evidence$1: $read.T[A]) = {
super.<init>();
()
}
};
The former has an extra <caseaccessor>
flag on evidence$1
when it should not. It seems as though all implicit parameters to case classes are mistakenly given this flag.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With