简体   繁体   English

与路径有关的类型-以下代码有什么问题?

[英]Path-dependent types - what's wrong with the following code?

The following code: 如下代码:

trait Foo {
  type T
  val x: T
}

trait Bar {
  type F <: Foo { type T <: F }
}

class C[B <: Bar](val f: B#F) {
  val x: f.T = f.x
}    

is rejected by the Scala compiler (2.11.5) with the following error message: 被Scala编译器(2.11.5)拒绝并显示以下错误消息:

error: type mismatch;
found   : C.this.f.x.type (with underlying type C.this.f.T)
required: this.T
      val x: f.T = f.x
                  ^

If the explicit type declaration is omitted, the type is correctly inferred, according to the output from typer phase: 如果省略显式类型声明,则根据typer阶段的输出正确推断类型:

private[this] val x: C.this.f.T = C.this.f.x;
<stable> <accessor> def x: C.this.f.T = C.this.x

The problem also disappears if F inside the bound in Bar is changed to a type that is not a member of Bar , ie 如果将Bar内边界中的F更改为Bar的成员以外的类型,该问题也将消失。

type F <: Foo { type T <: Foo }

works correctly. 正常工作。

Is it a bug? 是虫子吗? Or some fundamental misunderstanding on my part? 还是我有一些根本性的误解? Or some arcane feature? 或某些奥秘功能?

Not a definite answer, but some observations... 不是肯定的答案,而是一些观察...

Let's first see what does work: 首先让我们看看有效的方法:

class C[B <: Foo](val f: B) {
  val x: f.T = f.x
}

so the compiler loses you when use a type projection for value f . 因此,当对值f使用类型投影时,编译器会迷失您。 If you "fix" that projection, it also seems to work: 如果您“修复”该投影,它似乎也可以工作:

class D[B <: Bar](val f: B#F) {
  val g: Foo = f
  val x: g.T = g.x
}

I have long struggled with F-bounded types until I got them "water-tight". 我长期以来一直在使用F边界类型,直到获得“水密”。 There is something about type parameters versus type members that makes the former work. 关于类型参数与类型成员的某些事情使前者起作用。 For example: 例如:

trait FooRec[F <: FooRec[F]] extends Foo {
  type T = F
}

class E[F <: FooRec[F]](val f: F) {
  val x: f.T = f.x
}

Finally, you could also fix Bar 's type member by passing it in as a type parameter: 最后,您还可以通过将Bar的类型成员作为类型参数传递来修复它:

class G[F1 <: Foo { type T = F1 }, B <: Bar { type F = F1 }](val f: B#F) {
  val x: f.T = f.x
}

Similarily, if you fix the type already in the definition of Bar , it works: 同样,如果您修复了Bar定义中已经存在的类型,则可以使用:

trait Baz {
  type F <: Foo { type T = F }  // stable recursion
}

class H[B <: Baz](val f: B#F) {
  val x: f.T = f.x
}

So in your original definition and application having upper bounds seems not enough. 因此,在您的原始定义和应用程序中,拥有上限似乎还不够。 Probably you can proof that the compiler is right about its rejection, but I don't know how... 也许您可以证明编译器在拒绝方面是正确的,但我不知道如何...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM