Nie może być tylko jeden niejawny od rodzaju A
do B
w kontekście (lub masz niejednoznaczną niejawny), więc jeśli chcesz go znaleźć:
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>
Aby znaleźć sposób niejawny:
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))
}
Jeśli parametr silent
jest domyślnie ustawiony na false
(true
), zostanie wygenerowany TypecheckException
w przypadku błędu wnioskowania. Możesz więc go przeanalizować, aby znaleźć listę niejednoznacznych implicite.
P.S. Jeśli typ B
jest nieznany - nie ma (udokumentowanego) sposobu na znalezienie wszystkich implikacji przy użyciu makr: openImplicits
/enclosingImplicits
szukających tylko implikacji materializowanych w kontekście makro-ekspansji - nie dla wszystkich, które istnieją w kontekście. Kompilator-wtyczka może pomóc, ale nie jest to takie proste.
Jeśli naprawdę zdecydujesz się wypróbować "sposób kompilowania wtyczek" - logika wyszukiwania implikacji jest zaimplementowana jako here. Here można znaleźć kompilator Context
(nie taki sam jak makro) i jego pole implicitss
, które zawiera wszystkie implikacje w kontekście (ale nie jest tak banalnie, aby uzyskać odpowiedni kontekst).
I nie powinienem wam ale jest to trudne i niebezpieczne Hack podnieść z makro Context
na poziomie kompilatora i rób co chcesz:
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:
W każdym razie, trzeba zweryfikuj listę ImplicitInfo
, aby uzyskać implicite, czego szukasz i może nie być to banalne, jak widać ze źródeł Analizer
, ale przynajmniej możliwe jest uzyskanie przybliżonego wyniku, który może być odpowiedni dla twoich potrzeb. Ale znowu lepiej jest zrobić to bardzo ostrożnie, ponieważ struktury, z którymi pracujesz, są zmienne, a metody nie są czyste. I, jak zauważył @Eugene Burmako, to rozwiązanie nie daje implicite z obiektu towarzyszącego.
Przeczytałem to pytanie, mówiąc, że podano typ źródła, a cel nie był, w takim przypadku nie sądzę, że istnieje dobre rozwiązanie. –
@Travis Brown W takim przypadku nie widzę żadnych, oprócz wtyczki kompilatora. – dk14
@Travis Brown faktycznie istnieje nieudokumentowana niebezpieczna metoda wykonania tego (tak długo, jak inne sztuczki zależne od kompilatora) z makro :) Mój przykład daje wszystkie możliwe implicity, więc musi być dodatkowo analised (co jest również trudne) – dk14