使用宏获取Scala类的实现类型

使用宏获取Scala类的实现类型,scala,scala-macros,Scala,Scala Macros,我对scala宏和识别构造函数的实现类型有一些问题。 不确定我是否做错了什么,或者正确的电话是什么。 从文档中可以看出,typeSignatureIn应该返回正确的信息,例如ClassTag[Int],但是当我运行宏时,我实际得到的ClassTag[U]无法编译,因为U是类型参数,而不是实现的类型 import scala.language.experimental.macros import scala.reflect.ClassTag import scala.reflect.macros.

我对scala宏和识别构造函数的实现类型有一些问题。 不确定我是否做错了什么,或者正确的电话是什么。 从文档中可以看出,
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]]
运行它:

scala> foo[Foo[Int]]
Foo[Int]
Some(List(List(), List(scala.reflect.ClassTag[U]))

我需要以某种方式获取ClassTag[Int]以便以后能够生成正确的树,有什么想法吗?

在解析类型的每个位置尝试使用
dealias
。Scala保留引用,即使它知道引用的内容
dealias
获取已替换引用的类型的副本(?)

您还应该选择黑盒或白盒宏,而不仅仅是
scala.reflect.macros.Context

这似乎有效:

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]]
结果

Foo[Int]
Some(List(List(), List(scala.reflect.ClassTag[Int])))

非常感谢。仍在努力将其集成到更广泛的代码库中,但这给了我一个很好的线索,即下一步要调查什么