在宏扩展时访问特定符号的 typeSignature 时确认编译失败
Compilation failure is confirmed at the moment of accessing typeSignature of a specific symbol at macro expansion
我不得不查看宏中的特定声明并单独检查它们。
许多此类错误在尝试检查 akka 流声明时发生。
def getType(symbol: Symbol): Type = {
symbol.typeSignature
}
[error] error while loading SmallSortedMap$Entry, class file '/Users/xxx/.ivy2/cache/com.typesafe.akka/akka-protobuf_2.13/jars/akka-protobuf_2.13-2.5.23.jar(akka/protobuf/SmallSortedMap$Entry.class)' is broken
[error] (class java.util.NoSuchElementException/key not found: K)
这样看来,访问特定符号的typeSygnature时似乎出错了。
我要忽略这个,隐藏它,编译成功
def getType(symbol: Symbol): Option[Type] = {
Try {
symbol.typeSignature
}.getOrElse(None) // Can not capture
}
不过,好像“class坏掉了”用“Try”抓不到。
例如,带有此符号的包被排除在黑名单之外。因此,每次添加依赖时都可能发生复杂的维护。
if (symbol.isNotBroken) {
symbol.typeSignature
}
这种方式有办法解决吗?
尝试
我试过 typeCheck。
implicit class RichVectorSymbol(value: Vector[Symbol]) {
def accessible: Vector[Symbol] = {
value.flatMap { x =>
scala.util.Try {
print(s"typecheck ${x.fullName} ")
c.typecheck(q"${c.parse(x.fullName)}", silent = true)
} match {
case Success(r) if r.nonEmpty =>
println("Success")
Some(r.symbol)
case Failure(e) =>
println("Fail")
c.warning(c.enclosingPosition, e.getMessage)
None
case _ =>
println("Empty")
None
}
}
}
}
结果。
// Success case
typecheck akka.event.jul.Logger Success
typecheck akka.io.dns.CachePolicy Success
typecheck akka.io.dns.DnsSettings Success
// Fail case
typecheck com.fasterxml.jackson.databind.ObjectMapper [error] error while loading ObjectMapper, class file '/Users/xxxxx/.ivy2/cache/com.fasterxml.jackson.core/jackson-databind/bundles/jackson-databind-2.9.8.jar(com/fasterxml/jackson/databind/ObjectMapper.class)' is broken
[error] (class java.util.NoSuchElementException/key not found: T)
Empty
typecheck akka.protobuf.SmallSortedMap$Entry [error] error while loading SmallSortedMap$Entry, class file '/Users/xxxxx/.ivy2/cache/com.typesafe.akka/akka-protobuf_2.13/jars/akka-protobuf_2.13-2.5.23.jar(akka/protobuf/SmallSortedMap$Entry.class)' is broken
[error] (class java.util.NoSuchElementException/key not found: K)
Empty
像这样,我被逼编译出错了。
样本在这里。
https://github.com/giiita/scaladia/blob/master/scaladia-macro/src/main/scala/com/phylage/scaladia/internal/AutoDIExtractor.scala
调试
看了scala源码后,我在内部抛出一个明确的IOException,但我无法捕捉到它,所以我报告了这个问题以防万一
https://github.com/scala/bug/issues/11611
在宏中你可以试试
c.typecheck(q"${... some tree ...}", silent = true)
If tree 不对这个 returns 空树进行类型检查。
akka.protobuf.SmallSortedMap$Entry
中的内容似乎是美元符号。如果我们将 $
替换为 #
或 .
则错误 class file is broken
变为 class SmallSortedMap in package protobuf cannot be accessed in package akka.protobuf
,这是因为 SmallSortedMap
has package-private(Java默认)访问。
当我将类型作为字符串参数提供给宏并使用 #
或 .
而不是 $
时,我设法捕获了错误。
def foo[T]: Unit = macro fooImpl[T]
def fooImpl[T: c.WeakTypeTag](c: blackbox.Context): c.Tree = {
import c.universe._
try {
println(weakTypeOf[T].typeSymbol.typeSignature)
} catch {
case ex: Throwable => println(ex)
}
q"()"
}
def foo1(tpe: String): Unit = macro foo1Impl
def foo1Impl(c: blackbox.Context)(tpe: c.Tree): c.Tree = {
import c.universe._
val q"${tpeStr: String}" = tpe
try {
println(c.typecheck(c.parse(s"val ${c.freshName()}: $tpeStr = ???")))
// println(c.typecheck(c.parse(tpeStr), mode = c.TYPEmode))
// println(c.typecheck(c.parse(tpeStr), mode = c.TYPEmode).symbol.companion.typeSignature)
// println(c.typecheck(c.parse(tpeStr), mode = c.TYPEmode).tpe.typeSymbol.typeSignature)
// println(c.typecheck(c.parse(tpeStr), mode = c.TYPEmode).tpe)
} catch {
case ex: Throwable => println(ex)
}
q"()"
}
foo[Int]
// foo[akka.protobuf.SmallSortedMap$Entry]//Error:scalac: error while loading SmallSortedMap$Entry, class file '.ivy2/cache/com.typesafe.akka/akka-protobuf_2.13/jars/akka-protobuf_2.13-2.5.23.jar(akka/protobuf/SmallSortedMap$Entry.class)' is broken(class java.util.NoSuchElementException/key not found: K)
// foo[akka.protobuf.SmallSortedMap#Entry]//Error: class SmallSortedMap in package protobuf cannot be accessed in package akka.protobuf
// foo[akka.protobuf.SmallSortedMap.Entry]//Error:class SmallSortedMap in package protobuf cannot be accessed in package akka.protobuf
// foo1("Int")
// foo1("akka.protobuf.SmallSortedMap$Entry")//Error:scalac: error while loading SmallSortedMap$Entry, class file '.ivy2/cache/com.typesafe.akka/akka-protobuf_2.13/jars/akka-protobuf_2.13-2.5.23.jar(akka/protobuf/SmallSortedMap$Entry.class)' is broken (class java.util.NoSuchElementException/key not found: K)
foo1("akka.protobuf.SmallSortedMap#Entry")//Warning:scalac: scala.reflect.macros.TypecheckException: class SmallSortedMap in package protobuf cannot be accessed in package akka.protobuf
foo1("akka.protobuf.SmallSortedMap.Entry")//Warning:scalac: scala.reflect.macros.TypecheckException: class SmallSortedMap in package protobuf cannot be accessed in package akka.protobuf
否则,当您调用 foo[... SomeType ...]
时,SomeType
会在宏 foo
展开之前进行类型检查。
http://www.scala-archive.org/Expand-macros-before-typechecking-its-arguments-trees-td4641188.html
我不得不查看宏中的特定声明并单独检查它们。 许多此类错误在尝试检查 akka 流声明时发生。
def getType(symbol: Symbol): Type = {
symbol.typeSignature
}
[error] error while loading SmallSortedMap$Entry, class file '/Users/xxx/.ivy2/cache/com.typesafe.akka/akka-protobuf_2.13/jars/akka-protobuf_2.13-2.5.23.jar(akka/protobuf/SmallSortedMap$Entry.class)' is broken
[error] (class java.util.NoSuchElementException/key not found: K)
这样看来,访问特定符号的typeSygnature时似乎出错了。
我要忽略这个,隐藏它,编译成功
def getType(symbol: Symbol): Option[Type] = {
Try {
symbol.typeSignature
}.getOrElse(None) // Can not capture
}
不过,好像“class坏掉了”用“Try”抓不到。 例如,带有此符号的包被排除在黑名单之外。因此,每次添加依赖时都可能发生复杂的维护。
if (symbol.isNotBroken) {
symbol.typeSignature
}
这种方式有办法解决吗?
尝试
我试过 typeCheck。
implicit class RichVectorSymbol(value: Vector[Symbol]) {
def accessible: Vector[Symbol] = {
value.flatMap { x =>
scala.util.Try {
print(s"typecheck ${x.fullName} ")
c.typecheck(q"${c.parse(x.fullName)}", silent = true)
} match {
case Success(r) if r.nonEmpty =>
println("Success")
Some(r.symbol)
case Failure(e) =>
println("Fail")
c.warning(c.enclosingPosition, e.getMessage)
None
case _ =>
println("Empty")
None
}
}
}
}
结果。
// Success case
typecheck akka.event.jul.Logger Success
typecheck akka.io.dns.CachePolicy Success
typecheck akka.io.dns.DnsSettings Success
// Fail case
typecheck com.fasterxml.jackson.databind.ObjectMapper [error] error while loading ObjectMapper, class file '/Users/xxxxx/.ivy2/cache/com.fasterxml.jackson.core/jackson-databind/bundles/jackson-databind-2.9.8.jar(com/fasterxml/jackson/databind/ObjectMapper.class)' is broken
[error] (class java.util.NoSuchElementException/key not found: T)
Empty
typecheck akka.protobuf.SmallSortedMap$Entry [error] error while loading SmallSortedMap$Entry, class file '/Users/xxxxx/.ivy2/cache/com.typesafe.akka/akka-protobuf_2.13/jars/akka-protobuf_2.13-2.5.23.jar(akka/protobuf/SmallSortedMap$Entry.class)' is broken
[error] (class java.util.NoSuchElementException/key not found: K)
Empty
像这样,我被逼编译出错了。 样本在这里。 https://github.com/giiita/scaladia/blob/master/scaladia-macro/src/main/scala/com/phylage/scaladia/internal/AutoDIExtractor.scala
调试
看了scala源码后,我在内部抛出一个明确的IOException,但我无法捕捉到它,所以我报告了这个问题以防万一 https://github.com/scala/bug/issues/11611
在宏中你可以试试
c.typecheck(q"${... some tree ...}", silent = true)
If tree 不对这个 returns 空树进行类型检查。
akka.protobuf.SmallSortedMap$Entry
中的内容似乎是美元符号。如果我们将 $
替换为 #
或 .
则错误 class file is broken
变为 class SmallSortedMap in package protobuf cannot be accessed in package akka.protobuf
,这是因为 SmallSortedMap
has package-private(Java默认)访问。
当我将类型作为字符串参数提供给宏并使用 #
或 .
而不是 $
时,我设法捕获了错误。
def foo[T]: Unit = macro fooImpl[T]
def fooImpl[T: c.WeakTypeTag](c: blackbox.Context): c.Tree = {
import c.universe._
try {
println(weakTypeOf[T].typeSymbol.typeSignature)
} catch {
case ex: Throwable => println(ex)
}
q"()"
}
def foo1(tpe: String): Unit = macro foo1Impl
def foo1Impl(c: blackbox.Context)(tpe: c.Tree): c.Tree = {
import c.universe._
val q"${tpeStr: String}" = tpe
try {
println(c.typecheck(c.parse(s"val ${c.freshName()}: $tpeStr = ???")))
// println(c.typecheck(c.parse(tpeStr), mode = c.TYPEmode))
// println(c.typecheck(c.parse(tpeStr), mode = c.TYPEmode).symbol.companion.typeSignature)
// println(c.typecheck(c.parse(tpeStr), mode = c.TYPEmode).tpe.typeSymbol.typeSignature)
// println(c.typecheck(c.parse(tpeStr), mode = c.TYPEmode).tpe)
} catch {
case ex: Throwable => println(ex)
}
q"()"
}
foo[Int]
// foo[akka.protobuf.SmallSortedMap$Entry]//Error:scalac: error while loading SmallSortedMap$Entry, class file '.ivy2/cache/com.typesafe.akka/akka-protobuf_2.13/jars/akka-protobuf_2.13-2.5.23.jar(akka/protobuf/SmallSortedMap$Entry.class)' is broken(class java.util.NoSuchElementException/key not found: K)
// foo[akka.protobuf.SmallSortedMap#Entry]//Error: class SmallSortedMap in package protobuf cannot be accessed in package akka.protobuf
// foo[akka.protobuf.SmallSortedMap.Entry]//Error:class SmallSortedMap in package protobuf cannot be accessed in package akka.protobuf
// foo1("Int")
// foo1("akka.protobuf.SmallSortedMap$Entry")//Error:scalac: error while loading SmallSortedMap$Entry, class file '.ivy2/cache/com.typesafe.akka/akka-protobuf_2.13/jars/akka-protobuf_2.13-2.5.23.jar(akka/protobuf/SmallSortedMap$Entry.class)' is broken (class java.util.NoSuchElementException/key not found: K)
foo1("akka.protobuf.SmallSortedMap#Entry")//Warning:scalac: scala.reflect.macros.TypecheckException: class SmallSortedMap in package protobuf cannot be accessed in package akka.protobuf
foo1("akka.protobuf.SmallSortedMap.Entry")//Warning:scalac: scala.reflect.macros.TypecheckException: class SmallSortedMap in package protobuf cannot be accessed in package akka.protobuf
否则,当您调用 foo[... SomeType ...]
时,SomeType
会在宏 foo
展开之前进行类型检查。
http://www.scala-archive.org/Expand-macros-before-typechecking-its-arguments-trees-td4641188.html