2016-09-14 12 views
1

非常に単純なマクロ互換のマクロ注釈。Scalaマクロ:ValDefから型シグニチャを派生させる

def impl(c: blackbox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = { 
    import c.universe._ 

    annottees.map(_.tree) match { 
     case (classDef @ q"$mods class $tpname[..$tparams] $ctorMods(...$params) extends { ..$earlydefns } with ..$parents { $self => ..$stats }") 
     :: Nil if mods.hasFlag(Flag.CASE) => 
     val name = tpname.toTermName 
     val typeName = tpname.toTypeName 
     val res = q""" 
     $classDef 
     object $name { 
      ..${doStuff(c)(typeName, name, params.head)} 
     } 
     """ 
     c.Expr[Any](res) 

     case _ => c.abort(c.enclosingPosition, "Invalid annotation target, this must be a case class") 
    } 
    } 

だから、とても単純です。問題の原因となるビットは、上記の$paramsに由来します。ちょうどList[List[ValDef]]です。つまり、何とかタイプシグネチャが失われています。 ValDef

def accessors(c: blackbox.Context)(
    params: Seq[c.universe.ValDef] 
): Iterable[(c.universe.TermName, c.universe.TypeName)] = { 
    import c.universe._ 

    params.map { 
     case ValDef(mods: Modifiers, name: TermName, tpt: Tree, rhs: Tree) => { 
     // tpt.tpe = kaboom, null pointer 
     name -> TypeName(tpt.tpe.typeSymbol.fullName) 
     } 
    } 
    } 

tpenullとして戻ってくるので、DEFSはタイプされたが、私は私が望むものを達成するためのparamsの型シグネチャを必要とされていません。どのように私は爆破せずにパラメータの型署名を得ることができますか?

皮肉なことに、showCode(tpt)は正しいタイプの文字列を生成するので、これはTypeName(tpt.toString)で回避できますが、なぜtpeにアクセスできないのか分かりません。この場合

/** 
    * Retrieves the accessor fields on a case class and returns an iterable of tuples of the form Name -> Type. 
    * For every single field in a case class, a reference to the string name and string type of the field are returned. 
    * 
    * Example: 
    * 
    * {{{ 
    * case class Test(id: UUID, name: String, age: Int) 
    * 
    * accessors(Test) = Iterable("id" -> "UUID", "name" -> "String", age: "Int") 
    * }}} 
    * 
    * @param params The list of params retrieved from the case class. 
    * @return An iterable of tuples where each tuple encodes the string name and string type of a field. 
    */ 
    def accessors(
    params: Seq[ValDef] 
): Iterable[Accessor] = { 
    params.map { 
     case ValDef(_, name: TermName, tpt: Tree, _) => { 
     Accessor(
      name, 
      c.typecheck(tq"$tpt", c.TYPEmode).tpe 
     ) 
     } 
    } 
    } 

Accessorimport c.universe._が利用可能である範囲内で定義する必要がありますカスタムcase classです:

+0

:http://stackoverflow.com/questions/23671379/proper-way-to-pattern-match-the-値a-a-a-typero-from-a-valdef-in-scala-macro –

答えて

0

これを行うための正しい方法は、次のようにc.TypeModec.typepcheckを使用して型引数を評価することです:あなたはこの質問に答えとユージンBurmakoのコメントを見てみることをお勧めします

case class Accessor(
    name: TermName, 
    paramType: Type 
) { 
    def typeName: TypeName = symbol.name.toTypeName 

    def symbol = paramType.typeSymbol 
    } 
関連する問題