私はinferImplicitValue
を使用してマクロ内の暗黙の変数を表すツリーを取得し、その構文ツリーを評価したいScalaマクロ(Scala 2.11)を作成しています。値。私は実際にこれをしましたが、それはすべての状況で動作するようには思われません[1]。私はそれが失敗した簡単な例を作った。inferImplicitValueから返されたScala構文ツリーが評価に失敗しています
// a class for implicit evidence
class DemoEvidence(val value: Int)
// define 'foo' method for invoking the macro
object demoModule {
def foo: Int = macro DemoMacros.fooImpl
}
class DemoMacros(val c: whitebox.Context) {
import c.universe._
def fooImpl: Tree = {
val vInt = try {
// get the tree representing the implicit value
val impl = c.inferImplicitValue(typeOf[DemoEvidence], silent = false)
// print it out
println(s"impl= $impl")
// try to evaluate the tree (this is failing)
val eval = c.eval(c.Expr[DemoEvidence](c.untypecheck(impl.duplicate)))
eval.value
} catch {
case e: Throwable => {
// on failure print out the failure message
println(s"Eval failed with: $e\nStack trace:\n${e.printStackTrace}")
0
}
}
q"$vInt" // return tree representing the integer value
}
}
私は上記をコンパイルし、それを起動した場合:
object demo {
implicit val demoEvidence: DemoEvidence = new DemoEvidence(42)
val i: Int = demoModule.foo
}
私はコンパイルは次のように失敗を参照してください。
impl= demo.this.demoEvidence
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$compile$1.apply(ToolBoxFactory.scala:275)
...
全出力で: https://gist.github.com/erikerlandson/df48f64329be6ab9de9caef5f5be4a83
これで、宣言用のツリーが見つかりましたd暗黙の値demo.this.demoEvidence
ですが、そのツリーの評価に失敗しています。私はこの基本的なアプローチが私のプロジェクトのどこかで働いているのを見ました。違いが何であるか、なぜここで失敗するのか分かりません。
[1]更新:暗黙の値が(サブ)プロジェクトで定義され、コンパイルされ、そのプロジェクトの外部で使用される場合、期待どおりに動作します。それがこのアプローチが私のために働いているケースでした。
それは私が暮らしていなければならない基本的な制約か、賢明な回避策があるのか、これは修正されるかもしれないマクロ内の暗黙的な値を推測する「バグ」なのかという疑問です。
UPDATE:スタックトレースの表情からはhttps://github.com/scala/scala-dev/issues/353
少なくとも、スタックトレースと例外の 'toString'を含めることができます。 –
私は痕跡を得ていませんでした。しかしtry/catchを取り除いて私が得たものを見てみよう – eje
あるいは単に 'catch'で' e.printStackTrace'を使うだけです。 –