I understand the basic concept of macros in Scala, but currently fail to do this (simple?) job:
def
s/val
s currently visible to the compiler to transform from a given type to another one.What I'd expect to get is a List
of Method
objects or something similar. I already played around with enclosingImplicits
but always get an empty list and do not really know where to look next.
What do I need to do to get the list I am looking for?
Scala implicit allows you to omit calling method or parameter directly. For example, you can write a function that converts int to/from string explicitly but you can ask the compiler to do the same thing for you, implicitly.
In Scala, objects and values are treated mostly the same. An implicit object can be thought of as a value which is found in the process of looking up an implicit of its type.
Scala 2.10 introduced a new feature called implicit classes. An implicit class is a class marked with the implicit keyword. This keyword makes the class's primary constructor available for implicit conversions when the class is in scope. Implicit classes were proposed in SIP-13.
In Scala macros are a way to implement compile time reflection. One advantage that macros possess is that they are based on the same API which is also used for Scala runtime reflection and is provided in 'scala. reflect.
There can be only one implicit from type A
to B
in the context (or you get ambigious implicit), so if you want to find it:
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>
To find implicit method:
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))
}
If silent
parameter is false
(true
by default), TypecheckException
will be thrown in case of an inference error. So you could analize it to find list of ambigious implicits.
P.S. If type B
is uncknown - there is no (documented) way to find all implicits using macroses: openImplicits
/enclosingImplicits
just looking for implicits being materialized in context of macro-expansion - not for all, that exists in the context. Compiler-plugin may help, but it's not so easy then.
If you really decide to try "compiler-plugin" way - the logic of finding implicits is implemented here. Here you can find compiler's Context
(not same as macro's) and its implicitss
field, which contains all implicits in the context (but it's not so trivial to obtain appropriate context).
And I shouldn't tell you but there is a tricky and unsafe hack to lift from macro Context
to compiler's level and do what you want:
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:
Anyway, you have to analize a list of ImplicitInfo
to obtain implicits you're looking for and it may not be trivial, as you can see from Analizer
's sources, but at least it's possible to get approximate result, which may be fine for your needs. But again, it's better to do that very very very careful, as structures you working with are mutable and methods are not pure. And, as @Eugene Burmako noticed, this solution doesn't give you implicits from companion object.
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