How to combine type programming with Scala macros

I would like to use a macro that uses the type defined by the "type" keyword. How to do it?

My source code

import scala.reflect.macros.Context import scala.language.experimental.macros trait Demo6 { type T def add(param: Any): T = macro Demo6.addImpl[T] def fullAdd(param: Any, toStringBasedOnAST: String): T = { doesSomeThing_and_returnsSomething_OfTypeT } def doesSomeThing_and_returnsSomething_OfTypeT: T //just to allow compilation } object Demo6 { def addImpl[T: c.WeakTypeTag](c: Context)(param: c.Expr[Any]): c.Expr[T] = { import c.universe._ reify { (c.Expr[Demo6](c.prefix.tree)).splice.fullAdd(param.splice, c.literal(show(param.tree)).splice) } // ^ - type mismatch; found : org.autotdd.scalamacros.Demo6#T // required: T } } 

I noted a compiler error in the example. It is pretty clear what is happening: the type T defined by the keyword does not match the type T that I pass.

What I tried There is no documentation for scala-macros yet. The section at http://docs.scala-lang.org/overviews/macros/overview.html has been very useful to me so far, but its example uses the class level and the general method level. I looked at the code for Expecty and macrocosm, which are related to the projects specified in the documentation, but could not find such code.

+4
source share
1 answer

Your code is almost right, just change the parameter of type Expr :

 val expr = reify { ... } c.Expr[T](expr.tree) 

Without reify you should return this:

 c.Expr[T](Apply(Select(c.prefix.tree, newTermName("fullAdd")), List(param.tree, Literal(Constant(show(param.tree)))))) 

reify creates the same, but with the wrong type parameter.

See this answer for using showRaw .

In this case:

 scala> import reflect.runtime.universe._ import reflect.runtime.universe._ scala> { | object Demo { def fullAdd(param1: Any, param2: String): String = "result" } | showRaw{ reify { Demo.fullAdd("param1", "param2") } } | } res0: String = Expr(Apply(Select(Ident(newTermName("Demo")), newTermName("fullAdd")), List(Literal(Constant("param1")), Literal(Constant("param2"))))) 

Replace Ident(newTermName("Demo")) with c.prefix.tree , Literal(Constant("param1")) with param.tree and "param2" with show(param.tree) and you will get your result.

+4
source

Source: https://habr.com/ru/post/1479704/


All Articles