1

(マクロ) コンテキストの resetLocalAttrs メソッドを使用するマクロをコーディングしました。マクロが展開された後、奇妙なエラーが発生し、何が起こっているのかわかりません。まず、問題を紹介します。state (単純な Int として表します) とactionの 2 つのプリミティブがあります。状態はシステムの現在の状態を表し、アクションは状態の変更を担当します。アクションは、アトミックにすることも、アトミック アクションで構成することもできます。

trait Action {
  def andNext(action: PartialFunction[Int, Int => Action]): AndNext = AndNext(this, action)
}
case class ActionId extends Action
case class AndNext(action: Action, and: PartialFunction[Int, Int => Action]) extends Action

コードでわかるように、AndNextは部分関数を受け取ります。これは、その瞬間の現在の状態に応じて、1 つまたは別のアクションを起動できるためです。構成されたアクション内にあるアトミック アクションは、シーケンス内の先行するアトミック アクションによって残された先行状態を必要とする可能性があるため、Int => Actionで保護する必要があります。

ダミー関数を使用してテストにInt => Actionパラメーターを強制的に要求させて、コードをテストしてみましょう。

def f(lifted: Int => Action) = ???
f(implicit state => ActionId() andNext { case _ => implicit state => ActionId() })

大丈夫ですが、私は DSL に取り組んでおり、冗長な暗黙の状態をすべて記述するには冗長すぎます。このコードを DSL の使用に適したものにするために、それらを非表示にする必要があります。次のかわいい呼び出しに到達しようとしています...

f(ActionId() andNext { case _ => ActionId() })

アクションを保護されたアクションに変換するマクロを実装しました (Int => Action を思い出してください)。

implicit def lift[T](expr: T): Int => T = macro liftImpl[T]

def liftImpl[T: c.WeakTypeTag](c: Context)(expr: c.Expr[T]): c.Expr[Int => T] = {
  import c.mirror._
  import c.universe._

  //reify(implicit state => expr.splice)
  reify(implicit state => c.Expr[T](c.resetLocalAttrs(expr.tree)).splice)
}

(*)ビュー内のメソッドを変換するマクロ宣言の暗黙に注意してください。

前者 (およびコメント付き) の reify は問題なく動作しますが、いくつかの制限があるため、resetLocalAttrs() を呼び出す reifyを使用する必要があります (知りたくない場合は、この質問が長すぎます :)。この具体化は奇妙なエラーで失敗します:

class Any is abstract; cannot be instantiated

どこで Any をインスタンス化しようとしていますか? リセットが AST に大きな影響を与えるのはなぜですか? 私はそれを何度も使用しましたが、タイプとシンボルをうまくリセットしていました。

問題を見つけるためのより良いアプローチは何ですか? 私は showRaw を使用してtypeidsフラグを有効にしてきましたが、かなり難しくなっています。

4

1 に答える 1

1

部分関数は合成匿名クラスを生成し、匿名クラスには typecheck-reset-retypechecking に関する既知の問題があります: https://issues.scala-lang.org/browse/SI-6187

17:04 ~/Projects/Kepler_macrosnippet00/sandbox (topic/macrosnippet00)$ scalac -Ymacro-debug-lite Test.scala 
performing macro expansion Macros.lift[ActionId](ActionId.apply()) at source-/Users/xeno_by/Projects/Kepler_macrosnippet00/sandbox/Test.scala,line-11,offset=449
((implicit state) => ActionId.apply())
Function(List(ValDef(Modifiers(IMPLICIT | PARAM), newTermName("state"), TypeTree(), EmptyTree)), Apply(Select(Ident(ActionId), newTermName("apply")), List()))
performing macro expansion Macros.lift[AndNext](ActionId.apply().andNext(({
  @SerialVersionUID(0) final <synthetic> class $anonfun extends scala.runtime.AbstractPartialFunction[Int,Int => Action] with Serializable {
    def <init>(): anonymous class $anonfun = {
      $anonfun.super.<init>();
      ()
    };
    final override def applyOrElse[A1 >: Nothing <: Int, B1 >: Int => Action <: Any](x$1: A1, default: A1 => B1): B1 = (x$1: A1 @unchecked) match {
      case _ => ((implicit state: Int) => ActionId.apply())
    };
    final def isDefinedAt(x$1: Int): Boolean = (x$1: Int @unchecked) match {
      case _ => true
    }
  };
  new anonymous class $anonfun() // an anonymous class created for a partial function
}: PartialFunction[Int,Int => Action]))) at source-/Users/xeno_by/Projects/Kepler_macrosnippet00/sandbox/Test.scala,line-11,offset=421
((implicit state) => ActionId.apply().andNext(({
  final <synthetic> class $anonfun extends scala.runtime.AbstractPartialFunction[Int,Int => Action] with Serializable {
    def <init>() = {
      super.<init>();
      ()
    };
    final override def applyOrElse[A1 <: Int, B1 >: Int => Action](x$1, default) = (x$1: <type ?>) match {
      case _ => ((implicit state: Int) => ActionId.apply())
    };
    final def isDefinedAt(x$1: Int): Boolean = (x$1: Int @unchecked) match {
      case _ => true
    }
  };
  new <type ?>() // <= the problem is here: the type has been irreversibly erased by resetLocalAttrs
}: PartialFunction[Int,Int => Action])))
于 2012-12-01T16:08:27.837 に答える