通用类型的Scala宏中的编译错误

时间:2016-12-30 03:27:10

标签: scala generics macros

我正在尝试编写一个宏,在需要时隐式实现Play Formatter实例:

 {

  "buildOptions": {
    "emitEntryPoint": true,
    "debugType": "portable",
    "preserveCompilationContext": true
  },
  "dependencies": {
    "Microsoft.AspNetCore.Diagnostics": "1.1.0",
    "Microsoft.AspNetCore.Mvc": "1.1.0",
    "Microsoft.AspNetCore.Mvc.TagHelpers": "1.1.0",
    "Microsoft.AspNetCore.Server.IISIntegration": "1.1.0",
    "Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
    "Microsoft.AspNetCore.StaticFiles": "1.1.0",
    "Microsoft.EntityFrameworkCore": "1.1.0",
    "Microsoft.EntityFrameworkCore.Design": "1.1.0",
    "Microsoft.EntityFrameworkCore.Relational": "1.1.0",
    "Microsoft.EntityFrameworkCore.SqlServer": "1.1.0",
    "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0",
    "Microsoft.Extensions.Configuration.Json": "1.1.0"
  },
  "frameworks": {
    "netcoreapp1.1": {
      "dependencies": {
        "Microsoft.NETCore.App": {
      "type": "platform",
      "version": "1.1.0"
    }
  },
  "imports": [
    "dnxcore50"
      ]
    }
  },
  "publishOptions": {
    "include": [
      "wwwroot",
      "web.config"
    ]
  },
  "runtimeOptions": {
    "gcServer": true
  },
  "scripts": {
    "postpublish": [ "dotnet publish-iis --publish-folder     %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
  }
}

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

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]

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

val xx = materializeFormat[Seq[Apple]]

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

这是有道理的,因为WeakTypeTag不知道T.我的第一个问题是为什么这对Seq工作正常?

然而,我提出了我认为应该是一个可行的解决方法:

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

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]] 中的println现在正确显示参数类型t的实际值:

materializeFormatImpl

但是在我之后我仍然会遇到同样的错误:

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] materializeProxy上的类型注释分别更改为materializeProxyImplAny,但语法错误仍然存​​在,这表明我类型不匹配发生在宏引擎内部的某处。

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

1 个答案:

答案 0 :(得分:0)

似乎播放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])

现在它按预期工作。