2017-02-17 20 views
1

Я немного играю в новом стиле macro annotationsscala-meta. Так что я продлил пример @main аннотацию:scala-meta: несоответствие типов при нечеткости; найдено: Опция [scala.meta.Type.Arg] требуется: scala.meta.Type

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 в тип?

+0

Вы когда-нибудь это выясняли? – Kevin

+0

Да, после долгого исследования I found '[$ {Type.Name.apply (the.get.toString)}]'. Я не уверен, что это «чистый путь», но он работает для меня. –

+0

Это обходное решение в порядке, если вы предположили, что '' 'не имеет параметров типа (' x: List [Int] '), не является именем (' x: => T') или повторяется ('x: T * '). –

ответ

2

Я сам был укушен. В общем случае для таких случаев полезно проконсультироваться с Tree sources. Все Type являются Type.Arg (см trait Type extends X with 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 к Type

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

Я открыл билет, чтобы добавить этого помощника в модуль 'contrib', см. Https://github.com/scalameta/scalameta/issues/801 –