동일한 모듈의 암시 적 구체화

Dec 15 2020

다음과 같은 매개 변수화 된 클래스가 있습니다.

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

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

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

동일한 모듈에서 구체화 된 암시 적을 사용하면 오류가 발생합니다.

macro implementation not found

그러나 문제는 단일 클래스를 별도의 모듈로 추출하는 것이 절대적으로 추하고 번거로워 보인다는 것입니다. 이를 방지 할 수있는 "잘 알려진 해결 방법"이 있습니까? 형태가없는 것이 도움이 될 수 있습니까?

UPD :

scalaVersion in ThisBuild := "2.13.2"

다음은 내 최소한의 예입니다.

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

다음 오류가 발생합니다.

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

답변

3 DmytroMitin Dec 15 2020 at 21:35

별도의 모듈로 추출 할 수는 Test없지만TestMacro

핵심

import scala.language.experimental.macros

class Test[T]

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

implicitly[Test[Int]] // compiles

매크로

import scala.reflect.macros.blackbox

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

추악하든 아니든 매크로 구현은 적용하기 전에 컴파일해야합니다.

이것은 Scala 3에서 개선되었습니다.

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

Shapeless는 미리 정의 된 표준 매크로 집합을 숨길 뿐이며 사용자 고유의 매크로에는 도움이되지 않습니다.