Open
Description
Compiler version
3.3.1-RC1-bin-20230425-c9ca7ce-NIGHTLY
Minimized code
//> using scala "3.3.1-RC1-bin-20230425-c9ca7ce-NIGHTLY"
import scala.quoted.*
abstract class Foo:
def test: String
inline def showExpr(inline value: Any): String = ${showExprImpl('value)}
def showExprImpl(expr: Expr[Any])(using Quotes): Expr[String] =
import quotes.reflect.*
Expr(
s"""${expr.asTerm.show}
|
|${expr.asTerm.show(using Printer.TreeStructure)}""".stripMargin)
inline def generateFooOverride: Foo = ${generateFooImpl}
def generateFooImpl(using Quotes): Expr[Foo] =
import quotes.reflect.*
val fooRepr = TypeRepr.of[Foo]
val fooSymbol = fooRepr.dealias.classSymbol.get
val overridingSymbol = Symbol.newClass(Symbol.spliceOwner, Symbol.freshName("Foo"), List(fooRepr), _ => Nil, None)
def newInstance(clazz: Symbol, args: List[Term]): Term = Apply(Select(New(TypeTree.ref(clazz)), clazz.primaryConstructor), args)
val fooTestSymbol = fooSymbol.declaredMethod("test").head
val overridingTestSymbol = fooTestSymbol.overridingSymbol(overridingSymbol)
println(fooTestSymbol.flags.is(Flags.Private).toString) //false as expected
println(fooTestSymbol.isClassConstructor.toString) //false as expected
println(fooTestSymbol.maybeOwner.isClassDef.toString) //true as expected
println(overridingSymbol.isClassDef.toString) //true as expected
println(overridingTestSymbol.isNoSymbol.toString) //true but should be false
def overridingTestDef(term: Term): DefDef =
DefDef( //java.lang.AssertionError: assertion failed: expected a term symbol but received val <none>
overridingTestSymbol,
_ => Some(term)
)
def overridingClassDef(term: Term): ClassDef =
ClassDef(
overridingSymbol,
List(newInstance(fooSymbol, Nil)),
List(overridingTestDef(term))
)
def instance(term: Term): Term =
Block(
List(overridingClassDef(term)),
newInstance(overridingSymbol, Nil)
)
instance(Literal(StringConstant("hello"))).asExprOf[Foo]
In another file call generateFooOverride
Output
overridingTestSymbol
is NoSymbol
causing the DefDef
in overridingTestDef
to throw the following error:
[error] java.lang.AssertionError: assertion failed: expected a term symbol but received val <none>
[error] at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:8)
[error] at scala.quoted.runtime.impl.QuotesImpl$reflect$DefDef$.apply(QuotesImpl.scala:279)
[error] at scala.quoted.runtime.impl.QuotesImpl$reflect$DefDef$.apply(QuotesImpl.scala:278)
[error] at ClassGen$package$.overridingTestDef$1(ClassGen.scala:41)
[error] at ClassGen$package$.overridingClassDef$1(ClassGen.scala:48)
[error] at ClassGen$package$.instance$1(ClassGen.scala:53)
[error] at ClassGen$package$.generateFooImpl(ClassGen.scala:57)
Expectation
I'd expect overridingTestSymbol
to not be NoSymbol
and generate this code:
class Foo$macro$1 extends Foo:
override def test: String = "hello"
new Foo$macro$1
mostly like:
new Foo:
override def test: String = "hello"
Notes
- I use the low-level term API because in my current use case I need to generate this code for a generic type (
T
instead ofFoo
). I'm trying to reproduce this macro. - After diving into the compiler codebase, I checked if my arguments satisfy the criterias needed by
Symbol#overridingSymbol
(see line 34). They all pass.