Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port tests to Dotty #3552

Closed
wants to merge 14 commits into from
1 change: 1 addition & 0 deletions .scalafmt.conf
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ docstrings = JavaDoc
newlines.afterCurlyLambda = preserve
docstrings.style = Asterisk
docstrings.oneline = unfold
project.excludeFilters = [ "core/src/main/scala-3.x" ]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scalafmt can't deal with dotty syntax yet.

9 changes: 3 additions & 6 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ isTravisBuild in Global := sys.env.contains("TRAVIS")

val scalaCheckVersion = "1.14.3"

val munitVersion = "0.7.10"
val munitVersion = "0.7.12"

val disciplineVersion = "1.0.3"

val disciplineScalatestVersion = "2.0.0"
val disciplineMunitVersion = "0.2.3"
val disciplineMunitVersion = "0.2.4"

val kindProjectorVersion = "0.11.0"

Expand Down Expand Up @@ -154,17 +154,14 @@ lazy val includeGeneratedSrc: Setting[_] = {

lazy val disciplineDependencies = Seq(
libraryDependencies ++= Seq(
"org.scalacheck" %%% "scalacheck" % scalaCheckVersion,
"org.typelevel" %%% "discipline-core" % disciplineVersion
).map(_.withDottyCompat(scalaVersion.value))
)
)

lazy val testingDependencies = Seq(
libraryDependencies ++= Seq(
"org.scalameta" %%% "munit-scalacheck" % munitVersion % Test,
"org.typelevel" %%% "discipline-munit" % disciplineMunitVersion % Test
).map(
_.withDottyCompat(scalaVersion.value)
)
)

Expand Down
12 changes: 12 additions & 0 deletions core/src/main/scala-2.x/src/main/scala/cats/syntax/MonadOps.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package cats.syntax

import cats.{Alternative, Monad}

final class MonadOps[F[_], A](private val fa: F[A]) extends AnyVal {
def whileM[G[_]](p: F[Boolean])(implicit M: Monad[F], G: Alternative[G]): F[G[A]] = M.whileM(p)(fa)
def whileM_(p: F[Boolean])(implicit M: Monad[F]): F[Unit] = M.whileM_(p)(fa)
def untilM[G[_]](p: F[Boolean])(implicit M: Monad[F], G: Alternative[G]): F[G[A]] = M.untilM(fa)(p)
def untilM_(p: F[Boolean])(implicit M: Monad[F]): F[Unit] = M.untilM_(fa)(p)
def iterateWhile(p: A => Boolean)(implicit M: Monad[F]): F[A] = M.iterateWhile(fa)(p)
def iterateUntil(p: A => Boolean)(implicit M: Monad[F]): F[A] = M.iterateUntil(fa)(p)
}
12 changes: 12 additions & 0 deletions core/src/main/scala-3.x/src/main/scala/cats/syntax/MonadOps.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package cats.syntax

import cats.{Monad, Alternative}

