2012-09-26 17 views
17

最近、私は奇妙な(私に)コンパイラのエラーメッセージを見つけました。私が書く場合クラスAには1つの型パラメータがありますが、タイプBには1つがあります

process[MyFoo, MyFoo, List](new MyFoo) // fine 

::私は明示的に型パラメータを記述する必要がprocessメソッドを呼び出したい場合は、今すぐ

trait Foo { 
    type Res <: Foo 
    type Bar[X <: Res] 
} 

class MyFoo extends Foo { 
    override type Res = MyFoo 
    override type Bar[X <: Res] = List[X] 
} 

type FOO[F <: Foo, R <: Foo, B[_ <: R]] = F { type Res = R; 
               type Bar[X <: R] = B[X] } 

def process[F <: Foo, R <: Foo, B[_ <: R]](f: FOO[F, R, B]) {} 

:次のコードを考えてみましょう

process(new MyFoo) 

をか

process((new MyFoo): FOO[MyFoo, MyFoo, List]) 

私は、次のエラーメッセージを取得:型引数の

推論種類(MYFOO、MYFOO、リストを[X])型パラメータの予想される種類(タイプF、タイプR、タイプBに準拠していません)。クラスリストは、1種類のパラメータがありますが、私は明示的に記述がタイプBは、(なぜなタイプを推測することができ、コンパイラisn't 1

を持っている:リスト[X] 'sの型パラメータは、タイプBの期待パラメータと一致しませんそれらは呼び出しパラメータで)?そして、それはどういう意味ですか?class List has one type parameter, but type B has one?何かがありますが、もう1つはでもです。それで彼らは一緒には合わないのですか?

+0

私はscala 2.9.3-20120917-121530-db16547873を使用しています –

答えて

2

に与えられた特定のタイプと互換性があるかどうか確認してください、そのようなタイプが存在しませんScalaコンパイラでは、ソースが問題の内容を理解するのに役立ちます。私はScalaコンパイラに貢献したことは一度もありませんが、ソースを非常に読みやすくして、私はすでにそれについて調べています。

型推論を行うクラスはscala.tools.nsctypechecker.Inferです。これはScalaコンパイラのソースでエラーの一部を調べるだけで見つけることができます。次の断片を見つける:checkKindBounds(tparams, targs, pre, owner)は、これらのエラーを返す理由

/** error if arguments not within bounds. */ 
    def checkBounds(pos: Position, pre: Type, owner: Symbol, 
        tparams: List[Symbol], targs: List[Type], prefix: String) = { 
     //@M validate variances & bounds of targs wrt variances & bounds of tparams 
     //@M TODO: better place to check this? 
     //@M TODO: errors for getters & setters are reported separately 
     val kindErrors = checkKindBounds(tparams, targs, pre, owner) 

     if(!kindErrors.isEmpty) { 
     error(pos, 
      prefix + "kinds of the type arguments " + targs.mkString("(", ",", ")") + 
      " do not conform to the expected kinds of the type parameters "+ tparams.mkString("(", ",", ")") + tparams.head.locationString+ "." + 
      kindErrors.toList.mkString("\n", ", ", "")) 
     } 

は、だから今の点が理解されます。

:あなたはメソッド呼び出しのチェーンを下る場合は、checkKindBoundsあなたは問題がcheckKindBoundsHKの内側に、ライン5784で、高kindedタイプの境界を確認するに接続されて表示されます別の方法

val errors = checkKindBounds0(tparams, targs, pre, owner, true) 

を呼び出すことがわかります

hkargs$1 = {[email protected]}"List()" 
arg$1 = {[email protected]}"class List" 
param$1 = {[email protected]}"type B" 
paramowner$1 = {[email protected]}"method process" 
underHKParams$1 = {[email protected]}"List(type R)" 
withHKArgs$1 = {[email protected]}"List()" 
exceptionResult12 = null 
hkparams$1 = {[email protected]}"List(type R)" 

1つの高いkindedのparam、タイプRがあるようなので、それは表示されませんが、提供は一切あり:テストに合格していない

if (!sameLength(hkargs, hkparams)) { 
     if (arg == AnyClass || arg == NothingClass) (Nil, Nil, Nil) // Any and Nothing are kind-overloaded 
     else {error = true; (List((arg, param)), Nil, Nil) } // shortcut: always set error, whether explainTypesOrNot 
     } 

、私のデバッガであること表示されますそれのためのd値。

あなたが実際にcheckKindBoundsに戻すに行く場合は、あなたがスニペットの後にすることを参照してください。

val (arityMismatches, varianceMismatches, stricterBounds) = (
     // NOTE: *not* targ.typeSymbol, which normalizes 
     checkKindBoundsHK(tparamsHO, targ.typeSymbolDirect, tparam, tparam.owner, tparam.typeParams, tparamsHO) 
    ) 

arityMismatchesは、タプルのリストが含まれているB.そして今、あなたはまた、エラーメッセージが間違っていることがわかります。型引数の

推論種類(MYFOO、MYFOO、リスト[X])は は、型パラメータ(タイプF、タイプ R、タイプB)の予想される種類に適合していません。クラスリストは1種類のパラメータを持っていますが、あなたは、次の上の行5859にブレークポイントを置いた場合、タイプBは、実際にはZERO

を持っている:リスト[X] 'sの型パラメータは、タイプBの予想 パラメータと一致しません

checkKindBoundsHK(tparamsHO, targ.typeSymbolDirect, tparam, tparam.owner, tparam.typeParams, tparamsHO) 

は、あなたが見ることができる呼び出すこと

tparam = {[email protected]}"type B" 
targ = {[email protected]}"List[X]" 

結論:

何らかの理由で、あなたのような複雑な上位の型を扱う場合、Scalaコンパイラの推論には限界があります。コンパイラチームにバグを送ろうとしているかもしれません。

0

私はScalaの型推論の正確な動作をあいまいに理解しているので、この考え方を決定的な答えとはみなさないでください。

  1. タイプ推論は、一度に複数のタイプを推測することに問題があります。

  2. あなたがに変換FOOの定義における実存の種類、使用:我々は見ている場合、これはMYFOO

関連する問題