4

我有

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
}

superCallwhitebox 宏应该扩展到的地方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实现(通过删除不相关的条件略微简化,您可以在 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

这解释了错误是如何可能的,但没有解释2B不同之处。我尝试重命名BC,以防其中一个引用Foo.foo's ,但即使程序中只有一个B,它仍然显示有 2 个不同的 id 。CC

编辑 2:见Scala typer stage 说 type parameter 的两种用途是不同的。此处生成的树类型器(使用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扩展到Bar#26820.super.foo#26823[B#26833](x#26836, y#26837)了。

4

1 回答 1

0

试图通过类型参数的名称将类型信息汇集回来,这让你的生活变得更加艰难——简单的名称是一种非常有损的交换媒介——但是你为什么要提供类型参数呢?在没有相反的证据的情况下,你应该写q"super.$methodName(...$args)",他们会被推断出来。

于 2016-04-15T15:33:10.090 回答