diff --git a/core/src/main/scala/cats/syntax/either.scala b/core/src/main/scala/cats/syntax/either.scala index c333a00e4a..4845b24069 100644 --- a/core/src/main/scala/cats/syntax/either.scala +++ b/core/src/main/scala/cats/syntax/either.scala @@ -13,6 +13,8 @@ trait EitherSyntax { implicit def catsSyntaxLeft[A, B](left: Left[A, B]): LeftOps[A, B] = new LeftOps(left) implicit def catsSyntaxRight[A, B](right: Right[A, B]): RightOps[A, B] = new RightOps(right) + + implicit def catsSyntaxEitherId[A](a: A): EitherIdOps[A] = new EitherIdOps(a) } final class EitherOps[A, B](val eab: Either[A, B]) extends AnyVal { @@ -306,6 +308,14 @@ final class RightOps[A, B](val right: Right[A, B]) extends AnyVal { def leftCast[C]: Either[C, B] = right.asInstanceOf[Either[C, B]] } +final class EitherIdOps[A](val obj: A) extends AnyVal { + /** Wrap a value in `Left`. */ + def asLeft[B]: Either[A, B] = Left(obj) + + /** Wrap a value in `Right`. */ + def asRight[B]: Either[B, A] = Right(obj) +} + /** Convenience methods to use `Either` syntax inside `Either` syntax definitions. */ private[cats] object EitherUtil { def leftCast[A, B, C](right: Right[A, B]): Either[C, B] = diff --git a/tests/src/test/scala/cats/tests/EitherTests.scala b/tests/src/test/scala/cats/tests/EitherTests.scala index 5db908b543..1f09f03140 100644 --- a/tests/src/test/scala/cats/tests/EitherTests.scala +++ b/tests/src/test/scala/cats/tests/EitherTests.scala @@ -57,6 +57,13 @@ class EitherTests extends CatsSuite { } } + test("Left/Right id syntax") { + forAll { (e: Int) => + assert(Left[Int, String](e) === e.asLeft[String]) + assert(Right[String, Int](e) === e.asRight[String]) + } + } + test("implicit instances resolve specifically") { val eq = catsStdEqForEither[Int, String] assert(!eq.isInstanceOf[PartialOrder[_]])