Scala 3 中的显式类型转换宏

6

我在Scala 3中定义了以下特质:

trait A[T <: Tuple]

使用Scala 3的宏,我会创建实现进一步检查元组 T 实际类型的 trait 对象;特别地,我希望检查元组 T 所有类型 (T_1, …, T_n) 是否为另一个给定类型 B 的子类型:
trait B
private def allSubtypesOfB[T <: Tuple: Type](using quotes: Quotes): Boolean = {
    import quotes.reflect.*
    case '[Nothing] => false // I don't want nothing to be in T
    case '[head *: tail] if TypeRepr.of[head] <:< TypeRepr.of[B] => allSubtypesOfB[tail]
    case '[EmptyTuple] => true
    case _ => false
}

inline def createA[T <: Tuple] = ${ createAImpl[T] }
private def createAImpl[T <: Tuple: Type](using quotes: Quotes): Expr[A[T]] = {
    import quotes.reflect.*
    if !allSubtypesOfB[T] then report.error("All types in T must be subtypes of B")
    // ... create instance of A
}

问题在于之后,我需要对元组类型 T 中的每个类型调用具有以下签名的方法:
def doSomethingWithBSubtype[T <: B] = ??? // Do something with type T

因此,代码应该类似于这样:

private def createAImpl[T <: Tuple: Type](using quotes: Quotes): Expr[A[T]] = {
    import quotes.reflect.*
    if !allSubtypesOfB[T] then report.error("All types in T must be subtypes of B")
    Type.of[T] match {
        case '[head *: tail] => doSomethingWithBSubtype[head]
        case '[EmptyTuple] => ???
    }
    // ... create instance of A
}

这段代码无法编译,因为编译器指出 head 必须是 B 的子类型,才能在方法 doSomethingWithBSubtype 中使用。然而,在 match 前面的 if 语句中,我已经确保了 T 内部的所有类型都是 B 的子类型。是否有一种方式可以强制编译器将 head 视为 B 的子类型呢?


请查看更新。 - Dmytro Mitin
1个回答

2

有编译时和运行时的宏。有主代码(使用宏)的编译时和运行时。宏的运行时是主代码的编译时。

createAImpl内部,if !allSubtypesOfB[T]...这一行确保在createAImpl的运行时,所有T类型都是B的子类型。但是当你调用doSomethingWithBSubtype[head]时,你需要知道headcreateAImpl的编译时是B的子类型,因此你还没有来自createAImpl的运行时信息(if !allSubtypesOfB[T]...)。

你可以这样做

case '[head *: tail] => doSomethingWithBSubtype[head & B]

也许类似以下的东西是可能的。
Type.of[T] match {
  case '[head *: tail] =>
    '{foo[head]} match {
      case '{
        type h <: B
        foo[`h`]
      } => doSomethingWithBSubtype[h]
    }
  case '[EmptyTuple] => ???
}

// outside def createAImpl, otherwise "access to method foo from wrong staging level"
def foo[A] = ???

https://docs.scala-lang.org/scala3/guides/macros/quotes.html#type-variables-in-quoted-patterns

在某些情况下,我们需要定义一个模式变量,该变量被多次引用或具有某些类型边界。为了实现这一点,可以在模式的开头使用带有类型模式变量的type t创建模式变量。 在Scala 3中的fuseMap宏 在宏的上下文中,Scala 3语法可以匹配类型及其类型参数吗? 在Scala 3宏中获取类型信息 将内联varargs转换为通用元组

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接