2

我开发了一个 scala 宏注释,它丰富了具有各种定义的对象(参见 play form 宏)。除其他外,我希望该对象包含类型别名

type WFS = FS[_, _, _, _]

对于不同数量的通配符参数。

我已经尝试通过以下方式提取单个通配符类型的值

q"type WFS = FS[_]" match { q"type WFS = FS[$t]" => t }

并希望在类型参数列表中使用提取的值(例如 q"type WFS = FS[..$tplist]")。然而上面的语句产生了一个错误:

scala> q"type WFS = FS[_]" match { case q"type WFS = FS[$t]" => t }
scala.MatchError: type WFS = FS[_$1] forSome { 
  <synthetic> type _$1 >: _root_.scala.Nothing <: _root_.scala.Any
} (of class scala.reflect.internal.Trees$TypeDef)
    at .<init>(<console>:15)
    at .<clinit>(<console>)
    at .<init>(<console>:7)
    at .<clinit>(<console>)
    at $print(<console>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43

是否有另一种(可能更简单)的方法来构建必要的树?

4

1 回答 1

0

错误是打印您要匹配的值的实际形状,显然您需要在匹配的准引号中使用相同的形状:

scala> q"type WFS = FS[_]" match { case q"type WFS = FS[$a] forSome { $b }" => println(s"$a --- $b") }
_$1 --- <synthetic> type _$1 >: _root_.scala.Nothing <: _root_.scala.Any

如果您想允许更多参数,而不仅仅是一个,您最好使用"..$x"允许:

scala> q"type WFS = FS[_]" match { case q"type WFS = FS[..$a] forSome { ..$b }" => println(s"$a --- $b") }
List(_$1) --- List(<synthetic> type _$1 >: _root_.scala.Nothing <: _root_.scala.Any)

通配符被转换为存在 -FS[_]表示FS[T] forSome { type T }(关于存在的详细信息,有 Scala 语言规范,第 3.2.10 节,在“存在类型的占位符语法”下)。当您FS[$a]在匹配的准引号中写入时,这意味着“我希望在这里将类型构造函数应用于一个类型参数”。ButFS[T] forSome { type T }是一个存在类型,它包含对参数的类型构造函数的应用,因此模式将不匹配。

为了更好地理解这一点,并知道如何调试类似的问题,查看showRaw由 quasiquotes 生成的树很有见地——因为这些是类型,我们需要类型 quasiquotes,即tq"..."

scala> showRaw(tq"FS[_]")
res15: String = ExistentialTypeTree(AppliedTypeTree(Ident(newTypeName("FS")), List(Ident(newTypeName("_$1")))), List(TypeDef(Modifiers(DEFERRED | SYNTHETIC), newTypeName("_$1"), List(), TypeBoundsTree(Select(Select(Ident(nme.ROOTPKG), newTermName("scala")), newTypeName("Nothing")), Select(Select(Ident(nme.ROOTPKG), newTermName("scala")), newTypeName("Any"))))))

scala> showRaw(tq"FS[T]")
res16: String = AppliedTypeTree(Ident(newTypeName("FS")), List(Ident(newTypeName("T"))))

据我了解,与准引号匹配意味着与相应的树匹配。所以上面演示了我描述的问题。

不幸的是,quasiquotes 并没有隐藏 Scala 类型系统的这些细节。这可能是也可能不是 quasiquotes 的错误,但我不能对此发表评论 - 我确实认为如果不需要处理它会很酷

于 2014-02-04T21:37:48.430 回答