与宏的奇怪类型不匹配:找到:具有基础类型A的单例类型,必需:A [英] Strange type mismatch with a macro: found: singleton type with underlying type A, required: A
问题描述
我有
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
所显示的内容.问题在于它无法编译并显示以下错误:
where superCall
whitebox macro should expand to super.foo[B](x, y)
, and that's what -Ymacro-debug-lite
shows. The problem is that it fails to compile with following error:
[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
时发现它,那应该不是一个错误.甚至更陌生,如果我用扩展名super.foo[B](x, y)
替换superCall
,错误就消失了!
Which makes no sense to me: y.type
is more narrow than B
, so if it's found when B
is required it shouldn't be an error. Even stranger, if I replace superCall
with its expansion super.foo[B](x, y)
, the error goes away!
superCall
实现(通过删除无关条件而略有简化,您可以看到完整版本
superCall
implementation (slightly simplified by removing irrelevant conditionals, you can see the full version 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
的B
,但是即使程序中只有一个C
,它仍然显示带有2个不同ID的C
.
which explains how the error is possible, but doesn't explain how 2 B
's are different. I tried renaming B
to C
in case one of them referred to Foo.foo
's B
, but it still shows C
with 2 different ids even though there is only one C
in the program.
请参见 Scala Typer阶段说类型参数的两种用法是不同的.树型打字机在这里生成(用super.foo[B](x, y)
代替superCall
)是
EDIT 2: see Scala typer stage says two uses of type parameter are different. The tree typer produces here (with super.foo[B](x, y)
instead of superCall
) is
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)
.
推荐答案
尝试通过类型参数的名称来回填类型信息使您的生活更加艰难-简单的名称是一种非常有损的交换媒介-但为什么要提供类型参数呢?在没有相反证据的情况下,您应该写出q"super.$methodName(...$args)"
,他们会被推断出来.
You're making your life harder by trying to funnel your type information back through the names of type parameters - simple names are a very lossy medium of exchange - but why are you supplying the type arguments at all? In the absence of evidence to the contrary, you should write q"super.$methodName(...$args)"
and they will be inferred.
这篇关于与宏的奇怪类型不匹配:找到:具有基础类型A的单例类型,必需:A的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!