2017-02-04 6 views
0

スカラーマクロにいくつか問題があり、実現型のコンストラクタを識別しています。 ここで何か間違っているか、正しい呼び出しが行われているかわかりません。 ドキュメントからは、typeSignatureInのように正しい情報が返されるはずです。 ClassTag [Int]が、マクロを実行すると、実現タイプではなくタイプパラメータであるため、コンパイルに失敗したClassTag [U]が実際に取得されます。マクロを使用してScalaクラスの実現型を取得する

import scala.language.experimental.macros 
import scala.reflect.ClassTag 
import scala.reflect.macros.Context 

def macroImpl[T: c.WeakTypeTag](c: Context) = { 
    import c.universe._ 

    val typeToMock = weakTypeOf[T] 

    val primaryConstructorOpt = typeToMock.members.collectFirst { 
    case method: MethodSymbolApi if method.isPrimaryConstructor => method 
    } 

    val constructorArgumentsTypes = primaryConstructorOpt.map { 
    constructor => 
    val constructorTypeContext = constructor.typeSignatureIn(typeToMock) 
    val constructorArguments = constructor.paramss 
    constructorArguments.map { symbols => 
     symbols.map(_.typeSignatureIn(constructorTypeContext)) 
    } 
    } 

    println(typeToMock) 
    println(constructorArgumentsTypes) 

    c.literalUnit 
} 

def foo[T] = macro macroImpl[T] 

class Foo[U: ClassTag] 

foo[Foo[Int]] 

それを実行している:

scala> foo[Foo[Int]] 
Foo[Int] 
Some(List(List(), List(scala.reflect.ClassTag[U])) 

私は後で正しいツリーを生成することができるように何とかClassTag [のInt]を取得する必要があり、任意のアイデア?

答えて

0

タイプを解決する各場所でdealiasを試してみてください。 Scalaは、参照するものが分かっていても参照を保持します。 dealiasは、参照が置換された型のコピー(?)を取得します。

scala.reflect.macros.Contextではなく、ブラックボックスまたはホワイトボックスのマクロを選択する必要があります。

これは動作するようです:

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

def macroImpl[T: c.WeakTypeTag](c: Context) = { 
    import c.universe._ 

    val typeToMock = weakTypeOf[T].dealias 

    val primaryConstructorOpt = typeToMock.members.collectFirst { 
    case method: MethodSymbolApi if method.isPrimaryConstructor => method 
    } 

    val constructorArgumentsTypes = primaryConstructorOpt.map { constructor => 
    val constructorTypeContext = constructor.typeSignatureIn(typeToMock).dealias 
    val constructorArguments = constructorTypeContext.paramLists 
    constructorArguments.map { symbols => 
     symbols.map(_.typeSignatureIn(constructorTypeContext).dealias) 
    } 
    } 

    println(typeToMock) 
    println(constructorArgumentsTypes) 

    q"()" 
} 

def foo[T]: Any = macro macroImpl[T] 

class Foo[U: ClassTag] 

foo[Foo[Int]] 

結果

Foo[Int] 
Some(List(List(), List(scala.reflect.ClassTag[Int]))) 
+0

多くの感謝を。まだそれを広範囲のコードベースに統合するのには苦労していますが、それは私に次の調査をする良い指導を与えました –

関連する問題