How to set the symbol for a raw AST when writing a scala compiler plugin?

邮差的信 提交于 2019-12-06 03:56:17

问题


I'm working with a scala compiler plugin which replaces function calls like f(x) with a block

{
val newvalue = f(x)
newvalue
}

This block has the same value as f(x).

The compiler plugin works right after compiler phase "typer" and do the transformation above by replacing the AST of f(x) with the AST of the block.

Doing this after compiler phase "typer", the newly created block is a raw AST, without symbol and type, as well as its child ASTs. I need to call localTyper to give the raw ASTs symbols and types.

val newVal = (ValDef(Modifiers(0), newTermName("newvalue"), TypeTree(a.tpe), a))
val newIdent = (Ident(newTermName("newvalue")))
localTyper.atOwner(parSymbol).typed(Block(List(newVal), newIdent))

Note: a is the AST of function call "f(x)", newVal is the AST of "val newvalue = f(x)". and newIdent is the reference to "newvalue" in the block. parSymbol is the symbol of the owner of old AST "f(x)", or a.

The code above works well in most cases. However, when there are some definitions of values (no matter explicit or implicit) in the argument applied to function "f", the compiler issues error. For example, I want to transform:

object hello {

    def f(x : Unit) = {}

    def g =  f {
        try {  

        }
        catch {         
          case t : InterruptedException => t
        }
    }
}

Note that in the definition of function g, f takes a block

{
   try { 

   }
   catch {         
     case t : InterruptedException => t
   }
}

as its parameter, and t is a newly defined value (implicit) in this parameter. In this case, I get an error in the compiler phase "icode":

error: scala.reflect.internal.FatalError:
  symbol value t#16922 does not exist in hello.g, which contains locals value newvalue#16940.
Method code: def g(): scala.Unit = {
  val newvalue: scala#27.runtime#2827.BoxedUnit#4159 = {
    hello.this.f({
      {
        hello.this.liftedTree1$1(t);
        scala.runtime.BoxedUnit.UNIT
      }
    });
    scala.runtime.BoxedUnit.UNIT
  };
  ()
}
     while compiling: testSynthetic.scala
        during phase: icode
     library version: version 2.11.7
    compiler version: version 2.11.7
  reconstructed args: -Xplugin:output.jar -uniqid

  last tree to typer: Ident(liftedTree1)
       tree position: line 6 of testSynthetic.scala
            tree tpe: ()Unit#2648
              symbol: (final private[this]) method liftedTree1$1#16976 in object hello#8325
   symbol definition: final private[this] def liftedTree1$1#16976(t$1#27328: InterruptedException#151): Unit#2648 (a MethodSymbol)
      symbol package: <empty>
       symbol owners: method liftedTree1$1#16976 -> object hello#8325
           call site: object hello#8325 in package <empty>#4

In phase "icode" the ideal result of transformation should look like this:

def g(): Unit = {
      val newvalue: Unit = hello.this.f({
        {
          hello.this.liftedTree1$1();
          scala.runtime.BoxedUnit.UNIT
        }
      });
      newvalue
    };

However, in the error message:

def g(): scala.Unit = {
  val newvalue: scala#27.runtime#2827.BoxedUnit#4159 = {
    hello.this.f({
      {
        hello.this.liftedTree1$1(t);
        scala.runtime.BoxedUnit.UNIT
      }
    });
    scala.runtime.BoxedUnit.UNIT
  };
  ()
}

It seems that the t should disappear by phase "icode", but because of the transformation, it is somehow reserved but the definition of t is no longer available. I guess how to set symbols for the raw ASTs are the critical thing here.

来源:https://stackoverflow.com/questions/32389716/how-to-set-the-symbol-for-a-raw-ast-when-writing-a-scala-compiler-plugin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!