Macro implicita. Valore implicito predefinito. Come?

Sep 29 2020

Non so nemmeno come fare la domanda.

Ho una macro che crea un'istanza di IsEnum[T]per un tipo T.

Sto effettuando dei test e voglio assicurarmi che l'implicito non venga trovato per i tipi che non sono chiusi o che, in generale, non soddisfano i requisiti di un'enumerazione.

Quindi ho creato questo metodo per i test

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

E poi lo assicuro enumOf[NotAnEnum] == null

Ma invece, fallisce in fase di compilazione.

Una cosa è l'errore macro. Un'altra cosa è che la macro non si applica per un determinato caso. Come fare questa distinzione durante la creazione di macro?

Modifica: ho usato c.aborte c.error, entrambi mi hanno dato gli stessi risultati.

Risposte

2 DmytroMitin Sep 29 2020 at 23:43

Sembra che tu non abbia creato la tua IsEnumwhitebox di tipo macro materializzante . Normalmente le macro implicite dovrebbero essere 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

Utilizzo:

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

Il runtime delle macro è il tempo di compilazione del codice principale. Se una macro blackbox (anche una macro blackbox implicita) genera un'eccezione, sarà un errore di compilazione durante la compilazione del codice principale. Se una macro implicita di whitebox genera un'eccezione, durante la compilazione del codice principale l'implicito verrà rimosso silenziosamente dai candidati.

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