【问题标题】:What is wrong with this def macro?这个 def 宏有什么问题?
【发布时间】:2014-08-22 14:42:09
【问题描述】:

免责声明:此代码没有实际用途,仅用于教育目的。

tl;dr:大部分只是我尝试调试问题的结果,所以只有前 3 个 sn-ps 很重要。

这里是宏定义:

def tx[T](ds: GraphDatabaseService)(block: => T): Option[T] = 
  macro txmacros.blockTxImpl[T]

这里是实现:

def blockTxImpl[T: c.WeakTypeTag](c: whitebox.Context)(ds: c.Tree)(block: c.Tree):
    c.Tree = {
  import c.universe._

  q"""
    val tx = $ds.beginTx()
    val newRetVal = try {
      val retVal = {
        $block
      }
      tx.success()
      Option(retVal)
    } catch {
      case _ : Throwable =>
        tx.failure()
        None
    } finally {
      tx.close()
    }
    newRetVal
  """
}

这就是它的名称:

val nodePropK5 = tx(db) {
  // simplified for brevity
  val node = db.find(label, "key", 100).iterator().next()
  node.getProperty("k5", 300)
}

nodePropK5 should be (Some(200))

整个项目可以到https://github.com/cdshines/txMacro/找到(准备建一跑)。

此类调用失败并显示以下消息:

[error] symbol value node does not exist in MacroTest$$anonfun$3.apply$mcV$sp
[trace] Stack trace suppressed: run last core/test:compile for the full output.
[error] (core/test:compile) scala.reflect.internal.FatalError: symbol value node does not exist in MacroTest$$anonfun$3.apply$mcV$sp

但是,如果我将有问题的代码更改为

val nodePropK5 = tx(db) {
  db.findNodesByLabelAndProperty(label, "k4", 100).iterator().next().getProperty("k5", 300)
}

如预期的那样,返回值为Some(300)。添加不声明新变量(或使用node)的行不会破坏行为,而

val nodePropK5 = tx(db) {
  db.findNodesByLabelAndProperty(label, "k4", 100).iterator().next().getProperty("k5", 300)
  val x = 5
  x
}

产生相同的消息。

另一个奇怪的事情:如果我在宏扩展期间打印失败的block,我会得到以下代码:

{
  val tx = MacroTest.this.db.beginTx();
  val newRetVal = try {
    val retVal = {
      val node: org.neo4j.graphdb.Node = MacroTest.this.db.findNodesByLabelAndProperty(MacroTest.this.label, "k4", 100).iterator().next();
      node.getProperty("k5", 300)
    };
    tx.success();
    Option(retVal)
  } catch {
    case (_: Throwable) => {
      tx.failure();
      None
    }
  } finally tx.close();
  newRetVal
}

手动替换,效果很好。

我在这里缺少什么?我可以假设这是一个编译器错误吗?

【问题讨论】:

    标签: scala macros scala-macros


    【解决方案1】:

    当您看到此类错误时,首先要尝试对您在宏输出中“重用”的代码进行非类型检查。在这种情况下,替换以下内容:

    val retVal = {
      $block
    }
    

    与:

    val retVal = {
      ${ c.untypecheck(block) }
    }
    

    应该做的伎俩。

    请注意,在 2.10 中,untypecheck 的等效项为 resetAllAttrs / resetLocalAttrs。如果您搜索这些名称,您会发现很多关于您所看到问题的详细信息的讨论。

    【讨论】:

    • 对我来说还有一件有趣的事情需要思考:为什么注释宏在没有'untypechecking'的情况下工作?它是否与在这种情况下键入了 def 宏而没有注释宏的事实有某种关系?
    • 是的,def 宏的参数是类型检查的,而宏注解的参数不是。
    • 另外,关于反类型检查问题/解决方法的更多信息:github.com/scalamacros/macrology201/tree/part1
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-30
    • 2012-05-26
    相关资源
    最近更新 更多