scala元:取消引用时类型不匹配;找到:选项[scala.meta.Type.Arg]必需:scala.meta.Type

scala元:取消引用时类型不匹配;找到:选项[scala.meta.Type.Arg]必需:scala.meta.Type,scala,scala-macros,scalameta,Scala,Scala Macros,Scalameta,我正在玩一点新风格的游戏。因此,我扩展了@Main注释的示例: SConsumer.scala: import scala.meta._ class SConsumer extends scala.annotation.StaticAnnotation { inline def apply(defn: Any): Any = meta { defn match { case q"case class $name($param: $tpe) { ..$stats }"

我正在玩一点新风格的游戏。因此,我扩展了@Main注释的示例:

SConsumer.scala:

import scala.meta._


class SConsumer extends scala.annotation.StaticAnnotation {

  inline def apply(defn: Any): Any = meta {
    defn match {
      case q"case class $name($param: $tpe) { ..$stats }" =>
        val accept = q"def accept($param: $tpe): Unit = { ..$stats }"
        q"case class $name extends SConsumerProperty[${tpe}] { $accept }"
      case _ =>
        abort("error!")
    }
  }
}
SConsumerProperty.scala:

trait SConsumerProperty[T] {
  def accept(param: T): Unit
}
它给出以下编译器错误:

Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=256M; support was removed in 8.0
[info] Loading project definition from /home/erik/Entwicklung/IntelliJ/Android/Apps/scalandroid/project
[info] Set current project to scalandroid (in build file:/home/erik/Entwicklung/IntelliJ/Android/Apps/scalandroid/)
[info] Packaging /home/erik/Entwicklung/IntelliJ/Android/Apps/scalandroid/target/scala-2.11/scalandroid_2.11-0.0.23-sources.jar ...
[info] Done packaging.
[info] Wrote /home/erik/Entwicklung/IntelliJ/Android/Apps/scalandroid/target/scala-2.11/scalandroid_2.11-0.0.23.pom
[info] Compiling 4 Scala sources to /home/erik/Entwicklung/IntelliJ/Android/Apps/scalandroid/target/android/intermediates/classes...
[error] /home/erik/Entwicklung/IntelliJ/Android/Apps/scalandroid/src/main/scala/com/bertderbecker/scalandroid/event/SConsumer.scala:14: type mismatch when unquoting;
[error]  found   : Option[scala.meta.Type.Arg]
[error]  required: scala.meta.Type
[error]         q"case class $name extends com.bertderbecker.scalandroid.event.SConsumerProperty[${tpe}] { $accept }"
[error]                                                                                        
[error] one error found
[error] (compile:compileIncremental) Compilation failed
[error] Total time: 6 s, completed 17.02.2017 16:16:02
Process finished with exit code 1

那么,如何将Type.Arg转换为Type呢?

我自己也被这个问题困扰了。一般来说,对于这种情况,最好咨询。 所有
Type
都是
Type.Arg
(请参见
trait Type扩展X和Type.Arg
,但有两个
Type.Arg
不是
Type
Type.Arg.ByName
Type.Arg.Repeated

比如说,

q"def foo(k: Int, a: => Int, b: String*)".structure
res22: String = """
Decl.Def(Nil, Term.Name("foo"), Nil,
         Seq(Seq(Term.Param(Nil, Term.Name("k"), Some(Type.Name("Int")), None),
                 Term.Param(Nil, Term.Name("a"), Some(Type.Arg.ByName(Type.Name("Int"))), None),
                 Term.Param(Nil, Term.Name("b"), Some(Type.Arg.Repeated(Type.Name("String"))), None))),
         Type.Name("Unit"))
"""
我们可以创建一个助手实用程序来将
Type.Arg
转换为
类型

def toType(arg: Type.Arg): Type = arg match {
  case Type.Arg.Repeated(tpe) => tpe
  case Type.Arg.ByName(tpe) => tpe
  case tpe: Type => tpe
}

你明白了吗?是的,经过长时间的研究,我发现
[${Type.Name.apply(the.get.toString)}]
。我不确定这是否是“干净的方式”,但它对我有效。如果你假设
没有类型参数(
x:List[Int]
),不是按名称(
x:=>T
)或重复,那么这种解决方法是可行的(
x:T*
)。我已打开一个票证,将此助手添加到
contrib
模块,请参阅