我有
class Foo[A] {
def foo[B](x: A, y: B) = y
}
class Bar[A] extends Foo[A] {
override def foo[B](x: A, y: B) = superCall
}
其中superCall
whitebox宏应扩展为super.foo[B](x, y)
,这就是-Ymacro-debug-lite
所显示的内容。问题是它无法编译并出现以下错误:
[error] /home/aromanov/IdeaProjects/scala-dry/src/test/scala/com/github/alexeyr/scaladry/SuperTests.scala:80: type mismatch;
[error] found : y.type (with underlying type B)
[error] required: B
[error] override def foo[B](x: A, y: B) = superCall
[error] ^
这对我没有意义:y.type
比B
更窄,所以如果在需要B
时找到它,则不应该是错误。更奇怪的是,如果我用其扩展superCall
替换super.foo[B](x, y)
,错误就会消失!
superCall
实施(通过删除不相关的条件略有简化,您可以看到完整版at Github):
def superCall: Tree = {
val method = c.internal.enclosingOwner.asMethod
val args = method.paramLists.map(_.map(sym => c.Expr(q"$sym")))
val typeParams = method.typeParams.map(_.asType.name)
q"super.${method.name.toTermName}[..$typeParams](...$args)"
}
编辑:添加-uniqid
节目
[error] found : y#26847.type (with underlying type B#26833)
[error] required: B#26834
[error] override def foo[B](x: A, y: B) = superCall
[error] ^
[error] one error found
解释了错误的可能性,但没有解释 2 B
的不同之处。我尝试将B
重命名为C
,以防其中一个引用Foo.foo
的{{1}},但它仍显示B
有两个不同的ID,即使有程序中只有一个C
。
编辑2:见Scala typer stage says two uses of type parameter are different。这里生成的树形成器(C
而不是super.foo[B](x, y)
)是
superCall
所以似乎class Foo#26818[A#26819] extends scala#22.AnyRef#2757 {
def <init>#26822(): Foo#26818[A#26819] = {
Foo#26818.super.<init>#3104();
()
};
def foo#26823[B#26824](x#26827: A#26819, y#26828: B#26825): B#26824 = y#26828
};
class Bar#26820[A#26821] extends Foo#26818[A#26821] {
def <init>#26831(): Bar#26820[A#26821] = {
Bar#26820.super.<init>#26822();
()
};
override def foo#26832[B#26833](x#26836: A#26821, y#26837: B#26834): B#26833 = Bar#26820.super.foo#26823[B#26834](x#26836, y#26837)
};
会扩展为superCall
。
答案 0 :(得分:0)
你试图通过类型参数的名称来回输类型信息,这会让你的生活更加艰难 - 简单的名字是一种非常有损的交换媒介 - 但你为什么要提供类型参数呢?如果没有相反的证据,你应该写q"super.$methodName(...$args)"
并推断它们。