[英]Obtaining the realised type for a Scala Class using macros
I have some problems with scala macros and identifying the realised type of a constructor. 我在使用scala宏和确定构造函数的实现类型时遇到一些问题。 Not sure if i am doing something wrong here or what the correct call would be. 不知道我在这里做错了什么还是正确的电话。 From the documentation, it looks like typeSignatureIn
should return the correct information, eg ClassTag[Int], but when I run the macro, I actually get ClassTag[U] which fails to compile as U is the type parameter, rather than the realised type. 从文档看来, typeSignatureIn
应该返回正确的信息,例如ClassTag [Int],但是当我运行宏时,我实际上得到ClassTag [U],由于U是类型参数,而不是已实现的类型,因此无法编译。
import scala.language.experimental.macros
import scala.reflect.ClassTag
import scala.reflect.macros.Context
def macroImpl[T: c.WeakTypeTag](c: Context) = {
import c.universe._
val typeToMock = weakTypeOf[T]
val primaryConstructorOpt = typeToMock.members.collectFirst {
case method: MethodSymbolApi if method.isPrimaryConstructor => method
}
val constructorArgumentsTypes = primaryConstructorOpt.map {
constructor =>
val constructorTypeContext = constructor.typeSignatureIn(typeToMock)
val constructorArguments = constructor.paramss
constructorArguments.map { symbols =>
symbols.map(_.typeSignatureIn(constructorTypeContext))
}
}
println(typeToMock)
println(constructorArgumentsTypes)
c.literalUnit
}
def foo[T] = macro macroImpl[T]
class Foo[U: ClassTag]
foo[Foo[Int]]
running it: 运行它:
scala> foo[Foo[Int]]
Foo[Int]
Some(List(List(), List(scala.reflect.ClassTag[U]))
I need to get the ClassTag[Int] somehow to be able to generate the correct Tree later, any ideas? 我需要以某种方式获取ClassTag [Int],以便稍后能够生成正确的Tree,有什么想法吗?
Try using dealias
at each place you resolve a type. 尝试在您解析类型的每个位置使用dealias
。 Scala keeps references in place, even when it knows to what they refer. 即使知道引用的内容,Scala也会将引用保持在原位。 dealias
gets you a copy (?) of the type that has the references replaced. dealias
会为您提供替换了引用的类型的副本(?)。
You should also choose either blackbox or whitebox macros, rather than just scala.reflect.macros.Context
. 您还应该选择blackbox或whitebox宏,而不仅仅是scala.reflect.macros.Context
。
This seems to work: 这似乎可行:
import scala.language.experimental.macros
import scala.reflect.ClassTag
import scala.reflect.macros.whitebox.Context
def macroImpl[T: c.WeakTypeTag](c: Context) = {
import c.universe._
val typeToMock = weakTypeOf[T].dealias
val primaryConstructorOpt = typeToMock.members.collectFirst {
case method: MethodSymbolApi if method.isPrimaryConstructor => method
}
val constructorArgumentsTypes = primaryConstructorOpt.map { constructor =>
val constructorTypeContext = constructor.typeSignatureIn(typeToMock).dealias
val constructorArguments = constructorTypeContext.paramLists
constructorArguments.map { symbols =>
symbols.map(_.typeSignatureIn(constructorTypeContext).dealias)
}
}
println(typeToMock)
println(constructorArgumentsTypes)
q"()"
}
def foo[T]: Any = macro macroImpl[T]
class Foo[U: ClassTag]
foo[Foo[Int]]
Result 结果
Foo[Int]
Some(List(List(), List(scala.reflect.ClassTag[Int])))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.