宏Scala反映typeSymbol匹配结果导致超出了GC开销限制

时间:2018-07-08 08:45:36

标签: scala scala-macros scala-reflect scala-macro-paradise

我有一个宏插件,该插件检查实体是否为case类,然后以点表示法返回所有字段。

例如。

case class Language(name: String)
@Lenses
case class Page(a: Language)

因此main方法将返回

Seq("language.name")

这在scala 2.11.6和2.11.8上运行良好,但是,我刚刚将项目更新为2.11.12,并且开始出现GC开销错误。

我以前的方法曾经实现为:

def isCClass(tpe: Type): Boolean = {
  tpe.widen.dealias.typeSymbol.asInstanceOf[ClassSymbol].isCaseClass
}

正如我提到的那样,它可以在2.11.6和2.11.8上运行,但在2.11.12中出现转换错误而失败

exception during macro expansion:
[error] java.lang.ClassCastException:  scala.reflect.internal.Symbols$AbstractTypeSymbol cannot be cast to scala.reflect.api.Symbols$ClassSymbolApi

然后我更新了代码以匹配typeSymbol,如下所示:

  def isCClass(tpe: Type): Boolean = {
    tpe.widen.dealias.typeSymbol match {
      case typeSymbol: ClassSymbol => typeSymbol.asInstanceOf[ClassSymbol].isCaseClass
      case _ => false
    }
  }

但这会导致以下错误:

exception during macro expansion: [error] java.lang.OutOfMemoryError: GC overhead limit exceeded

我的内存增加到了3 / 4gb,但出现了同样的错误。 在我的zsh配置上使用:

alias sbt="sbt -mem 3092"

我添加了一个规范,几乎复制了我感兴趣的实体的所有依赖项类型,这些实体我希望在我的插件项目中提取所有字段名称,包括@Lenses依赖项和测试通过。但到目前为止没有运气。

任何提示都说明匹配是否昂贵

但是,在真实项目中,它是大型代码库中的多个模块,因此它是GC。

更新: 我已更改匹配的实现方式:

def isCClass(tpe: Type): Boolean = {
    val tpeSymbol = tpe.widen.dealias.typeSymbol 
    if (tpeSymbol.isClass) tpeSymbol.asInstanceOf[ClassSymbol].isCaseClass else false
  }

这解决了2.11.12的问题,但是,我尝试使用带有深度嵌套类型的参数的实体回到2.11.8,并且GC引发错误。 看起来这种宏扩展正在引起一些开销或无限循环,因为即使将内存增加到12GB,我仍然看到Java编译器的内存在增加

0 个答案:

没有答案