The following code snippet is a short scala macro bundle definition from a thoughtworks project:
private[SelfType] final class Macros(val c: whitebox.Context) {
import c.universe._
def apply[A: WeakTypeTag]: Tree = {
val a = weakTypeOf[A]
val selfTypes: List[Type] = {
val selfTypeBuilder = List.newBuilder[Type]
def buildSelfTypes(t: Type): Unit = {
val dealiased = t.dealias
dealiased match {
case RefinedType(superTypes, refinedScope) =>
superTypes.foreach(buildSelfTypes)
case typeRef: TypeRef =>
val symbol = dealiased.typeSymbol
if (symbol.isClass) {
selfTypeBuilder += symbol.asClass.selfType.asSeenFrom(dealiased, symbol)
}
case _ =>
}
}
buildSelfTypes(a)
selfTypeBuilder.result()
}
val out = selfTypes match {
case Nil =>
definitions.AnyTpe
case _ =>
internal.refinedType(selfTypes, c.internal.enclosingOwner)
}
q"_root_.com.thoughtworks.feature.SelfType.make[$a, $out]"
}
}
The last line as a quasiquote seems to contain a lot of boilerplate text:
q"_root_.com.thoughtworks.feature.SelfType.make[$a, $out]"
Assuming that this macro bundle is defined inside a trait as part of a family polymorphism design pattern: there is no deterministic q"_root_.com.thoughtworks.feature.SelfType.make[$a, $out]"
, it has to be derived from an object variable vvv
of the macro bundle when it is being compiled. How do I use this variable to make the quasiquote shorter and more adaptive?
There may be multiple methods to achieve this (e.g. for each implementation, define a Liftable for SelfType
object). But that's even more boilerplate. I'm looking for the shortest solution. Ideally, something like this:
val sym = Term(vvv)
q"$sym.make[$a, $out]"
If you have a static reference (e.g. the type/companion is imported), you can do:
q"${symbolOf[SelfType.type]}.make[$a, $out]"
You can also use symbolOf[A].companion
if you have A: WeakTypeTag
but no info about its companion. That might not work if the compiler doesn't consider the object A
a companion to class A