2017-03-29 2 views
2

inferImplicitValue을 사용하여 매크로 내부의 암시 적 변수를 나타내는 트리를 가져오고 해당 구문 트리를 평가하려는 스칼라 매크로 (스칼라 2.11)를 작성하고 있습니다. 값. 나는 실제로이 일을했지만 모든 상황에서 효과가있는 것 같지 않습니다. [1]. 나는 실패한 간단한 예제를 만들었다.inferImplicitValue에서 반환 된 스칼라 구문 트리가 평가하지 못했습니다.

// 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 : 나는 이것에 대한 스칼라 문제를 제기 :의 eval 주어진 의미가 실행을위한 클래스 파일 형태로 존재하는 object demo을 기대하고있다 스택 트레이스의 모습에서 https://github.com/scala/scala-dev/issues/353

+0

최소한 스택 트레이스와 예외의'toString'을 포함 할 수 있습니다. –

+0

나는 어떤 흔적도 얻지 못했습니다. 하지만 try/catch를 제거하고 내가 얻은 것을 보도록하겠습니다. – eje

+1

아니면 그냥'catch'에서'e.printStackTrace'를 사용하십시오. –

답변

1

당신이있어 값 계산을 시도하는 것은 object demo의 구성원 인 val demoEvidence에 달려 있습니다.

그러나 object demo의 typechecking 중에 eval이 발생하므로 클래스 파일이 아직 존재하지 않으므로 오류가 발생합니다. 하위 프로젝트에 정의 된 암시 적 값을 가진 버전에서 하위 프로젝트가 먼저 컴파일되고 따라서 eval에 필요한 클래스 파일이 존재하므로 예상대로 예상대로 진행됩니다.

+0

그것이 어떻게 문제를 일으키는 지 알 수 있습니다. 'inferImplicitValue'는 정규 암시 적 매개 변수에 대해 비대칭으로 만듭니다. 암시 적 매개 변수가있는'foo'를 선언하면 _does_가 작동합니다. 완전한 세계에서''inferImplicitValue''가 매크로 내부의''DemoEvidence (42)''와 같은 트리를 리턴하기를 바랬습니다. 이론적으로는 현재 매크로 컨텍스트의 어딘가에서 사용할 수 있어야합니다. 그럴 가능성이 얼마나 확실한가. – eje

+0

매크로가 아닌 경우에는'eval'에 대한 호출이 없으므로 실행을 위해 코드를 컴파일 할 필요가 없다는 것을 설명했습니다 ... 문제는 모두'eval'에 있습니다. –