免责声明:此代码不具有实际用途,仅用于教育目的。
tl; dr:大部分只是我试图调试问题的结果,所以只有前3个片段很重要。
这是宏定义:
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
}
其中,手动替换,效果很好。
我在这里缺少什么?我可以自由地假设这是一个编译器错误吗?
答案 0 :(得分:2)
当你看到这种错误时,首先要尝试的是在宏输出中“重复使用”的非类型检查代码。在这种情况下,替换以下内容:
val retVal = {
$block
}
使用:
val retVal = {
${ c.untypecheck(block) }
}
应该做的伎俩。
请注意,在2.10中,untypecheck
的等效值为resetAllAttrs
/ resetLocalAttrs
。如果你搜索这些名字,你会发现很多关于你所看到的问题细节的讨论。