在宏上下文中查找隐式方法定义

时间:2015-04-23 20:57:47

标签: scala macros scala-macros

我理解Scala中宏的基本概念,但目前无法做到这一点(简单?)工作:

  • 查找编译器当前可见的所有隐式def s / val,以便从给定类型转换为另一种类型。

我期望获得ListMethod个对象或类似内容。我已经玩过enclosingImplicits,但总是得到一个空列表,并且不知道接下来要去哪里看。

我需要做些什么来获取我要找的列表?

1 个答案:

答案 0 :(得分:2)

在上下文中只能有一个从AB的隐式隐式(或者你得到隐含的隐含),所以如果你想找到它:

import reflect.macros.Context, scala.language.experimental.macros

def fImpl(c: Context): c.Expr[Unit] = {
  import c.mirror._         
  println(c.inferImplicitValue(typeOf[Int]))
  c.universe.reify( () )
}
def f = macro fImpl

scala> f
<empty>

scala> implicit val a = 5
a: Int = 5

scala> f
$line24.$read.$iw.$iw.$iw.$iw.a

scala> implicit val b = 5
b: Int = 5

scala> f //result will be empty, but error printed to the log
error: ambiguous implicit values:
 both value a of type => Int
 and value b of type => Int
 match expected type Int
<empty>

找到隐式方法:

def fImpl(c: Context): c.Expr[Unit] = {
      import c.mirror._       
      println(c.inferImplicitValue(typeOf[String => Int]))        
      c.universe.reify( () )
 }
def f = macro fImpl

scala> f
<empty>

scala> implicit def aaa(a: String) = 5
warning: there was one feature warning; re-run with -feature for details
aaa: (a: String)Int

scala> "A" : Int
res10: Int = 5

scala> f
{
  ((a: String) => $line47.$read.$iw.$iw.$iw.$iw.$iw.$iw.aaa(a))
}

如果silent参数为false(默认情况下为true),则在推理错误时会抛出TypecheckException。因此,您可以对其进行分析,以找到具有暧昧含义的列表。

P.S。如果类型B未被明确 - 没有(记录)方法来查找使用宏的所有含义:openImplicits / enclosingImplicits只是寻找在宏扩展的背景下实现的含义 - 而不是所有,存在于上下文中。编译器插件可能有所帮助,但它并不那么容易。

如果你真的决定尝试“编译器 - 插件”方式 - 找到隐含的逻辑是hereHere您可以找到编译器的Context(与宏不同)及其implicitss字段,其中包含上下文中的所有含义(但获取适当的上下文并非如此简单)。

并且我不应该告诉你但是从宏Context升级到编译器级别并且做你想做的事情有一个棘手和不安全的黑客攻击:

 scala>  def fImpl(c: Context): c.Expr[Unit] = {
 |       val cc = c.asInstanceOf[reflect.macros.contexts.Context]
 |       println(cc.callsiteTyper.context.implicitss.flatten)
 |       c.universe.reify( () )
 |  }
fImpl: (c: reflect.macros.Context)c.Expr[Unit]

scala> def f = macro fImpl

scala> f //I've defined aaaaaaaa etc. implicits while playing with that
List(aaaaaaaa: ?, lllllllllllllllllllllzzzz: ?, lllllllllllllllllllll: ?, lllllllllllllllllllll: ?, aaa: ?, aaa: ?, aaa: ?, aaa: ?, aaa: ?, aaa: ?, b: ?, a: ?, macros: ?, RuntimeClassTag:

总之,你必须analize的ImplicitInfo获得你正在寻找implicits列表,并且它可能不会是微不足道的,因为你可以从Analizer的来源看,但至少它的可以获得近似结果,这可能适合您的需求。但同样,最好这样做非常非常小心,因为你使用的结构是可变的而且方法并不纯粹。并且,正如@Eugene Burmako注意到的那样,这个解决方案并没有给你伴侣对象的暗示。