简体   繁体   English

Scala宏中泛型类型的编译错误

[英]Compilation error in Scala macro for generic type

I am trying to write a macro that implicitly materializes Play Formatter instances when they are required: 我正在尝试编写一个在需要时隐式实现Play Formatter实例的宏:

class FormattableImpl(override val c: whitebox.Context) extends Utils(c) {
    import c.universe._

    def materializeFormatImpl[T : c.WeakTypeTag]: c.Expr[play.api.libs.json.Format[T]] = {
        val tpe = implicitly[c.WeakTypeTag[T]].tpe
        val x = c.Expr[play.api.libs.json.Format[T]](q" com.ubookr.macros.Json.format[$tpe] ")
        println(show(x))
        x
    }
}

object Format {
    implicit def materializeFormat[T]: play.api.libs.json.Format[T] = macro FormattableImpl.materializeFormatImpl[T]
}

This works just fine for non-parameterized types (eg. 对于非参数类型(例如,

case class Apple(id: Long, name: String)
val x = materializeFormat[Apple]

). )。

It also works for collections 它也适用于收藏

val xx = materializeFormat[Seq[Apple]]

When I try to use it for my own parameterized type, however, it loses the value of the type parameter: 但是,当我尝试将其用于自己的参数化类型时,它将丢失类型参数的值:

case class Proxy[+T](id: Long, name: String)
val xxx = materializeFormat[Proxy[Apple]]

which responds with 回应

[error] package.scala:112: type mismatch;
[error]  found   : play.api.libs.json.OFormat[com.ubookr.macros.Proxy[Nothing]]
[error]  required: play.api.libs.json.Format[com.ubookr.macros.Proxy[Apple]]
[error] Note: com.ubookr.macros.Proxy[Nothing] <: com.ubookr.macros.Proxy[Apple], but trait Format is invariant in type A.
[error] You may wish to define A as +A instead. (SLS 4.5)
[error]     val xxx: Any = com.ubookr.macros.Format.materializeFormat[Proxy[Apple]]
[error]

This makes sense because WeakTypeTag doesn't know about T. My first question is why does this work correctly with Seq?? 这是有道理的,因为WeakTypeTag不了解T。我的第一个问题是, 为什么Seq可以正确使用?

However, I came up with what I think should be a feasible workaround: 但是,我提出了我认为应该可行的解决方法:

def materializeProxy[T]: play.api.libs.json.Format[Proxy[T] = macro FormattableImpl.materializeProxyImpl[T]

where the implementation of materializeProxyImpl is materializeProxyImpl的实现在哪里

def materializeProxyImpl[T : c.WeakTypeTag]: c.Expr[play.api.libs.json.Format[Proxy[T]]] = materializeFormatImpl[Proxy[T]]

the println in materializeFormatImpl now correctly shows the actual value of parameter type t: 现在, materializeFormatImplprintln可以正确显示参数类型t的实际值:

Expr[play.api.libs.json.Format[com.ubookr.macros.Proxy[Apple]]](com.ubookr.macros.Json.format[com.ubookr.macros.Proxy[Apple]])

but I am still getting the same error immediately after: 但在之后我仍然立即收到相同的错误:

[error] package.scala:112: type mismatch;
[error]  found   : play.api.libs.json.OFormat[com.ubookr.macros.Proxy[Nothing]]
[error]  required: play.api.libs.json.Format[com.ubookr.macros.Proxy[Apple]]
[error] Note: com.ubookr.macros.Proxy[Nothing] <: com.ubookr.macros.Proxy[Apple], but trait Format is invariant in type A.
[error] You may wish to define A as +A instead. (SLS 4.5)
[error]     val xxx: Any = Format.materializeProxy[Apple]
[error]

I have tried changing the type annotation on both materializeProxy and materializeProxyImpl to Any and Tree respectively, but the syntax error still occurs, which suggests to me that the type mismatch is happening somewhere internal to the macro engine. 我尝试将materializeProxymaterializeProxyImpl的类型批注分别更改为AnyTree ,但是语法错误仍然出现,这向我暗示在宏引擎内部某个地方发生类型不匹配。

Am I doing something wrong? 难道我做错了什么? Or is this a bug in the macro engine? 还是这是宏引擎中的错误?

It seems that the play json macro implementation didn't expect generic case classes. 似乎play json宏实现不希望使用通用案例类。 It was outputting 它正在输出

(
     (JsPath \ "id").format[Long] and
     (JsPath \ "name").format[String]
)(Proxy.apply, unlift(Proxy.unapply)

I amended the play macro so that it outputs 我修改了play宏,使其输出

(
     (JsPath \ "id").format[Long] and
     (JsPath \ "name").format[String]
)(Proxy.apply[Apple], unlift(Proxy.unapply[Apple])

and now it works as expected. 现在它可以正常工作了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM