2012-07-19 22 views
15

Khi sử dụng .isInstanceOf[GenericType[SomeOtherType]], nơi GenericTypeSomeOtherType nhiều loại tùy ý (của loại hình phù hợp), trình biên dịch Scala đưa ra một cảnh báo không được kiểm soát do chô bôi loại:Tại sao một số (123) .isInstanceOf [Tùy chọn [Liệt kê [Chuỗi]]] `* không * đưa ra một cảnh báo không được kiểm tra?

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 

Tuy nhiên, nếu SomeOtherType là bản thân một kiểu generic (ví dụ List[String]), không có cảnh báo được phát ra:

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 

(nhớ lại rằng tuples và => là cú pháp đường cho Tuple2[]Function2[] kiểu generic)

Tại sao không có cảnh báo nào được phát ra? (Tất cả những đang ở trong Scala REPL 2.9.1, với tùy chọn -unchecked.)

Trả lời

19

tôi đã có một cái nhìn vào nguồn biên dịch Scala, và tôi phát hiện ra một cái gì đó thú vị nhìn vào

scala.tools.nsc.typechecker.Infer 

mà là nơi bạn tìm thấy cảnh báo. Nếu bạn xem xét cẩn thận tại dòng 1399 để:

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

đó là nơi mà các cảnh báo được tạo ra, bạn sẽ thấy một số phương pháp lồng nhau bao gồm các phương pháp kiểm tra:

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 ") 
     } 
    } 

Trong khi tôi không phải là chuyên gia trong Trình biên dịch Scala, tất cả chúng ta nên cảm ơn các bạn để làm cho đoạn code tự giải thích. Chúng ta hãy nhìn vào bên trong các tp match khối và các trường hợp điều trị:

  • Nếu nó một loại duy nhất
  • Nếu nó là một loại ref
    • Nếu là trừu tượng loại
    • Nếu là một loại bí danh
    • Nếu Null, Nothing hoặc Anyval
    • Tất cả các trường hợp khác

Nếu bạn nhìn vào tất cả các trường hợp khác, có một dòng mà cũng nhận xét:

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

Điều đó nói với bạn chính xác những gì xảy ra nếu loại của bạn có tham số kiểu khác (như Function2, hoặc Tuple2). Hàm kiểm tra trả về đơn vị mà không thực hiện bất kỳ phép thử nào.

Tôi không mà lý do này đã được thực hiện theo cách này, nhưng bạn có thể muốn mở một lỗi tại https://issues.scala-lang.org/browse/SI cung cấp mã bạn được đăng ở đây như là một trường hợp thử nghiệm tuyệt vời, và tham chiếu đến các nguồn Infer.scala mà Tôi đã sao chép ở trên.

+8

Điều tra tuyệt vời! –

+0

Thật vậy, công việc tốt! – pedrofurla

+1

+1 để trích dẫn trình biên dịch. :-) –

Các vấn đề liên quan