Existe-t-il un moyen de transmettre un identifiant de type à une annotation de macro ? Voici ce que je veux dire :

@compileTimeOnly("Compile-time only annotation")
class mymacro(val typeName: universe.TypeName) extends StaticAnnotation { // <-- does not work
  def macroTransform(annottees: Any*): Any = macro impl
}

object mymacro {
  def impl(c: whitebox.Context)(annottees: c.Expr[Any]*) = //...
}

Cas d'utilisation:

trait SomeTrait

@mymacro(SomeTrait)
class Test {
    //...
}

Ou peut-être existe-t-il un autre moyen de transmettre l'identificateur de type d'un type non générique arbitraire à une implémentation d'annotation de macro ?

Motivation derrière cela : J'ai besoin de générer une fonction membre class Test def foo en fonction du type passé en argument à l'annotation de macro (SomeTrait).

0
Some Name 30 oct. 2020 à 01:30

1 réponse

Meilleure réponse

Par exemple, vous pouvez passer typeName sous forme de chaîne

import scala.annotation.{StaticAnnotation, compileTimeOnly}
import scala.language.experimental.macros
import scala.reflect.macros.blackbox

@compileTimeOnly("Compile-time only annotation")
class mymacro(typeName: String) extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro mymacro.impl
}

object mymacro {
  def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
    import c.universe._
    val typeName = TypeName(c.prefix.tree match {
      case q"new mymacro(${str: String})" => str
    })

    println(typeName)

    q"..$annottees"
  }
}

Usage:

trait SomeTrait

@mymacro("SomeTrait")
class Test 

// scalac: SomeTrait

Obtenir des paramètres à partir de l'annotation de macro Scala

Si vous préférez l'approche d'objet compagnon proposée par @user dans les commentaires alors vous pouvez faire

import scala.annotation.{StaticAnnotation, compileTimeOnly}
import scala.language.experimental.macros
import scala.reflect.macros.blackbox

@compileTimeOnly("Compile-time only annotation")
class mymacro(companionObject: Any) extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro mymacro.impl
}

object mymacro {
  def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
    import c.universe._

    val companionTrait = c.typecheck(c.prefix.tree) match {
      case q"new mymacro($arg)" => arg.symbol.companion
    }

    println(companionTrait)

    q"..$annottees"
  }
}

Usage:

trait SomeTrait
object SomeTrait

@mymacro(SomeTrait)
class Test

//scalac: trait SomeTrait
3
Dmytro Mitin 30 oct. 2020 à 01:10