如何检查宏中的 F[T] 是否<:G[T] for All { type T }



我有一个宏注释:

import language.experimental.macros
import reflect.macros.whitebox.Context
class annot extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro annot.impl
}
object annot {
  def impl(c: Context)(annottees: c.Tree*): c.Tree = ...
}

我希望它按如下方式使用:

@annot case class A[B1, B2, ...](c: C) extends D1 with D2 with ...

但它应该只有在(C <: D1 with D2 with ...) forAll { type B1; type B2; ... }时才有效

@annot case class OK1(i: Int) extends Any
@annot case class NO1(s: String) extends AnyVal
@annot case class OK2[A <: Other1, B[_]](bas: Other2[B[A]])
  extends (Other2[B[T]] forSome { type T <: Other1 })
type ConstLInt[A] = List[Int]
@annot case class NO2[T](ts: List[T]) extends ConstLInt[T] // Only works if T = Int

我可以到达一半,因为如果D1, D2, ...不依赖于B1, B2, ...,那么我的条件相当于(C forSome { type B1; type B2; ... }) <: D1 with D2 with ...,我可以检查为

val fieldTypeE = c.typecheck(ExistentialTypeTree(fieldType, tparams), c.TYPEmode).tpe
parents.forall(fieldTypeE <:< _)

这足以允许

@annot case class D[E[A] <: Seq[A]](ei: E[Int]) extends Seq[Int]

但不足以允许

@annot case class D[E, C <: E](c: C) extends E // extends clause references E

如何概括?

这是一个简单的解决方案:

val implicitly = q"_root_.scala.Predef.implicitly"
val <:< = tq"_root_.scala.Predef.<:<"
val checks = parents.map { parent =>
  q"$implicitly[${<:<}[$fieldType, $parent]]"
}
// checks = Seq(q"implicitly[C <:< D1]", q"implicitly[C <:< D2]", ...)
val checker = q"trait ${TypeName(c.freshName())} { ..$tparams; ..$checks }"
// trait <syn> {
//   type B1
//   type B2 // Bring them into scope as abstract types (the forall part)
//   ..
//   implicitly[C <:< D1]
//   implicitly[C <:< D2] // Do checks against them, knowing only their constraints
//   ..
// }
c.typecheck(checker)

相关内容

最新更新