Closed
Description
Current macro system exposes symbol.tree
to get the tree of a symbol. However, its usage in macros easily leads to CyclicReference
exception.
minimized code
Macro_1.scala
:
import scala.quoted._
import scala.tasty._
inline def debug: Unit = ${debugImpl}
def debugImpl given (qctx: QuoteContext): Expr[Unit] = {
import qctx.tasty._
def nearestEnclosingDef(owner: Symbol): Symbol =
owner match {
case IsDefDefSymbol(x) => x
case IsClassDefSymbol(x) => x
case _ => nearestEnclosingDef(owner.owner)
}
nearestEnclosingDef(rootContext.owner) match {
case IsDefDefSymbol(x) =>
val code = x.tree.show
'{ println(${code.toExpr}) }
case _ =>
'{()}
}
}
}
Test_2.scala
:
object Test {
def main(args: Array[String]): Unit = {
bar("world", 100, true)
}
def bar(a1: String, a2: Long, a3: Boolean) = { // works fine with explicit return type
debug
}
}
expectation
The code above leads to CyclicReference
exception:
stack trace
-- Error: Test_2.scala:7:4 --------------------------------------------------------------------- 7 | debug | ^^^^^ |Exception occurred while executing macro expansion. |dotty.tools.dotc.core.CyclicReference: | at dotty.tools.dotc.core.CyclicReference$.apply(TypeErrors.scala:157) | at dotty.tools.dotc.core.SymDenotations$SymDenotation.completeFrom(SymDenotations.scala:249) | at dotty.tools.dotc.core.Denotations$Denotation.completeInfo$1(Denotations.scala:180) | at dotty.tools.dotc.core.Denotations$Denotation.info(Denotations.scala:182) | at dotty.tools.dotc.ast.tpd$.polyDefDef(tpd.scala:224) | at dotty.tools.dotc.ast.tpd$.DefDef(tpd.scala:221) | at dotty.tools.dotc.ast.tpd$.DefDef(tpd.scala:218) | at dotty.tools.dotc.tastyreflect.FromSymbol$.defDefFromSym(FromSymbol.scala:46) | at dotty.tools.dotc.tastyreflect.ReflectionCompilerInterface.DefDefSymbol_tree(ReflectionCompilerInterface.scala:1644) | at dotty.tools.dotc.tastyreflect.ReflectionCompilerInterface.DefDefSymbol_tree(ReflectionCompilerInterface.scala:1643) | at scala.tasty.reflect.SymbolOps$DefDefSymbolAPI.tree(SymbolOps.scala:217) | at Macros$.debugImpl(Macro_1.scala:24) | | This location is in code that was inlined at Test_2.scala:7
To avoid such crashes with symbol.tree
, we may either:
- remove
symbol.tree
in the API (scala2 macros doesn't have such an API) - only expose the API in black-box macros, and make black-box macros expand in a later phase