2015-04-23 24 views
6

ho capito il concetto di base di macro in Scala, ma attualmente non riescono a fare questo (semplice?) Lavoro:Trovare definizioni dei metodi impliciti nel contesto macro

  • Trova tutti impliciti def s/val s attualmente visibile al compilatore per trasformare da un dato tipo a un altro.

Quello che mi aspetto di ottenere è un List di Method oggetti o qualcosa di simile. Ho già giocato con enclosingImplicits ma ottengo sempre una lista vuota e non so davvero dove guardare dopo.

Cosa devo fare per ottenere l'elenco che sto cercando?

risposta

2

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.

+0

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. –

+0

@Travis Brown In tal caso, non ne vedo nemmeno uno, eccetto il compilatore-plugin. – dk14

+0

@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

Problemi correlati