我使用隐式宏来生成类型类。
trait ColumnType[+A]
object ColumnType {
implicit def materializeColumnType[A <: Product]: ColumnType[A] = macro MappedColumnTypeMacro.materializeColumnType[A]
}
case class MappedColumnTypeMacro(c: Context) {
import c.universe._
def materializeColumnType[A: c.WeakTypeTag]: c.Tree = {
val typeOfA = c.weakTypeOf[A]
val companion = typeOfA.typeSymbol.companion
val applyMethod = findMethod(companion.typeSignature, "apply", typeOfA)
val unapplyMethod = findMethod(companion.typeSignature, "unapply", typeOfA)
val typeOfB = applyMethod.paramLists.head.head.asTerm.typeSignature
q"MappedColumnType[$typeOfA, $typeOfB]($companion.$applyMethod, $companion.$unapplyMethod(_).get)"
}
def findMethod(companionType: Type, name: String, typeOfA: Type) = {
companionType.member(TermName(name)) match {
case method: MethodSymbol if method.paramLists.flatten.length == 1 => method
case _ => c.abort(c.enclosingPosition, s"No matching $name method found on $typeOfA")
}
}
}
def column[A](name: String)(implicit columnType: ColumnType[A]) =
TableColumn[A](tableAlias, name)(columnType)
case class WrappedInt(int: Int)
// This fails
val myColumn = column[WrappedInt]("mycolumn")
失败的原因是因为typeOfA
未被解析为WrappedInt
。使用whitebox上下文时,此问题已解决为A
,使用黑盒子上下文时,此问题将解析为Nothing
我做错了什么或有解决方法吗?
答案 0 :(得分:1)
问题在于方差注释 - scalac认为ColumnType[Nothing]
是最具体的隐式候选者,所以它会在A
中推断materializeColumnType
到{{ 1}}无论在Nothing
的调用中提供了什么A
。
在我们的flatMap 2014宏观研讨会上,我们将解释如何解决这个问题:https://github.com/scalamacros/macrology201/commit/78779cc7f565dde003fe0da9e5357821b009917b。