Implicit macro. Default implicit value. How?

我与影子孤独终老i 提交于 2020-12-15 07:07:08

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!