In a Scala 3 macro that takes a type parameter T, you can use TypeRepr.of[T] and the new Scala 3 reflection API to explore the companionClass of T, and find the Symbol for an arbitrary method on that companion class (eg companionClass.declarations.find(_.name == "list") to find a list() method).
Given the Symbol for a companion object method, how would you then invoke that method within a quoted code block?
I'm guessing I would need to convert that Symbol to a Expr[T], but I don't know how to do that!
In a Scala 2 macro, the invocation of a listMethod of type c.universe.Symbol in a q"..." quasiquote seems pretty simple - just say $listMethod, and then you can start mapping on the resulting list, eg:
q"""
$listMethod.map(_.toString)
"""
Trying to do a similar thing in a Scala 3 macro gets an error like this:
[error] 27 | ${listMethod}.map(_.toString)
[error] | ^^^^^^^^^^
[error] | Found: (listMethod : x$1.reflect.Symbol)
[error] | Required: quoted.Expr[Any]
What is the correct code to get this working in Scala 3?
You can see more code context in the AvroSerialisableMacro classes (Scala 2 compiles, Scala 3 currently nowhere near!) here: https://github.com/guardian/marley/pull/77/files
First, let's talk how to call a method using symbol name in general.
You might need
Select. You can call obtain it in a a few different ways, e.g.:Once you selected method you can provide arguments:
There are also other methods like
appliedToType,appliedToTypeTrees, but if you have a method name as aSymboland want to use it to call something this should be a good starting point.And remember that source code of
Quotesis your friend, so even when your IDE doesn't give you any suggestions, it can point you towards some solution.In theory these methods are defined on
Termrather thanSelect(<: Term) but your use case will be most likely picking an expression and calling a method on it with some parameters. So a full example could be e.g.Obviously, proving that the
expressioncan callmethodand making sure that types ofTerms inargsmatch allowed types of values that you pass to the method, is on you. It is a bit more hassle than it was in Scala 2 since quotes allow you to work withType[T]andExpr[T]only, so anything that doesn't fall under that category has to be implemented with macros/Tasty ADT until you get to the point that you can returnExprinside${}.That said, the example you linked shows that these calls are rather hardcoded, so you don't have to look up
Symbols and call them. Your code will most likely do away with: