如何调试宏注释?

2024-04-01

背景

我正在尝试添加一个@PrismsMonocle 的注释将按如下方式工作。鉴于:

@Prisms sealed trait Foo
case object A extends Foo
case object B extends Foo

它将生成一个伴随对象Foo:

object Foo {
  val a = monocle.macros.GenPrism.apply[Foo, A]
  val b = monocle.macros.GenPrism.apply[Foo, B]
}

(或者如果伴生对象已经存在,它将向其中添加这些方法)。

宏依赖于directKnownSubclasses找到A and B,所以 Monocle 自述文件中会有一条注释建议人们使用 Typelevel Scala。我已将 Monocle 配置为在我的分支上使用 TLS。

第一次尝试

我尝试使用TypeNames 代表父类型Foo和子类型(A or B):

def findSubclasses(typeName: TypeName): Set[TypeName] = {
  // Note: disable macros to prevent stack overflow caused by infinite typing loop!
  val tpe = c.typecheck(Ident(typeName), mode = c.TYPEmode, silent = true, withMacrosDisabled = true)
  tpe.symbol.asClass.knownDirectSubclasses.map(_.asType.name)
}

def prisms(parentTypename: TypeName, childNames: Set[TypeName]): Set[Tree] = childNames.map { childName =>
  val prismName = TermName(prefix + childName.decodedName.toString.toLowerCase)
  q"""val $prismName = monocle.macros.GenPrism.apply[$parentTypename, $childName]"""
}

这会生成看起来合理的代码:

{
  sealed trait Foo;
  object Foo {
    val a = monocle.macros.GenPrism.apply[Foo, A];
    val b = monocle.macros.GenPrism.apply[Foo, B]
  };
  ()
}

但它似乎不起作用:

[error] /Users/chris/code/Monocle/test/shared/src/test/scala/other/PrismsAnnotationSpec.scala:5: not found: type A
[error] @monocle.macros.Prisms sealed trait Foo
[error]  ^
[error] one error found

第二次尝试

我也尝试过使用TypeSymbols 而不是TypeNames:

def prisms(parentTypename: TypeName, childSymbols: Set[TypeSymbol]): Set[Tree] = {
  val parentSymbol: TypeSymbol = 
    c.typecheck(Ident(parentTypename), mode = c.TYPEmode, silent = true, withMacrosDisabled = true)
      .symbol
      .asType
  childSymbols.map { childSymbol =>
    val prismName = TermName(prefix + childSymbol.name.decodedName.toString.toLowerCase)
    q"""val $prismName = monocle.macros.GenPrism.apply[$parentSymbol, $childSymbol]"""
  }
}

但这给了我以下错误,所以我猜测生成的树是无效的:

[error] /Users/chris/code/Monocle/test/shared/src/test/scala/other/PrismsAnnotationSpec.scala:5: macro annotation could not be expanded (the most common reason for that is that you need to enable the macro paradise plugin; another possibility is that you try to use macro annotation in the same compilation run that defines it)
[error] @monocle.macros.Prisms sealed trait Foo
[error]  ^
[error] one error found

第三次尝试

我也尝试过转动TypeSymbols into Types:

def prisms(parentTypename: TypeName, childSymbols: Set[TypeSymbol]): Set[Tree] = {
  val parentSymbol: TypeSymbol = 
    c.typecheck(Ident(parentTypename), mode = c.TYPEmode, silent = true, withMacrosDisabled = true)
      .symbol
      .asType
  childSymbols.map { childSymbol =>
    val prismName = TermName(prefix + childSymbol.name.decodedName.toString.toLowerCase)
    q"""val $prismName = monocle.macros.GenPrism.apply[${parentSymbol.toType}, ${childSymbol.toType}]"""
  }
}

但我得到同样的错误,说注释无法扩展。

现在我没有主意了。

如何重现

完整的代码可以在这个分支上找到:https://github.com/cb372/Monocle/tree/sealed-trait-macro-annotation https://github.com/cb372/Monocle/tree/sealed-trait-macro-annotation.

  • 第一次尝试 https://github.com/cb372/Monocle/blob/c0185125665d2378275985ba83978f7fa8843cc1/macro/shared/src/main/scala/monocle/macros/Prisms.scala
  • 第二次尝试 https://github.com/cb372/Monocle/blob/efd54537f10bd1e0ed7a9764121e8e900de123f1/macro/shared/src/main/scala/monocle/macros/Prisms.scala
  • 第三次尝试 https://github.com/cb372/Monocle/blob/3290ca6e01c57c08ec0ad0fc755efbf774551cb7/macro/shared/src/main/scala/monocle/macros/Prisms.scala

该宏用于test/shared/src/test/scala/other/PrismsAnnotationSpec.scala。要编译它,请运行sbt test:compile.


None

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何调试宏注释? 的相关文章

随机推荐