Stave Escura
Stave Escura

Reputation: 2098

How do I combine Type Programming with Scala Macros

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.

Upvotes: 4

Views: 408

Answers (1)

senia
senia

Reputation: 38045

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.

Upvotes: 4

Related Questions