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

Applying type to a type constructor in macro throws exception

考虑以下简单的宏片段:

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(Typers.scala:44)
[error]         at scala.reflect.macros.contexts.Typers.$anonfun$typecheck(Typers.scala:38)
[error]         at scala.reflect.macros.contexts.Typers.doTypecheck(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)

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

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,所以你得到了错误。


现在,要从 Type 中得到一个 Ident,您可以使用 .typeSymbol 方法(尽管 idents 没有类型参数信息,是否你之前是否做过 .typeConstructor)。这应该有效:

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

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