2012-09-06 102 views
1

我有一个简单的测试宏,它使用了reify。它在宏扩展期间导致StackOverflowError。实现宏扩展期间的StackOverflowError

def test() = macro testimpl 

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

为什么会发生这种情况?可以以某种方式避免吗?

编辑:这是M6发生的事情。我只是M7尝试过了,现在它说

实施限制:不能具体化类型对象{DEF():O.type}(ClassInfoType)

这样回答为什么的问题,但是否有办法解决这个问题仍然存在问题。

回答

3

目前,修饰者不知道如何通过引用在被指定的块内定义的东西来指定类型。因此错误。

但是它与你的例子有什么关系?这是它的工作原理。

为了具体化您的代码块,则编译器使用def apply[T: AbsTypeTag](mirror: MirrorOf[self.type], treec: TreeCreator): Expr[T](UPD。在2.10.0-RC1 AbsTypeTag已更名为WeakTypeTag)来创建具体化的表达类型expr的一个对象。然而,在Expr的合同中隐含的是,它也捕捉了reifee的类型,并且引起了这个问题。

因此您需要一种解决方法。最简单的方法是在片段的最后一行将O转换为可确定的内容,例如,编写O.asInstanceOf[Object]。然后,您可以手动剥离结果中的asInstanceOf部分。

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

最近我碰到同样的问题。但我无法承受铸造对象类型,因为我在其他宏中使用了单例类型来区分(编译时间)“变量”。所以如果你真的需要一个对象的通用化,你可以在一个宏中做下面的事情,所以reify返回对象而不是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"))) 
    }) 
}