Materialização implícita no mesmo módulo
Eu tenho uma classe parametrizada como
class Test[T]{
//...
}
object Test{
implicit def materializeTest[T]: Test[T] = macro impl[T]
def impl[T: c.WeakTypeTag](c: blackbox.Context) = //...
}
Se usar o implícito materializado do mesmo módulo, ocorrerá um erro:
macro implementation not found
Mas o problema é que extrair uma única classe em um módulo separado parece absolutamente feio e complicado. Talvez haja alguma "solução alternativa bem conhecida" para evitar isso? Talvez o disforme pode ser útil aqui?
UPD:
scalaVersion in ThisBuild := "2.13.2"
Aqui está meu exemplo mínimo:
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
object Main {
sealed trait Adt
case object Adt1 extends Adt
case object Adt2 extends Adt
trait Test[Adtt <: Adt] {
def restrict(restrictions: List[Int]): List[Int]
}
object Test {
def apply[Adtt <: Adt](implicit ev: Test[Adtt]): Test[Adtt] = ev
implicit def implicitMaterializer[
Adtt <: Adt
]: Test[Adtt] = macro impl[Adtt]
def impl[Adtt <: Adt: c.WeakTypeTag](
c: blackbox.Context
): c.Expr[Test[Adtt]] = {
import c.universe._
c.Expr[Test[Adtt]](q"""???""")
}
}
def main(args: Array[String]): Unit = {
Test[Adt1.type].restrict(List(1, 2, 3))
}
}
o que resulta no seguinte erro:
[error] Main.scala:32:9: macro implementation not found: implicitMaterializer
[error] (the most common reason for that is that you cannot use macro implementations in the same compilation run that defines them)
Respostas
Você pode extrair para um módulo separado, Test
mas nãoTestMacro
testemunho
import scala.language.experimental.macros
class Test[T]
object Test {
implicit def materializeTest[T]: Test[T] = macro TestMacro.impl[T]
}
implicitly[Test[Int]] // compiles
macros
import scala.reflect.macros.blackbox
object TestMacro {
def impl[T: c.WeakTypeTag](c: blackbox.Context) = {
import c.universe._
q"new Test[${weakTypeOf[T]}]"
}
}
Feias ou não, mas as implementações de macro devem ser compiladas antes de serem aplicadas.
Isso foi melhorado no Scala 3
http://dotty.epfl.ch/docs/reference/metaprogramming/macros.html#defining-a-macro-and-using-it-in-a-single-project
O Shapeless apenas esconde alguns conjuntos predefinidos de macros padrão, não pode ajudar com suas próprias macros.