diff --git a/kyo-actor/shared/src/main/scala/kyo/Actor.scala b/kyo-actor/shared/src/main/scala/kyo/Actor.scala index 52bf6fa7b..8eb3f50f8 100644 --- a/kyo-actor/shared/src/main/scala/kyo/Actor.scala +++ b/kyo-actor/shared/src/main/scala/kyo/Actor.scala @@ -455,7 +455,6 @@ object Actor: Scope.run, // Close used resources Fiber.init // Start the actor's processing loop in an async context ) - _ <- Scope.ensure(mailbox.close) // Registers a finalizer in the outer scope to provide the actor hierarchy behavior yield new Actor[E, A, B](_subject, _consumer): def close(using Frame) = mailbox.close end Actor diff --git a/kyo-data/shared/src/main/scala/kyo/ConcreteTag.scala b/kyo-data/shared/src/main/scala/kyo/ConcreteTag.scala index c5e5227e6..46cd271aa 100644 --- a/kyo-data/shared/src/main/scala/kyo/ConcreteTag.scala +++ b/kyo-data/shared/src/main/scala/kyo/ConcreteTag.scala @@ -1,7 +1,7 @@ package kyo import kyo.Maybe -import kyo.internal.SafeClassTagMacro +import kyo.internal.ConcreteTagMacro import scala.quoted.* /** An alternative to ClassTag that supports union and intersection types. @@ -42,7 +42,7 @@ object ConcreteTag: case object AnyValTag extends Element case object NothingTag extends Element - inline given apply[A]: ConcreteTag[A] = ${ SafeClassTagMacro.derive[A] } + inline given apply[A]: ConcreteTag[A] = ${ ConcreteTagMacro.derive[A] } extension [A](self: ConcreteTag[A]) diff --git a/kyo-data/shared/src/main/scala/kyo/internal/SafeClassTagMacro.scala b/kyo-data/shared/src/main/scala/kyo/internal/ConcreteTagMacro.scala similarity index 50% rename from kyo-data/shared/src/main/scala/kyo/internal/SafeClassTagMacro.scala rename to kyo-data/shared/src/main/scala/kyo/internal/ConcreteTagMacro.scala index cda24b2dc..9964dccde 100644 --- a/kyo-data/shared/src/main/scala/kyo/internal/SafeClassTagMacro.scala +++ b/kyo-data/shared/src/main/scala/kyo/internal/ConcreteTagMacro.scala @@ -5,7 +5,7 @@ import kyo.ConcreteTag import kyo.ConcreteTag.* import scala.quoted.* -private[kyo] object SafeClassTagMacro: +private[kyo] object ConcreteTagMacro: def derive[A: Type](using Quotes): Expr[ConcreteTag[A]] = import quotes.reflect.* @@ -55,43 +55,48 @@ private[kyo] object SafeClassTagMacro: end create def createSingle(tpe: TypeRepr): Expr[ConcreteTag[Any]] = - checkType(tpe) - tpe match - case ConstantType(const) => - val value = - const.value match - case x: Int => Expr(x) - case x: Long => Expr(x) - case x: Float => Expr(x) - case x: Double => Expr(x) - case x: Boolean => Expr(x) - case x: Char => Expr(x) - case x: String => Expr(x) - case x => report.errorAndAbort(s"Unsupported literal type: $x") - '{ LiteralTag($value) } + Implicits.search(TypeRepr.of[[A] =>> ConcreteTag[A]].appliedTo(tpe)) match + case result: ImplicitSearchSuccess => + val tagExpr: Expr[Any] = result.tree.asExpr + '{ $tagExpr.asInstanceOf[ConcreteTag[Any]] } case _ => - tpe.asType match - case '[Nothing] => '{ NothingTag } - case '[Unit] => '{ UnitTag } - case '[Int] => '{ IntTag } - case '[Long] => '{ LongTag } - case '[Double] => '{ DoubleTag } - case '[Float] => '{ FloatTag } - case '[Byte] => '{ ByteTag } - case '[Short] => '{ ShortTag } - case '[Char] => '{ CharTag } - case '[Boolean] => '{ BooleanTag } - case _ if tpe =:= TypeRepr.of[AnyVal] => '{ AnyValTag } - case '[t] => - val classOfSym = Symbol.requiredMethod("scala.Predef.classOf") - val classOfExpr = Select(Ref(Symbol.requiredModule("scala.Predef")), classOfSym) - .appliedToType(TypeRepr.of[t]) - val expr = classOfExpr.asExprOf[Any] - '{ $expr.asInstanceOf[ConcreteTag[Any]] } - end match + checkType(tpe) + tpe match + case ConstantType(const) => + val value = + const.value match + case x: Int => Expr(x) + case x: Long => Expr(x) + case x: Float => Expr(x) + case x: Double => Expr(x) + case x: Boolean => Expr(x) + case x: Char => Expr(x) + case x: String => Expr(x) + case x => report.errorAndAbort(s"Unsupported literal type: $x") + '{ LiteralTag($value) } + case _ => + tpe.asType match + case '[Nothing] => '{ NothingTag } + case '[Unit] => '{ UnitTag } + case '[Int] => '{ IntTag } + case '[Long] => '{ LongTag } + case '[Double] => '{ DoubleTag } + case '[Float] => '{ FloatTag } + case '[Byte] => '{ ByteTag } + case '[Short] => '{ ShortTag } + case '[Char] => '{ CharTag } + case '[Boolean] => '{ BooleanTag } + case _ if tpe =:= TypeRepr.of[AnyVal] => '{ AnyValTag } + case '[t] => + val classOfSym = Symbol.requiredMethod("scala.Predef.classOf") + val classOfExpr = Select(Ref(Symbol.requiredModule("scala.Predef")), classOfSym) + .appliedToType(TypeRepr.of[t]) + val expr = classOfExpr.asExprOf[Any] + '{ $expr.asInstanceOf[ConcreteTag[Any]] } + end match end createSingle val result = create(TypeRepr.of[A].dealias) '{ $result.asInstanceOf[ConcreteTag[A]] } end derive -end SafeClassTagMacro +end ConcreteTagMacro diff --git a/kyo-data/shared/src/test/scala/kyo/ConcreteTagTest.scala b/kyo-data/shared/src/test/scala/kyo/ConcreteTagTest.scala index daed1c97d..d583c80c0 100644 --- a/kyo-data/shared/src/test/scala/kyo/ConcreteTagTest.scala +++ b/kyo-data/shared/src/test/scala/kyo/ConcreteTagTest.scala @@ -2,7 +2,7 @@ package kyo case class CustomInt(value: Int) extends AnyVal -class SafeClassTagTest extends Test: +class ConcreteTagTest extends Test: trait Animal trait Mammal extends Animal @@ -794,6 +794,22 @@ class SafeClassTagTest extends Test: assert(complexTag.accepts("hello")) assert(!complexTag.accepts(true)) } + + "deriving" - { + "union" in { + def union[A: ConcreteTag, B: ConcreteTag]: ConcreteTag[A | B] = + summon[ConcreteTag[A | B]] + + assert(union[Int, Boolean] == (ConcreteTag[Int] | ConcreteTag[Boolean])) + } + + "intersection" in { + def intersection[A: ConcreteTag, B: ConcreteTag]: ConcreteTag[A & B] = + summon[ConcreteTag[A & B]] + + assert(intersection[Int, Boolean] == (ConcreteTag[Int] & ConcreteTag[Boolean])) + } + } } -end SafeClassTagTest +end ConcreteTagTest