2017-03-29 4 views
2

私は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

+0

少なくとも、スタックトレースと例外の 'toString'を含めることができます。 –

+0

私は痕跡を得ていませんでした。しかしtry/catchを取り除いて私が得たものを見てみよう – eje

+1

あるいは単に 'catch'で' e.printStackTrace'を使うだけです。 –

答えて

1

evalobject demoを実行するためにクラスファイル形式で存在することが期待され、値は、あなたがしていることを考えると理にかなっている:私はこのためにScalaの問題を提起し計算しようとするのはobject demoのメンバーであるval demoEvidenceに依存します。

しかし、は、タイプチェック中にobject demoが起きているので、クラスファイルはまだ存在しないため、エラーです。サブプロジェクトで定義されている暗黙的な値を持つバージョンでは、サブプロジェクトが最初にコンパイルされていると考えられますので、evalに必要なクラスファイルが存在するため、期待通りに評価が進みます。

+0

それはどのように問題を引き起こすのか分かります。 'inferImplicitValue'を通常の暗黙的なパラメータと少し非対称にします。なぜなら暗黙のパラメータ_does_を持つ' foo'をそのシナリオで宣言するだけなのでです。完全な世界では、 'inferImplicitValue'がマクロ内の' 'DemoEvidence(42)' 'に相当するツリーを返すことを期待していました。理論的には、現在のマクロコンテキストのどこかで利用できるはずです。それがいかに実現可能であるかわからない。 – eje

+0

非マクロの場合、あなたは 'eval'への呼び出しがないので、実行のためにコードをコンパイルする必要はないと説明しました。問題はすべて' eval'にあります。 –

関連する問題