路径依赖类型 - 以下代码有什么问题?

Mar*_*Łoś 6 types scala path-dependent-type

以下代码:

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
}    
Run Code Online (Sandbox Code Playgroud)

被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
                  ^
Run Code Online (Sandbox Code Playgroud)

如果省略显式类型声明,则根据typer阶段的输出正确推断类型:

private[this] val x: C.this.f.T = C.this.f.x;
<stable> <accessor> def x: C.this.f.T = C.this.x
Run Code Online (Sandbox Code Playgroud)

如果F在绑定内部Bar更改为不是其成员的类型Bar,即,该问题也会消失

type F <: Foo { type T <: Foo }
Run Code Online (Sandbox Code Playgroud)

工作正常.

这是一个错误吗?或者我的一些根本误解?还是一些神秘的功能?

0__*_*0__ 2

不是一个明确的答案,但一些观察......

让我们首先看看有什么作用:

class C[B <: Foo](val f: B) {
  val x: f.T = f.x
}
Run Code Online (Sandbox Code Playgroud)

因此,当对 value 使用类型投影时,编译器会迷失你f。如果你“修复”这个投影,它似乎也有效:

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

我长期以来一直在与 F 边界类型作斗争,直到我让它们“水密”。类型参数与类型成员之间的某些因素使得前者能够发挥作用。例如:

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

class E[F <: FooRec[F]](val f: F) {
  val x: f.T = f.x
}
Run Code Online (Sandbox Code Playgroud)

最后,您还可以Bar通过将其作为类型参数传递来修复 的类型成员:

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

类似地,如果您修复 定义中已有的类型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
}
Run Code Online (Sandbox Code Playgroud)

因此,在您最初的定义和应用程序中,具有上限似乎还不够。也许你可以证明编译器的拒绝是正确的,但我不知道如何......