2012-09-06 47 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"))) 
    }) 
}