I'm trying to extract ClassSymbol
s for all type parameters' bounds of a method.
The "solution" I came up with:
Macro annotation implementation:
@compileTimeOnly("Compile-time only annotation")
class classSyms extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro impl
}
object classSyms {
def impl(c: whitebox.Context)(annottees: c.Tree*) = {
import c.universe._
annottees.toList foreach {
case q"$mods def $templatename[..$typeparams](...$paramss): $tpt = $body" =>
typeparams foreach {
case q"$mods type $name[..$tparams] >: $low <: $high" =>
if (!high.isEmpty) {
//requires FQCN, does not work with imported names
val classSymbol = c.mirror.staticClass(high.toString)
println(classSymbol)
}
}
}
q"..$annottees"
}
}
Example:
package pack.age
trait Test
package another.pack.age
import pack.age._
trait Bar{
@classSyms
def foo[M <: pack.age.Test, T](): Unit //works ok
@classSyms
def baz[M <: Test, T](): Unit //throws scala.ScalaReflectionException: class Test not found.
}
The problem is such requirements of specifying fully-qualified class name as a parameter bound does not make this macro implementation very useful (no one wants to write this long fqcn stuff, especially if the name is imported).
Is it possible to extract ClassSymbol
by an imported name?
Try to use c.typecheck
.
Replace
val classSymbol = c.mirror.staticClass(high.toString)
with
val classSymbol = c.typecheck(tq"$high", mode = c.TYPEmode).symbol.asClass