How to get the class of an instance at compile time?

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 2.13.3> val tb = runtimeMirror(getClass.getClassLoader).mkToolBox()
val tb:[reflect.runtime.universe.type] =$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 (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”:

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