我正在尝试在 Scala 3 中编写一个宏,它将解析案例类中定义的类型,然后查找这些类型的给定/隐式方法。
下面是宏代码。
import scala.quoted.*
object TransformerMacro:
inline def resolveTransformer[T] = ${ resolveTransformerImpl[T] }
def resolveTransformerImpl[T: Type](using Quotes) =
import quotes.reflect.*
val tpe = TypeRepr.of[T]
val typeMembersAll = tpe.typeSymbol.declaredTypes.map {
case typ if typ.isType =>
val typeName = typ.name
val typeBound = tpe.memberType(typ)
typeName -> typeBound
}
val outType = typeMembersAll.head._2
val inType = typeMembersAll.last._2
(outType, inType) match {
case (TypeBounds(_, oT), TypeBounds(_, iT)) =>
(oT.asType, iT.asType) match {
case ('[o], '[i]) =>
val itn = Type.show[i]
val otn = Type.show[o]
Expr.summon[TR[o, i]] match {
case Some(instance) =>
report.info(s"We might find the implicit now $itn, $otn $instance")
'{Some(${instance})}
case None =>
report.error(s"No Implicit Found for type: \nReModel[$itn, $otn]")
'{ None }
}
}
}
示例:
case class Person(name: String, age: Int, email: Option[String]):
type R = String
type M = Int
trait TR[A, B]:
def f(a: A) : B
object TR:
given strToInt: TR[Int, String] with
override def f(from: Int): String = from.toString
对于案例类 Person,宏将解析 R 和 M 的类型,并尝试在范围内找到 TR 类型的隐式。
但是宏也会进入 None 情况并给出以下错误
report.error(s"No Implicit Found for type: \nTR[$itn, $otn]")
宏的驱动程序代码
def main(args: Array[String]): Unit =
val resolved = TransformerMacro.resolveTransformer[Person]
println(resolved)
错误在这里:
Expr.summon[TR[o, i]]
在其他地方,您使用
i
前缀作为输入,使用 o
作为输出,但在这里您将这些值交换在一起:您查找 TR[String, Int]
,失败时打印 not found TR[Int, String]
- 这就是为什么重复数据删除逻辑很有用,如果是 not found TR[String, Int]
,问题就会立即显而易见。
它可以更容易地实现:
import scala.quoted.*
object TransformerMacro:
inline def resolveTransformer[T] = ${ resolveTransformerImpl[T] }
def resolveTransformerImpl[T: Type](using Quotes) =
import quotes.reflect.*
// Help us extract member types without weird shenanigans
type Aux[I, O] = Person { type R = O; type M = I }
Type.of[T] match {
case '[Aux[i, o]] => // much simpler extraction
// reuse computed type for both summoning and printing
def handle[A: Type] = {
Expr.summon[A] match {
case Some(instance) =>
report.info(s"We might find the implicit now ${instance.asTerm.show}: ${TypeRepr.of[A].show}")
'{Some(${instance})}
case None =>
report.error(s"No Implicit Found for type: \n${TypeRepr.of[A].show}")
'{ None }
}
}
handle(using Type.of[TR[i, o]])
}