How to implement a Scala 3 macro that adds the inline keyword (aka Flag) to a Def/Val

52 Views Asked by At

I am currently implementing a macro annotation called getInline and I am hitting an issue where specifically for Scala 3 macro annotations I can't seem to write such a macro.

Given we have the following macro annotation

@experimental class getInline extends MacroAnnotation {
  override def transform(using quotes: Quotes)(
      tree: quotes.reflect.Definition
  ): List[quotes.reflect.Definition]

and with the following body where we implement the macro

    tree match {
      case e@ DefDef(name, params, tpt, rhs) =>
        val flagsWithInline = e.symbol.flags | Flags.Inline

        val methodWithInline = Symbol.newMethod(tree.symbol.owner,
                         e.name,
                         e.symbol.typeRef,
                         flagsWithInline,
                         e.symbol.privateWithin.map(_.termSymbol).getOrElse(Symbol.noSymbol)
        )

        ???
      case e: ValDef =>
        val flagsWithInline = e.symbol.flags | Flags.Inline

        val valWithInline = Symbol.newVal(tree.symbol.owner,
                      e.name,
                      e.symbol.typeRef,
                      flagsWithInline,
                      e.symbol.privateWithin.map(_.termSymbol).getOrElse(Symbol.noSymbol)
        )

        ???
    }
  }

The core problem I have is how to return a new AST tree (in place of ???) with the methodWithInline and valWithInline respectively. Assuming we have the following code that calls the macro annotation

@getInline final def myVal = 5

The tree returned by methodWithInline using the .show method is

inline final def myVal: org.mdedetrich.Test.myVal = 5

Which is exactly what we want. The problem is that if we return methodWithInline as is using List(DefDef(methodWithInline, _ => e.rhs)) as the implementation of the macro annotation then the following error message appears

[error]   |Transformed tree for @getInline final def myVal: Int = 5 was not return by `(new org.mdedetrich.getinline.getInline()).transform(..)` during macro expansion

It appears that the proper way to do this is to use DefDef.copy on the current tree (which in our case is represented by the value e). The problem here is that DefDef.copy does not appear to accept an altered list of Flags (represented by the flagsWithInline variable).

0

There are 0 best solutions below