Macro implicite. Valeur implicite par défaut. Comment?
Je ne sais même pas comment poser la question.
J'ai une macro qui crée une instance de IsEnum[T]pour un type T.
Je fais des tests pour cela, et je veux m'assurer que l'implicite n'est pas trouvé pour les types qui ne sont pas scellés ou qui, en général, ne répondent pas aux exigences d'une énumération.
J'ai donc créé cette méthode pour tester
def enumOf[T](implicit isEnum:IsEnum[T] = null) = isEnum
Et puis je m'assure que enumOf[NotAnEnum] == null
Mais au lieu de cela, il échoue au moment de la compilation.
Une chose est l'erreur de macro. Une autre chose est que la macro ne s'applique tout simplement pas à un cas donné. Comment faire cette distinction lors de la création de macros?
Edit: j'ai utilisé c.abortet c.error, les deux me donnant les mêmes résultats.
Réponses
On dirait que vous n'avez pas IsEnumcréé votre boîte blanche de classe de type de matérialisation de macro . Normalement, les macros implicites doivent être des boîtes blanches.
import scala.language.experimental.macros
import scala.reflect.macros.whitebox
trait IsEnum[T]
object IsEnum {
implicit def mkIsEnum[T]: IsEnum[T] = macro mkIsEnumImpl[T]
def mkIsEnumImpl[T: c.WeakTypeTag](c: whitebox.Context): c.Tree = {
import c.universe._
val typ = weakTypeOf[T]
val classSymbol = typ.typeSymbol.asClass
if (!classSymbol.isTrait || !classSymbol.isSealed) c.abort(c.enclosingPosition, s"$typ must be sealed trait") val symbols = classSymbol.knownDirectSubclasses symbols.collectFirst { case symbol if !symbol.isModuleClass || !symbol.asClass.isCaseClass => c.abort(c.enclosingPosition, s"${symbol.asClass.toType} must be case object")
}
q"new IsEnum[$typ] {}"
}
}
def enumOf[T](implicit isEnum: IsEnum[T] = null) = isEnum
Usage:
sealed trait A
object A {
case object B extends A
case object C extends A
case class D() extends A
}
enumOf[A] //null
sealed trait A
object A {
case object B extends A
case object C extends A
class D extends A
}
enumOf[A] //null
sealed trait A
object A {
case object B extends A
object C extends A
}
enumOf[A] //null
trait A
object A {
case object B extends A
case object C extends A
}
enumOf[A] //null
sealed trait A
object A {
case object B extends A
case object C extends A
}
enumOf[A] //App$$anon$1@47f37ef1
Le temps d'exécution des macros correspond à la compilation du code principal. Si une macro boîte noire (même une macro boîte noire implicite) lève une exception, ce sera une erreur de compilation lors de la compilation du code principal. Si une macro implicite de boîte blanche lève une exception, pendant la compilation du code principal, l'implicite sera supprimée silencieusement des candidats.
https://docs.scala-lang.org/overviews/macros/blackbox-whitebox.html