2015-10-22 77 views
2

有沒有辦法使用宏而不是從內部類的實例獲取父類,而不是run-time reflection當提供內部類的實例時,找到外部類

我有這樣一組類:

trait IdProvider { 
    type IdObject = Id.type 
    case class Id(underlying: Int) 
} 

case class SomeEntity(id: SomeEntity.Id) 

object SomeEntity extends IdProvider 

而且一些代碼,任意IdProvider#Id作品:

val lookup = Map[IdProvider#IdObject, Set[Operation]] 

def can(operation: Operation, id: IdProvider#Id): Boolean = { 
    val idObject = findIdTypeFromInstance(id) // This is what I don't have 
    lookup.get(idObject).exists(s => s(operation)) 
} 

以葉出this gist by Paul P.我現在有這個宏:

def findIdTypeFromInstance[T <: AnyRef : c.WeakTypeTag](
    c: blackbox.Context)(thing: c.Expr[T]): c.Expr[T] = { 
    import c.universe._ 
    val companion = thing.actualType.typeSymbol.companion match { 
    case NoSymbol => 
     c.abort(c.enclosingPosition, s"Instance of ${thing.actualType} has no companion object") 
    case sym => sym 
    } 

    def make[U: c.WeakTypeTag] = c.Expr[U](internal.gen.mkAttributedRef(companion)) 

    make(c.WeakTypeTag(companion.typeSignature)) 
} 

這適用於更簡單的情況(頂級案例cla類,對象,甚至嵌套的case類)。然而,隨着IdProvider設置的宏試圖上方時務生成此樹:

Select(This(TypeName("IdProvider")), TermName("Id")) 

這將導致一個非常長的堆棧跟蹤在我的測試,其開頭:

scala.reflect.internal.Types$TypeError: value is not a member of my.spec.MacroSpec

我沒有能夠找到從實例或伴侶(IdProvider#Id)到父類(在這種情況下爲SomeEntity)的路徑。有沒有辦法得到SomeEntity或我必須使用run-time reflection

回答

1

Id伴侶基本上是一個懶惰的val。您需要封閉實例來檢索其值,因爲它不是一個靜態定義的穩定路徑。

隨着-Yshow-syms你可以看到它得到mixin相求:

 object SomeEntity 
      constructor SomeEntity 
*   method Id$lzycompute (private) 
      method apply (case <synthetic>) 
       value id 
      method readResolve (private <synthetic>) 
      method unapply (case <synthetic>) 
       value x$0 (<synthetic>) 
*   object Id (<synthetic> <stable>) 
      value <local SomeEntity> 
*   variable Id$module (private <local> <synthetic>) 

Id$outer領域explicitouter加入。

只是明確暴露伴隨引用更容易嗎?

case class Id(underlying: Int) { 
    def c = Id 
    } 

這只是一個快速的樣子;也許有一個聰明的方法來做到這一點。

+0

這是一個好主意 - 我已經暴露了外部實例(通過'self'類型),所以我可能能夠以這種方式獲得。 –