c.inferImplicitValue
infers implicit values in the call site scope. Is it possible to infer implicits using the c.prefix
scope?
This is not valid code, but expresses what I need:
c.prefix.inferImplicitValue
I'm currently using a naive implementation for this purpose[1], but it has some limitations like not inferring implicit values from def
s and detecting duplicated/ambiguous implicit values.
[1] https://github.com/getquill/quill/blob/9a28d4e6c901d3fa07e7d5838e2f4c1f3c16732b/quill-core/src/main/scala/io/getquill/util/InferImplicitValueWithFallback.scala#L12
Simply generating a block with an appropriate (local) import followed by a call to implicitly
does the trick:
q"""{import ${c.prefix}._; _root_.scala.Predef.implicitly[$T] }
Where T
is an instance of Type
representing the type of the implicit value to lookup.
To check if the implicit lookup actually succeeded, you can call Context.typeCheck
with silent=true
and check if the resulting tree is empty or not.
As an illustration, here is an example that implements an infer
method returning None
if the implicit was not found in the members of the target object, and otherwise wraps the result in a Some
.
import scala.reflect.macros.Context
import scala.language.experimental.macros
def inferImplicitInPrefixContext[T:c.WeakTypeTag](c: Context): c.Tree = {
import c.universe._
val T = weakTypeOf[T]
c.typeCheck(
q"""{
import ${c.prefix}._
_root_.scala.Predef.implicitly[$T]
}""",
silent = true
)
}
def infer_impl[T:c.WeakTypeTag](c: Context): c.Expr[Option[T]] = {
import c.universe._
c.Expr[Option[T]](
inferImplicitInPrefixContext[T](c) match {
case EmptyTree => q"_root_.scala.None"
case tree => q"_root_.scala.Some($tree)"
}
)
}
trait InferOp {
def infer[T]: Option[T] = macro infer_impl[T]
}
Let's test it:
object Foo extends InferOp {
implicit val s = "hello"
}
Foo.infer[String] // res0: Some[String] = Some(hello)
Foo.infer[Int] // res1: None.type = None
implicit val lng: Long = 123L
Foo.infer[Long] // res2: Some[Long] = Some(123)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With