我在 Scala 3 中有一个宏处理类型,该宏是我在 airframe-surface 库中面临的问题的最小化重现。该宏显然工作正常,但一旦我将选项
-Xcheck-macros
添加到 build.sbt 中,我就会得到一个断言。我已将问题追溯到从 BySkinny
类型 lambda 中提取的类型参数。当我返回时,我收到一个错误:
断言失败:孤立参数:SkinnyA,活页夹哈希 = 1384130361,树 = ,类型 = ConstantType(Constant(TypeParamRef(SkinnyA)))
这使得调试其他宏变得困难,因为异常会中止编译。
递归宏最重要的部分是这样的:
def clsOf(t: TypeRepr): Expr[Class[_]] =
Literal(ClassOfConstant(t)).asInstanceOf[Expr[Class[_]]]
def extract(t: TypeRepr): Expr[Class[_]] = {
t match
case t if t.typeSymbol.isType && t.typeSymbol.isAliasType && !belongsToScalaDefault(t) =>
val dealiased = t.dealias
println(s"=== alias factory: ${t} => ${dealiased} == ${t.simplified}")
extract(dealiased)
case h: TypeLambda =>
println(s"TypeLambda $h")
val len = h.paramNames.size
val args = Option.when(len > 0)(h.param(0)).map(extract)
args.getOrElse(clsOf(h.resType))
case a: AppliedType =>
println(s"AppliedType")
val typeArgs = a.args.map(extract)
typeArgs.head
}
我只是深入研究描述类型的 AST 并在其中定位单个节点。
我正在处理的类型是
Holder[Holder.BySkinny]
,其中:
trait Holder[M[_]]
class MyTask[TaskA]
object Holder {
type BySkinny[SkinnyA] = MyTask[SkinnyA]
def bySkinny: Holder[BySkinny] = ???
}
我不确定该错误是否是 Scala 3 编译器中的错误,或者我(和机身表面)是否做错了什么。
感谢@Mateusz Kubuszok的提示。对
clsOf
进行修改后,在大多数情况下解决了该问题:
private def clsOf(t: TypeRepr): Expr[Class[_]] =
Literal(ClassOfConstant(t)).changeOwner(Symbol.spliceOwner).asExpr.asInstanceOf[Expr[Class[_]]]
演示项目中的一个案例仍然失败,但使用此代码的真实库现在工作正常。
修复所有者的另一种方法是拼接并引用表达式:
private def clsOf(t: TypeRepr): Expr[Class[_]] =
val cls = Literal(ClassOfConstant(t)).asExpr.asInstanceOf[Expr[Class[_]]]
'{ $cls }
IDE 将
'{ $cls }
突出显示为与 cls
等效,但它修复了所有者。