【问题标题】:Compilation error in Scala macro for generic type泛型类型的 Scala 宏中的编译错误
【发布时间】:2016-12-30 03:27:09
【问题描述】:

我正在尝试编写一个宏,在需要时隐式实现 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]
}

这适用于非参数化类型(例如。

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

)。

它也适用于集合

val xx = materializeFormat[Seq[Apple]]

但是,当我尝试将它用于我自己的参数化类型时,它会丢失类型参数的值:

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

回应

[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]

这是有道理的,因为 WeakTypeTag 不知道 T。我的第一个问题是为什么这在 Seq 中可以正常工作??

但是,我想出了一个我认为应该是可行的解决方法:

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

materializeProxyImpl的实现在哪里

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

materializeFormatImpl 中的println 现在正确显示参数类型 t 的实际值:

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

但之后我仍然收到同样的错误:

[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]

我尝试将materializeProxymaterializeProxyImpl 上的类型注释分别更改为AnyTree,但是仍然出现语法错误,这表明类型不匹配发生在宏引擎。

我做错了吗?或者这是宏引擎中的错误?

【问题讨论】:

  • 嗯,我认为它对 Seq 正常工作的事实是一个线索。 JsMacroImpl 代码具有 Seq 参数的显式助手。我怀疑发生错误是因为播放宏忽略了我的类型参数。
  • 这是一个已知限制,现已修复:github.com/playframework/playframework/pull/5384

标签: scala generics macros


【解决方案1】:

看来 play json 宏实现并没有期望通用案例类。它正在输出

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

我修改了播放宏以便它输出

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

现在它按预期工作了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-30
    • 2021-09-21
    • 2016-05-06
    • 1970-01-01
    • 2020-01-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多