宏扩展包含自由变量

时间:2019-07-10 19:31:47

标签: scala scala-macros

我的代码编译出现以下错误:Macro expansion contains free term variable Hello ... 我已将其简化为最小的示例:

class Hello(val hi: String) {
  val xx = reify(hi)
  var yy = q""
}

def setYYImpl(c: Context)(hExpr: c.Expr[Hello]): c.Expr[Hello] = {
  import c.universe._
  val hello = c.eval(c.Expr[Hello](c.untypecheck(hExpr.tree.duplicate)))
  val xxVal = c.internal.createImporter(u).importTree(hello.xx.tree)
  c.Expr(q"""{val h = new Hello("HO"); h.yy=$xxVal; h}""") // it should set `h.yy` to Tree:"HO"
}

def setYY(hExpr: Hello): Hello = macro setYYImpl


setYY(new Hello("HI"))

在检查了类似的问题后:Can this free-term-variable error (produced at macro expansion) be avoided?

我已经得出结论,问题是reify(hi),它涉及编译时间值Hello.hi

是否可以解决此问题? reify(hi)返回Expr Hello.hi,我可以以某种方式删除Hello.前缀吗?

1 个答案:

答案 0 :(得分:0)

尝试更换

val xx = reify(hi)

使用

val xx = Literal(Constant(hi))

即手动构建树(和 .importTree(hello.xx.tree).importTree(hello.xx)

(如果仅在您的示例中为Literal(Constant...,而在实际用例中为更复杂的树,则无论如何都应尝试手动构建它,而不要使用reify。)

然后您将遇到其他错误

Error: type mismatch;
 found   : String("HI")
 required: reflect.runtime.universe.Tree
  setYY(new Hello("HI"))

因为您的宏返回了

Expr[Hello]({
  val h = new Hello("HO");
  h.yy = "HI"; // h.yy is q"" i.e. Tree, "HI" is String
  h
})