2014-06-15 14 views
5

La seguente macro è una versione semplificata dello illTyped di che tenta di digitare il codice fornito dall'utente come stringa. Restituisce None se riesce e l'eccezione come Option[String] in caso di errore.Perché questo codice digita tipicamente in Scala 2.11 e cosa posso fare al riguardo?

import scala.language.experimental.macros 
import scala.reflect.macros.TypecheckException 
import scala.reflect.macros.whitebox.Context 

def typecheck_impl(c: Context)(code: c.Expr[String]): c.Expr[Option[String]] = { 
    import c.universe._ 

    val Expr(Literal(Constant(codeStr: String))) = code 

    try { 
    c.typecheck(c.parse(codeStr)) 
    c.Expr(q"None: Option[String]") 
    } catch { 
    case e: TypecheckException => 
     c.Expr(q"Some(${ e.toString }): Option[String]") 
    } 
} 

def typecheck(code: String): Option[String] = macro typecheck_impl 

Ora supponiamo che io ho una classe case Foo. Perché è una classe case, Foo avrà un estrattore generato automaticamente per esso, ma mettiamoci anche definire la nostra estrattore Bar che fa la stessa cosa:

object Test { 
    case class Foo(i: Int, c: Char) 

    object Bar { 
    def unapply(foo: Foo): Option[(Int, Char)] = Some((foo.i, foo.c)) 
    } 
} 

Ora possiamo scrivere la seguente:

scala> import Test._ 
import Test._ 

scala> val Foo(x, y) = Foo(1, 'a') 
x: Int = 1 
y: Char = a 

scala> val Bar(x, y) = Foo(1, 'a') 
x: Int = 1 
y: Char = a 

scala> val Foo(x, y, z) = Foo(1, 'a') 
<console>:15: error: wrong number of arguments for pattern Test.Foo(i: Int,c: Char) 
     val Foo(x, y, z) = Foo(1, 'a') 
      ^

scala> val Bar(x, y, z) = Foo(1, 'a') 
<console>:15: error: too many patterns for object Bar offering (Int, Char): expected 2, found 3 
     val Bar(x, y, z) = Foo(1, 'a') 
     ^

scala> typecheck("val Foo(x, y) = Foo(1, 'a')") 
res0: Option[String] = None 

scala> typecheck("val Bar(x, y) = Foo(1, 'a')") 
res1: Option[String] = None 

scala> typecheck("val Foo(x, y, z) = Foo(1, 'a')") 
res2: Option[String] = Some(scala.reflect.macros.TypecheckException: wrong number of arguments for pattern Test.Foo(i: Int,c: Char)) 

Niente di tutto questo è sorprendente, le cose che penseresti potrebbero compilare compilazioni, cose che non faresti, e la nostra macro è d'accordo. Ma poi prova questo:

scala> typecheck("val Bar(x, y, z) = Foo(1, 'a')") 
<macro>:1: error: too many patterns for object Bar offering (Int, Char): expected 2, found 3 
val Bar(x, y, z) = Foo(1, 'a') 
    ^

E la macro si strozza. Cambiare il blocco catch per gestire qualsiasi vecchio throwable dà lo stesso risultato. Il codice equivalente funzionava come previsto in 2.10.

Come posso rilevare questo errore in modo che la mia macro funzioni come previsto in 2.11?

+0

Buona domanda. Avrò bisogno di pensarci dopo ScalaDays. questo funzionerebbe per te? –

+0

Di sicuro, Eugene, senza fretta, grazie! Mi sono imbattuto in questo in un ramo con alcune modifiche per l'estrattore 'Sized' di Shapeless ieri, ma non è affatto urgente (il ramo ha già mesi). –

+0

https://issues.scala-lang.org/browse/SI-8719 –

risposta

Problemi correlati