4

How do I get the ("current") type of a macro annottee?

import scala.annotation.StaticAnnotation
import scala.reflect.macros._
import language.experimental.macros

class myself extends StaticAnnotation {
  def macroTransform(annottees: Any*) = macro myselfMacro.impl
}
object myselfMacro {
  def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    import c.universe._
    val a = annottees.head
    println(s"static type = ${a.staticType}")
    println(s"actual type = ${a.actualType}")
    c.Expr[Any](Literal(Constant()))
  }
}

Test:

@myself class Foo

Output:

static type = Nothing
actual type = null

The reason I want that type is that I want to use it as a type parameter, e.g. Bar[Foo]


Edit:

Ok, so I think the correct approach is like this:

def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
  import c.universe._
  val v    = annottees.head.asInstanceOf[ClassDef]
  val tpe  = v.tpe // <- tpe is null as the annotated type is not yet type checked!
  val tpe2 = if (tpe == null)
    c.typeCheck(v).tpe // <- fails with a compiler error (assertion failure)
  else
    tpe
  println(s"Type of annottee: $tpe2")
  ???
}

But given this post by Eugene Burmako, it looks like it is currently not possible...

0__
  • 66,707
  • 21
  • 171
  • 266
  • I thought macro annotations were not happening in 2.11.x. Has that changed? – wheaties Jan 10 '14 at 13:59
  • 1
    They have already happened in both 2.10 and 2.11 via the macro paradise plugin. If we're talking about being included in the standard distribution, then neither vanilla 2.10, nor vanilla 2.11 are going to have them. – Eugene Burmako Jan 10 '14 at 15:06
  • Could you elaborate on the use case? The thing is that when the macro annotation is being expanded, the annottee doesn't have a symbol created for it yet (sometimes it does, but it's not at given). As a result, it cannot be referenced by a symbol/type, only by a tree. Sure, the result of c.typecheck will give you some symbol/type, but it would be usable only for introspection purposes, not as a point of reference. – Eugene Burmako Jan 10 '14 at 15:12
  • @EugeneBurmako Thanks for taking time. The use case is [this question](http://stackoverflow.com/questions/21032869/create-or-extend-a-companion-object-using-a-macro-annotation-on-the-class); i.e., given `@mkCompanion class Foo`, I want to synthesise a companion `object Foo { implicit def serializer: Serializer[Foo] = ... }`, so I need the type of `Foo` to define the `serializer` method. – 0__ Jan 10 '14 at 15:15
  • The problem then is `"type arguments [] do not conform to trait Serializer's type parameter bounds [A]"` – 0__ Jan 10 '14 at 15:33
  • Would it work for you to just write `Ident(TypeName("Foo"))`? – Eugene Burmako Jan 10 '14 at 16:53
  • At least that lets me compile `@mkCompanion class Foo; implicitly[Serializer[Foo]]`, so it's an improvement. I can't say at the moment whether there will be subsequent problems, for example if a serializer for type `A` depends on an implicitly found serializer for type `B`. But if this is the only way to get the "type" right now, I will accept this as an answer. – 0__ Jan 10 '14 at 16:58
  • Everything should be fine as long you don't run into situations that I've outlined in my answer. – Eugene Burmako Jan 10 '14 at 18:24

1 Answers1

4

When the macro annotation is being expanded, the annottee doesn't have a symbol created for it yet (sometimes it does, but it's not at given). As a result, it cannot be referenced by a symbol/type, only by a tree, e.g. Ident(TypeName("Foo")). Sure, the result of c.typecheck will give you some symbol/type, but it would be usable only for introspection purposes, not as a point of reference.

This approach should work just fine if you steer clear from hygiene problems. If your companion object defines a class/type member called Foo, then Foo in Serializer[Foo] is going to bind to companion's member, not to the original class. At the moment there's no good way of dealing with that (scalac itself has to solve this problem when generating apply/unapplymethods for case classes, but you don't want to know how it's done). We're planning to provide a solution for this, but we'll only start working on it in the next month, so it'll be a while until it lands in trunk or even paradise.

Eugene Burmako
  • 13,028
  • 1
  • 46
  • 59
  • 1
    "but you don't want to know how it's done" ... but we do. Still can't find any way to typecheck a moduleDef or classDef passed into a macro annotation. – Jeffrey Aguilera Jan 26 '16 at 06:20