如何正确从TypeLambda中提取类型参数?

问题描述 投票:0回答:1

我在 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 编译器中的错误,或者我(和机身表面)是否做错了什么。

完整项目位于 https://github.com/OndrejSpanel/OrphanParamIssue

scala reflection macros scala-macros scala-3
1个回答
0
投票

感谢@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
等效,但它修复了所有者。

© www.soinside.com 2019 - 2024. All rights reserved.