The problem is that the weak type tag for U
in the macro implementation has as its argument what's essentially the symbol T
, not Int
.
The following will work (note that I've shortened some names for clarity and replaced deprecated methods):
import scala.language.experimental.macros
import scala.reflect.macros.Context
object Macros {
def applyImpl[
T: c.WeakTypeTag,
U: c.WeakTypeTag
](c: Context)(e: c.Expr[T]): c.Expr[U] = {
import c.universe._
c.Expr[U](
Apply(
Select(
New(
TypeTree(
appliedType(weakTypeOf[U].typeConstructor, weakTypeOf[T] :: Nil)
)
),
nme.CONSTRUCTOR
),
List(e.tree, Literal(Constant(e.tree.toString)))
)
)
}
}
class Signal[T](val expression: T, val expressionText: String)
object Signal {
def apply[T](e: T) = macro Macros.applyImpl[T, Signal[T]]
}
And then:
scala> Signal(1).expressionText
res0: String = 1
As expected.
As Miles Sabin points out on Twitter, it would be nicer to have U
be a type constructor, since in the version above the macro implementation makes some assumptions about U
that aren't captured in the types. The following is a safer approach in this respect:
import scala.language.experimental.macros
import scala.language.higherKinds
import scala.reflect.macros.Context
object Macros {
def applyImpl[
T: c.WeakTypeTag,
U[_]
](c: Context)(e: c.Expr[T])(implicit u: c.WeakTypeTag[U[_]]): c.Expr[U[T]] = {
import c.universe._
c.Expr[U[T]](
Apply(
Select(
New(
TypeTree(
appliedType(u.tpe.typeConstructor, weakTypeOf[T] :: Nil)
)
),
nme.CONSTRUCTOR
),
List(e.tree, Literal(Constant(e.tree.toString)))
)
)
}
}
class Signal[T](val expression: T, val expressionText: String)
object Signal {
def apply[T](e: T) = macro Macros.applyImpl[T, Signal]
}
Note especially the change to the second argument of applyImpl
in Signal
.