While analysing code from a compiler plugin, is it possible to get the class of an instance?
e.g. if the user code was “myCat.walk()” could I get the information just from that line that the myCat is of class Cat somehow?
At the moment I can match the whole line with app@Apply(name, args)
Compiler phase is after refchecks
Short answer: myTree match { case Apply(Select(x, _), _) => x.tpe.widen }
Longer, REPL-based demonstration:
scala 2.13.3> class Cat { def walk() = { } }
class Cat
scala 2.13.3> val myCat = new Cat
val myCat: Cat = Cat@388be5fd
scala 2.13.3> import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe._
scala 2.13.3> val tree = reify { myCat.walk() }.tree
val tree: reflect.runtime.universe.Tree = myCat.walk()
scala 2.13.3> import scala.tools.reflect.ToolBox
import scala.tools.reflect.ToolBox
scala 2.13.3> val tb = runtimeMirror(getClass.getClassLoader).mkToolBox()
val tb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = scala.tools.reflect.ToolBoxFactory$ToolBoxImpl@125ba798
scala 2.13.3> showRaw(tree)
val res4: String = Apply(Select(Select(Select(Select(Ident(TermName("$read")), TermName("read")), TermName("$iw")), TermName("myCat")), TermName("walk")), List())
scala 2.13.3> tb.typecheck(tree) match { case Apply(Select(x, _), _) => x.tpe.widen }
val res0: reflect.runtime.universe.Type = Cat
This is almost entirely cribbed from https://docs.scala-lang.org/overviews/reflection/symbols-trees-types.html (which I hope you’ve read?). But note the use of .widen
to get from a singleton type (myCat.type
) to a regular type (Cat
).
I include the REPL-based demonstration because being able to interactively explore and experiment with this stuff is a superpower. See Jason Zaugg’s “Scalac Survival Guide”: https://www.youtube.com/watch?v=06oP5IXWveM
Hi thanks tpe.widen worked!
I did read that but a while back so I should read it again, I don’t see anything about tpe.widen in there though? The example with getType doesn’t seem to work for me for some reason… (errors saying compiler mirror not found).
thanks for the ressource
I don’t recall what docs/resources might cover widen
.
The getType
example should work in the REPL if you’ve done import scala.reflect.runtime.universe._
.
1 Like