2012-07-19 73 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

相關問題