Search code examples
scalascala-macrosscala-3

How can I convert an Expr to a Tree in Scala 3?


I need to convert an Expr to a Tree doing Scala 3 macro development, and I did not yet find an appropriate conversion mechanism for that.

In Scala 2 there existed a tree method on Expr which made this task easy as I see, like this:

def expr_impl(c: blackbox.Context)(expr: c.Expr[AnyRef]): c.Expr[Expression] = {
    import c.universe._
    expr.tree match {
      //...
    }
}

But this method seems to be removed in Scala 3.

I need this to examine the results of using a Quotes expression. If I use showRaw, the output is not verbose, which is a problem is my case:

import scala.quoted.*
import scala.reflect.runtime.universe.showRaw
import quotes.reflect.*

//...

val obj: Expr[_] = '{object AnObject}
report.error(s"from macro annotation1 ${showRaw(obj)}")

This results in a non-verbose output like this: from macro annotation1 '{ ... }

Also tried Printer.TreeStructure.show, which expects a Tree instead of Expr, and that's why I need the mentioned conversion, as Printer.TreeStructure.show would result in a verbose output.

If there is any method that is verbose and similar to Printer.TreeStructure.show and expects an Expr as an argument, that would also solve my problem.


Solution

  • I wouldn't say .tree was removed - Scala 3's Quotes should be consider completely new implementation which can have some counterparts to Scala 2's Contexts content but not always and even when it has, it might be named differently.

    To turn Expr[A] into quotes.reflect.Tree you should call .asTerm on it - Term is a subtype of Tree.

    And to print AST in raw form rather than a pretty print, one can provide (using Printer.TreeStructure) to the show extension method (available when you convert Expr to Term and import things from Quotes):

    inline def printExpr[A](a: A): Unit = ${ printExprImpl[A]('{ a }) }
    
    def printExprImpl[A: Type](expr: Expr[A])(using quotes: Quotes): Expr[Unit] = {
      import quotes.*, quotes.reflect.*
      report.info(expr.asTerm.show(using Printer.TreeStructure))
      '{ () }
    }