我尝试向Monocle添加@Prisms
注释,其工作原理如下。给出:
@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
和B
,因此Monocle自述文件中会有一条注释,建议人们使用Typelevel Scala。我已将Monocle配置为在我的分支上使用TLS。
我尝试使用TypeName
来表示父类型Foo
和子类型(A
或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
我还尝试使用TypeSymbol
代替TypeName
s:
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
我也尝试将TypeSymbol
转换为Type
s:
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。
宏用于test/shared/src/test/scala/other/PrismsAnnotationSpec.scala
。要编译它,请运行sbt test:compile
。