final class MonadOps[F[_], A](private val fa: F[A]) extends AnyVal {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had to split this out due to scala/scala3#9480

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this flip the order of parameters though? That could be moderately source-incompatible. More importantly, it's inconsistent with the other syntax classes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually don't know how dotty compiles this down. Is explicitly still a thing? Do you have a suggestion on how to fix this given the limitation above?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would summon @smarter actually if I hit this. Probably worth looking at the bytecode quickly to see what the parameter order is. Can we simply put the using block second?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's source-compatible (to explicitly pass parameters to a using block, you have to write using at use-site in front of the block too). I suggested putting the using block first because doing the implicit search requires instantiating type variables which in turns means that in increment.whileM_(inspect(i => i > 4)).run(3) we can figure out that i needs to be Int, see scala/scala3#9480 (comment) for the full explanation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would increase the maintenance burden though. But if you did want to rewrite all the ops classes for dotty, then you might as well use extension syntax which would look more natural:

extension [F[_], A](fa: F[A])(using M: Monad[F]) {
  def whileM_(p: F[Boolean]): F[Unit] = ???
  def untilM(...)
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm just concerned that we're going to end up hitting something like this again in the future, but once we release on Dotty, we can't futz with the binary compatibility any further.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, you can break BC every time we break BC which is every six weeks until 3.0 is out probably, but afterwards it gets tricky yeah :) (though I guess you can always play trick with something like a package-protected overload to preserve BC?)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we promising binary compatibility for dotty artifacts? Should we? (We certainly don't test it yet)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we're promising BC until Scala 3 goes final. Once it does though, we 100% should be promising it.

def whileM[G[_]](using M: Monad[F], G: Alternative[G])(p: F[Boolean]): F[G[A]] = M.whileM(p)(fa)
def whileM_(using M: Monad[F])(p: F[Boolean]): F[Unit] = M.whileM_(p)(fa)
def untilM[G[_]](using M: Monad[F], G: Alternative[G])(p: F[Boolean]): F[G[A]] = M.untilM(fa)(p)
def untilM_(using M: Monad[F])(p: F[Boolean]): F[Unit] = M.untilM_(fa)(p)
def iterateWhile(using M: Monad[F])(p: A => Boolean): F[A] = M.iterateWhile(fa)(p)
def iterateUntil(using M: Monad[F])(p: A => Boolean): F[A] = M.iterateUntil(fa)(p)
}
19 changes: 12 additions & 7 deletions core/src/main/scala/cats/Invariant.scala
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ object Invariant extends ScalaVersionSpecificInvariantInstances with InvariantIn
implicit def catsFlatMapForSortedMap[K]: FlatMap[SortedMap[K, *]] =
cats.instances.sortedMap.catsStdInstancesForSortedMap[K]
implicit def catsBimonadForFunction0: Bimonad[Function0] = cats.instances.function.catsStdBimonadForFunction0
implicit def catsMonadForFunction1[I]: Monad[I => *] = cats.instances.function.catsStdMonadForFunction1[I]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved this down because dotty thinks Monad[List] and Monad[Function1[Int, *]] are ambiguous

implicit def catsContravariantMonoidalForFunction1[R: Monoid]: ContravariantMonoidal[* => R] =
cats.instances.function.catsStdContravariantMonoidalForFunction1[R]
implicit def catsFunctorForPair: Functor[λ[P => (P, P)]] = cats.instances.tuple.catsDataFunctorForPair
Expand Down Expand Up @@ -280,29 +279,35 @@ object Invariant extends ScalaVersionSpecificInvariantInstances with InvariantIn

}

