Scala宏返回抽象类型的ClassTag和抽象路径依赖类型

时间:2015-06-05 02:02:29

标签: scala scala-macros

我一直在尝试编写一个生成抽象类型的类标记的宏。

我概括了https://stackoverflow.com/a/19502658/2859613中提供的代码:

object Macro {
  import scala.reflect.ClassTag
  import scala.reflect.macros.blackbox

  def typeClassTag[A: c.WeakTypeTag]
    (c: blackbox.Context): c.Expr[ClassTag[A]] = {
    import c.universe._

    val A = c.prefix.tree.tpe.member(weakTypeOf[A].typeSymbol.name).typeSignature

    c.Expr(q"implicitly[ClassTag[$A]]").asInstanceOf[c.Expr[ClassTag[A]]]
  }
}

使用类型类进行测试,抽象类型与路径无关:

import scala.language.experimental.macros
import scala.reflect.ClassTag
import Macro._

trait GatewayService {
  type Request
  type Response

  def requestTag : ClassTag[Request]  = macro typeClassTag[Request]
  def responseTag: ClassTag[Response] = macro typeClassTag[Response]
}

trait TransferRequest
trait TransferResponse

trait TransferService extends GatewayService {
  type Request  = TransferRequest
  type Response = TransferResponse
}

class TransferServiceImpl extends TransferService

"TransferServiceImpl  requestTag and responseTag" should {
  "equal ClassTag[TransferRequest] and ClassTag[TransferResponse] respectively" in {
    val transferService = new TransferServiceImpl

    transferService.requestTag  shouldEqual implicitly[ClassTag[TransferRequest]]
    transferService.responseTag shouldEqual implicitly[ClassTag[TransferResponse]]
  }
}

上面的代码编译并且测试成功。当抽象类型不依赖于路径时,宏将按预期工作。

现在看看这个类型类尝试使用与路径相关的抽象类型调用此宏:

import scala.language.experimental.macros
import scala.reflect.ClassTag
import Macro._

trait GatewayFrontend {
  type Service <: GatewayService  // GatewayService was defined in the code above

  def requestTag : ClassTag[Service#Request]  = macro typeClassTag[Service#Request]
  def responseTag: ClassTag[Service#Response] = macro typeClassTag[Service#Response]
}

trait TransferFrontend extends GatewayFrontend {
  type Service = TransferService  // TransferService was defined in the code above
}

class TransferFrontendImpl extends TransferFrontend

"TransferFrontendImpl requestTag and responseTag" should {
  "equal ClassTag[TransferRequest] and ClassTag[TransferResponse] respectively" in {
    val transferFrontend = new TransferFrontendImpl

    transferFrontend.requestTag  shouldEqual implicitly[ClassTag[TransferRequest]]
    transferFrontend.responseTag shouldEqual implicitly[ClassTag[TransferResponse]]
  }
}

代码甚至没有编译。我明白了:

[error] No ClassTag available for <notype>
[error]       transferFrontend.requestTag  shouldEqual implicitly[ClassTag[TransferRequest]]
[error]                        ^
[error]
[error] No ClassTag available for <notype>
[error]       transferFrontend.responseTag shouldEqual implicitly[ClassTag[TransferResponse]]
[error]                        ^
[error]
[error] two errors found
[error] (macro-utils/test:compileIncremental) Compilation failed

如何更改宏实现以支持此用例?

我认为这需要某种递归,但我仍然是一个scala宏新手,我对如何使用宏的递归没有任何线索。

那里有没有支持开箱即用的图书馆?

0 个答案:

没有答案