2

I am developing a macro and in its implementation I get the weakTypeOf T where T is a type parameter of the macro function. I want to splice info, from the method definitions of this concrete type to a new class declaration tree. I cannot get the AST of the type argument (in order to pattern match over it) so I must definitely play with the symbol-based API. My question is how do I splice symbols in more locations than in the indent and member selection?

For example to get a list of symbols I do:

val methodDefs = tpe.declarations
.filter(decl => decl.isMethod && decl.isPublic && !decl.asMethod.isConstructor && !decl.isSynthetic)
.map(symb => symb.asMethod)

And then to splice info to a q interpolator I would like to do this:

val newdefs : List[Tree] = methodDefs.map(methodDef => { q"def ${methodDef.name}[..${methodDef.typeParams}](...${methodDef.paramss}): ${methodDef.returnType} = ???"})

According to how symbols can be spliced (described here (PDF)), I cannot do directly this kind of splicing. What is the correct way of achieving this?

Aggelos Biboudis
  • 1,175
  • 8
  • 27

1 Answers1

2

I suppose something like that would be sufficient:

val newdefs = tpe
    .declarations
    .collect {
        case m: MethodSymbol if !m.isConstructor && m.typeParams.length > 0 => 
            val typeParams =  m.typeParams.map(TypeDef(_))
            val paramss = m.paramss.map(_.map(ValDef(_)))
            val returns = TypeTree(m.returnType)
            q"def ${m.name}[..${typeParams}](...${paramss}): ${returns} = ???"
    }.toList
Aggelos Biboudis
  • 1,175
  • 8
  • 27
  • Yeah, there are some Symbol => Tree factories in the reflection API. You could even say `DefDef(m, q"???")` to the same effect. However, they are all deprecated and might be removed in 2.11.0 :) – Eugene Burmako Jan 04 '14 at 06:28
  • The reason for deprecation is that symbols bring a lot of tricky problems to tree construction, so, whenever possible, we want to get rid of tree APIs that use them. Some background info: https://groups.google.com/forum/#!topic/scala-internals/TtCTPlj_qcQ. – Eugene Burmako Jan 04 '14 at 06:38
  • @EugeneBurmako If `DefDef` is deprecated now, what is the preferred approach? I can't seem to find any straight forward documentation. The deprecation for `DefDef` just says to import `compat` or migrate away. When importing `compat`, you're told to use `internal.defDef`. It's not apparent what other approach would work here. – purefn Feb 04 '16 at 23:01
  • 2
    `internal.defDef` forwards to exactly the same functionality that `DefDef` uses. The `internal` part is there to signify the fact that it's an advanced API and shouldn't be used if you don't have much experience with compiler internals. If you're hesitant about whether you should use `internal` or not, err on the side of caution and try to achieve the same thing with quasiquotes instead. – Eugene Burmako Feb 05 '16 at 10:25
  • Thanks @EugeneBurmako, that makes sense. – purefn Feb 05 '16 at 20:57
  • I have ` This method has been removed from the public API. Import compat._ or migrate away. [error] val termTypeParams = term.typeSignature.typeParams.map(TypeDef(_)) ` on TypeDef(_) – Will Sargent Jan 31 '18 at 05:38