у меня есть
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
макрос белого ящика должен расширяться до 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
что объясняет, как возможна ошибка, но не объясняет, чем отличаются 2 B
. Я попытался переименовать B
в C
на случай, если один из них ссылается на B
пользователя Foo.foo
, но он по-прежнему показывает C
с двумя разными идентификаторами, хотя в программе есть только один C
.
РЕДАКТИРОВАТЬ 2: см. На этапе ввода Scala указано два варианта использования параметра типа отличаются. Здесь древовидный тип (с 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)
.
args
наmethod.paramLists.map(_.map(_.asTerm.name))
должно сработать, хотя я не уверен, что могу объяснить, почему на данный момент. - person Travis Brown   schedule 13.04.2016