2

コンパニオンオブジェクトにメソッドを追加するケースクラスの簡単なマクロ注釈を作成しようとしています。新しいメソッドは、注釈付きのケースクラスの型パラメータを考慮する必要があるということです。Scalaマクロの注釈 - 型パラメータを持つケースクラス

ここで私は

package my.macros 

import org.scalatest._ 

class DefaultApplyTest extends FlatSpec with Matchers { 

    @defaultApply case class Generic[A, B](a: A, b: B) 

    it should "define defaultApply method in companion object" in { 
    assert(Generic.defaultApply("str", 1) == Generic("str", 1)) 
    } 
} 

を渡す必要がありますテストはここで私は、私はそれが私がliftしようとするということであることを理解としてこの

package my.macros 

import scala.reflect.macros._ 
import scala.language.experimental.macros 
import scala.annotation.StaticAnnotation 

class defaultApply extends StaticAnnotation { 
    def macroTransform(annottees: Any*): Any = macro DefaultApply.impl 
} 

object DefaultApply { 

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

    def defaultApplyCompanion(classDecl: ClassDef) = { 
     val (name, typeParams, valueParams) = try { 
     val q"case class ${name: TypeName}[..${typeParams: Seq[TypeDef]}](..${valueParams: Seq[ValDef]}) extends ..$bases { ..$body }" = classDecl 
     (name, typeParams, valueParams) 
     } catch { 
     case e: MatchError => 
      c.warning(c.enclosingPosition, e.toString) 
      c.abort(c.enclosingPosition, "Annotation is only supported on case class") 
     } 

     val applyDef = q"""${name.toTermName}.apply[..$typeParams]""" 
     c.warning(c.enclosingPosition, showRaw(applyDef)) 

     q""" 
     object ${name.toTermName} { 
      def defaultApply: (..${valueParams.map(_.tpt)}) => $name[..$typeParams] = $applyDef 
     } 
     """ 
    } 

    def modifiedDeclaration(classDecl: ClassDef) = { 
     val compDecl = defaultApplyCompanion(classDecl) 

     c.Expr(q""" 
     $classDecl 
     $compDecl 
     """) 
    } 

    annottees.map(_.tree) match { 
     case (classDecl: ClassDef) :: Nil => modifiedDeclaration(classDecl) 
     case _ => c.abort(c.enclosingPosition, "Invalid annottee") 
    } 
    } 
} 

問題を達成するために書かれたコードだです型パラメータのリストを結果の構文木に追加すると、元のツリーと同じ型パラメータとして認識されません。

だから私は上の焦点だと、マクロ

val applyDef = q"""${name.toTermName}.apply[..$typeParams]""" 
    c.warning(c.enclosingPosition, showRaw(applyDef)) 

のこの部分のために、生の構文木が

TypeApply(Select(Ident(TermName("Generic")), TermName("apply")), List(TypeDef(Modifiers(PARAM), TypeName("A"), List(), TypeBoundsTree(EmptyTree, EmptyTree)), TypeDef(Modifiers(PARAM), TypeName("B"), List(), TypeBoundsTree(EmptyTree, EmptyTree)))) 

として放出されていることですが、コンパイラは、この

に満足していません
type arguments [<notype>,<notype>] do not conform to method apply's type parameter bounds [A,B] 

最終的な使用例は、キャッシュ可能な型クラスのインスタンスを生成するためのものです1k行のコード。パラメータ化されていないバージョンはすでに動作しています。これはケーキのアイシングです。私が理解していないが、したいスカラックのフードの下に何かがあります。これを読んだあなたの時間は非常に感謝しています。

私はmacro paradise 2.1.0

答えて

0

の問題をScalaの2.11.8を使用していますが、あなたが型引数の代わりに型パラメータを使用していることのようです。これはうまくいくようです(私はdefaultApplyメソッド宣言に型パラメータを追加しなければなりませんでした):

val typeArgs = typeParams.map(_.name) 
    val applyDef = q"""${name.toTermName}.apply[..$typeArgs]""" 
    c.warning(c.enclosingPosition, showRaw(applyDef)) 

    q""" 
    object ${name.toTermName} { 
     def defaultApply[..$typeParams]: 
      (..${valueParams.map(_.tpt)}) => $name[..$typeArgs] = $applyDef 
    } 
    """ 
+0

それでした。ありがとうございました! – dbaumann

関連する問題