在JSON库jsfacile中,我能够自动将具有递归类型引用thanx的类型的类型类派生到缓冲区,其中宏的外部执行存储实例的实例,universe.Tree
稍后由同一宏或其他宏的内部执行使用。只要universe.Tree
未对实例进行类型检查(使用Typers.typecheck
方法),此方法就可以正常工作。
问题在于,这迫使Tree
多次对同一实例进行类型检查:在创建该实例的宏执行中进行了一次(将其存储在缓冲区中之后);并且在每个需要它的内部宏执行中执行更多次。
这个问题的目的是要找到一种Tree
在类型检查后在宏执行之间共享实例的方法。为了提高编译速度。
我试图将类型检查的代码包装Tree
到中,universe.Expr[Unit]
然后将其迁移到通过该Expr.in[U <: Universe](otherMirror: Mirror[U]): U # Expr[T]
方法使用它的宏执行的镜像中。但是它失败并出现内部错误:
Internal error: unable to find the outer accessor symbol of class <Name of the class where the macro is expanded>
任何想法?
通常,手动对树进行类型检查并在不同的上下文之间共享类型化的树是一个坏主意。请参见以下示例:
import scala.language.experimental.macros
import scala.reflect.macros.whitebox
import scala.collection.mutable
object Macros {
val mtcCache = mutable.Map[whitebox.Context#Type, whitebox.Context#Tree]()
trait MyTypeclass[A]
object MyTypeclass {
implicit def materialize[A]: MyTypeclass[A] = macro materializeImpl[A]
def materializeImpl[A: c.WeakTypeTag](c: whitebox.Context): c.Tree = {
import c.universe._
val typA = weakTypeOf[A]
if (!mtcCache.contains(typA))
mtcCache += (typA -> c.typecheck(q"new MyTypeclass[$typA] {}"))
mtcCache(typA).asInstanceOf[Tree]
}
}
}
import Macros.MyTypeclass
object App { // Internal error: unable to find the outer accessor symbol of object App
class A { // Internal error: unable to find the outer accessor symbol of class A
class B { // Internal error: unable to find the outer accessor symbol of class A
class C {
implicitly[MyTypeclass[Int]] // new MyTypeclass[Int] {} is created and typechecked here
}
implicitly[MyTypeclass[Int]] // cached typed instance is inserted here, this is the reason of above error
}
implicitly[MyTypeclass[Int]] // cached typed instance is inserted here, this is the reason of above error
}
implicitly[MyTypeclass[Int]] // cached typed instance is inserted here, this is the reason of above error
}
Scala 2.13.3。
随着implicitly
我们把一些地方不正确的符号所有者链树。
如果你做A
,B
,C
对象则错误消失(这可以防止编译,所以是否依赖于运气)。
同样,如果删除,c.typecheck
错误也会消失。
同样,如果我们返回c.untypecheck(mtcCache(typA).asInstanceOf[Tree])
而不是返回,mtcCache(typA).asInstanceOf[Tree]
错误也会消失。但有时c.typecheck
+c.untypecheck
可能会损坏树。
因此,如果需要,您可以尝试将树的无类型和无类型版本都放入缓存中,但返回无类型的树
type CTree = whitebox.Context#Tree
val mtcCache = mutable.Map[whitebox.Context#Type, (CTree, CTree)]()
trait MyTypeclass[A]
object MyTypeclass {
implicit def materialize[A]: MyTypeclass[A] = macro materializeImpl[A]
def materializeImpl[A: c.WeakTypeTag](c: whitebox.Context): c.Tree = {
import c.universe._
val typA = weakTypeOf[A]
val tree = q"new MyTypeclass[$typA] {}"
if (!mtcCache.contains(typA))
mtcCache += (typA -> (tree, c.typecheck(tree)))
mtcCache(typA)._1.asInstanceOf[Tree]
}
}
或者如果您只需要类型检查来触发递归,则可以对一棵树进行类型检查,将未类型化的树放入缓存中并返回未类型化的树
val mtcCache = mutable.Map[whitebox.Context#Type, whitebox.Context#Tree]()
trait MyTypeclass[A]
object MyTypeclass {
implicit def materialize[A]: MyTypeclass[A] = macro materializeImpl[A]
def materializeImpl[A: c.WeakTypeTag](c: whitebox.Context): c.Tree = {
import c.universe._
val typA = weakTypeOf[A]
val tree = q"new MyTypeclass[$typA] {}"
c.typecheck(tree)
if (!mtcCache.contains(typA)) mtcCache += (typA -> tree)
mtcCache(typA).asInstanceOf[Tree]
}
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句