这个def宏出了什么问题? [英] What is wrong with this def macro?

查看:61
本文介绍了这个def宏出了什么问题?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

免责声明:此代码不实际使用,仅用于教育目的.

Disclaimer: this code is not of practical use and serves education purposes only.

tl; dr:大多数只是我尝试调试此问题的结果,因此仅前三个摘要很重要.

tl;dr: most of it is just a result of me trying to debug the issue, so only first 3 snippets matter.

这是宏定义:

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/中找到整个项目(已准备好运行).

The whole project can be found to https://github.com/cdshines/txMacro/ (ready to be built an run).

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

Such an invocation fails with the following message:

[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

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

If I, however, change the problematic code to

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

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

the return value is Some(300) as expected. Adding lines that don't declare new variables (or use node) doesn't break the behavior, while

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

产生相同的消息.

另一件事:如果在宏扩展过程中打印失败的 block ,我将得到以下代码:

Another peculiar thing: if I print the failing block during macro expansion, i get the following code:

{
  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
}

手动替换哪个效果很好.

Which, being manually substituted, works just fine.

我在这里想念什么?我可以自由地假设这是一个编译器错误吗?

What am I missing here? Am I free to assume that this is a compiler bug?

推荐答案

当您看到这种错误时,首先要尝试的是取消对宏输出中正在重用"的代码的类型检查.在这种情况下,请替换以下内容:

When you see this kind of error the first thing to try is un-typechecking code that you're "reusing" in your macro output. In this case replacing the following:

val retVal = {
  $block
}

使用:

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

应该做到这一点.

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

Note that in 2.10 the equivalent of untypecheck was resetAllAttrs / resetLocalAttrs. If you search for those names you'll find a lot of discussion of the details of the problem you're seeing.

这篇关于这个def宏出了什么问题?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