scala - type parameter mismatch with WeakTypeTag reflection + quasiquoting (I think!) -


inspired travisbrown, i'm trying use macro create "smart constructors".

given

package mypkg sealed trait hello[a] case class ohayo[a,b](a: (a,b)) extends hello[a] 

and

val smartconstructors = freemacros.liftconstructors[hello] 

the macro should find subclasses of hello, @ constructors, , extract few elements populate tree "smart constructor":

q"""   def $methodname[..$typeparams](...$paramlists): $basetype =     $companionsymbol[..$typeargs](...$arglists)  """ 

i hoped get:

val smartconstructors = new {   def ohayo[a, b](a: (a, b)): hello[a] = ohayo[a, b](a) } 

but instead get:

error: type mismatch;  found   : (a(in class ohayo), b(in class ohayo))  required: ((some other)a(in class ohayo), (some other)b(in class ohayo))        val liftedconstructors = freemacros.liftconstructors[hello] 

at glance, tree looks ok me:

scala> q" new { ..$welltyped }" res1: u.tree = {   final class $anon extends scala.anyref {     def <init>() = {       super.<init>();       ()     };     def ohayo[a, b](a: (a, b)): net.arya.constructors.hello[a] = ohayo[a, b](a)   };   new $anon() } 

but guess invisibly isn't. if naively try freshen typeparams info.typeparams.map(p => typename(p.name.tostring)), "can't splice type parameter" when quasiquoting.

where going wrong? taking look.

-arya

import scala.language.experimental.macros import scala.reflect.api.universe import scala.reflect.macros.whitebox  class freemacros(val c: whitebox.context) {   import c.universe._   import freemacros._     def liftedimpl[f[_]](implicit t: c.weaktypetag[f[_]]): tree = {     val atc = t.tpe      val childsymbols: set[classsymbol] = subcaseclasssymbols(c.universe)(atc.typesymbol.asclass)     val welltyped = childsymbols.map(ctorsforsymbol(c.universe)(atc)).unzip       q"new { ..${welltyped} }"   } }   object freemacros {   def liftconstructors[f[_]]: = macro freemacros.liftedimpl[f]     def smartname(name: string): string = (     name.tolist match {       case h :: t => h.tolower :: t       case nil => nil     }   ).mkstring     def subcaseclasssymbols(u: universe)(root: u.classsymbol): set[u.classsymbol] = {     val subclasses = root.knowndirectsubclasses     val cast = subclasses.map(_.asinstanceof[u.classsymbol])     val partitioned = mapped.partition(_.iscaseclass)     partitioned match {       case (caseclasses, regularclasses) => caseclasses ++ regularclasses.flatmap(r => subcaseclasssymbols(u)(r))     }   }     def ctorsforsymbol(u: universe)(atc: u.type)(caseclass: u.classsymbol): (u.defdef, u.defdef) = {     import u._     import internal._  // these didn't //    def cleartypesymbol(s: symbol): typesymbol = internal.newtypesymbol(nosymbol, s.name.totypename, s.pos, if(s.isimplicit)flag.implicit else noflags) //    def cleartypesymbol2(s: symbol): typesymbol = internal.newtypesymbol(nosymbol, s.name.totypename, noposition, if(s.isimplicit)flag.implicit else noflags) //    def cleartypedef(d: typedef): typedef = internal.typedef(cleartypesymbol(d.symbol))      val companionsymbol: symbol = caseclass.companion     val info: type = caseclass.info      val primaryctor: symbol = caseclass.primaryconstructor     val method = primaryctor.asmethod     val typeparams = info.typeparams.map(internal.typedef(_)) //    val typeparams = info.typeparams.map(s => typedef(newtypesymbol(nosymbol, s.name.totypename, noposition, noflags))) //    val typeparams = info.typeparams.map(s => internal.typedef(cleartypesymbol2(s)))     val typeargs = info.typeparams.map(_.name)     val paramlists = method.paramlists.map(_.map(internal.valdef(_)))     val arglists = method.paramlists.map(_.map(_.asterm.name))     val basetype = info.basetype(atc.typesymbol)     val list(returntype) = basetype.typeargs      val methodname = termname(smartname(caseclass.name.tostring))      val welltyped =       q"""           def $methodname[..$typeparams](...$paramlists): $basetype =             $companionsymbol[..$typeargs](...$arglists)         """       welltyped   } } 

p.s. have been experimenting toolbox.untypecheck / typecheck per this article haven't found working combination.

you need using

clas.typeargs.map(_.tostring).map(name => {   typedef(modifiers(flag.param),typename(name), list(),typeboundstree(emptytree, emptytree))       } 

replace info.typeparams.map(p => typename(p.name.tostring))

it si code

object getsealedsubclass {    def ol3[t]: = macro getsealedsubclassimpl.ol3[t] }  class getsealedsubclassimpl(val c: context) {    import c.universe._    def showinfo(s: string) =     c.info(c.enclosingposition, s.split("\n").mkstring("\n |---macro info---\n |", "\n |", ""), true)    def ol3[t: c.weaktypetag]: c.universe.tree = {      //get sub class     val subclass = c.weaktypeof[t]       .typesymbol.asclass.knowndirectsubclasses       .map(e => e.asclass.totype)      //check type params must ia s sealed class     if (subclass.size < 1)       c.abort(c.enclosingposition, s"${c.weaktypeof[t]} not sealed class")      // sub class constructor params     val subconstructorparams = subclass.map { e =>       //get constructor       e.members.filter(_.isconstructor)         //if class has many constructor need filter main constructor         .head.map(s => s.asmethod)       //get function param list     }.map(_.asmethod.paramlists.head)       .map(_.map(e => q"""${e.name.totermname}:${e.info} """))      val outfunc = subclass zip subconstructorparams map {       case (clas, parm) =>         q"def smartconstructors[..${           clas.typeargs.map(_.tostring).map(name => {             typedef(modifiers(flag.param), typename(name), list(), typeboundstree(emptytree, emptytree))           })         }](..${parm})=${clas.typesymbol.name.totermname} (..${parm})"     }      val outclass =       q"""          object term{                  ..${outfunc}                  }           """     showinfo(show(outclass))     q"""{       $outclass         term       }       """   } } 

using

sealed trait hello[a]  case class ohayo[a, b](a: (a, b)) extends hello[a]  object getsealed extends app {   val = getsealedsubclass.ol3[hello[_]]   val b=a.asinstanceof[ {def smartconstructors[a, b](a: (a, b)): ohayo[a, b]}].smartconstructors(1, 2).a   println(b) } 

Comments

Popular posts from this blog

javascript - gulp-nodemon - nodejs restart after file change - Error: listen EADDRINUSE events.js:85 -

Fatal Python error: Py_Initialize: unable to load the file system codec. ImportError: No module named 'encodings' -

javascript - oscilloscope of speaker input stops rendering after a few seconds -