抽象类型 + 自身类型 + 类型覆盖,以及错误 "Value xxx is not a member of Component.this.T"

Abstract types + self types + type overriding, and error "Value xxx is not a member of Component.this.T"

错误说明如下:

trait Base { type T }

trait Component { self: Base =>
  override type T <: MyT

  val factory: Factory 

  trait Factory { def get_t: T }

  trait MyT { def xxx: Unit }

  class User {
    val t: T = factory.get_t

    def yyy = t.xxx
  }
}

trait ComponentImpl { self: Component => 
  type T = TImpl

  class TImpl extends MyT {
    def xxx = println("xxx")
  }

  val factory = new Factory {
    def get_t: T = new TImpl
  }
}

我收到错误:

<console>:26: error: value xxx is not a member of Component.this.T
       def yyy = t.xxx

由于有些冗余,我还post @slouc 和@Kolmar 建议的最小示例

trait Base { type T }

trait MyT { def xxx: Unit }

trait Component { self: Base =>
  override type T <: MyT
  val t: T
  def yyy = t.xxx // error
} 

看来我无法利用约束给出的增量、部分知识。

我的问题不是关于方法,而是我想了解错误背后的原因。

为了提供更多上下文,我还要补充一点,我在尝试将继承关系转换为两个组件之间基于自身类型的关系时遇到了这个问题。

使用自我类型注释,您基本上是在告诉编译器自我引用具有不同的类型

self: Base

如果您要对任何普通表达式执行此操作,self 现在唯一的类型是 Base。不知何故,类型注释被作为一种特殊情况处理,并保持其原始类型,我们实际上得到的类型似乎是

self: Base with Component

现在,不知何故,如果你参考 Component.this 它似乎在覆盖类型成员的情况下丢失了这个信息(或者覆盖可能只是错误的方式,但我看不出任何解释这是不是错误)

现在,如果您真的注释了这种类型,问题就会消失:

trait Component { self: Base with Component => ... }

这也清楚地表明这是一个错误,因为它工作正常:

trait Component { self: Base =>
  val v:  Base with Component = self
}

这实际上是一个已知错误:

https://issues.scala-lang.org/browse/SI-7255?jql=text%20~%20%22override%20self%20type%20abstract%22

有趣的问题。这是一个简化的例子:

trait Base { type T }

trait MyT { def xxx: Unit }

trait Component { self: Base =>
  override type T <: MyT
  val t: T
  def yyy = t.xxx // error
}

这里注意三件事:

1.Changing 对继承的自类型注释使一切顺利:

trait Component extends Base {
  override type T <: MyT
  val t: T
  def yyy = t.xxx
}

2.Overriding方法自类型没有问题:

trait Base { def foo }

trait Component { self: Base =>
  override def foo = println("foo")
}

3.If 我们不是缩小类型 T,而是将其具体化,然后压倒一切:

trait Base { type T }

trait Component { self: Base =>
  override type T = List[Int]
  val t: T
  def yyy = t.reverse
}

所以,我对这个问题的表述是 - 为什么在继承的情况下所有三种情况都工作得很好(1. 覆盖方法,2. 通过缩小覆盖抽象类型成员,3. 通过缩小覆盖抽象类型成员使它具体化),但如果是自我类型,第二种情况是有问题的,而其他两个工作正常?

考虑编辑您的问题(删除 ComponentImplFactory 等)以简化其他读者的问题。