How to call the constructor of an inner class in a Scala 3 macro?

39 Views Asked by At

I'm trying to use a macro to save the code used to create a function for pretty-printing. Except the function is used in the constructor of an inner class. I had this working when the class was external, but I can't figure out how to make it work for an inner class.

Here's some (simplified) example code:

class Outer[X](stuff: X):
  def makeInner[Y, Z](l: List[Y], f: Y => Z): Inner[Y, Z] = 
    makeInnerMacro(this, l, f).asInstanceOf[Inner[Y, Z]]

  case class Inner[Y, Z](l: List[Y], f: Y => Z, code: String)

object MyOuter extends Outer("abc"):
  val inner: Inner[Int, String] = makeInner(List(0, 1, 2), num => num.toString)

In an ideal world, inner would be Inner(List(0, 1, 2), <func>, "num => num.toString") and I would do a happy dance. But here's an attempt with a macro:

inline def makeInnerMacro[X, Y, Z](
  inline outer: Outer[X],
  inline l: List[Y],
  inline f: Y => Z,
): Outer[X]#Inner[Y, Z] = ${ makeInnerImpl('{outer}, '{l}, '{f}) }

def makeInnerImpl[X: Type, Y: Type, Z: Type](
  outer: Expr[Outer[X]],
  l: Expr[List[Y]],
  f: Expr[Y => Z],
)(using qCtx: Quotes): Expr[Outer[X]#Inner[Y, Z]] =
  import qCtx.reflect.*
  val fString: Expr[String] = Expr(f.toString)
  '{ $outer.Inner($l, $f, $fString) }

Unfortunately, I get an error when I try to compile:

scalac: Error: stale symbol; class Inner#4362 in class Outer, 
  defined in Period(1..7, run = 2), is referred to in run Period(2..2, run = 3)
dotty.tools.dotc.core.Denotations$StaleSymbol: stale symbol; 
  class Inner#4362 in class Outer, defined in Period(1..7, run = 2), is 
  referred to in run Period(2..2, run = 3)

Is there a way around this?

0

There are 0 best solutions below