2012-07-19 28 views
15

当使用.isInstanceOf[GenericType[SomeOtherType]],其中GenericTypeSomeOtherType是任意类型的(合适的那种),Scala编译器给出了一个未检查警告由于类型擦除:为什么`Some(123).isInstanceOf [Option [List [String]]]`* *不会给出未经检查的警告?

scala> Some(123).isInstanceOf[Option[Int]] 
<console>:8: warning: non variable type-argument Int in type Option[Int] is unchecked since it is eliminated by erasure 
       Some(123).isInstanceOf[Option[Int]] 
            ^
res0: Boolean = true 

scala> Some(123).isInstanceOf[Option[String]] 
<console>:8: warning: non variable type-argument String in type Option[String] is unchecked since it is eliminated by erasure 
       Some(123).isInstanceOf[Option[String]] 
            ^
res1: Boolean = true 

然而,如果SomeOtherType本身是一个通用类型(例如List[String] ),无警告发出:

scala> Some(123).isInstanceOf[Option[List[String]]] 
res2: Boolean = true 

scala> Some(123).isInstanceOf[Option[Option[Int]]] 
res3: Boolean = true 

scala> Some(123).isInstanceOf[Option[List[Int => String]]] 
res4: Boolean = true 

scala> Some(123).isInstanceOf[Option[(String, Double)]] 
res5: Boolean = true 

scala> Some(123).isInstanceOf[Option[String => Double]] 
res6: Boolean = true 

(记得,元组和=>Tuple2[]Function2[]一般类型语法糖)

为什么没有发出警告? (所有这些都在斯卡拉REPL 2.9.1,与-unchecked选项。)

回答

19

我有一个看看Scala编译器源,我发现了一些有趣的东西在

scala.tools.nsc.typechecker.Infer 

寻找这是你找到警告。如果您在行1399仔细看:

def checkCheckable(pos: Position, tp: Type, kind: String) 

这是哪里产生的警告,你看到一些嵌套的方法,包括检查方法:

def check(tp: Type, bound: List[Symbol]) { 
     def isLocalBinding(sym: Symbol) = 
      sym.isAbstractType && 
      ((bound contains sym) || 
      sym.name == tpnme.WILDCARD || { 
      val e = context.scope.lookupEntry(sym.name) 
      (e ne null) && e.sym == sym && !e.sym.isTypeParameterOrSkolem && e.owner == context.scope 
      }) 
     tp match { 
      case SingleType(pre, _) => 
      check(pre, bound) 
      case TypeRef(pre, sym, args) => 
      if (sym.isAbstractType) { 
       if (!isLocalBinding(sym)) patternWarning(tp, "abstract type ") 
      } else if (sym.isAliasType) { 
       check(tp.normalize, bound) 
      } else if (sym == NothingClass || sym == NullClass || sym == AnyValClass) { 
       error(pos, "type "+tp+" cannot be used in a type pattern or isInstanceOf test") 
      } else { 
       for (arg <- args) { 
       if (sym == ArrayClass) check(arg, bound) 
       else if (arg.typeArgs.nonEmpty)() // avoid spurious warnings with higher-kinded types 
       else arg match { 
        case TypeRef(_, sym, _) if isLocalBinding(sym) => 
        ; 
        case _ => 
        patternWarning(arg, "non variable type-argument ") 
       } 
       } 
      } 
      check(pre, bound) 
      case RefinedType(parents, decls) => 
      if (decls.isEmpty) for (p <- parents) check(p, bound) 
      else patternWarning(tp, "refinement ") 
      case ExistentialType(quantified, tp1) => 
      check(tp1, bound ::: quantified) 
      case ThisType(_) => 
      ; 
      case NoPrefix => 
      ; 
      case _ => 
      patternWarning(tp, "type ") 
     } 
    } 

虽然我不是专家在Scala编译器,我们都应该感谢这些人让代码如此明了。让我们来看看在tp match块和治疗的病例中:

  • 如果它是一个单一类型
  • 如果它是一种裁判
    • 如果是抽象类型
    • 如果是一个别名类型
    • 如果它的Null,Nothing或Anyval
    • 所有其他情况

如果你看看所有其他情况下,有这样一行还评论说:

else if (arg.typeArgs.nonEmpty)() // avoid spurious warnings with higher-kinded types 

这就告诉你,如果你的类型有其他类型的参数正是发生(如函数2,或Tuple2 )。检查功能返回单位而不执行任何测试。

我不为这个原因,这项工作已经完成这种方式,但你可能想在 https://issues.scala-lang.org/browse/SI 打开一个错误,为您提供张贴在这里作为一个优秀的测试案例的代码,并参考Infer.scala来源,我在上面复制。

+8

大调查! – 2012-07-19 08:06:30

+0

的确,工作很好! – pedrofurla 2012-07-19 14:46:52

+1

用于引用编译器。 :-) – 2012-07-19 18:03:19

相关问题