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?