2015-02-07 2 views
6

Следующий код:Типы, зависящие от пути - что не так в следующем коде?

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 
}  

отвергается компилятором 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 
       ^

Если объявление явного типа опущена, тип правильно Inferred , в соответствии с выходом из TypeR фазы:

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

проблема также исчезает, если F внутри связаны в Bar изменяется к типу, который не является членом Bar, т.е.

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

работает правильно.

Это ошибка? Или какое-то фундаментальное недоразумение с моей стороны? Или какая-то тайная функция?

ответ

2

не однозначный ответ, но некоторые наблюдения ...

Давайте сначала посмотрим, что делает работу:

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

поэтому компилятор теряет вас при использовании типа проекции для значения f. Если вы «исправить» эту проекцию, он также, кажется, работает:

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

Я долго боролся с 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 
} 

Наконец, вы можете также исправить Bar «s члена типа, передав его в качестве параметра типа:

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

, подобным образом, если зафиксировать тип уже в определении 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 
} 

Таким образом, в вашем первоначальном определении и применении с верхними границами кажется недостаточно. Возможно, вы можете доказать, что компилятор прав насчет его отказа, но я не знаю, как ...

+0

Спасибо, что вам интересно. Смешно, без этого объявления компилятор _infers_ типа 'x' как' f.T' сам, как упоминалось в вопросе. Кроме того, он позволяет использовать его как таковой в коде с помощью 'Foo' и' C'. Таким образом, единственная проблема заключается в явной декларации - отсюда и мое замешательство. –

Смежные вопросы