Non ci può essere un solo implicita da tipo A
-B
nel contesto (o si ottiene ambigua implicita), quindi se si vuole trovare:
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>
Per trovare metodo implicito:
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))
}
Se il parametro silent
è false
(true
per impostazione predefinita), TypecheckException
verrà generato in caso di errore di inferenza. Quindi potresti analizzarlo per trovare una lista di implicazioni ambigue.
P.S. Se il tipo B
non è noto, non esiste un modo (documentato) per trovare tutti gli impliciti utilizzando macrose: openImplicits
/enclosingImplicits
solo cercando gli impliciti che si materializzano nel contesto della macro-espansione - non per tutti, che esiste nel contesto. Il compilatore-plugin può aiutare, ma non è così facile allora.
Se si decide davvero di provare il modo "compiler-plugin", la logica di ricerca degli impliciti viene implementata here. Here è possibile trovare il Context
del compilatore (non uguale a quello delle macro) e il suo campo implicitss
, che contiene tutti gli impliciti nel contesto (ma non è così banale ottenere un contesto appropriato).
E non si dovrebbe dire ma c'è un hack difficile e pericoloso per sollevare dal macro Context
al livello di compilatore e fare quello che vuoi:
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:
In ogni caso, si deve analizza un elenco di ImplicitInfo
per ottenere impliciti che stai cercando e potrebbe non essere banale, come puoi vedere dalle origini di Analizer
, ma almeno è possibile ottenere risultati approssimativi, che potrebbero andare bene per le tue esigenze. Ma ancora una volta, è meglio fare quello molto molto molto attento, in quanto le strutture con cui si sta lavorando sono modificabili ei metodi non sono puri. E, come ha notato @Eugene Burmako, questa soluzione non ti dà impliciti dall'oggetto compagno.
Ho letto la domanda dicendo che il tipo di fonte è stato dato e l'obiettivo non lo era, nel qual caso non penso che ci sia una buona soluzione. –
@Travis Brown In tal caso, non ne vedo nemmeno uno, eccetto il compilatore-plugin. – dk14
@Travis Brown in realtà esiste un modo non documentato non sicuro di farlo (a patto di qualsiasi altro trucco dipendente dal compilatore) con macro :) Il mio esempio fornisce tutti i possibili impliciti, quindi deve essere analizzato ulteriormente (che è anche complicato) – dk14