编写scala编译器插件时,如何为原始AST设置符号?

use*_*007 5 scala abstract-syntax-tree

我正在使用一个scala编译器插件,该插件f(x)用块替换函数调用

{
val newvalue = f(x)
newvalue
}
Run Code Online (Sandbox Code Playgroud)

此块的值与相同f(x)

编译器插件在编译器阶段“ typer”之后立即工作,并通过用块的AST替换f(x)的AST进行上述转换。

在编译器阶段“ typer”之后执行此操作,新创建的块是未包含符号和类型的原始AST及其子AST。我需要调用localTyper来提供原始ASTs符号和类型。

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

注意:a是函数调用“ f(x)newVal的AST ,是“ ” 的AST val newvalue = f(x)。并且newIdentnewvalue该块中对“ ” 的引用。parSymbol是旧版AST的所有者的符号“ f(x)”,或a

上面的代码在大多数情况下都能正常工作。但是,当在应用于函数“ f”的参数中有一些值的定义(无论是显式的还是隐式的)时,编译器都会发出错误。例如,我要转换:

object hello {

    def f(x : Unit) = {}

    def g =  f {
        try {  

        }
        catch {         
          case t : InterruptedException => t
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,在函数g的定义中,f占用了一​​个块

{
   try { 

   }
   catch {         
     case t : InterruptedException => t
   }
}
Run Code Online (Sandbox Code Playgroud)

作为其参数,并且t是此参数中新定义的值(隐式)。在这种情况下,在编译器阶段“ 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
Run Code Online (Sandbox Code Playgroud)

在“ icode”阶段,理想的转换结果应如下所示:

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

但是,在错误消息中:

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
  };
  ()
}
Run Code Online (Sandbox Code Playgroud)

似乎t应该在“ icode”阶段消失,但是由于进行了转换,因此以某种方式保留了该代码,但是t不再提供的定义。我猜想如何为原始AST设置符号是关键。