Implizite Materialisierung im selben Modul

Dec 15 2020

Ich habe eine parametrisierte Klasse wie

class Test[T]{
    //...
}

object Test{
    implicit def materializeTest[T]: Test[T] = macro impl[T]

    def impl[T: c.WeakTypeTag](c: blackbox.Context) = //...
}

Wenn Sie das materialisierte Implizit aus demselben Modul verwenden, wird ein Fehler ausgegeben:

macro implementation not found

Das Problem ist jedoch, dass das Extrahieren einer einzelnen Klasse in ein separates Modul absolut hässlich und umständlich aussieht. Vielleicht gibt es eine "bekannte Problemumgehung", um dies zu vermeiden? Vielleicht kann hier formlos hilfreich sein?

UPD:

scalaVersion in ThisBuild := "2.13.2"

Hier ist mein minimales Beispiel:

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))
  }
}

was zu folgendem Fehler führt:

[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)

Antworten

3 DmytroMitin Dec 15 2020 at 21:35

Sie können Testaber nicht in ein separates Modul extrahierenTestMacro

Ader

import scala.language.experimental.macros

class Test[T]

object Test {
  implicit def materializeTest[T]: Test[T] = macro TestMacro.impl[T]
}

implicitly[Test[Int]] // compiles

Makros

import scala.reflect.macros.blackbox

object TestMacro {
  def impl[T: c.WeakTypeTag](c: blackbox.Context) = {
    import c.universe._
    q"new Test[${weakTypeOf[T]}]"
  }
}

Hässlich oder nicht, aber Makroimplementierungen müssen kompiliert werden, bevor sie angewendet werden.

Dies wird in Scala 3 verbessert

http://dotty.epfl.ch/docs/reference/metaprogramming/macros.html#defining-a-macro-and-using-it-in-a-single-project

Shapeless verbirgt nur einige vordefinierte Standardmakros. Es kann nicht mit Ihren eigenen Makros helfen.