From a2e88541509aea8f646308cdc01353eca68e81e3 Mon Sep 17 00:00:00 2001 From: Alexandru Nedelcu Date: Mon, 23 Apr 2018 11:19:21 +0300 Subject: [PATCH 1/7] Add Mima filters --- build.sbt | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/build.sbt b/build.sbt index d6ccb5f97e..d0c6a8a71e 100644 --- a/build.sbt +++ b/build.sbt @@ -1,5 +1,7 @@ import microsites._ import ReleaseTransformations._ +import com.typesafe.tools.mima.core.{MissingClassProblem, ProblemFilters, ReversedMissingMethodProblem} + import scala.xml.transform.{RewriteRule, RuleTransformer} import org.scalajs.sbtplugin.cross.CrossProject @@ -213,9 +215,30 @@ lazy val docSettings = Seq( lazy val binaryCompatibleVersion = "1.0.0" -def mimaSettings(moduleName: String) = Seq( - mimaPreviousArtifacts := Set("org.typelevel" %% moduleName % binaryCompatibleVersion) -) +def mimaSettings(moduleName: String) = + Seq( + mimaPreviousArtifacts := Set("org.typelevel" %% moduleName % binaryCompatibleVersion), + mimaBinaryIssueFilters ++= (moduleName match { + case "cats-core" => + Seq( + // Internal classes, moved due to refactoring, not a problem + ProblemFilters.exclude[MissingClassProblem]("cats.syntax.EitherUtil$"), + ProblemFilters.exclude[MissingClassProblem]("cats.syntax.EitherUtil"), + // Scala 2.11 only — internal classes, not a problem + ProblemFilters.exclude[ReversedMissingMethodProblem]("cats.data.EitherTMonadErrorF.redeem"), + ProblemFilters.exclude[ReversedMissingMethodProblem]("cats.data.EitherTMonadErrorF.redeemWith"), + ProblemFilters.exclude[ReversedMissingMethodProblem]("cats.data.EitherTMonadErrorF.handleError"), + ProblemFilters.exclude[ReversedMissingMethodProblem]("cats.data.EitherTMonadErrorF.attempt"), + ProblemFilters.exclude[ReversedMissingMethodProblem]("cats.data.EitherTMonadError.redeem"), + ProblemFilters.exclude[ReversedMissingMethodProblem]("cats.data.EitherTMonadError.redeemWith"), + // BREAKAGE — Scala 2.11 only! + ProblemFilters.exclude[ReversedMissingMethodProblem]("cats.MonadError.redeem"), + ProblemFilters.exclude[ReversedMissingMethodProblem]("cats.MonadError.redeemWith") + ) + case _ => + Seq.empty + }) + ) lazy val docs = project .enablePlugins(MicrositesPlugin) @@ -305,7 +328,7 @@ lazy val core = crossProject.crossType(CrossType.Pure) .configureCross(disableScoverage210Js) .settings(libraryDependencies += "org.scalacheck" %%% "scalacheck" % scalaCheckVersion % "test") .jsSettings(commonJsSettings) - .jvmSettings(commonJvmSettings ++ mimaSettings("cats-core") ) + .jvmSettings(commonJvmSettings ++ mimaSettings("cats-core")) lazy val coreJVM = core.jvm lazy val coreJS = core.js From 663bca392eb119cdb290ff2c695fae0fa9a51b68 Mon Sep 17 00:00:00 2001 From: Alexandru Nedelcu Date: Tue, 24 Apr 2018 07:03:24 +0300 Subject: [PATCH 2/7] Rename upcastL to leftWiden, upcastR to rightWiden --- core/src/main/scala/cats/data/EitherT.scala | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/core/src/main/scala/cats/data/EitherT.scala b/core/src/main/scala/cats/data/EitherT.scala index 470607719f..6f35c094a2 100644 --- a/core/src/main/scala/cats/data/EitherT.scala +++ b/core/src/main/scala/cats/data/EitherT.scala @@ -33,11 +33,11 @@ import cats.internals.EitherUtil.{eitherCast, rightBox, leftBox} * * Note that in this function the error type is part of the signature and * is more specific than the customary `Throwable` or `Exception`. You can - * always "upcast" its error type to `Throwable` later using [[upcastL]]: + * always "upcast" its error type to `Throwable` later using [[leftWiden]]: * * {{{ * val num: EitherT[Eval, Throwable, Long] = - * parseNum("10210", 10).upcastL + * parseNum("10210", 10).leftWiden * }}} * * The power of `EitherT` is that it combines `F[_]` with the `Either` @@ -163,12 +163,12 @@ final case class EitherT[F[_], A, B](value: F[Either[A, B]]) { * EitherT.rightT(10210) * * val num2: EitherT[Eval, Throwable, Long] = - * num.upcastL + * num.leftWiden * }}} * - * @see [[upcastR]] + * @see [[rightWiden]] */ - @inline def upcastL[AA >: A]: EitherT[F, AA, B] = + @inline def leftWiden[AA >: A]: EitherT[F, AA, B] = this.asInstanceOf[EitherT[F, AA, B]] /** @@ -187,12 +187,12 @@ final case class EitherT[F[_], A, B](value: F[Either[A, B]]) { * EitherT.rightT(List(10)) * * val iter: EitherT[Eval, String, Iterable[Int]] = - * list.upcastR + * list.rightWiden * }}} * - * @see [[upcastL]] + * @see [[leftWiden]] */ - @inline def upcastR[BB >: B]: EitherT[F, A, BB] = + @inline def rightWiden[BB >: B]: EitherT[F, A, BB] = this.asInstanceOf[EitherT[F, A, BB]] /** From 1197f39924e82f38c13c4a579288b3d4c1aa2bd4 Mon Sep 17 00:00:00 2001 From: Alexandru Nedelcu Date: Tue, 24 Apr 2018 07:14:19 +0300 Subject: [PATCH 3/7] Rename rightWiden to widen --- core/src/main/scala/cats/data/EitherT.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/scala/cats/data/EitherT.scala b/core/src/main/scala/cats/data/EitherT.scala index 6f35c094a2..0b040546a4 100644 --- a/core/src/main/scala/cats/data/EitherT.scala +++ b/core/src/main/scala/cats/data/EitherT.scala @@ -166,7 +166,7 @@ final case class EitherT[F[_], A, B](value: F[Either[A, B]]) { * num.leftWiden * }}} * - * @see [[rightWiden]] + * @see [[widen]] */ @inline def leftWiden[AA >: A]: EitherT[F, AA, B] = this.asInstanceOf[EitherT[F, AA, B]] @@ -187,12 +187,12 @@ final case class EitherT[F[_], A, B](value: F[Either[A, B]]) { * EitherT.rightT(List(10)) * * val iter: EitherT[Eval, String, Iterable[Int]] = - * list.rightWiden + * list.widen * }}} * * @see [[leftWiden]] */ - @inline def rightWiden[BB >: B]: EitherT[F, A, BB] = + @inline def widen[BB >: B]: EitherT[F, A, BB] = this.asInstanceOf[EitherT[F, A, BB]] /** From f917f4e75eb9d2a8633ba29780d36dadb8f4bf92 Mon Sep 17 00:00:00 2001 From: Alexandru Nedelcu Date: Tue, 24 Apr 2018 08:18:48 +0300 Subject: [PATCH 4/7] Modify attemptF --- core/src/main/scala/cats/data/EitherT.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/data/EitherT.scala b/core/src/main/scala/cats/data/EitherT.scala index 0b040546a4..3690bd1cae 100644 --- a/core/src/main/scala/cats/data/EitherT.scala +++ b/core/src/main/scala/cats/data/EitherT.scala @@ -322,14 +322,15 @@ final case class EitherT[F[_], A, B](value: F[Either[A, B]]) { */ def attemptF[E](implicit F: ApplicativeError[F, E]): EitherT[F, A, Either[E, B]] = EitherT(F.map(F.attempt(value)) { - case error @ Left(_) => - Right(eitherCast(error)) case Right(eitherB) => eitherB match { case right @ Right(_) => Right(eitherCast(right)) // N.B. pattern match does not do `case Left(_)` on purpose case _ => eitherCast(eitherB) } + case error => + // N.B. pattern match does not do `case Left(_)` on purpose + Right(eitherCast(error)) }) /** From ecdc544398c11267acc83c73e8ad99b739da802f Mon Sep 17 00:00:00 2001 From: Alexandru Nedelcu Date: Tue, 24 Apr 2018 08:55:59 +0300 Subject: [PATCH 5/7] Remove widen/leftWiden --- core/src/main/scala/cats/data/EitherT.scala | 53 +-------------------- 1 file changed, 2 insertions(+), 51 deletions(-) diff --git a/core/src/main/scala/cats/data/EitherT.scala b/core/src/main/scala/cats/data/EitherT.scala index 3690bd1cae..fef3bc92b4 100644 --- a/core/src/main/scala/cats/data/EitherT.scala +++ b/core/src/main/scala/cats/data/EitherT.scala @@ -33,7 +33,8 @@ import cats.internals.EitherUtil.{eitherCast, rightBox, leftBox} * * Note that in this function the error type is part of the signature and * is more specific than the customary `Throwable` or `Exception`. You can - * always "upcast" its error type to `Throwable` later using [[leftWiden]]: + * always "upcast" its error type to `Throwable` later using + * [[Bifunctor.leftWiden]]: * * {{{ * val num: EitherT[Eval, Throwable, Long] = @@ -145,56 +146,6 @@ final case class EitherT[F[_], A, B](value: F[Either[A, B]]) { def swap(implicit F: Functor[F]): EitherT[F, B, A] = EitherT(F.map(value)(_.swap)) - /** - * Casts the left type parameter to a super type. - * - * Like many types described in Cats, the type parameters of `EitherT` - * are invariant, even if the `Either` data type is covariant in both - * type parameters. - * - * This operator is a shortcut for safely upcasting the left type parameter - * to a compatible super type, an operation that would be automatic under - * Scala's type system if the parameters were declared as being covariant. - * - * Example: - * - * {{{ - * val num: EitherT[Eval, NumberFormatException, Long] = - * EitherT.rightT(10210) - * - * val num2: EitherT[Eval, Throwable, Long] = - * num.leftWiden - * }}} - * - * @see [[widen]] - */ - @inline def leftWiden[AA >: A]: EitherT[F, AA, B] = - this.asInstanceOf[EitherT[F, AA, B]] - - /** - * Casts the right type parameter to a super type. - * - * Like many types described in Cats, the type parameters of `EitherT` - * are invariant, even if the `Either` data type is covariant in both - * type parameters. - * - * This operator is a shortcut for safely upcasting the right type parameter - * to a compatible super type, an operation that would be automatic under - * Scala's type system if the parameters were declared as being covariant. - * - * {{{ - * val list: EitherT[Eval, String, List[Int]] = - * EitherT.rightT(List(10)) - * - * val iter: EitherT[Eval, String, Iterable[Int]] = - * list.widen - * }}} - * - * @see [[leftWiden]] - */ - @inline def widen[BB >: B]: EitherT[F, A, BB] = - this.asInstanceOf[EitherT[F, A, BB]] - /** * If the underlying `Either` is a `Right`, then returns its value in * the `F[_]` context, otherwise returns `default`. From 310404695741b54091e2b0f4e3c47128277e4a55 Mon Sep 17 00:00:00 2001 From: Arman Bilge Date: Mon, 27 Jun 2022 12:36:05 +0000 Subject: [PATCH 6/7] Fix compile --- .../shared/src/test/scala/cats/tests/RegressionSuite.scala | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/shared/src/test/scala/cats/tests/RegressionSuite.scala b/tests/shared/src/test/scala/cats/tests/RegressionSuite.scala index b326f39c3b..810e29adb3 100644 --- a/tests/shared/src/test/scala/cats/tests/RegressionSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/RegressionSuite.scala @@ -191,12 +191,6 @@ class RegressionSuite extends CatsSuite with ScalaVersionSpecificRegressionSuite MonadError[EitherT[Option, String, *], Unit] } - { - implicit val me: MonadError[EitherT[Option, String, *], Unit] = - EitherT.catsDataMonadErrorFForEitherT[Option, Unit, String] - EitherT.right[String](Option(1)).handleErrorWith((_: Unit) => EitherT.pure(2)) - } - } test("#2809 MonadErrorOps.reject runs effects only once") { From c5cf43e3a4d90ce2e471e3cb1e69d7cf5019e541 Mon Sep 17 00:00:00 2001 From: Arman Bilge Date: Mon, 27 Jun 2022 13:17:11 +0000 Subject: [PATCH 7/7] Add `A1` type param --- core/src/main/scala/cats/data/EitherT.scala | 17 ++++++++--------- .../test/scala/cats/tests/RegressionSuite.scala | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/core/src/main/scala/cats/data/EitherT.scala b/core/src/main/scala/cats/data/EitherT.scala index 9cc1216118..9744ff2b5f 100644 --- a/core/src/main/scala/cats/data/EitherT.scala +++ b/core/src/main/scala/cats/data/EitherT.scala @@ -320,11 +320,10 @@ final case class EitherT[F[_], A, B](value: F[Either[A, B]]) { * * @see [[handleErrorF]] for recovering errors thrown in `F[_]` */ - def handleError(f: A => B)(implicit F: Functor[F]): EitherT[F, A, B] = + def handleError[A1](f: A => B)(implicit F: Functor[F]): EitherT[F, A1, B] = EitherT(F.map(value) { - case Left(a) => Right(f(a)) - // N.B. pattern match does not do `case Right(_)` on purpose - case right => right + case Left(a) => Right(f(a)) + case Right(a) => Right(a) }) /** @@ -352,8 +351,8 @@ final case class EitherT[F[_], A, B](value: F[Either[A, B]]) { * * @see [[handleError]] for recovering errors expressed via `EitherT` */ - def handleErrorF[E](f: E => B)(implicit F: ApplicativeError[F, E]): EitherT[F, A, B] = - EitherT(F.handleError(value)(e => Right(f(e)))) + def handleErrorF[A1 >: A, E](f: E => B)(implicit F: ApplicativeError[F, E]): EitherT[F, A1, B] = + EitherT(F.widen(F.handleError(value)(e => Right(f(e))))) /** * Handle any error, potentially recovering from it, by mapping it via @@ -391,7 +390,7 @@ final case class EitherT[F[_], A, B](value: F[Either[A, B]]) { * * @see [[handleErrorWithF]] for recovering errors thrown in `F[_]` */ - def handleErrorWith(f: A => EitherT[F, A, B])(implicit F: Monad[F]): EitherT[F, A, B] = + def handleErrorWith[A1 >: A](f: A => EitherT[F, A1, B])(implicit F: Monad[F]): EitherT[F, A1, B] = EitherT(F.flatMap(value) { case Left(a) => f(a).value // N.B. pattern match does not do `case Right(_)` on purpose @@ -430,8 +429,8 @@ final case class EitherT[F[_], A, B](value: F[Either[A, B]]) { * * @see [[handleErrorWith]] for recovering errors expressed via `EitherT` */ - def handleErrorWithF[E](f: E => EitherT[F, A, B])(implicit F: ApplicativeError[F, E]): EitherT[F, A, B] = - EitherT(F.handleErrorWith(value)(f(_).value)) + def handleErrorWithF[A1 >: A, E](f: E => EitherT[F, A1, B])(implicit F: ApplicativeError[F, E]): EitherT[F, A1, B] = + EitherT(F.handleErrorWith[Either[A1, B]](F.widen(value))(f(_).value)) /** * Example: diff --git a/tests/shared/src/test/scala/cats/tests/RegressionSuite.scala b/tests/shared/src/test/scala/cats/tests/RegressionSuite.scala index 810e29adb3..56ae7dac07 100644 --- a/tests/shared/src/test/scala/cats/tests/RegressionSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/RegressionSuite.scala @@ -185,7 +185,7 @@ class RegressionSuite extends CatsSuite with ScalaVersionSpecificRegressionSuite test("#2022 EitherT syntax no long works the old way") { import cats.data._ - EitherT.right[String](Option(1)).handleErrorWith((_: String) => EitherT.pure(2)) + EitherT.right[String](Option(1)).handleErrorWith((_: String) => EitherT.pure[Option, String](2)) { MonadError[EitherT[Option, String, *], Unit]