将类型应用于宏中的类型构造函数会引发异常

问题描述

考虑以下简单的宏片段:

val lstConstructor = weakTypeTag[List[String]].tpe.typeConstructor
println(c.typecheck(tq"$lstConstructor[String]",mode = c.TYPEmode))

这似乎是一段非常简单的代码失败,并出现以下信息异常:

[error] scala.reflect.macros.TypecheckException: Any does not take type parameters
[error]         at scala.reflect.macros.contexts.Typers.$anonfun$typecheck$3(Typers.scala:44)
[error]         at scala.reflect.macros.contexts.Typers.$anonfun$typecheck$2(Typers.scala:38)
[error]         at scala.reflect.macros.contexts.Typers.doTypecheck$1(Typers.scala:37)
[error]         at scala.reflect.macros.contexts.Typers.typecheck(Typers.scala:51)
[error]         at scala.reflect.macros.contexts.Typers.typecheck$(Typers.scala:32)
[error]         at scala.reflect.macros.contexts.Context.typecheck(Context.scala:18)
[error]         at scala.reflect.macros.contexts.Context.typecheck(Context.scala:18)

将类型参数 aoply 到类型构造函数的正确方法是什么?

UPD

手动指定类型构造函数的硬编码名称

println(c.typecheck(tq"List[String]",mode = c.TYPEmode))

工作正常

解决方法

欢迎来到无类型编译器的无证之地。

拟引用 tq"List[String]" 生成以下树:

AppliedTypeTree(Ident(TypeName("List")),List(Ident(TypeName("String"))))

请注意,第一个参数不是 Type,而是 Ident。因此,您的准引用 tq"$lstConstructor[String]" 会悄悄地用空的 TypeTree() 替换不适当类型的树:

AppliedTypeTree(TypeTree(),List(Ident(TypeName("String"))))

我很确定它等价于 Any,所以你会得到错误。


现在,要从 Ident 中获取 Type,您可以使用 .typeSymbol 方法(尽管 idents 没有类型参数信息,但您是否这样做并不重要.typeConstructor 之前与否)。这应该有效:

c.typecheck(tq"${lstConstructor.typeSymbol}[String]",mode = c.TYPEmode)

Scastie 上的代码(使用运行时 Universe)here