Я пишу макрос Scala (Scala 2.11), в котором я хотел бы получить дерево, представляющее неявную переменную внутри макроса, используя inferImplicitValue
, оценить это синтаксическое дерево и использовать значение. Я действительно сделал это, но, похоже, это работает не во всех обстоятельствах [1]. Я построил упрощенный пример, где это не удается.
// 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/df48f64329be6ab9de9caef5be6ab9de9caef5be6b6ab9caef5be5be6ab9caef5f5
Итак, вы можете видеть, что он находит дерево для объявленного неявного значения demo.this.demoEvidence
, но оценка этого дерева не выполняется. Я видел, как этот базовый подход работает в другом месте моего проекта. Не уверен, в чем разница и почему здесь не работает.
[1] ОБНОВЛЕНИЕ: если неявное значение определено в (под) проекте и скомпилировано, а затем используется вне этого проекта, оно работает должным образом. Это тот случай, когда этот подход работает для меня.
Итак, вопрос в том, является ли это просто фундаментальным ограничением, с которым мне приходится жить, или есть какой-то умный обходной путь, или это «ошибка» с выводом неявных значений внутри макросов, которые могут быть исправлены.
ОБНОВЛЕНИЕ: я отправил сообщение о проблеме Scala для этого: https://github.com/scala/scala-dev/issues/353
toString
исключения. - person Alexey Romanov   schedule 30.03.2017e.printStackTrace
в своемcatch
. - person Alexey Romanov   schedule 30.03.2017printStackTrace
; полный вывод находится здесь: gist.github.com/erikerlandson/df48f64329be6ab9de9caef5f5be4a, сейчас Weirdbe4a полный стек перед он печатает ошибку (и трассировка стека для ошибки пуста) - person eje   schedule 30.03.2017object demo
. В рабочем сценарии имплициты объявляются и компилируются перед вызовом макросов, которые их ищут. - person eje   schedule 30.03.2017