Попробуйте макроаннотацию для запечатанного признака
import scala.annotation.{StaticAnnotation, compileTimeOnly}
import scala.language.experimental.macros
import scala.reflect.macros.whitebox
@compileTimeOnly("enable macro paradise to expand macro annotations")
class checkNoObjectChild extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro checkNoObjectChildMacro.impl
}
object checkNoObjectChildMacro {
def impl(c: whitebox.Context)(annottees: c.Tree*): c.Tree = {
import c.universe._
annottees match {
case q"$mods trait $tpname[..$tparams] extends { ..$earlydefns } with ..$parents { $self => ..$stats }" :: _
if mods.hasFlag(Flag.SEALED) =>
val checkRecursion = c.openMacros.count(check =>
(c.macroApplication.toString == check.macroApplication.toString) &&
(c.enclosingPosition.toString == check.enclosingPosition.toString)
)
if (checkRecursion > 2)
q"..$annottees"
else {
val tpe = c.typecheck(tq"$tpname", mode = c.TYPEmode, silent = true)
val objectChildren = tpe.symbol.asClass.knownDirectSubclasses.filter(_.isModuleClass)
if (objectChildren.isEmpty)
q"..$annottees"
else
c.abort(c.enclosingPosition, s"Trait $tpname has object children: $objectChildren")
}
case _ =>
c.abort(c.enclosingPosition, s"Not a sealed trait: $annottees")
}
}
}
@checkNoObjectChild
sealed trait OnlyForClasses {
}
class Foo extends OnlyForClasses {
// compiles
}
object Bar extends OnlyForClasses {
// doesn't compile
}
https://stackoverflow.com/a/20466423/5249621
Как отладить макроаннотацию?
Или попробуйте материализованный класс типа
trait NoObjectChild[T]
object NoObjectChild {
implicit def materialize[T]: NoObjectChild[T] = macro impl[T]
def impl[T: c.WeakTypeTag](c: whitebox.Context): c.Tree = {
import c.universe._
val tpe = weakTypeOf[T]
val cls = tpe.typeSymbol.asClass
if (!(cls.isTrait && cls.isSealed))
c.abort(c.enclosingPosition, s"$tpe is not a sealed trait")
val objectChildren = cls.knownDirectSubclasses.filter(_.isModuleClass)
if (objectChildren.isEmpty)
q"new NoObjectChild[$tpe] {}"
else
c.abort(c.enclosingPosition, s"Trait $tpe has object children: $objectChildren")
}
}
sealed trait OnlyForClasses {
}
object OnlyForClasses {
implicitly[NoObjectChild[OnlyForClasses]]
}
class Foo extends OnlyForClasses {
// compiles
}
object Bar extends OnlyForClasses {
// doesn't compile
}