0

While maintaining the old Scala code written in Scala 2.10.x, something unexpected happened to me when I tried to type check a TypeTree in macros. Look at the following code,

annottees.map(_.tree).toList match {
  case q"$mods def $name[..$tpes](...$args) : $returnType = { ..$body }" :: Nil =>
    val isUnit = c.typeCheck(q"type T = $returnType; ()").children.head match {
      case TypeDef(_, _, _, tpt) => tpt.tpe =:= typeOf[Unit]
    }
    //... business logic

As you can see, what I want to do is simple - trying to decide if the return type of the annotated method is Unit. It serves the purpose, however I noticed that sometimes AST of returnType got rewritten when returnType is indeed Unit. For example,

The original AST for returnType is,

Select(Ident(scala), newTypeName("Unit"))

After isUnit,

Select(Ident(scala), scala.Unit)

As a result, the macro expansions for some of the methods that return Unit are failed to compile.

Is this a bug or something I should expect? Is there a way to get around it?

Chris Martin
  • 30,334
  • 10
  • 78
  • 137
Sheng
  • 1,697
  • 4
  • 19
  • 33

1 Answers1

0

Ok, so indeed AST tree can be mutable. I have figured I need to pass in a duplicate of returnType to keep it from being transformed to something else.

annottees.map(_.tree).toList match {
  case q"$mods def $name[..$tpes](...$args) : $returnType = { ..$body }" :: Nil =>
    val isUnit = c.typeCheck(q"type T = ${returnType.duplicate}; ()").children.head match {
      case TypeDef(_, _, _, tpt) => tpt.tpe =:= typeOf[Unit]
    }
//... business logic
Sheng
  • 1,697
  • 4
  • 19
  • 33