Странная ошибка компиляции с существующими скалами с ограниченным полиморфизмом

Почему приведенный ниже код не компилируется?

  trait B[T <: B[T]]
  case class A[T <: B[T]](t: T)

  class C() extends B[C]
  val c: C = new C()

  val r2: A[_]         = A(c)     //compiles
  val r3: A[_]         = A(c)     //compiles fine
  val r4: A[_]         = r3       //compiles fine
  val r5: (A[_])       = (r3)     //compiles fine
  val r6: (A[_], A[_]) = (r3, r3) // does not compile, strange

Это дает:

Error:(68, 22) type arguments [_$7] do not conform to class A's type parameter bounds [T <: _experiment.akka_persistence.Test2.B[T]]
  val r6:(A[_],A[_])=(r3,r3)

РЕДАКТИРОВАТЬ:

Вот связанный фрагмент кода:

  import scala.language.existentials


  trait B[T <: B[T]]
  case class A[T <: B[T]](t: T)

  class C() extends B[C]
  val c: C = new C()
  type SomeB = T forSome { type T <: B[T] }
  val r3: A[_<:SomeB]         = A(c)     //compiles fine
  val r4: A[C]         = A(c)     //compiles fine
  val r5: (A[_<:SomeB])       = (r3)     //compiles fine
  val r6:((_<:SomeB),((_<:SomeB))) = (c,c)  // compiles fine
  val r7:(A[_<:SomeB],((_<:SomeB))) = (A(c),c)  // compiles fine
  val r8:(A[_<:SomeB],(A[_<:SomeB])) = (A(c),A(c))  // compiles fine
  val r10:(A[_<:SomeB],(A[_<:SomeB])) = (A(c),r4)  // compiles fine
  val r9:(A[_<:SomeB],(A[_<:SomeB])) = (A(c),r3)  // does not compile
  • Кажется, что r4 должен иметь тип A[C] а потом r10 компилирует.
  • Так что это говорит о том, что A[_<:SomeB] за r3 не достаточно конкретен. Но почему нет?
  • И почему A[_<:SomeB] достаточно для val r5: (A[_<:SomeB]) = (r3) но не для r9?

1 ответ

Прежде всего, ваш r4 а также r5 на самом деле эквивалентны. Объявить val типа Tuple1 Вы должны быть явными:

val r5: Tuple1[A[_]] = Tuple1(r3)

И тогда вы обнаружите, что он также не работает с той же ошибкой.

В REPL:

scala> Tuple1(r3)
<console>:24: warning: inferred existential type (A[_$1],) forSome { type _$1 }, which cannot be expressed by wildcards,  should be enabled
by making the implicit value scala.language.existentials visible.
This can be achieved by adding the import clause 'import scala.language.existentials'
or by setting the compiler option -language:existentials.
See the Scaladoc for value scala.language.existentials for a discussion
why the feature should be explicitly enabled.
       Tuple1(r3)
             ^
<console>:24: error: type arguments [_$1] do not conform to class A's type parameter bounds [T <: B[T]]
       Tuple1(r3)
       ^

Вы видите, что данный экзистенциально типизирован r3 компилятор выводит кортеж как (A[_$1],) forSome { type _$1 },

Этот случай действительно аналогичен случаю из @jhegedus ( экзистенциальные типы для F-ограниченных полиморфных типов и неуниверсальных подтипов?), И применяется то же решение, т. Е. Дать компилятору некоторую помощь, явно указав параметр типа Tuple1:

val r5 = Tuple1[A[_]](r3)

Или дать r3 более конкретный тип:

val r3: A[C] = A(c)
val r5: Tuple1[A[_]] = Tuple1(r3)

И то же самое касается r6 / Tuple2

Другие вопросы по тегам