Как вывести правильный тип параметра из типа проекции?

У меня есть некоторые проблемы с Scala, чтобы вывести правильный тип из проекции типа.

Рассмотрим следующее:

trait Foo {
  type X
}

trait Bar extends Foo {
  type X = String
}

def baz[F <: Foo](x: F#X): Unit = ???

Затем выполняются следующие компилирования:

val x: Foo#X = ???    
baz(x)

Но следующее не будет компилироваться:

val x: Bar#X = ???    
baz(x)

Scala видит "базовый тип String" для x, но потерял информацию о том, что x является Bar#X. Он отлично работает, если я аннотирую тип:

baz[Bar](x)

Есть ли способ сделать Scala вывести правильный параметр типа для baz?
Если нет, то каков общий ответ, который делает невозможным?

Ответ 1

Программа компилируется путем добавления этого неявного преобразования в контексте:

implicit def f(x: Bar#X): Foo#X = x

Поскольку это неявное преобразование является правильным для любого F <: Foo, мне интересно, почему компилятор этого не делает сам по себе.

Ответ 2

Вы также можете:

trait Foo {
    type X
}
trait Bar extends Foo {
    type X = String
}
class BarImpl extends Bar{
  def getX:X="hi"
}
def baz[F <: Foo, T <: F#X](clz:F, x: T): Unit = { println("baz worked!")}
val bi = new BarImpl
val x: Bar#X = bi.getX
baz(bi,x)

а

def baz2[F <: Foo, T <: F#X](x: T): Unit = { println("baz2 failed!")}
baz2(x)

сбой:

test.scala:22: error: inferred type arguments [Nothing,java.lang.String] do not conform to method baz2 type parameter bounds [F <: this.Foo,T <: F#X]
baz2(x)
^
one error found

Я думаю, в основном, F <: Foo сообщает компилятору, что F должен быть подтипом Foo, но когда он получает X, он не знает, из какого класса возникает ваш конкретный X. Ваш X является просто строкой и не поддерживает информацию, указывающую на панель.

Обратите внимание, что:

def baz3[F<: Foo](x : F#X) = {println("baz3 worked!")}
baz3[Bar]("hi")

Также работает. Тот факт, что вы определили val x: Bar # X =??? просто означает, что??? ограничивается тем, что Bar # X может оказаться во время компиляции... компилятор знает, что Bar # X является String, поэтому тип x является просто строкой, отличной от любой другой строки.