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
Action
of traitBase
and the symbol of traitTest
are different. The type memberAction
is a type alias forTest
but definitions of traitTest
and typeAction
are different (symbols represent definitions).The type member
Action
is 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#Action
intoTest
) but it turns out that here dealiasing is aggressive and automatical sotq"$actionType".tpe
is enough (the typeTest
already). Its symboltq"$actionType".tpe.typeSymbol
is the symbol of class (trait)Test
and we can check that it's aClassSymbol
(and cast to it) with.asClass
.