Resolve type projection in scala macro

112 Views Asked by At

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?

1

There are 1 best solutions below

2
On BEST ANSWER

Try firstly take the type of a tree

tq"$actionType".tpe.typeSymbol.asClass

I guess val baseType = weakTypeOf[B] will be shorter than val baseType = weakTypeOf[B].typeSymbol.asType. It's not clear why to go from type to symbol and then back to type.

couldn't you please give a bit of explanation? It's not really obvious

The symbol of type member Action of trait Base and the symbol of trait Test are different. The type member Action is a type alias for Test but definitions of trait Test and type Action 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 type Base#Action into Test) but it turns out that here dealiasing is aggressive and automatical so tq"$actionType".tpe is enough (the type Test already). Its symbol tq"$actionType".tpe.typeSymbol is the symbol of class (trait) Test and we can check that it's a ClassSymbol (and cast to it) with .asClass.