Макрос Tasty Reflection в Scala 3: CyclicReference

Я пытаюсь получить доступ к параметрам метода, который реализуется как макрос.

      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 _ =>
                        nearestEnclosingMethod(owner.owner)
                }
            nearestEnclosingMethodParams(Symbol.spliceOwner)
        }
        println(params) // I would do something useful with params names and types here
        '{()}
    }
}

Сайт для звонков может выглядеть примерно так:

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

На данный момент я получаю CyclicReferenceошибка при расширении макроса на. Я это понимаю defSym.treeявляется циклическим, потому что он включает в себя код текущего раскрывающегося макроса, но мне все еще нужно получить доступ к «древовидной» версии определения метода, чтобы получить доступ к его имени и параметрам без тела метода. Как я могу получить эту информацию без езды на велосипеде?

1 ответ

Решение

Эта проблема была исправлена ​​в недавно выпущенной версии Scala 3.0.0-RC1.

с помощью defSym.tree в def foo(a: String, b: Int) = Foo.impl пример теперь работает нормально и просто использует EmptyTreeдля тела макроса. Вы можете легко извлечь любую необходимую информацию из аргумента метода или иерархии типов, где foo определено, что было моим вариантом использования.

      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 <root>)),object scala),class Int)],
                EmptyTree
            )
        )
    ),
    TypeTree[TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Unit)],
    EmptyTree
)
Другие вопросы по тегам