Macro implícita. Valor implícito padrão. Quão?
Eu nem sei como fazer a pergunta.
Eu tenho uma macro que cria uma instância de IsEnum[T]para um tipo T.
Estou fazendo testes para isso e quero ter certeza de que o implícito não seja encontrado para tipos que não são lacrados ou que, em geral, não atendem aos requisitos de um enum.
Então eu criei este método para testar
def enumOf[T](implicit isEnum:IsEnum[T] = null) = isEnum
E então eu garanto que enumOf[NotAnEnum] == null
Mas em vez disso, ele falha em tempo de compilação.
Uma coisa é o erro de macro. Outra coisa é a macro simplesmente não se aplicar a um determinado caso. Como fazer essa distinção ao criar macros?
Edit: Eu usei c.aborte c.error, ambos me dando os mesmos resultados.
Respostas
Parece que você não fez sua IsEnumcaixa branca de classe de tipo de materialização de macro . Normalmente, as macros implícitas devem ser uma caixa branca.
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
O tempo de execução de macros é o tempo de compilação do código principal. Se uma macro de caixa preta (mesmo a macro de caixa preta implícita) lançar uma exceção, será um erro de compilação durante a compilação do código principal. Se uma macro implícita de caixa branca lançar uma exceção, durante a compilação do código principal, o implícito será removido silenciosamente dos candidatos.
https://docs.scala-lang.org/overviews/macros/blackbox-whitebox.html