In a Scala 3 macro, given a Symbol
for a method, what would be the most straightforward way to get the return type of that method?
More concretely, suppose I have a type name Foo
that corresponds to a trait, and a method name. I can obtain a Symbol
for that name with this:
// elsewhere
trait Foo:
def bar[A](a: A)(b: String): Boolean
// in the macro
val methodSymbol = TypeRepr.of[Foo].typeSymbol.methodMember("bar").head
I can use methodSymbol.info
to get the full signature of methodSymbol
, but that can be an arbitrarily nested chain of MethodType
s and PolyType
s. How do I get the final return type without traversing this chain? In the example, how do I get a TypeRepr
that corresponds to Boolean
.
Note that in the macro Foo
is actually a type-parameter, so I can only look up the method by its name and I don't have any further info about it.
Thanks
I am using something like:
def returnTypeOf(tpe: TypeRepr, method: Symbol): Type[?] =
tpe.memberType(method).widenByName match {
case lambda: LambdaType => lambda.resType.asType
case out => out.asType
}
It's basically an existential type, which is hard to work with, so I am usually using it with:
trait ExistentialType {
type Underlying
implicit val Underlying: Type[Underlying]
}
val someType = new ExistentialType {
val Underlying = returnTypeOf(repr, method).asInstanceOf[Type[Underlying]]
}
import someType.Underlying as SomeType
Type.of[SomeType]
TypeRepr.of[SomeType]
term.asExprOf[SomeType[
etc
EDIT if you want to expand it recursively you need to use
def returnTypeOf(tpe: TypeRepr, method: Symbol): Type[?] = {
def loop(tpe: TypeRepr): Type[?] = tpe match {
case lambda: LambdaType => loop(lambda.resType)
case out => out.asType
}
loop(tpe.memberType(method).widenByName)
}
There is support for such things in public reflection API, it's one of these things that do have API - in compiler's internals, which are not public, are not set in stone, and are not intended to be used by users. If you want a stable way of using features like this, you have to implement them yourself on top of the raw quotes.reflect API.