From 8c058678ca5fd4bf30172772b3e1db27860dac7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Andr=C3=A9n?= Date: Fri, 21 Sep 2018 15:24:01 +0200 Subject: [PATCH] Disallow nested mixed widen usages, #25604 --- .../scala/akka/actor/typed/WidenSpec.scala | 49 ++++++++++++++++--- .../typed/internal/InterceptorImpl.scala | 9 +++- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/akka-actor-typed-tests/src/test/scala/akka/actor/typed/WidenSpec.scala b/akka-actor-typed-tests/src/test/scala/akka/actor/typed/WidenSpec.scala index a108497478..439dc5c847 100644 --- a/akka-actor-typed-tests/src/test/scala/akka/actor/typed/WidenSpec.scala +++ b/akka-actor-typed-tests/src/test/scala/akka/actor/typed/WidenSpec.scala @@ -6,12 +6,22 @@ package akka.actor.typed import java.util.concurrent.atomic.AtomicInteger +import akka.actor.ActorInitializationException import akka.actor.testkit.typed.scaladsl.ScalaTestWithActorTestKit import akka.actor.testkit.typed.scaladsl.TestProbe import akka.actor.typed.scaladsl.Behaviors +import akka.actor.typed.scaladsl.adapter._ +import akka.testkit.EventFilter import org.scalatest.WordSpecLike -class WidenSpec extends ScalaTestWithActorTestKit with WordSpecLike { +import scala.concurrent.duration._ + +class WidenSpec extends ScalaTestWithActorTestKit( + """ + akka.loggers = [akka.testkit.TestEventListener] + """) with WordSpecLike { + + implicit val untypedSystem = system.toUntyped def intToString(probe: ActorRef[String]): Behavior[Int] = { Behaviors.receiveMessage[String] { msg ⇒ @@ -36,11 +46,14 @@ class WidenSpec extends ScalaTestWithActorTestKit with WordSpecLike { val probe = TestProbe[String]() val ref = spawn(intToString(probe.ref)) - ref ! 42 - ref ! 13 - ref ! 43 - probe.expectMessage("42") - probe.expectMessage("43") + // TestEventListener logs unhandled as warnings, silence that + EventFilter.warning(occurrences = 1).intercept { + ref ! 42 + ref ! 13 + ref ! 43 + probe.expectMessage("42") + probe.expectMessage("43") + } } "not build up when the same widen is used many times (initially)" in { @@ -105,6 +118,30 @@ class WidenSpec extends ScalaTestWithActorTestKit with WordSpecLike { transformCount.get should ===(2) } + + "not allow mixing different widens in the same behavior stack" in { + val probe = TestProbe[String]() + + def widen(behavior: Behavior[String]): Behavior[String] = + behavior.widen[String] { + case s ⇒ s.toLowerCase + } + + EventFilter[ActorInitializationException](occurrences = 1).intercept { + val ref = spawn( + widen( + widen( + Behaviors.receiveMessage[String] { msg ⇒ + Behaviors.same + } + ) + ) + ) + + probe.expectTerminated(ref, 3.seconds) + } + + } } } diff --git a/akka-actor-typed/src/main/scala/akka/actor/typed/internal/InterceptorImpl.scala b/akka-actor-typed/src/main/scala/akka/actor/typed/internal/InterceptorImpl.scala index 6e21664a7f..0feecfec3f 100644 --- a/akka-actor-typed/src/main/scala/akka/actor/typed/internal/InterceptorImpl.scala +++ b/akka-actor-typed/src/main/scala/akka/actor/typed/internal/InterceptorImpl.scala @@ -138,9 +138,14 @@ private[akka] final case class WidenedInterceptor[O, I](matcher: PartialFunction import BehaviorInterceptor._ override def isSame(other: BehaviorInterceptor[Any, Any]): Boolean = other match { - // can only be elimintated if it is the same partial function + // If they use the same pf instance we can allow it, to have one way to workaround defining + // "recursive" narrowed behaviors. case WidenedInterceptor(`matcher`) ⇒ true - case _ ⇒ false + case WidenedInterceptor(otherMatcher) ⇒ + // there is no safe way to allow this + throw new IllegalStateException("Widen can only be used one time in the same behavior stack. " + + s"One defined in ${LineNumbers(matcher)}, and another in ${LineNumbers(otherMatcher)}") + case _ ⇒ false } def aroundReceive(ctx: ActorContext[O], msg: O, target: ReceiveTarget[I]): Behavior[I] = {