Current Quotes
API is not perfect. To add annotation try compiler internals
extension (symb: Symbol)
def addAnnotation(annotation: Term): Symbol =
// libraryDependencies += scalaOrganization.value %% "scala3-compiler" % scalaVersion.value
given dotty.tools.dotc.core.Contexts.Context =
quotes.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx
symb.asInstanceOf[dotty.tools.dotc.core.Symbols.Symbol]
.denot
.addAnnotation(
dotty.tools.dotc.core.Annotations.ConcreteAnnotation(
annotation.asInstanceOf[dotty.tools.dotc.ast.tpd.Tree]
)
)
symb
Symbol.newMethod(...)
.addAnnotation('{new scala.annotation.targetName("foo")}.asTerm)
For example
import scala.annotation.experimental
import scala.quoted.*
inline def newClass[A]: A = ${newClassImpl[A]}
@experimental
def newClassImpl[A: Type](using Quotes): Expr[A] =
import quotes.reflect.*
extension (symb: Symbol)
def addAnnotation(annotation: Term): Symbol = ...
val name: String = TypeRepr.of[A].typeSymbol.name + "Impl"
val parents = List(TypeTree.of[A])
def decls(cls: Symbol): List[Symbol] =
List(
Symbol.newMethod(cls, "func", MethodType(List("s"))(_ => List(TypeRepr.of[String]), _ => TypeRepr.of[String]), Flags.Override, Symbol.noSymbol)
.addAnnotation('{new scala.annotation.targetName("foo")}.asTerm)
)
val cls = Symbol.newClass(Symbol.spliceOwner, name, parents = parents.map(_.tpe), decls, selfType = None)
val funcSym = cls.declaredMethod("func").head
val funcDef = DefDef(funcSym, argss => Some('{ "override" }.asTerm))
val clsDef = ClassDef(cls, parents, body = List(funcDef))
val newCls = Typed(Apply(Select(New(TypeIdent(cls)), cls.primaryConstructor), Nil), TypeTree.of[A])
Block(List(clsDef), newCls).asExprOf[A]
class TestClass:
def func(s: String) = "base"
val res: TestClass = newClass[TestClass]
// scalacOptions += "-Xprint:pickleQuotes"
// {
// class TestClassImpl extends TestClass {
// @targetName override def func(s: String): String = "override"
// }
// new TestClassImpl():TestClass
// }:TestClass
Scala 3 macros: create a new polynmorphic function using the reflect api
Method Override with Scala 3 Macros
`tq` equivalent in Scala 3 macros
Scala3: Crafting Types Through Metaprogramming?
Not sure whether this @targetName
works as expected.
Also we can define
extension (symb: Symbol)
def addTargetName(name: String): Symbol =
given dotty.tools.dotc.core.Contexts.Context =
quotes.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx
import dotty.tools.dotc.core.Decorators.toTermName
symb.asInstanceOf[dotty.tools.dotc.core.Symbols.Symbol]
.denot
.setTargetName(name.toTermName)
symb
It's possible that @targetName
is handled before macros are expanded. In such case it's too late to add it with macros.