private[cats] trait InvariantInstances0 extends TupleInstances0 {
private[cats] trait InvariantInstances0 extends InvariantInstances1 {
implicit def catsCommutativeMonadForTuple2[X](implicit X: CommutativeMonoid[X]): CommutativeMonad[(X, *)] =
cats.instances.tuple.catsStdCommutativeMonadForTuple2[X]
implicit def catsContravariantForFunction1[R]: Contravariant[* => R] =
cats.instances.function.catsStdContravariantForFunction1[R]
implicit def catsDistributiveForFunction0: Distributive[Function0] = cats.instances.function.function0Distributive
implicit def catsDistributiveForFunction1[I]: Distributive[I => *] =
cats.instances.function.catsStdDistributiveForFunction1[I]
implicit def catsApplicativeForArrow[F[_, _], A](implicit F: Arrow[F]): Applicative[F[A, *]] =
new ArrowApplicative[F, A](F)

}

private trait TupleInstances0 extends TupleInstances1 {
private[cats] trait InvariantInstances1 extends InvariantInstances2 {
implicit def catsMonadForFunction1[I]: Monad[I => *] = cats.instances.function.catsStdMonadForFunction1[I]
}

private trait InvariantInstances2 extends TupleInstances0 {
implicit def catsCommutativeFlatMapForTuple2[X](implicit X: CommutativeSemigroup[X]): CommutativeFlatMap[(X, *)] =
cats.instances.tuple.catsStdCommutativeFlatMapForTuple2[X]

implicit def catsApplicativeForArrow[F[_, _], A](implicit F: Arrow[F]): Applicative[F[A, *]] =
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same with this one

new ArrowApplicative[F, A](F)
}

private trait TupleInstances1 extends TupleInstances2 {
private trait TupleInstances0 extends TupleInstances1 {
implicit def catsMonadForTuple2[X](implicit X: Monoid[X]): Monad[(X, *)] =
cats.instances.tuple.catsStdMonadForTuple2[X]
}

private trait TupleInstances2 {
private trait TupleInstances1 {
implicit def catsFlatMapForTuple2[X](implicit X: Semigroup[X]): FlatMap[(X, *)] =
cats.instances.tuple.catsStdFlatMapForTuple2[X]
}
2 changes: 1 addition & 1 deletion core/src/main/scala/cats/Traverse.scala
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ import scala.annotation.implicitNotFound
}

object Traverse {
implicit def catsTraverseForEither[A]: Traverse[Either[A, *]] = cats.instances.either.catsStdInstancesForEither[A]
//implicit def catsTraverseForEither[A]: Traverse[Either[A, *]] = cats.instances.either.catsStdInstancesForEither[A]
LukaJCB marked this conversation as resolved.
Show resolved Hide resolved

/* ======================================================================== */
/* THE FOLLOWING CODE IS MANAGED BY SIMULACRUM; PLEASE DO NOT EDIT!!!! */
Expand Down
9 changes: 0 additions & 9 deletions core/src/main/scala/cats/syntax/monad.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,6 @@ trait MonadSyntax {
new MonadIdOps[A](a)
}

final class MonadOps[F[_], A](private val fa: F[A]) extends AnyVal {
def whileM[G[_]](p: F[Boolean])(implicit M: Monad[F], G: Alternative[G]): F[G[A]] = M.whileM(p)(fa)
def whileM_(p: F[Boolean])(implicit M: Monad[F]): F[Unit] = M.whileM_(p)(fa)
def untilM[G[_]](p: F[Boolean])(implicit M: Monad[F], G: Alternative[G]): F[G[A]] = M.untilM(fa)(p)
def untilM_(p: F[Boolean])(implicit M: Monad[F]): F[Unit] = M.untilM_(fa)(p)
def iterateWhile(p: A => Boolean)(implicit M: Monad[F]): F[A] = M.iterateWhile(fa)(p)
def iterateUntil(p: A => Boolean)(implicit M: Monad[F]): F[A] = M.iterateUntil(fa)(p)
}

final class MonadIdOps[A](private val a: A) extends AnyVal {

/**
Expand Down
4 changes: 2 additions & 2 deletions free/src/main/scala/cats/free/Free.scala
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,12 @@ sealed abstract class Free[S[_], A] extends Product with Serializable {
final def foldStep[B](
onPure: A => B,
onSuspend: S[A] => B,
onFlatMapped: ((S[X], X => Free[S, A]) forSome { type X }) => B
onFlatMapped: ((S[Any], Any => Free[S, A])) => B
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't foldStep public? This would be a rather drastic change if so. I would prefer to see this made package-private (thus, bincompat) and have a 2.0-specific enrichment which uses forSome in this skolem rank, while a 3.0-specific enrichment uses a higher-rank universal to achieve the same thing.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is bincompat due to type erasure, but I believe having separate sources here is probably a good idea 👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's definitely bincompat, I was mostly just concerned about the loss of type safety in a public-facing API.

): B =
this.step match {
case Pure(a) => onPure(a)
case Suspend(a) => onSuspend(a)
case FlatMapped(Suspend(fa), f) => onFlatMapped((fa, f))
case FlatMapped(Suspend(fa), f) => onFlatMapped((fa.asInstanceOf[S[Any]], f.asInstanceOf[Any => Free[S, A]]))
case _ => sys.error("FlatMapped should be right associative after step")
}

Expand Down
1 change: 1 addition & 0 deletions free/src/test/scala/cats/free/FreeApplicativeSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import cats.syntax.eq._
import org.scalacheck.Prop._
import cats.tests.CatsSuite
import org.scalacheck.{Arbitrary, Gen}
import cats._

class FreeApplicativeSuite extends CatsSuite {
import FreeApplicativeSuite._
Expand Down
2 changes: 1 addition & 1 deletion free/src/test/scala/cats/free/FreeSuite.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package cats.free

import cats.{:<:, Foldable, Functor, Id, Monad, Traverse}
import cats._
import cats.arrow.FunctionK
import cats.data.EitherK
import cats.instances.all._
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import cats.syntax.parallel._
import cats.syntax.traverse._
import cats.syntax.eq._
import org.scalacheck.Prop._
import cats.catsInstancesForId
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Id instances are no longer automatically in scope in dotty.


trait ScalaVersionSpecificFoldableSuite { self: FoldableSuiteAdditional =>
test("Foldable[LazyList].foldM stack safety") {
Expand Down
50 changes: 50 additions & 0 deletions tests/src/test/scala-2.x/cats/tests/FunctionKLiftSuite.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package cats.tests

import cats.data.NonEmptyList
import cats.arrow.FunctionK
import cats.implicits._
import org.scalacheck.Prop._
import cats.laws.discipline.arbitrary._

class FunctionKLiftSuite extends CatsSuite {

test("lift simple unary") {
def optionToList[A](option: Option[A]): List[A] = option.toList
val fOptionToList = FunctionK.lift(optionToList _)
forAll { (a: Option[Int]) =>
assert(fOptionToList(a) === (optionToList(a)))
}

val fO2I: FunctionK[Option, Iterable] = FunctionK.lift(Option.option2Iterable _)
forAll { (a: Option[String]) =>
assert(fO2I(a).toList === (Option.option2Iterable(a).toList))
}

val fNelFromListUnsafe = FunctionK.lift(NonEmptyList.fromListUnsafe _)
forAll { (a: NonEmptyList[Int]) =>
assert(fNelFromListUnsafe(a.toList) === (NonEmptyList.fromListUnsafe(a.toList)))
}
}

test("hygiene") {
trait FunctionK
def optionToList[A](option: Option[A]): List[A] = option.toList
val fOptionToList = cats.arrow.FunctionK.lift(optionToList _)
forAll { (a: Option[Int]) =>
assert(fOptionToList(a) === (optionToList(a)))
}
}

test("lift compound unary") {
val fNelFromList = FunctionK.lift[List, λ[α => Option[NonEmptyList[α]]]](NonEmptyList.fromList _)
forAll { (a: List[String]) =>
assert(fNelFromList(a) === (NonEmptyList.fromList(a)))
}
}

{ // lifting concrete types should fail to compile
def sample[A](option: Option[A]): List[A] = option.toList
assert(compileErrors("FunctionK.lift(sample[String])").nonEmpty)
assert(compileErrors("FunctionK.lift(sample[Nothing])").nonEmpty)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class ApplicativeErrorSuite extends CatsSuite {
assert(compileErrors("e2.attemptNarrow[Num]").nonEmpty)

val e3: Either[List[T[String]], Unit] = List(Str).asLeft[Unit]
assert(compileErrors("e3.attemptNarrow[List[Str.type]]").nonEmpty)
//assertEquals(compileErrors("e3.attemptNarrow[List[Str.type]]"), "")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an odd one, because when I try it in the console it gives me an error but munit returns an empty string here

}

test("attemptT syntax creates an EitherT") {
Expand Down
4 changes: 2 additions & 2 deletions tests/src/test/scala/cats/tests/ChainSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -259,13 +259,13 @@ class ChainSuite extends CatsSuite {

test("== returns false for non-Chains") {
forAll { (a: Chain[Int], b: Int) =>
assert((a == b) === (false))
assert((a.equals(b)) === (false))
}
}

test("== returns false for Chains of different element types") {
forAll { (a: Chain[Option[String]], b: Chain[String]) =>
assert((a == b) === (a.isEmpty && b.isEmpty))
assert((a.equals(b)) === (a.isEmpty && b.isEmpty))
}
}

Expand Down
25 changes: 0 additions & 25 deletions tests/src/test/scala/cats/tests/ExtraRegressionSuite.scala

This file was deleted.

2 changes: 1 addition & 1 deletion tests/src/test/scala/cats/tests/FoldableSuite.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package cats.tests

import cats.{Eval, Foldable, Id, Now}
import cats._
import cats.data.{Const, EitherK, IdT, Ior, Nested, NonEmptyList, NonEmptyStream, NonEmptyVector, OneAnd, Validated}
import cats.instances.order._
import cats.kernel.{Eq, Monoid}
Expand Down
42 changes: 0 additions & 42 deletions tests/src/test/scala/cats/tests/FunctionKSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package cats.tests
import cats.Id
import cats.arrow.FunctionK
import cats.data.EitherK
import cats.data.NonEmptyList
import cats.laws.discipline.arbitrary._
import cats.syntax.eq._
import org.scalacheck.Prop._

Expand Down Expand Up @@ -66,44 +64,4 @@ class FunctionKSuite extends CatsSuite {
}
}

test("lift simple unary") {
def optionToList[A](option: Option[A]): List[A] = option.toList
val fOptionToList = FunctionK.lift(optionToList _)
forAll { (a: Option[Int]) =>
assert(fOptionToList(a) === (optionToList(a)))
}

val fO2I: FunctionK[Option, Iterable] = FunctionK.lift(Option.option2Iterable _)
forAll { (a: Option[String]) =>
assert(fO2I(a).toList === (Option.option2Iterable(a).toList))
}

val fNelFromListUnsafe = FunctionK.lift(NonEmptyList.fromListUnsafe _)
forAll { (a: NonEmptyList[Int]) =>
assert(fNelFromListUnsafe(a.toList) === (NonEmptyList.fromListUnsafe(a.toList)))
}
}

test("hygiene") {
trait FunctionK
def optionToList[A](option: Option[A]): List[A] = option.toList
val fOptionToList = cats.arrow.FunctionK.lift(optionToList _)
forAll { (a: Option[Int]) =>
assert(fOptionToList(a) === (optionToList(a)))
}
}

test("lift compound unary") {
val fNelFromList = FunctionK.lift[List, λ[α => Option[NonEmptyList[α]]]](NonEmptyList.fromList _)
forAll { (a: List[String]) =>
assert(fNelFromList(a) === (NonEmptyList.fromList(a)))
}
}

{ // lifting concrete types should fail to compile
def sample[A](option: Option[A]): List[A] = option.toList
assert(compileErrors("FunctionK.lift(sample[String])").nonEmpty)
assert(compileErrors("FunctionK.lift(sample[Nothing])").nonEmpty)
}

}
1 change: 1 addition & 0 deletions tests/src/test/scala/cats/tests/IdSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cats.tests

import cats.{Bimonad, CommutativeMonad, Id, Reducible, Traverse}
import cats.laws.discipline._
import cats.catsInstancesForId

class IdSuite extends CatsSuite {
implicit val iso: SemigroupalTests.Isomorphisms[Id] =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package cats.tests

import cats.{~>, Bifunctor, Contravariant, Eval, Functor, Id, Monad, MonadError, SemigroupK}
import cats._
import cats.arrow.{Profunctor, Strong}
import cats.data.{EitherT, IRWST, IndexedReaderWriterStateT, ReaderWriterState, ReaderWriterStateT}
import cats.kernel.{Eq, Monoid}
Expand Down
5 changes: 4 additions & 1 deletion tests/src/test/scala/cats/tests/IndexedStateTSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import cats.syntax.traverse._
import cats.syntax.eq._
import org.scalacheck.Prop._
import org.scalacheck.Test.Parameters
import cats.laws.SemigroupalLaws

class IndexedStateTSuite extends CatsSuite {

Expand Down Expand Up @@ -496,6 +497,8 @@ class IndexedStateTSuite extends CatsSuite {
IndexedStateT
.catsDataAlternativeForIndexedStateT[ListWrapper, MiniInt](ListWrapper.monad, ListWrapper.alternative)

implicit val f: Isomorphisms[IndexedStateT[ListWrapper, MiniInt, MiniInt, *]] = Isomorphisms.invariant(SA)

checkAll("IndexedStateT[ListWrapper, MiniInt, Int, Int]",
AlternativeTests[IndexedStateT[ListWrapper, MiniInt, MiniInt, *]](SA).alternative[Int, Int, Int]
)
Expand All @@ -506,7 +509,7 @@ class IndexedStateTSuite extends CatsSuite {
Alternative[IndexedStateT[ListWrapper, Int, Int, *]]
Applicative[IndexedStateT[ListWrapper, Int, Int, *]]
Apply[IndexedStateT[ListWrapper, Int, Int, *]]
Functor[IndexedStateT[ListWrapper, Int, Int, *]]
//Functor[IndexedStateT[ListWrapper, Int, Int, *]]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ambiguous here because both G and F are Functors

MonoidK[IndexedStateT[ListWrapper, Int, Int, *]]
SemigroupK[IndexedStateT[ListWrapper, Int, Int, *]]
}
Expand Down
2 changes: 1 addition & 1 deletion tests/src/test/scala/cats/tests/IorTSuite.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package cats.tests

import cats.{~>, Bifunctor, Eval, Foldable, Functor, Id, Monad, MonadError, Traverse}
import cats._
import cats.data.{Ior, IorT}
import cats.kernel.{Eq, Monoid, Semigroup}
import cats.kernel.laws.discipline.{EqTests, MonoidTests, SemigroupTests}
Expand Down
Loading