Я пишу неявный макрос Scala, который автоматически генерирует класс типа для классов case (с использованием квазиквадрата, как Scala 2.10.3, с плагином компилятора макроса и Scala 2.11.0-M7).
Неявный макрос рекурсивно ищет типы классов для параметра.
Пока класс case не принимает параметры типа или параметры типа не используются в генерируемом коде, он отлично работает.
Но когда требуется неявное значение <TypeClass>[<TypeParameter of case class>]
, компиляция сайта вызова не выполняется с "не удалось найти неявное значение для параметра e".
Вот код, который воспроизводит проблему:
trait TestTypeClass[A] {
def str(x: A): String
}
object Test {
implicit def BooleanTest = new TestTypeClass[Boolean] {
def str(x: Boolean) = x.toString
}
def CaseClassTestImpl[A: c.WeakTypeTag](c: Context): c.Expr[TestTypeClass[A]] = {
import c.universe._
val aType = weakTypeOf[A]
val TestTypeClassType = weakTypeOf[TestTypeClass[_]]
val typeName = aType.typeSymbol.name.decoded
val params = aType.declarations.collectFirst { case m: MethodSymbol if m.isPrimaryConstructor => m }.get.paramss.head
val paramTypes = aType.declarations.collectFirst { case m: MethodSymbol if m.isPrimaryConstructor => m }.get.paramss.head.map(_.typeSignature)
val paramList = for (i <- 0 until params.size) yield {
val param = params(i)
val paramType = paramTypes(i)
val paramName = param.name.decoded
q"str($param)"
}
println(paramList)
val src =
q"""
new TestTypeClass[$aType] {
def str(x: $aType) = Seq(..$paramList).mkString(",")
}
"""
c.Expr[TestTypeClass[A]](src)
}
implicit def CaseClassTest[A]: TestTypeClass[A] = macro CaseClassTestImpl[A]
def str[A: TestTypeClass](x: A) = implicitly[TestTypeClass[A]].str(x)
}
// somewhere in other module
implicitly[TestTypeClass[TestClass]] // OK.
implicitly[TestTypeClass[TestClass2[Boolean]]] // Error
// could not find implicit value for parameter e: TestTypeClass[TestClass2[Boolean]]
implicitly[TestTypeClass[TestClass2[TestClass]]] // Error
// could not find implicit value for parameter e: TestTypeClass[TestClass2[TestClass]]
Это так по дизайну, я делаю что-то неправильно или это ошибка компилятора?