0

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?

Luke Eller
  • 627
  • 1
  • 7
  • 23

1 Answers1

1

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).

Mateusz Kubuszok
  • 24,995
  • 4
  • 42
  • 64
  • I have a clarification which I'll add to the question, but wanted to check if it changes anything. I don't need to pass the type from the call site, but instead obtain it from within the macro runtime. The call site can be ignorant of the types that are generated. Just imagine some object within the macro that provides a means to obtain the Class instance. Does that change things? I'm guessing it would only because I am able to get the Class instance I need and could in theory obtain the correct result with that verbose syntax, so I'm really just looking for a way to simplify that. – Luke Eller Apr 02 '20 at 22:30