这个def宏出了什么问题? [英] What is wrong with this def macro?
问题描述
免责声明:此代码不实际使用,仅用于教育目的.
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屋!