Macro implícita. Valor implícito predeterminado. ¿Cómo?

Sep 29 2020

Ni siquiera sé cómo hacer la pregunta.

Tengo una macro que crea una instancia de IsEnum[T]para un tipo T.

Lo estoy probando y quiero asegurarme de que no se encuentre el implícito para los tipos que no están sellados o que, en general, no cumplen con los requisitos de una enumeración.

Entonces creé este método para probar

    def enumOf[T](implicit isEnum:IsEnum[T] = null) = isEnum

Y luego me aseguro de que enumOf[NotAnEnum] == null

Pero en cambio, falla en tiempo de compilación.

Una cosa es el error macro. Otra cosa es que la macro simplemente no se aplica a un caso determinado. ¿Cómo hacer esa distinción al crear macros?

Editar: he usado c.aborty c.error, ambos me dan los mismos resultados.

Respuestas

2 DmytroMitin Sep 29 2020 at 23:43

Parece que no hiciste tu IsEnumcaja blanca de clase de tipo de materialización macro . Normalmente, las macros implícitas deberían ser de caja blanca.

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

Uso:

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

El tiempo de ejecución de las macros es el tiempo de compilación del código principal. Si una macro de caja negra (incluso una macro de caja negra implícita) arroja una excepción, será un error de compilación durante la compilación del código principal. Si una macro implícita de caja blanca arroja una excepción, durante la compilación del código principal, la implícita se eliminará silenciosamente de los candidatos.

https://docs.scala-lang.org/overviews/macros/blackbox-whitebox.html