使用resetLocalAttrs时出现奇怪的错误

时间:2012-11-30 09:22:16

标签: scala macros abstract-syntax-tree scala-2.10 partialfunction

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

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 =>保护它。操作

让我们测试代码,使用虚函数强制测试需要 Int =>行动参数:

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 标志,这变得相当困难。

1 个答案:

答案 0 :(得分: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])))