Scala macro that returns a ClassTag of an abstract type and an abstract type-dependent path
I am trying to write a macro that generates abstract type class tags.
I summarized the code provided at StackOverflow question / 2231708 / ... :
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]]]
}
}
Testing with a type class whose abstract type is independent of the path:
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]]
}
}
The above compiled code and test are successful. The macro works as expected when the abstract type is path independent.
Now, consider a type class trying to call this macro with a path dependent abstract type:
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]]
}
}
The code doesn't even compile. I get:
[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
How can I change the implementation of the macro to support this use case as well?
I think this will require some kind of recursion, but I'm still new to scala macros and I don't know how to use recursion with macros.
Is there a library out there that supports this out of the box?
source to share
No one has answered this question yet
See similar questions:
or similar: