2 votes

Scala 3 Tasty Reflection Macro: Référence cyclique

Je suis en train d'essayer d'accéder aux paramètres d'une méthode qui est implémentée en tant que macro.

object Macros {
    def impl()(using Quotes): Expr[Unit] = {    
        import quotes.reflect._
        val params: List[List[ValDef]] = {
            def nearestEnclosingMethodParams(owner: Symbol): List[List[ValDef]] =
                owner match {
                    case defSym if defSym.isDefDef =>
                        defSym.tree.asInstanceOf[DefDef].paramss
                    case _ =>
                        nearestEnclosingMethodParams(owner.owner)
                }
            nearestEnclosingMethodParams(Symbol.spliceOwner)
        }
        println(params) // Je ferais quelque chose d'utile avec les noms et les types des paramètres ici
        '{()}
    }
}

Le site d'appel pourrait ressembler à quelque chose comme :

object Test {
    def foo(a: String, b: Int) = Foo.impl
    @main def run(): Unit = {
        val x = foo("blah", 24)
        ()
    }
}

object Foo {
    inline def impl = ${ Macros.impl() }
}

Pour l'instant, j'obtiens une erreur CyclicReference lorsque la macro se développe, sur defSym.tree. Je comprends que defSym.tree est cyclique car il inclut le code de la macro en cours d'expansion, mais j'ai toujours besoin d'accéder à une version "arborescente" de la définition de la méthode pour accéder à son nom et ses paramètres, sans le corps de la méthode. Comment puis-je obtenir cette information sans boucler ?

1voto

francoisr Points 1396

Ce problème a été résolu dans la version récemment publiée de Scala 3.0.0-RC1.

l'utilisation de defSym.tree dans l'exemple def foo(a: String, b: Int) = Foo.impl fonctionne désormais parfaitement et utilise simplement un EmptyTree pour le corps de la macro. Vous pouvez facilement extraire toutes les informations dont vous avez besoin de l'argument de méthode, ou de la hiérarchie des types où foo est défini, ce qui était mon cas d'utilisation.

DefDef(
    foo,
    List(
        List(
            ValDef(
                a,
                TypeTree[TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class scala)),object Predef),type String)],
                EmptyTree
            ), 
            ValDef(
                b,
                TypeTree[TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class )),object scala),class Int)],
                EmptyTree
            )
        )
    ),
    TypeTree[TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Unit)],
    EmptyTree
)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X