4

I would like to use a macro that uses a type defined by the "type" keyword. How do I reference it?

My starting code is

import scala.reflect.macros.Context
import scala.language.experimental.macros

trait Demo6 {
  type T

  def add(param: Any): T = macro Demo6.addImpl[T]

  def fullAdd(param: Any, toStringBasedOnAST: String): T = {
    doesSomeThing_and_returnsSomething_OfTypeT
  }
  def doesSomeThing_and_returnsSomething_OfTypeT: T //just to allow compilation
}

object Demo6 {
  def addImpl[T: c.WeakTypeTag](c: Context)(param: c.Expr[Any]): c.Expr[T] = {
    import c.universe._
    reify { (c.Expr[Demo6](c.prefix.tree)).splice.fullAdd(param.splice, 
                                        c.literal(show(param.tree)).splice) }
    //        ^ - type mismatch; found : org.autotdd.scalamacros.Demo6#T 
    //                           required: T
  }
}

I have marked up the compiler error in the example. It's pretty clear what is happening: the type T defined by keyword isn't the same as the type T that I am passing in.

Things I've tried There isn't a lot of documentation yet on scala-macros. The section in http://docs.scala-lang.org/overviews/macros/overview.html was very helpful in getting me this far, but its example uses a class level and a method level generic. I've browsed the code for Expecty and macrocosm, which are projects referenced in the documentation, but couldn't find code like this.

1
  • Do you need to use the type tag for T? If not, you don't even need the T parameter for addImpl—you should be able to use Typed and TypeName("T"). Commented May 8, 2013 at 11:59

1 Answer 1

4

Your code is almost correct, just change type parameter of Expr:

val expr = reify { ... }
c.Expr[T](expr.tree)

Without reify you should return this:

c.Expr[T](Apply(Select(c.prefix.tree, newTermName("fullAdd")),
                List(param.tree, Literal(Constant(show(param.tree))))))

reify creates the same, but with wrong type parameter.

See this answer for showRaw usage.

In this case:

scala> import reflect.runtime.universe._
import reflect.runtime.universe._

scala> {
     |   object Demo { def fullAdd(param1: Any, param2: String): String = "result" }
     |   showRaw{ reify { Demo.fullAdd("param1", "param2") } }
     | }
res0: String = Expr(Apply(Select(Ident(newTermName("Demo")), newTermName("fullAdd")), List(Literal(Constant("param1")), Literal(Constant("param2")))))

Replace Ident(newTermName("Demo")) with c.prefix.tree, Literal(Constant("param1")) with param.tree and "param2" with show(param.tree) and you'll get your result.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you: really worked well. I'm struggling with understanding how you worked that out. Can you suggest any code to look at that would help me here?
That is a really nice link thank you. I can see me spending a few hours reading it :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.