Matérialisation implicite dans le même module
J'ai une classe paramétrée comme
class Test[T]{
//...
}
object Test{
implicit def materializeTest[T]: Test[T] = macro impl[T]
def impl[T: c.WeakTypeTag](c: blackbox.Context) = //...
}
Si vous utilisez l'implicite matérialisé du même module, cela génère une erreur:
macro implementation not found
Mais le problème est l'extraction d'une seule classe dans un module séparé semble absolument moche et encombrant. Peut-être existe-t-il une «solution de contournement bien connue» pour éviter cela? Peut-être qu'informe peut être utile ici?
UPD:
scalaVersion in ThisBuild := "2.13.2"
Voici mon exemple minimal:
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))
}
}
ce qui entraîne l'erreur suivante:
[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)
Réponses
Vous pouvez extraire vers un module séparé non Test
maisTestMacro
cœur
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]}]"
}
}
Moche ou pas, mais les implémentations de macro doivent être compilées avant d'être appliquées.
Ceci est amélioré dans Scala 3
http://dotty.epfl.ch/docs/reference/metaprogramming/macros.html#defining-a-macro-and-using-it-in-a-single-project
Shapeless cache juste un ensemble prédéfini de macros standard, il ne peut pas vous aider avec vos propres macros.