Hello,
I’ve been working on a compile plugin whose components run after typer and I’ve run into a handful of different issues that seem to relate to naming. I have a couple examples here which produce different but seemingly related errors. Can someone help with looking into these errors? Thanks.
My plugin component
to which I’ve added to Transformer.transform in each of the cases
private class Component extends PluginComponent with TypingTransformers with Transform {
val global: TestPlugin.this.global.type = TestPlugin.this.global
val runsAfter = List[String]("typer")
val phaseName = "myPlugin"
protected def newTransformer(unit: CompilationUnit): Transformer = new Transformer(unit)
class Transformer(unit: global.CompilationUnit) extends TypingTransformer(unit) {
override def transform(t: global.Tree): global.Tree = {
t match {
// Add more cases here...
case _ => super.transform(t)
}
}
}
}
Case 1: Renaming/creating new function and calling it
Expectation: I expect my program to print out hello after this transformation.
Reality: Compilation error
Note: If I print out the tree after the transformation the tree looks as I would expect, with hello replacing goodbye properly.
Source File:
object Test extends App {
def goodbye(): Unit = { //Transform to def hello()
println("goodbye")
}
goodbye() // Transform to hello()
}
Added match-case in transform: (this fails even if the funcCall case is in a different plugin component that runs after)
case def @ DefDef(_, TermName("hello"), _, _, _, _) =>
val tree =
q"""
def hello(): Unit= {
println("hello")
}
""".asInstanceOf[DefDef]
val DefDef(modifiers, name, tparams, vparams, tpt, rhs) = tree
val source = treeCopy.DefDef(tree, modifiers, name, tparams, vparams, tpt, rhs)
localTyper.namer.enterDefDef(source)
localTyper typed source
...
// transform goodbye() to hello()
case funcCall @ Apply(Select(This(TypeName("Test")), TermName("goodbye")), List()) =>
val source = Apply(Select(This(TypeName("Test")), TermName("hello")), List())
localTyper typed source
Error when compiling:
[error] scala.reflect.internal.Types$TypeError: value goodbye is not a member of object test.Test
Case 2: Overwriting an object /copying an object (post-typer)
Expectation: Should compile fine with nothing effectively changed since I’m replacing object Test with a copy of itself.
Reality: Compilation Error
Note: If I print out the tree after the transformation, the tree looks as I would expect, exactly like the source file should look at this point in the compiler.
Source File:
object Test extends App {
val x = 0 // works without this line.
}
Added match-case in transform: (this fails even if the funcCall case is in a different plugin component that runs after)
case obj@ModuleDef(_, termName("Test"), _) =>
val q"$mods object $tname extends { ..$earlydefns } with ..$parents { $self => ..$body }" = obj
//Effectively just copy the tree
val source = q"$mods object $tname extends { ..$earlydefns } with ..$parents { $self => ..$body }".asInstanceOf[ModuleDef]
localTyper.namer.enterModuleDef(source)
localTyper typed source
Error when compiling:
scala.reflect.internal.Types$TypeError: value x in object Test cannot be accessed in object Test
exception when typing Test.this.x/class scala.reflect.internal.Trees$Select