2

I've defined a simple generic macro:

object MyMacro {

  def readWrite[T](readParse: String => T, label: String, format: T => String): Unit = macro readWriteImpl[T]

  def readWriteImpl[T: c.WeakTypeTag](c: Context)(readParse: c.Expr[String => T], label: c.Expr[String], format: c.Expr[T => String]): c.Tree = {
    import c.universe._

    q"""
    def read[WIRE](path: Path, reader: Transceiver[WIRE], isMapKey: Boolean = false): T =
      reader.readString(path) match {
        case null => null.asInstanceOf[T]
        case s => Try( $readParse(s) ) match {
          case Success(d) => d
          case Failure(u) => throw new ReadMalformedError(path, "Failed to parse "+$label+" from input '"+s+"'", List.empty[String], u)
        }
      }

    def write[WIRE](t: T, writer: Transceiver[WIRE], out: Builder[Any, WIRE]): Unit =
      t match {
        case null => writer.writeNull(out)
        case _    => writer.writeString($format(t), out)
      }
      """
  }
}

In a separate compilation unit I use it like this:

object DurationTypeAdapterFactory extends TypeAdapter.=:=[Duration] {
  MyMacro.readWrite[Duration]((s: String) => Duration.parse(s), "Duration", (t: Duration) => t.toString)
}

When built, the compiler complains it doesn't know about T:

[error] /Users/me/git/ScalaJack/core/src/main/scala/co.blocke.scalajack/typeadapter/TimePrimitives.scala:13:30: not found: type T
[error]   MyMacro.readWrite[Duration]((s: String) => Duration.parse(s), "Duration", (t: Duration) => t.toString)
[error] 

It doesn't like the 'T' references in my quasiquote, which I kinda understand. How can I represent the T paraeter passed into readWriteImpl inside the quasiquote so that it unpacks properly?

1 Answer 1

2

Use the tag to inspect the type or compare it to other types using =:=, or use it in the expansion.

For example,

scala 2.13.0-M5> def fImpl[A: c.WeakTypeTag](c: Context)(a: c.Expr[A]) = { import c._, universe._
               | q"null.asInstanceOf[${implicitly[c.WeakTypeTag[A]].tpe}]" }
fImpl: [A](c: scala.reflect.macros.blackbox.Context)(a: c.Expr[A])(implicit evidence$1: c.WeakTypeTag[A])c.universe.Tree

scala 2.13.0-M5> import language.experimental.macros ; def f[A](a: A): A = macro fImpl[A]
import language.experimental.macros
defined term macro f: [A](a: A)A

scala 2.13.0-M5> f(42)
res2: Int = 0

scala 2.13.0-M5> f("")
res3: String = null
Sign up to request clarification or add additional context in comments.

2 Comments

This got me past this point of being stuck.... but opened a new macro problem I'll post as a new question.
Instead of macros, they should have called them stuckos.

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.