Jeśli spojrzymy na kompilator Scala, źródła mogą pomóc nam zrozumieć, na czym polega problem. Nigdy nie brałem udziału w kompilacji Scali, ale znalazłem źródła bardzo czytelne i już to zbadałem.
Klasa odpowiedzialna za wnioskowanie o typ to scala.tools.nsctypechecker.Infer
, którą można znaleźć po prostu patrząc w źródłach kompilatora Scala jako część błędu. Dowiesz się następujący fragment:
/** 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", ", ", ""))
}
Więc teraz punktem jest zrozumienie, dlaczego checkKindBounds(tparams, targs, pre, owner)
zwraca te błędy.Jeśli pójdziesz w dół łańcucha metoda połączenia, widać, że checkKindBounds wywołać inną metodę
val errors = checkKindBounds0(tparams, targs, pre, owner, true)
Zobaczysz problem jest podłączony do sprawdzania granic wyższej kinded typu, na linii 5784, wewnątrz checkKindBoundsHK:
wydaje
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
}
Test nie jest przekazywana, że w moim debugera:
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)"
Wygląda więc na to jak jeden jest wyższy kinded param typu R, ale nie ma to zapewnić d wartość za to.
Jeśli rzeczywiście wrócić do do checkKindBounds, widać, że po fragmencie:
val (arityMismatches, varianceMismatches, stricterBounds) = (
// NOTE: *not* targ.typeSymbol, which normalizes
checkKindBoundsHK(tparamsHO, targ.typeSymbolDirect, tparam, tparam.owner, tparam.typeParams, tparamsHO)
)
arityMismatches
zawiera listę krotka, B. I teraz można również zobaczyć, że komunikat o błędzie jest źle:
wywnioskowaną typy argumentów typu (MyFoo, MyFoo, lista [X]) nie zgodne z oczekiwanymi rodzaju parametrów typu (typu f typu R typu B). Lista [X] 's parametry typu nie pasują oczekiwanych parametrów typu B: Lista klasa ma jeden parametr typu, ale typ B ma ZERO
W rzeczywistości, jeśli umieścić punkt przerwania na linii 5859 na następujących zadzwoń
checkKindBoundsHK(tparamsHO, targ.typeSymbolDirect, tparam, tparam.owner, tparam.typeParams, tparamsHO)
widać, że
tparam = {[email protected]}"type B"
targ = {[email protected]}"List[X]"
Wniosek:
Z jakiegoś powodu, kiedy mamy do czynienia ze złożonymi typami o wyższych typach, takimi jak wasze, wnioskowanie kompilatora Scala jest ograniczone. Nie wiem skąd się to bierze, być może chcesz wysłać błąd do zespołu kompilatora
Używam scala 2.9.3-20120917-121530-db16547873 –