Я пытаюсь заставить существующий макрос, который генерирует экземпляры класса типов, работать для параметризованных типов, где аргумент типа уже имеет экземпляр класса типов. Я удивлен, что в этом случае не удается разрешить существующий класс типов (аргумент типа), но, похоже, именно это и происходит.
Я попытался свести это к небольшому примеру, демонстрирующему поведение. Вот определение макроса:
package test
import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context
trait Read[A] {
def read(in: String): A
}
object Read {
def CaseClassReadImpl[A: c.WeakTypeTag](c: Context): c.Expr[Read[A]] = {
import c.universe._
val aType = weakTypeOf[A]
val params = aType.decls.collect {
case m: MethodSymbol if m.isCaseAccessor => m
}.toList
val paramList = params.map(param => q"Read.read[${param.typeSignature}](in)")
val src = q"""
new Read[$aType] {
def read(in: String) = ${aType.typeSymbol.companion}.apply(..$paramList)
}
"""
c.Expr[Read[A]](src)
}
def readFor[A]: Read[A] = macro CaseClassReadImpl[A]
def read[A](in: String)(implicit A: Read[A]): A = A.read(in)
}
Вот код, который его тренирует:
package test
object MacroTest {
case class Foo[A](bar: A)
implicit def fooRead[A](implicit A: Read[A]): Read[Foo[A]] =
Read.readFor[Foo[A]]
}
Я ожидал, что это удастся, думая, что неявный параметр для сгенерированного вызова Read.read
будет преобразован в неявный аргумент для функции fooRead
. Вместо этого происходит сбой при определении fooRead
с помощью:
Error:(7, 17) could not find implicit value for parameter A: test.Read[A]
Read.readFor[Foo[A]]
Почему он не использует неявный параметр от A
до fooRead
? Это в лексическом контексте.
Я понимаю, что должен преобразовать эту кодовую базу в бесформенную или какую-то подобную библиотеку, но сейчас я просто пытаюсь заставить ее работать с минимальными усилиями.
Обновление:
Я понял, что проблема заключается в наличии двух разных A
с. Из-за вышеприведенной ошибки выглядит так, что требуемый неявный тип имеет тот же тип, что и у меня в области видимости, но после того, как я немного поковырялся с ним и явно передал неявное, мне удалось получить это (гораздо более полезное) сообщение об ошибке:
Error: type mismatch;
found : A(in class Foo)
required: A(in method fooRead)
implicit def fooRead[A](implicit read: Read[A]): Read[Foo[A]] = Read.readFor[Foo[A]]
Я до сих пор не смог найти способ заставить Scala понять, что я хочу, чтобы A
s были такими же: тот, который был передан в функцию fooRead
.