Search code examples
scalametaprogrammingscala-macros

Extract ClassSymbols for method's parameter bounds


I'm trying to extract ClassSymbols 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?


Solution

  • 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