与宏的奇怪类型不匹配:找到:具有基础类型A的单例类型,必需:A [英] Strange type mismatch with a macro: found: singleton type with underlying type A, required: A

查看:101
本文介绍了与宏的奇怪类型不匹配:找到:具有基础类型A的单例类型,必需: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.typeB更窄,因此如果在需要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.fooB,但是即使程序中只有一个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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