2017-05-05 53 views
1

爲什麼下面的代碼不能編譯?帶有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 

它提供:

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]然後012編譯。
  • 所以這表明A[_<:SomeB]對於r3不夠具體。但爲什麼不呢?
  • 爲什麼A[_<:SomeB]不夠val r5: (A[_<:SomeB]) = (r3)但不是r9
+0

嗯,這似乎有點相關:http://stackoverflow.com/questions/28674486/existential-types-for-f-bounded-polymorphic-types-and-non-generic-subtypes – jhegedus

+0

看起來像另一個bug。你的第一個代碼片段可以用dotty/master編譯。 – OlivierBlanvillain

+0

嗯....奇怪...我應該開始使用dotty? :) – jhegedus

回答

1

首先,您的r4r5實際上是等效的。要聲明類型的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一(Existential types for F-Bounded Polymorphic types and non-generic subtypes?),和相同的解決方案適用即給編譯器一些幫助被明確指定的Tuple1的Param類型:

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

或者給r3一個更具體的類型:

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

而且同樣適用於r6/Tuple2