I have the following macro:
def testMacro[T](x: T): Option[T] = macro testMacroImpl[T] def testMacroImpl[T: c.WeakTypeTag](c: Context)(x: c.Expr[T]): c.Expr[Option[T]] = { import c.universe._ val newTree = x.tree match { case Block(List(first), second) => { val newFirst = first match { case ValDef(mods, name, _, rhs) => ValDef(mods, name, EmptyTree, q"Some($rhs)") } Block(List(newFirst), second) } } c.Expr[Option[T]](newTree) }
Basically, this should just transform this:
testMacro { val aa = "hello" aa }
in
{ val aa = Some("hello") aa }
However, it does not work with the following error:
[error] found : String [error] required: Option[String] [error] val f = IdiomBracket.testMacro{ [error] ^
My investigation shows that this is because it gets a typed tree for which the identifier aa is of type String . Due to code conversion, it is now of type Option[String] , but the type of identifier is not updated. I tried to create a new (untyped) identifier and this only makes an error:
[error] found : <notype> [error] required: Option[String] [error] val f = IdiomBracket.testMacro{ [error] ^
I tried the tree check type before sending it back in the hope that it fills the correct type, but this does not seem to have any effect.
For reference, here is the same macro that creates a new identifier and performs type checking, which, unfortunately, does not work yet.
def testMacroImpl[T: c.WeakTypeTag](c: Context)(x: c.Expr[T]): c.Expr[Option[T]] = { import c.universe._ val newTree = x.tree match { case Block(List(first), second) => { val newFirst = first match { case ValDef(mods, name, _, rhs) => ValDef(mods, name, EmptyTree, q"Some($rhs)") } val newSecond = second match { case ident: Ident => Ident(ident.name) } Block(List(newFirst), newSecond) } } c.Expr[Option[T]](c.typecheck(newTree)) }