1

我编写了一个宏,它使用(宏)上下文的 resetLocalAttrs 方法。宏展开后,我收到一个奇怪的错误,我无法弄清楚发生了什么。首先,我将介绍问题。我们有两个原语:状态(我将表示为一个简单的 Int)和动作。状态代表系统的当前状态,而动作负责修改状态。动作可以是原子的或由原子动作组成。

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接收一个部分函数,​​因为它可以根据当时的当前状态启动一个或另一个动作。组合动作内部的原子动作可能需要序列中前一个原子动作留下的前一个状态,所以我需要用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 (你不想知道,这个问题变得太长:)。这个 reify 失败并出现一个奇怪的错误:

class Any is abstract; cannot be instantiated

我在哪里尝试实例化 Any?为什么重置对 AST 的影响如此之大?我已经使用了很多次,它很好地重置了类型和符号。

找到问题的更好方法是什么?我一直在使用 showRaw 启用类型ids标志,这变得相当困难。

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 回答