如何将 Quotes 实例获取到 Scala 3 宏中的 Expr 中?

问题描述 投票:0回答:1

我有这个:

def myMacroImpl[T:Type](t: Expr[T])(using quotes:Quotes): Expr[String] = {

  def fooFn(): Expr[(Any,StringBuilder) => StringBuilder] = 
    // quotes visible here

    val qq = Expr(quotes) //wrap quotes in Expr to access inside Expr below
    ‘{(a:Any, sb:StringBuilder) =>
        implicit val qt:Quotes = $qq
        // use qt here for something that needs a Quotes instance, for ex reflection
        sb.apply(“ok”)
     }
}

当我尝试编译它时,我得到类似这样的东西,来自我实际调用顶级宏的地方:

[error] 16 |  println(co.blocke.scala_reflection.ZType.myMacro(person))
[error]    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[error]    |Exception occurred while executing macro expansion.
[error]    |java.lang.AssertionError: assertion failed
[error]    |    at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:11)
[error]    |    at scala.quoted.runtime.impl.QuotesImpl$reflect$Ref$.apply(QuotesImpl.scala:444)
[error]    |    at scala.quoted.runtime.impl.QuotesImpl$reflect$Ref$.apply(QuotesImpl.scala:443)
[error]    |    at co.blocke.scala_reflection.ZType$given_ToExpr_Quotes$.apply(ZType.scala:32)
[error]    |    at co.blocke.scala_reflection.ZType$given_ToExpr_Quotes$.apply(ZType.scala:30)
[error]    |    at scala.quoted.Expr$.apply(Expr.scala:37)
[error]    |    at co.blocke.scala_reflection.ZType$.fooFn$1(ZType.scala:76)
[error]    |    at co.blocke.scala_reflection.ZType$.myMacroImpl(ZType.scala:121)

Quotes 没有 Expr 转换器,所以我添加了这个:

  given ToExpr[Quotes] with {                               
    def apply(x: Quotes)(using q:Quotes) = {
      import q.reflect._
      Ref(defn.AnyClass).appliedToType(TypeRepr.typeConstructorOf(x.getClass)).asExpr.asInstanceOf[Expr[Quotes]]
    }
  }

我的直觉告诉我,我正在以艰难的方式做这件事——而且它显然不起作用,但我不知道答案。如何让 Quotes 实例可见/“传递到”我的 '{} 块?

scala macros scala-macros scala-3
1个回答
0
投票

Quotes
传递到引用中的唯一方法是:

// using quotes: Quotes
'{
  val a = sth
  someRuntimeMethod(
    ${ someCompileTimeMethod('{ a })(using quotes) }
  )
}

您可以将

${}
放入
'{}
内,反之亦然。你做不到的是

// using quotes: Quotes
'{
  someCompileTimeMethod(using quotes) // quotes from outside of '{}
}

因为它必须生成运行时代码,该代码期望值仅在编译期间可用(并且仅在此上下文中有效!)。

对于某些类型(通常是基元),您将拥有

given ToExpr[A]
,它允许您将
A
值转换为
Expr[A]
并在
'{}
中使用它(基本上让您在某个值中定义一个宏,然后使用它在引用的代码中),但
Quotes
不是这种类型。即使您手动构造了一些
ToExpr[Quotes]
的值,它几乎肯定会被破坏。

因此,要么在

${}
中使用
'{}
,要么在
inline def
中编写对
'{}
方法的调用,以便编译器创建一个新的嵌套
Quote
并将其传递给您。

© www.soinside.com 2019 - 2024. All rights reserved.