Scala コンパイラに目を向けると、ソースが問題の原因を理解するのに役立つ可能性があります。私は Scala コンパイラーに貢献したことはありませんが、ソースは非常に読みやすく、それについては既に調査済みです。
型推論を担当するクラスscala.tools.nsctypechecker.Infer
は、エラーの一部について Scala コンパイラ ソースを調べるだけで見つけることができます。次のフラグメントが見つかります。
/** 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(tparams, targs, pre, owner)
これらのエラーが返される理由を理解することです。メソッド呼び出しチェーンをたどると、checkKindBounds が別のメソッドを呼び出していることがわかります。
val errors = checkKindBounds0(tparams, targs, pre, owner, true)
checkKindBoundsHK 内の 5784 行目で、問題が高次型の境界のチェックに関連していることがわかります。
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
}
テストに合格しませんでした。デバッガーでは次のように表示されます。
hkargs$1 = {scala.collection.immutable.Nil$@2541}"List()"
arg$1 = {scala.tools.nsc.symtab.Symbols$ClassSymbol@2689}"class List"
param$1 = {scala.tools.nsc.symtab.Symbols$TypeSymbol@2557}"type B"
paramowner$1 = {scala.tools.nsc.symtab.Symbols$MethodSymbol@2692}"method process"
underHKParams$1 = {scala.collection.immutable.$colon$colon@2688}"List(type R)"
withHKArgs$1 = {scala.collection.immutable.Nil$@2541}"List()"
exceptionResult12 = null
hkparams$1 = {scala.collection.immutable.$colon$colon@2688}"List(type R)"
そのため、タイプ R という上位の種類のパラメーターが 1 つあるように見えますが、その値は提供されていません。
実際に 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、List[X]) は、型パラメーターの予想される種類 (型 F、型 R、型 B) に準拠していません。List[X] の型パラメーターは、型 B の予期されるパラメーターと一致しません: クラス List には 1 つの型パラメーターがありますが、型 B には0があります
実際、次の呼び出しで 5859 行目にブレークポイントを設定すると、
checkKindBoundsHK(tparamsHO, targ.typeSymbolDirect, tparam, tparam.owner, tparam.typeParams, tparamsHO)
あなたはそれを見ることができます
tparam = {scala.tools.nsc.symtab.Symbols$TypeSymbol@2472}"type B"
targ = {scala.tools.nsc.symtab.Types$UniqueTypeRef@2473}"List[X]"
結論:
何らかの理由で、あなたのような複雑な高カインド型を扱う場合、Scala コンパイラーの推論は制限されます。それがどこから来たのかはわかりません。バグをコンパイラ チームに送りたいと思うかもしれません。