2012-09-06 2 views
1

J'ai une macro de test simple qui utilise reify. Il provoque une erreur StackOverflowError lors de l'expansion de la macro.StackOverflowError lors de l'expansion de la macro de reify

def test() = macro testimpl 

def testimpl(c:Context)():c.Expr[Any] = { 
    import c.universe._ 
    val o = reify { // StackOverflowError here 
    object O 
    O 
    } 
    o 
} 

Pourquoi cela se produit-il? Cela peut-il être évité?

EDIT: C'est ce qui se passe avec M6. Je viens d'essayer avec M7 et maintenant il dit

restriction de mise en œuvre: ne peut pas réifier type Object {def(): O.type} (ClassInfoType)

donc qui répond à la question pourquoi, mais le la question demeure de savoir s'il existe un moyen de contourner ce problème.

Répondre

3

Actuellement, le réifier ne sait pas comment réifier les types qui référencent les objets définis dans le bloc en cours de réification. D'où l'erreur.

Mais qu'est-ce que cela a à voir avec votre exemple? Voici comment cela fonctionne.

réifier votre bloc de code, le compilateur utilise def apply[T: AbsTypeTag](mirror: MirrorOf[self.type], treec: TreeCreator): Expr[T] (UPD. En 2.10.0-RC1 AbsTypeTag a été renommé WeakTypeTag) pour créer un objet de type Expr qui réifie l'expression. Cependant, implicitement dans le contrat d'Expr, c'est qu'il capte aussi le type de reifee, et cela donne lieu au problème.

Par conséquent, vous avez besoin d'une solution de contournement. Le plus simple serait de lancer O dans la dernière ligne de l'extrait à quelque chose de réifiable, par exemple. écrire O.asInstanceOf[Object]. Ensuite, vous pouvez supprimer manuellement la partie asInstanceOf du résultat.

scala> reify { object O; O } 
<console>:26: error: implementation restriction: cannot reify type Object{def <init>(): O.type} (ClassInfoType) 
       reify { object O; O } 
        ^

scala> reify { object O; O.asInstanceOf[Object] } 
res1 @ 2d059fd6: reflect.runtime.universe.Expr[Object] = 
Expr[java.lang.Object]({ 
    object O extends AnyRef { 
    def <init>() = { 
     super.<init>(); 
    () 
    } 
    }; 
    O.asInstanceOf[Object] 
}) 
1

Je suis récemment tombé sur le même problème. Mais je ne pouvais pas me permettre de lancer le type d'objet, car j'ai utilisé le type singleton dans une autre macro pour faire la distinction entre (variables de compilation). Donc, si vous avez vraiment besoin de réifier un objet, vous pouvez faire ce qui suit dans une macro afin que reify retourne l'objet au lieu d'une valeur Unit.

def mkObject(c: Context) = { 
    import c.universe._ 

    val objectO = reify { object O } 
    c.Expr(objectO.tree match { 
    case Block(stats, expr) => Block(stats, Ident(newTermName("O"))) 
    }) 
} 
Questions connexes