Reputation: 966
Following on from Compilation issue when accessing parameter value in Scala macro, I want to define a macro that applies a predicate. If the statement fn = c.eval( pred ) is present, then client code fails to compile, without any indication as to the nature of the problem.
def fnInvocation( value : Int, pred : c.Expr[ Int => Boolean ] ): Boolean = fnInvocationImpl
def fnInvocationImpl(c: Context)( value : Int, pred : c.Expr[ Int => Boolean ] ) : c.Expr[Boolean] = {
var fn = x => x % 2 == 0
// fn = c.eval( pred ) // client compilation fails if this line is included
val result = fn( value )
c.literal( result )
}
Should I be able to do this from within a macro?
Upvotes: 2
Views: 455
Reputation: 139028
Macro methods themselves don't have an initial context parameter list, and it doesn't make sense for them to have expression arguments. In their implementations, on the other hand, every argument (after the initial parameter list with the context) must be an expression.
In your case the signatures would need to look like this:
def fnInvocation(value: Int, pred: Int => Boolean): Boolean =
macro fnInvocationImpl
def fnInvocationImpl(c: Context)(
value: c.Expr[Int],
pred: c.Expr[Int => Boolean]
): c.Expr[Boolean] = ???
The comments in my previous answer apply here as well. If both arguments are compile-time literals, you can perform the application at compile-time—see my gist here for an example of how this kind of thing works with function literals. If they're not both literals, you can build a tree that performs the application at runtime. You could even check whether the arguments are both literals, apply the function and return a compile-time literal if they are, and fall back to generating a tree otherwise. What you can't do is perform the application at compile-time if the values aren't literals.
Upvotes: 1