Я думаю, что фундаментальное недоразумение, лежащее в основе всего вашего вопроса, заключается в том, что вы предполагаете, что конструкция:
trait / class ClassName {
type T = something
}
создает зависимый тип. Это не так. Если вы откроете подраздел 3.5.1 Эквивалентность раздела 3.5 «Отношения между типами» спецификации, вы можете увидеть, что:
- Если
t
определяется псевдонимом типа t = T
, то t
эквивалентно T
.
Вот почему в вашем первом примере, например, компилятор видит x1.Y
и x2.Y
и X#Y
как просто String
. Если вы замените все это просто String
, то не останется вопросов о том, почему этот код компилируется.
Точно так же в вашем третьем примере просто определите некоторые псевдонимы. Если вы замените эти псевдонимы их определениями, то снова станет ясно, почему этот код компилируется и дает сбой.
Ваш второй пример использует другую конструкцию
trait / class ClassName {
trait / class InnerName
}
Это конструкция, которая создает зависимый от пути тип, и, следовательно, код, который вы не собираетесь компилировать, на самом деле дает сбой. Насколько я понимаю, это единственный из ваших примеров, в котором действительно используются зависимые типы.
Также, если вы откроете статьи Tour of Scala Абстрактные члены типа и Внутренние классы , которые описывают первую и вторую конструкции, вы можете заметить, что только последняя (но не первая) !) упоминает "зависимые от пути типы".