如果我们查看 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)
您将看到问题与检查更高种类的边界有关,在第 5784 行,在 checkKindBoundsHK 内:
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,但没有提供值。
如果你真的回到checkKindBounds,你会在sn-p之后看到:
val (arityMismatches, varianceMismatches, stricterBounds) = (
// NOTE: *not* targ.typeSymbol, which normalizes
checkKindBoundsHK(tparamsHO, targ.typeSymbolDirect, tparam, tparam.owner, tparam.typeParams, tparamsHO)
)
arityMismatches 包含一个元组 List,B。现在您还可以看到错误消息是错误的:
类型参数的推断类型 (MyFoo,MyFoo,List[X]) 不
符合类型参数的预期种类(类型 F,类型
R,B型)。 List[X] 的类型参数与类型 B 的预期不匹配
参数:类List有一个类型参数,但是类型B有ZERO
事实上,如果你在以下调用的第 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 编译器推断是有限的。我不知道它是从哪里来的,也许你想向编译团队发送一个错误