I ran into a problem using reflect.toolbox. It seemed either eval() or untypecheck() had some side effects. See my code and error log at the end. I am not sure if this was due to my improper usage, or it was really a Scala issue.
-
This happened to both 2.11.12 and 2.12.8 that I tried.
-
If I move mkToolBox() inside c, the thing would work. (see commented lines inside the function.)
-
If I exchanged the two calls to annotatedMethods() (get “requires” before “publishable”, see commented lines at the bottom of the FlowContext class), the thing worked as well.
Questions:
- How do I know when I need a brand new toolbox? It seemed that I do not need to re-initialize it every time I want to use it, but when I don’t, sometimes it could fail.
- It makes no sense to me why exchanging the two annotatedMethods() calls would make the error go away.
Thanks.
C.J.
========== Code ==========
import scala.reflect.runtime.{universe => ru}
import ru._
import scala.reflect.ClassTag
type StepMethod = (Seq[_]*) => Seq[_]
class Requires(val steps: StepMethod*) extends scala.annotation.StaticAnnotation
class Publishable(val str: String) extends scala.annotation.StaticAnnotation
trait Flow
class FlowContext[F <: Flow :TypeTag :ClassTag](val flow: F) {
import scala.tools.reflect.ToolBox
val fields = typeOf[F].decls.filter(_.isMethod)
val mirror = runtimeMirror(getClass.getClassLoader)
val tb = mirror.mkToolBox()
private def annotatedMethods[A <: annotation.StaticAnnotation : TypeTag] = {
// Move toolbox creating here would work
//val tb = mirror.mkToolBox()
def fromAnnotation(a: Annotation) = {
tb.eval(tb.untypecheck(a.tree)).asInstanceOf[A]
}
fields
.flatMap(f => {
f.annotations
.find(_.tree.tpe =:= typeOf[A])
.map(a => {
println(s"field=${f.name.toString}")
println(a.tree.children.mkString("\n"))
val x = f.name.toString -> fromAnnotation(a)
println("done")
x
})
})
.toMap
}
val publishable = annotatedMethods[Publishable]
val requires = annotatedMethods[Requires]
// Exchange requires and publishable would work too
// val requires = annotatedMethods[Requires]
// val publishable = annotatedMethods[Publishable]
}
object FlowContextTest{
object TestFlowF extends Flow{
@Publishable("XXX")
def x(args: Seq[_]*)= {
println("inX")
Seq(1,2,3,4)
}
@Requires(x)
def y(args: Seq[_]*)= args.head.asInstanceOf[Seq[Int]].map(_ + 2)
@Publishable("ZZZ")
@Requires(y,x)
def z(args: Seq[_]*)= {
val zz = args.map(_.asInstanceOf[Seq[Int]])
zz(0) zip zz(1)
}
def w()=123
}
}
val x = new FlowContext(FlowContextTest.TestFlowF)
========= Error ==========
field=x
new Publishable
“XXX”
done
field=z
new Publishable
“ZZZ”
done
field=y
new Requires
{
((args: Seq[Seq[]]) => TestFlowF.this.x((args: *)))
}
scala.tools.reflect.ToolBoxError: reflective compilation has failed:
type mismatch;
found : collection.Seq[Int]
required: (in ).scala.collection.Seq[(in ).scala.collection.Seq[]] => (in ).scala.collection.Seq[]
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.throwIfErrors(ToolBoxFactory.scala:331)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.wrapInPackageAndCompile(ToolBoxFactory.scala:213)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.compile(ToolBoxFactory.scala:267)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl.$anonfun$compile$13(ToolBoxFactory.scala:444)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$withCompilerApi$.apply(ToolBoxFactory.scala:370)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl.compile(ToolBoxFactory.scala:437)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl.eval(ToolBoxFactory.scala:459)
at FlowContext.fromAnnotation$1(:35)
at FlowContext.$anonfun$annotatedMethods$3(:45)
at scala.Option.map(Option.scala:163)
at FlowContext.$anonfun$annotatedMethods$1(:42)
at scala.collection.TraversableLike.$anonfun$flatMap$1(TraversableLike.scala:244)
at scala.reflect.internal.Scopes$Scope.foreach(Scopes.scala:415)
at scala.collection.TraversableLike.flatMap(TraversableLike.scala:244)
at scala.collection.TraversableLike.flatMap$(TraversableLike.scala:241)
at scala.reflect.internal.Scopes$Scope.flatMap(Scopes.scala:67)
at FlowContext.annotatedMethods(:39)
… 41 elided