Consider the following traits:
sealed trait Test
//Test's branches
trait Base {
type Action = Test
}
Now I need to get a ClassSymbol of Test referring to it as Base#Action.
Here is my attempt:
def macroImpl[B <: Base: c.WeakTypeTag](c: blackbox.Context): c.Tree = {
import c.universe._
val baseType = weakTypeOf[B].typeSymbol.asType
val actionType = c.typecheck(tq"$baseType#Action", mode = c.TYPEMode)
println(tq"$actionType") //prints pack.age.Base#Action
println(tq"$actionType".symbol) //prints type Action
println(tq"$actionType".symbol.asClass) //raises scala.ScalaReflectionException: type Action is not a class
}
In my case Base#Action = Test which is definitely a class.
Is there a way to refer to its ClassSymbol from the macro implementation via type projection?
Try firstly take the type of a tree
I guess
val baseType = weakTypeOf[B]will be shorter thanval baseType = weakTypeOf[B].typeSymbol.asType. It's not clear why to go from type to symbol and then back to type.The symbol of type member
Actionof traitBaseand the symbol of traitTestare different. The type memberActionis a type alias forTestbut definitions of traitTestand typeActionare different (symbols represent definitions).The type member
Actionis not a class (trait) itself, it's a type. It's an alias for the type of a class (trait), but not a class itself.Equal types can have different symbols.
I thought that we need to dealias in
tq"$actionType".tpe.dealias(transforming the typeBase#ActionintoTest) but it turns out that here dealiasing is aggressive and automatical sotq"$actionType".tpeis enough (the typeTestalready). Its symboltq"$actionType".tpe.typeSymbolis the symbol of class (trait)Testand we can check that it's aClassSymbol(and cast to it) with.asClass.