Scala宏 - 使用`c.prefix`推断隐式值

时间:2015-09-16 08:56:29

标签: scala scala-macros

c.inferImplicitValue推断出调用网站范围中的隐含值。是否可以使用c.prefix范围来推断隐含?

这不是有效的代码,但表达了我的需求:

c.prefix.inferImplicitValue

我目前正在为此目的使用一个天真的实现[1],但它有一些限制,例如不从def推断隐含值并检测重复/模糊隐含值。

[1] https://github.com/getquill/quill/blob/9a28d4e6c901d3fa07e7d5838e2f4c1f3c16732b/quill-core/src/main/scala/io/getquill/util/InferImplicitValueWithFallback.scala#L12

1 个答案:

答案 0 :(得分:6)

只需生成一个具有适当(本地)导入的块,然后调用implicitly即可:

q"""{import ${c.prefix}._; _root_.scala.Predef.implicitly[$T] }

其中TType的实例,表示要查找的隐式值的类型。

要检查隐式查找是否实际成功,您可以使用Context.typeCheck调用silent=true并检查结果树是否为空。

作为示例,这里是一个示例,如果在目标对象的成员中找不到隐式,则实现infer方法返回None,否则将结果包装在{{1 }}

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]
}