问题
I'm writing a macro called assign
whose job is to assign values from members of one instance to another with a particular prefix added to the name of the member. For example, I have an instance with members named my_prefix_data, my_prefix_rden, ...
and I want to assign values to these members from another instance with corresponding members named data, rden, ...
. I've made a prototype version of the macro that just handles the my_prefix_data <- data
assignment. The assignments are to be made using a special method :=
, because this macro is ultimately going to be applied to Chisel code.
Unfortunately, it's not working. The macro implementation looks like this
package my_macros
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
object Macro {
def assign(foo: Any, prefix: String, bundle: Any): Unit = macro Impl.assign
}
class Impl(val c: blackbox.Context) {
def assign(
foo: c.Tree, // Foo
prefix: c.Tree, // string
bundle: c.Tree // bundle
): c.Tree = {
import c.universe._
val Literal(Constant(p: String)) = prefix
Apply(
Select(
Select(
foo,
TermName(s"${p}_data")
),
TermName(":=")
),
List(
Select(
bundle,
TermName("data")
)
)
)
}
}
I have a failing test case set up like this
package my_macros
import org.scalatest._
class MacroSpec extends FlatSpec {
behavior of "Macro"
it should "access parent methods" in {
class Data(initial: Int) {
var value: Int = initial
def :=(other: Data): Unit = {
value += other.value
}
}
class UInt(initial: Int) extends Data(initial) {}
class FooBundle {
val my_prefix_data = new UInt(1)
}
class BarBundle {
val data = new UInt(2)
}
val foo = new FooBundle
val bar = new BarBundle
Macro.assign(foo, "my_prefix", bar)
assert(foo.my_prefix_data.value == bar.data.value)
}
}
It's failing with error
[error] value := is not a member of UInt
[error] Expression does not convert to assignment because receiver is not assignable.
[error] Macro.assign(foo, "my_prefix", bar)
[error] ^
Why does the Select
AST node fail to find the inherited :=
from UInt
's parent class Data
?
回答1:
Inheritance is irrelevant. For
class UInt(initial: Int) {
var value: Int = initial
def :=(other: UInt): Unit = {
value += other.value
}
}
behavior is the same.
Replace TermName(":=")
with TermName("$colon$eq")
or with TermName(":=").encodedName
or replace manually built tree
val Literal(Constant(p: String)) = prefix
Apply(
Select(
Select(
foo,
TermName(s"${p}_data")
),
TermName(":=")
),
List(
Select(
bundle,
TermName("data")
)
)
)
with quasiquote
val q"${p: String}" = prefix
val pdata = TermName(s"${p}_data")
q"$foo.$pdata.:=($bundle.data)"
Then the code compiles.
来源:https://stackoverflow.com/questions/61002619/scala-ast-select-node-cant-find-members-inherited-from-parent