问题
I don't even know how to ask the question.
I have a macro that creates an instance of IsEnum[T]
for a type T
.
I'm doing testing for it, and want to make sure that the implicit is not found for types that are not sealed, or that, in general, don't meet the requirements of an enum.
So I created this method for testing
def enumOf[T](implicit isEnum:IsEnum[T] = null) = isEnum
And then I ensure that enumOf[NotAnEnum] == null
But instead, it fails at compile time.
One thing is the macro erroring. Another thing is the macro just not applying for a given case. How to make that distinction when creating macros?
Edit: I've used c.abort
and c.error
, both giving me the same results.
回答1:
Sounds like you didn't make your macro materializing type class IsEnum
whitebox. Normally implicit macros should be whitebox.
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
Runtime of macros is compile time of main code. If a blackbox macro (even implicit blackbox macro) throws an exception then it will be a compile error during compilation of main code. If a whitebox implicit macro throws an exception then during compilation of main code the implicit will be silently removed from candidates.
https://docs.scala-lang.org/overviews/macros/blackbox-whitebox.html
来源:https://stackoverflow.com/questions/64122310/implicit-macro-default-implicit-value-how