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

len*_*nkt 7 macros scala scala-macros

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

  • 查找编译器当前可见的所有隐式defs/vals,以从给定类型转换为另一个类型.

我会期望得到的是一个ListMethod物体或类似的东西.我已经玩过,enclosingImplicits但总是得到一个空列表,并不知道下一步该在哪里.

我需要做什么才能获得我想要的列表?

dk1*_*k14 4

在上下文中从 typeA到只能有一个隐式(或者你会得到不明确的隐式),所以如果你想找到它:B

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>
Run Code Online (Sandbox Code Playgroud)

查找隐式方法:

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))
}
Run Code Online (Sandbox Code Playgroud)

如果silent参数为falsetrue默认情况下),TypecheckException则在出现推理错误时将抛出异常。所以你可以分析它来找到不明确的隐式列表。

PS 如果类型B未知 - 没有(记录的)方法可以使用宏查找所有隐式:openImplicits/enclosingImplicits只是寻找在宏扩展上下文中具体化的隐式 - 不适用于上下文中存在的所有隐式。编译器插件可能会有所帮助,但并不那么容易。

如果您真的决定尝试“编译器插件”方式 - 查找隐式的逻辑就在这里实现。在这里您可以找到编译器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:
Run Code Online (Sandbox Code Playgroud)

无论如何,您必须分析一个列表ImplicitInfo才能获得您正在寻找的隐式,这可能并不简单,正如您从Analizer的来源中看到的那样,但至少可以获得近似结果,这可能适合您的需求。但同样,最好非常非常小心地这样做,因为您使用的结构是可变的并且方法不是纯粹的。而且,正如@Eugene Burmako 注意到的那样,这个解决方案不会为您提供伴随对象的隐含信息。