2012-07-19 13 views
15

Usando .isInstanceOf[GenericType[SomeOtherType]], dove GenericType e SomeOtherType sono tipi arbitrarie (di adatta natura), il compilatore Scala dà un avvertimento incontrollato a causa della tipologia di cancellazione:Perché `Some (123) .isInstanceOf [Option [List [String]]] * * non fornisce un avviso non controllato?

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 

Tuttavia, se SomeOtherType è essa stessa un tipo generico (es List[String]), nessun avviso viene emesso:

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 

(Ricordiamo che tuple e => sono zucchero sintattico per Tuple2[] e Function2[] tipi generici)

Perché non viene emesso alcun avviso? (Tutti questi sono nella Scala REPL 2.9.1, con l'opzione -unchecked.)

risposta

19

Ho dato un'occhiata alle fonti compilatore Scala, e ho scoperto qualcosa di interessante guardare

scala.tools.nsc.typechecker.Infer 

che è dove si trova l'avviso Se si guarda con attenzione alla riga 1399 a:

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

che è dove il l'avvertimento sono generati, vedete alcuni metodi annidati tra cui il metodo di controllo:

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

Mentre io non sono esperto in Compilatore di Scala, dovremmo tutti ringraziare i ragazzi per aver reso il codice così auto-esplicativo. Diamo un'occhiata all'interno del tp match blocco ed i casi trattati:

  • Se la sua un singolo tipo
  • Se si tratta di un tipo di Rif
    • Se è astratta tipo
    • Se è un tipo alias
    • Se il valore Null, Nothing, o Anyval
    • Tutti gli altri casi

Se si guarda a tutti gli altri casi, v'è una linea che è anche commentato:

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

che ti dice esattamente che cosa accadrebbe se il tipo ha altro parametro di tipo (come Function2, o Tuple2). La funzione di controllo restituisce l'unità senza eseguire alcun test.

Non per cui questo è stato fatto in questo modo, ma si potrebbe desiderare di aprire un bug a https://issues.scala-lang.org/browse/SI fornendo il codice che hai postato qui come un ottimo banco di prova, e riferimento alla fonte Infer.scala che Ho copiato sopra.

+8

Grande indagine! –

+0

Effettivamente, buon lavoro! – pedrofurla

+1

+1 per aver citato il compilatore. :-) –

Problemi correlati