2017-05-05 2 views
1

Pourquoi le code ci-dessous ne compile pas?erreur de compilation étrange avec des existences scala avec polymorphisme borné f

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 

Il donne:

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) 

EDIT:

est ici un apparenté, autonome extrait de code:

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 
  • Il semble que r4 doit avoir le type de A[C] puis r10 compile. Cela suggère donc que A[_<:SomeB] pour r3 n'est pas assez spécifique. Mais pourquoi pas ?
  • Aussi pourquoi est A[_<:SomeB] assez pour val r5: (A[_<:SomeB]) = (r3) mais pas pour r9?
+0

hmmm, cela semble être un peu pertinent: http://stackoverflow.com/questions/28674486/existential-types-for-f-bounded-polymorphic-types-and-non-generic-subtypes – jhegedus

+0

On dirait un autre bug. Votre premier extrait compile bien avec dotty/master. – OlivierBlanvillain

+0

Hmm .... étrange ... devrais-je commencer à utiliser dotty? :) – jhegedus

Répondre

1

Tout d'abord, vos r4 et r5 sont réellement équivalents. Pour déclarer un val de type Tuple1 vous devez être explicite:

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

Et vous découvrirez alors qu'il échoue aussi avec la même erreur.

En 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) 
    ^

Vous voyez que, compte tenu dactylographiée existentielle r3 le compilateur déduit tuple comme (A[_$1],) forSome { type _$1 }.

Cette affaire est en effet similaire à celui de @jhegedus (Existential types for F-Bounded Polymorphic types and non-generic subtypes?), et la même solution s'applique le compilateur donne par exemple une aide en spécifier explicitement le type PARAM Tuple1:

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

Ou donner un r3 type plus spécifique:

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

Et la même chose pour r6/Tuple2