我正在尝试编写一个编译器插件,它将在 Scala 的特征中注入对基类方法的调用。对于以下输入源:
class Component {
def valCallback[T](ref: T, name: String): T = ???
}
trait MyTrait {
this: Component =>
val v = 5
}
我希望转换结果看起来像:
trait MyTrait {
this: Component =>
val v = valCallback(5, "v")
}
这是我到目前为止所得到的:
object ValCallbackTransformer extends Transformer {
override def transform(tree: global.Tree): global.Tree = {
val transformed = super.transform(tree)
transformed match {
case cd: ClassDef if cd.mods.hasFlag(Flag.TRAIT) =>
// ... check of self type omitted ...
val clazz = cd.impl.self.tpt.tpe.parents.find(_.toString == "Component").get.typeSymbol
val func = clazz.tpe.members.find(_.name.toString == "valCallback").get
val body = cd.impl.body.map {
case vd: ValDef if !vd.mods.isParamAccessor && vd.rhs.nonEmpty =>
val lit = Literal(Constant(vd.getterName.toString))
val thiz = This(clazz)
val sel = Select(thiz, func)
val appl = Apply(sel, List(vd.rhs, lit))
thiz.tpe = clazz.tpe
sel.tpe = func.tpe
appl.tpe = definitions.UnitTpe
lit.setType(definitions.StringTpe)
treeCopy.ValDef(vd, vd.mods, vd.name, vd.tpt, appl)
case e => e
}
val impl = treeCopy.Template(cd.impl, cd.impl.parents, cd.impl.self, body)
treeCopy.ClassDef(cd, cd.mods, cd.name, cd.tparams, impl)
case other => transformed
}
}
}
但是,编译器会抱怨以下内容:
Internal error: unable to find the outer accessor symbol of trait MyTrait
[error] val v = 5
什么是特征的“外部访问器”?为什么编译器找不到它?我应该如何正确构造Apply
?
:我设法让它工作(参见发布的答案),但是有点令人困惑,为什么我必须从特征中调用 this 指针上的方法。
Select
与
This(<trait type>)
的方法。但是,由于该函数本身不存在于特征类中,因此我需要在 self 类型中单独找到它。工作版本:val clazz = cd.impl.symbol.owner
val valCallbackClazz = cd.impl.self.tpt.tpe.parents.find(_.toString == "Component").get.typeSymbol
val func = valCallbackClazz.tpe.members.find(_.name.toString == "valCallback").get
val body = cd.impl.body.map {
// ....
val thiz = This(clazz)
val sel = Select(thiz, func)
// ...
}