Luke Eller
Luke Eller

Reputation: 627

How to dynamically generate a type application with scala quasiquotes

I want to generate a type application so I can call a function like foo.bar[com.a.b.SomeType](baz) where com.a.b.SomeType could be any of a broad range of types. I used reflection within the macro runtime to get a reference to actual class represented by SomeType so I can do things like get the package name, the simple name and the fully-qualified name.

When I write tq"com.a.b.SomeType" I get the desired results, and can use interpolation in my expression, e.g.

val someType = tq"com.a.b.SomeType"
q"""
  foo.bar[$someType](baz)
"""

I need to dynamically create that tq expression using class information that I can obtain from within the macro runtime from a string. I looked at the tree generated by tq"com.example.SomeType" and there is a series of nested Select nodes for each of the packages com, a, b, c, which seems cumbersome to generate manually.

Select(Select(Select(Ident(TermName("com")), TermName("a")), TermName("b")), TypeName("SomeType"))

I imagine there is an easier way that I'm just not seeing.

To that end I tried things like:

tq"${someType.getPackage.getName}.${someType.getSimpleName}"

but I can see that isn't right and get errors like:

Compilation error[MyMacro.this.c.universe.Name expected but MyMacro.this.c.universe.Tree found]

So what is a concise way to achieve what I'm trying to do where the type name is only available via reflection, e.g. as an instance of Class?

Upvotes: 0

Views: 156

Answers (1)

Mateusz Kubuszok
Mateusz Kubuszok

Reputation: 27535

You cannot get a type from runtime reflection because this type will be used in generated code and land in binary. However, you can get the type in compile time from the call site using TypeTag or WeakTypeTag

def myMethod[T] = macro macroImplementation

def macroImplementation[T: c.WeakTypeTag](c: Context) = {
  val typeT = weakTypeOf[T].tpe
  val body = q"""
    foo.bar[$typeT](baz)
  """
  ...
}

that should let you create macros for methods with a type parameters, that you could safely fill in runtime (this typeT will then make sure not that you are using a known type, but that you use something that comes from a type parameter and not from a thin air).

Upvotes: 1

Related Questions