如何使用在一个Scala宏执行中和另一个宏执行中创建并类型检查的`universe.Tree`?

读人

在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>

任何想法?

米米(Dmytro Mitin)

通常,手动对树进行类型检查并在不同的上下文之间共享类型化的树是一个坏主意。请参见以下示例:

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我们把一些地方不正确的符号所有者链树。

如果你做ABC对象则错误消失(这可以防止编译,所以是否依赖于运气)。

同样,如果删除,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]
  }
}

拉取请求:https : //github.com/readren/json-facile/pull/1

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

使用sendKeys函数停止使用另一个宏(按钮)的宏执行

来自分类Dev

如何检查宏的元素是否在另一个宏中

来自分类Dev

如何使用另一个宏创建 C 宏名称?

来自分类Dev

如何使用一个板条箱中的另一个宏?

来自分类Dev

如何使用从另一个宏中的宏变量返回的值

来自分类Dev

如何使用从另一个宏中的宏变量返回的值

来自分类Dev

如何执行启动另一个 python 脚本的 python 宏?

来自分类Dev

尝试在另一个工作簿中的一个工作簿中执行宏时发生错误

来自分类Dev

如何创建一个 Excel 宏来停止另一个宏并重新调用它?

来自分类Dev

(C99)在另一个宏中展开一个宏

来自分类Dev

如何使用str变量在另一个脚本中执行一个脚本?

来自分类Dev

Clojure宏在另一个宏中:如何从符号生成字符串

来自分类Dev

在guile方案中,如何从另一个宏调用宏时防止重命名?

来自分类Dev

如何在调用另一个宏时使用宏参数?

来自分类Dev

如何定义使用另一个宏的C宏?

来自分类Dev

在Haskell中为Tree数据定义一个Map

来自分类Dev

从另一个工作簿中的另一个工作表在一个工作簿中的一个Excel工作表上执行筛选宏

来自分类Dev

GCC宏扩展以调用另一个宏

来自分类Dev

在另一个宏内展开X宏

来自分类Dev

当类型在另一个模块内部时,宏中的哪个符号允许类型构造?

来自分类Dev

当类型在另一个模块内部时,宏中的哪个符号允许类型构造?

来自分类Dev

宏以检查值是否在另一个列表中,如果是,则添加今天的日期

来自分类Dev

创建一个使用参数执行另一个任务的任务

来自分类Dev

Excel:创建一个宏以将活动选择复制并粘贴到另一个工作表中

来自分类Dev

如何从可变长度函数创建宏?其中宏值是另一个可变长度函数

来自分类Dev

揭露者在活动时隐藏另一个揭露者(gtk_tree_store)-GTK3,C

来自分类Dev

如何创建执行左外部联接以及另一个表中的计数的SQL?

来自分类Dev

从另一个excel文件运行一个excel文件中存在的宏

来自分类Dev

如何确保一个线程在另一个CORE中执行?

Related 相关文章

  1. 1

    使用sendKeys函数停止使用另一个宏(按钮)的宏执行

  2. 2

    如何检查宏的元素是否在另一个宏中

  3. 3

    如何使用另一个宏创建 C 宏名称?

  4. 4

    如何使用一个板条箱中的另一个宏?

  5. 5

    如何使用从另一个宏中的宏变量返回的值

  6. 6

    如何使用从另一个宏中的宏变量返回的值

  7. 7

    如何执行启动另一个 python 脚本的 python 宏?

  8. 8

    尝试在另一个工作簿中的一个工作簿中执行宏时发生错误

  9. 9

    如何创建一个 Excel 宏来停止另一个宏并重新调用它?

  10. 10

    (C99)在另一个宏中展开一个宏

  11. 11

    如何使用str变量在另一个脚本中执行一个脚本?

  12. 12

    Clojure宏在另一个宏中:如何从符号生成字符串

  13. 13

    在guile方案中,如何从另一个宏调用宏时防止重命名?

  14. 14

    如何在调用另一个宏时使用宏参数?

  15. 15

    如何定义使用另一个宏的C宏?

  16. 16

    在Haskell中为Tree数据定义一个Map

  17. 17

    从另一个工作簿中的另一个工作表在一个工作簿中的一个Excel工作表上执行筛选宏

  18. 18

    GCC宏扩展以调用另一个宏

  19. 19

    在另一个宏内展开X宏

  20. 20

    当类型在另一个模块内部时,宏中的哪个符号允许类型构造?

  21. 21

    当类型在另一个模块内部时,宏中的哪个符号允许类型构造?

  22. 22

    宏以检查值是否在另一个列表中,如果是,则添加今天的日期

  23. 23

    创建一个使用参数执行另一个任务的任务

  24. 24

    Excel:创建一个宏以将活动选择复制并粘贴到另一个工作表中

  25. 25

    如何从可变长度函数创建宏?其中宏值是另一个可变长度函数

  26. 26

    揭露者在活动时隐藏另一个揭露者(gtk_tree_store)-GTK3,C

  27. 27

    如何创建执行左外部联接以及另一个表中的计数的SQL?

  28. 28

    从另一个excel文件运行一个excel文件中存在的宏

  29. 29

    如何确保一个线程在另一个CORE中执行?

热门标签

归档