Scala 3 (Dotty) Pattern dopasowuje funkcję do makra cudzysłowu

Dec 08 2020

Próbuję uzyskać nazwę funkcji za pomocą makr w Scali 3.0.0-M2 Rozwiązanie, które wymyśliłem, wykorzystuje TreeAccumulator

import scala.quoted._

inline def getName[T](inline f: T => Any): String = ${getNameImpl('f)}

def getNameImpl[T](f: Expr[T => Any])(using Quotes): Expr[String] = {
  import quotes.reflect._
  val acc = new TreeAccumulator[String] {
    def foldTree(names: String, tree: Tree)(owner: Symbol): String = tree match {
      case Select(_, name) => name
      case _ => foldOverTree(names, tree)(owner)
    }
  }
  val fieldName = acc.foldTree(null, Term.of(f))(Symbol.spliceOwner)
  Expr(fieldName)
}

Po wywołaniu ten kod tworzy nazwę funkcji:

case class B(field1: String)
println(getName[B](_.field1)) // "field1"

Zastanawiam się, czy można to zrobić w łatwiejszy sposób za pomocą cudzysłowów.

Odpowiedzi

2 DmytroMitin Dec 13 2020 at 14:44

Myślę, że wystarczy zdefiniować

def getNameImpl[T: Type](f: Expr[T => Any])(using Quotes): Expr[String] = {
  import quotes.reflect._
  Expr(TypeTree.of[T].symbol.caseFields.head.name)
}

Właściwie nie używam f.

Testowanie:

println(getName[B](_.field1)) // "field1"

Przetestowano w wersji 3.0.0-M3-bin-20201211-dbc1186-NIGHTLY.

Jak uzyskać dostęp do listy parametrów klasy przypadku w makrze dotty

Alternatywnie możesz spróbować

def getNameImpl[T](f: Expr[T => Any])(using Quotes): Expr[String] = {
  import quotes.reflect._
    
  val fieldName = f.asTerm match {
    case Inlined(
      _,
      List(),
      Block(
        List(DefDef(
          _,
          List(),
          List(List(ValDef(_, _, _))),
          _,
          Some(Select(Ident(_), fn))
        )),
        Closure(_, _)
      )
    ) => fn
  }
    
  Expr(fieldName)
}