2012-07-19 10 views
15

Al utilizar .isInstanceOf[GenericType[SomeOtherType]], donde GenericType y SomeOtherType son tipos arbitrarios (de tipo adecuado), el compilador Scala da una advertencia sin control debido al tipo de borrado:¿Por qué `Some (123) .isInstanceOf [Option [List [String]]]` * not * da una advertencia no marcada?

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 

Sin embargo, si SomeOtherType es en sí mismo un tipo genérico (por ejemplo List[String]), sin previo aviso se emite:

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 

(Recordemos que tuplas y => son azúcar sintáctica para Tuple2[] y Function2[] los tipos genéricos)

¿Por qué no se emite ninguna advertencia? (Todos estos son en el Scala REPL 2.9.1, con la opción -unchecked.)

Respuesta

19

Tenía una mirada a las fuentes del compilador Scala, y descubrí algo interesante para ver

scala.tools.nsc.typechecker.Infer 

que es donde se encuentra la advertencia Si se fijan bien en la línea 1399 a:

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

que es donde se genera la la la advertencia, que vea algunos métodos anidados incluyendo el método de control:

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

Aunque no soy experto en el Compilador de Scala, todos deberíamos agradecer a los muchachos por hacer que el código sea tan fácil de entender. Veamos el interior del bloque tp match y los casos tratados:

  • Si es un solo tipo
  • Si se trata de una referencia de tipo
    • Si es abstracta tipo
    • Si es el tipo de alias
    • Si es Nulo, Nada o Anyval
    • Todos los demás casos

Si nos fijamos en todos los demás casos, hay una línea que también se comentó:

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

que te dice exactamente lo que sucedería si el tipo tiene otro tipo de parámetro (como Función2 o Tuple2) La función de verificación devuelve la unidad sin realizar ninguna prueba.

No por lo que esto se ha hecho de esta manera, pero es posible que desee abrir un error en https://issues.scala-lang.org/browse/SI proporcionar el código que envió aquí como un caso de prueba excelente, y la referencia a la fuente de la que Infer.scala Copié arriba.

+8

¡Gran investigación! –

+0

De hecho, ¡buen trabajo! – pedrofurla

+1

+1 para citar el compilador. :-) –

Cuestiones relacionadas