Skip to content

Commit

Permalink
Merge pull request #540 from rossabaker/sbt-tpolecat
Browse files Browse the repository at this point in the history
Use sbt-tpolecat, fix ensuing warnings and bug
  • Loading branch information
djspiewak authored May 26, 2019
2 parents 08e8c4b + d9a2bc3 commit cbd7a26
Show file tree
Hide file tree
Showing 31 changed files with 123 additions and 112 deletions.
5 changes: 3 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ matrix:
scala: 2.11.12
env: COVERAGE=
- jdk: openjdk8
scala: 2.12.8
scala: 2.13.0-RC2
env: COVERAGE=
# We want the latest stable Scala last so sbt-travisci makes it the default
- jdk: openjdk8
scala: 2.13.0-RC2
scala: 2.12.8
env: COVERAGE=
- jdk: openjdk11
scala: 2.12.8
Expand Down
63 changes: 15 additions & 48 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,17 @@ addCommandAlias("ci", ";test ;mimaReportBinaryIssues; doc")
addCommandAlias("release", ";project root ;reload ;+publish ;sonatypeReleaseAll ;microsite/publishMicrosite")

val commonSettings = Seq(
scalaVersion := "2.12.8",

crossScalaVersions := Seq("2.11.12", "2.12.8", "2.13.0-RC2"),

scalacOptions ++= PartialFunction.condOpt(CrossVersion.partialVersion(scalaVersion.value)) {
case Some((2, n)) if n >= 13 =>
Seq(
"-Ymacro-annotations"
)
// Necessary for simulacrum
Seq("-Ymacro-annotations")
}.toList.flatten,

scalacOptions in (Compile, console) ~= (_ filterNot Set("-Xfatal-warnings", "-Ywarn-unused-import").contains),
scalacOptions --= PartialFunction.condOpt(CrossVersion.partialVersion(scalaVersion.value)) {
case Some((2, 11)) =>
// Falsely detects interpolation in @implicitNotFound
Seq("-Xlint:missing-interpolator")
}.toList.flatten,

scalacOptions in (Compile, doc) ++= {
val isSnapshot = git.gitCurrentTags.value.map(git.gitTagToVersionNumber.value).flatten.isEmpty
Expand All @@ -68,6 +67,9 @@ val commonSettings = Seq(
scalacOptions in (Compile, doc) ++=
Opts.doc.title("cats-effect"),

scalacOptions in Test += "-Yrangepos",
scalacOptions in Test ~= (_.filterNot(Set("-Wvalue-discard", "-Ywarn-value-discard"))),

// Disable parallel execution in tests; otherwise we cannot test System.err
parallelExecution in Test := false,
parallelExecution in IntegrationTest := false,
Expand Down Expand Up @@ -208,7 +210,11 @@ lazy val scalaJSSettings = Seq(
val l = (baseDirectory in LocalRootProject).value.toURI.toString
val g = s"https://raw.githubusercontent.com/typelevel/cats-effect/$versionOrHash/"
s"-P:scalajs:mapSourceURI:$l->$g"
})
},

// Work around "dropping dependency on node with no phase object: mixin"
scalacOptions in (Compile, doc) -= "-Xfatal-warnings",
)

lazy val skipOnPublishSettings = Seq(
skip in publish := true,
Expand Down Expand Up @@ -398,45 +404,6 @@ licenses in ThisBuild += ("Apache-2.0", url("http://www.apache.org/licenses/"))
coursierUseSbtCredentials in ThisBuild := true
coursierChecksums in ThisBuild := Nil // workaround for nexus sync bugs

// Adapted from Rob Norris' post at https://tpolecat.github.io/2014/04/11/scalac-flags.html
scalacOptions in ThisBuild ++= Seq(
"-language:_",
"-deprecation",
"-encoding", "UTF-8", // yes, this is 2 args
"-feature",
"-unchecked",
"-Ywarn-dead-code"
)

scalacOptions in ThisBuild ++= (
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, v)) if v <= 12 => Seq(
"-Xfatal-warnings",
"-Yno-adapted-args",
"-Ypartial-unification"
)
case _ =>
Nil
}
)

scalacOptions in ThisBuild ++= {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, 12)) => Seq(
"-Ywarn-numeric-widen",
"-Ywarn-unused:imports",
"-Ywarn-unused:locals",
"-Ywarn-unused:patvars",
"-Ywarn-unused:privates",
"-Xlint:-missing-interpolator,-unused,_"
)
case _ =>
Seq("-Xlint:-missing-interpolator,_")
}
}

scalacOptions in Test += "-Yrangepos"

enablePlugins(GitVersioning)

val ReleaseTag = """^v(\d+\.\d+(?:\.\d+(?:[-.]\w+)?)?)$""".r
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ private[effect] object IOAppPlatform {
def handler(code: Int) = () =>
fiber.cancel.unsafeRunAsync { result =>
result.swap.foreach(Logger.reportFailure)
IO(sys.exit(code + 128))
sys.exit(code + 128)
}

IO {
Expand All @@ -91,6 +91,7 @@ private[effect] object IOAppPlatform {
process.on("SIGHUP", handler(1))
process.on("SIGINT", handler(2))
process.on("SIGTERM", handler(15))
()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ private[effect] object IOPlatform {
* so all we can do is to throw an error.
*/
def unsafeResync[A](ioa: IO[A], limit: Duration): Option[A] = {
val _ = limit // is used on the JVM
val cb = new ResyncCallback[A]
val cancel = ioa.unsafeRunCancelable(cb)

Expand Down
3 changes: 2 additions & 1 deletion core/js/src/main/scala/cats/effect/internals/IOTimer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ private[internals] object IOTimer {

private def clearTimeout(task: js.Dynamic): Unit = {
js.Dynamic.global.clearTimeout(task)
()
}

private final class ScheduledTick(
Expand All @@ -80,4 +81,4 @@ private[internals] object IOTimer {
cb(Callback.rightUnit)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ private[effect] object IOAppPlatform {
}
}

def mainFiber(args: Array[String], contextShift: Eval[ContextShift[IO]], timer: Eval[Timer[IO]])(run: List[String] => IO[ExitCode]): IO[Fiber[IO, Int]] = {
def mainFiber(args: Array[String], contextShift: Eval[ContextShift[IO]], timer: Eval[Timer[IO]])(run: List[String] => IO[ExitCode]): IO[Fiber[IO, Int]] = {
val _ = timer // is used on Scala.js
val io = run(args.toList).redeem(
e => {
Logger.reportFailure(e)
Expand All @@ -56,5 +57,6 @@ private[effect] object IOAppPlatform {
// Should block the thread until all finalizers are executed
fiber.cancel.unsafeRunSync()
}
()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ private[effect] object IOPlatform {
// synchronization is needed for visibility
ref = a
latch.releaseShared(1)
()
}

limit match {
Expand Down
5 changes: 4 additions & 1 deletion core/jvm/src/main/scala/cats/effect/internals/IOTimer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ private[internals] final class IOTimer private (
// Race condition test
if (!conn.isCanceled) {
val f = sc.schedule(new ShiftTick(conn, cb, ec), timespan.length, timespan.unit)
ref.complete(IO(f.cancel(false)))
ref.complete(IO {
f.cancel(false)
()
})
} else {
ref.complete(IO.unit)
}
Expand Down
4 changes: 2 additions & 2 deletions core/shared/src/main/scala/cats/effect/ConcurrentEffect.scala
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ object ConcurrentEffect {

override def runCancelable[A](fa: EitherT[F, Throwable, A])
(cb: Either[Throwable, A] => IO[Unit]): SyncIO[CancelToken[EitherT[F, Throwable, ?]]] =
F.runCancelable(fa.value)(cb.compose(_.right.flatMap(x => x))).map(EitherT.liftF(_)(F))
F.runCancelable(fa.value)(cb.compose(_.flatMap(x => x))).map(EitherT.liftF(_)(F))
}

private[effect] trait WriterTConcurrentEffect[F[_], L]
Expand All @@ -106,6 +106,6 @@ object ConcurrentEffect {

override def runCancelable[A](fa: WriterT[F, L, A])
(cb: Either[Throwable, A] => IO[Unit]): SyncIO[CancelToken[WriterT[F, L, ?]]] =
F.runCancelable(fa.run)(cb.compose(_.right.map(_._2))).map(WriterT.liftF(_)(L, F))
F.runCancelable(fa.run)(cb.compose(_.map(_._2))).map(WriterT.liftF(_)(L, F))
}
}
4 changes: 2 additions & 2 deletions core/shared/src/main/scala/cats/effect/Effect.scala
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ object Effect {
protected def F: Effect[F]

def runAsync[A](fa: EitherT[F, Throwable, A])(cb: Either[Throwable, A] => IO[Unit]): SyncIO[Unit] =
F.runAsync(fa.value)(cb.compose(_.right.flatMap(x => x)))
F.runAsync(fa.value)(cb.compose(_.flatMap(x => x)))

override def toIO[A](fa: EitherT[F, Throwable, A]): IO[A] =
F.toIO(F.rethrow(fa.value))
Expand All @@ -110,7 +110,7 @@ object Effect {
protected def L: Monoid[L]

def runAsync[A](fa: WriterT[F, L, A])(cb: Either[Throwable, A] => IO[Unit]): SyncIO[Unit] =
F.runAsync(fa.run)(cb.compose(_.right.map(_._2)))
F.runAsync(fa.run)(cb.compose(_.map(_._2)))

override def toIO[A](fa: WriterT[F, L, A]): IO[A] =
F.toIO(fa.value(F))
Expand Down
5 changes: 4 additions & 1 deletion core/shared/src/main/scala/cats/effect/IO.scala
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,10 @@ sealed abstract class IO[+A] extends internals.IOBinaryCompat[A] {
*/
final def unsafeToFuture(): Future[A] = {
val p = Promise[A]
unsafeRunAsync(_.fold(p.failure, p.success))
unsafeRunAsync { cb =>
cb.fold(p.failure, p.success)
()
}
p.future
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ object Deferred {
F.delay(p.future.value.flatMap(_.toOption))

def complete(a: A): F[Unit] =
F.map(asyncBoundary)(_ => p.success(a))
F.map(asyncBoundary) { _ => p.success(a); () }

private[this] val asyncBoundary =
F.async[Unit](cb => cb(Callback.rightUnit))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,12 @@ private[effect] object Callback {
* Builds a callback from a standard Scala `Promise`.
*/
def promise[A](p: Promise[A]): T[A] = {
case Right(a) => p.success(a)
case Left(e) => p.failure(e)
case Right(a) =>
p.success(a)
()
case Left(e) =>
p.failure(e)
()
}

/** Helpers async callbacks. */
Expand Down
4 changes: 4 additions & 0 deletions core/shared/src/main/scala/cats/effect/internals/IORace.scala
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ private[effect] object IORace {
cb(Right(Left((a, IOStart.fiber[B](promiseR, connR)))))
} else {
promiseL.trySuccess(Right(a))
()
}
case Left(err) =>
if (active.getAndSet(false)) {
Expand All @@ -130,6 +131,7 @@ private[effect] object IORace {
}
} else {
promiseL.trySuccess(Left(err))
()
}
})

Expand All @@ -141,6 +143,7 @@ private[effect] object IORace {
cb(Right(Right((IOStart.fiber[A](promiseL, connL), b))))
} else {
promiseR.trySuccess(Right(b))
()
}

case Left(err) =>
Expand All @@ -152,6 +155,7 @@ private[effect] object IORace {
}
} else {
promiseR.trySuccess(Left(err))
()
}
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ private[effect] object IOStart {
// Starting the source `IO`, with a new connection, because its
// cancellation is now decoupled from our current one
val conn2 = IOConnection()
IORunLoop.startCancelable(IOForkedStart(fa, cs), conn2, p.success)
val cb0 = { ea: Either[Throwable, A] => p.success(ea); () }
IORunLoop.startCancelable(IOForkedStart(fa, cs), conn2, cb0)

cb(Right(fiber(p, conn2)))
}
Expand Down
16 changes: 16 additions & 0 deletions core/shared/src/main/scala/cats/effect/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,20 @@ package object effect {
* is a useful property to keep in mind when building such values.
*/
type CancelToken[F[_]] = F[Unit]

/**
* Provides missing methods on Scala 2.11's Either while allowing
* -Xfatal-warnings along with -Ywarn-unused-import
*/
private[effect] implicit class scala211EitherSyntax[A, B](val self: Either[A, B]) extends AnyVal {
def map[B2](f: B => B2): Either[A, B2] = self match {
case l @ Left(_) => l.asInstanceOf[Either[A, B2]]
case Right(b) => Right(f(b))
}

def flatMap[B2](f: B => Either[A, B2]): Either[A, B2] = self match {
case Right(a) => f(a)
case l @ Left(_) => l.asInstanceOf[Either[A, B2]]
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ import cats.effect.{Bracket, ExitCase}


trait BracketSyntax {
// Bracket instance here is required to ensure correct inference for E
implicit def catsEffectSyntaxBracket[F[_], A, E](fa: F[A])(implicit bracket: Bracket[F, E]): BracketOps[F, E, A] =
implicit def catsEffectSyntaxBracket[F[_], A, E](fa: F[A])(implicit bracket: Bracket[F, E]): BracketOps[F, E, A] = {
// Bracket instance here is required to ensure correct inference for E
val _ = bracket
new BracketOps[F, E, A](fa)
}
}

final class BracketOps[F[_], E, A](val self: F[A]) extends AnyVal {
Expand Down
4 changes: 3 additions & 1 deletion core/shared/src/test/scala/cats/effect/SyntaxTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ import scala.concurrent.duration._

object SyntaxTests extends AllCatsEffectSyntax {
def mock[A]: A = ???
def typed[A](a: A): Unit = ()
def typed[A](a: A): Unit = {
val _ = a
}

def bracketSyntax[F[_]: Bracket[?[_], Throwable], A, B] = {
val acquire = mock[F[A]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import cats.implicits._
import org.scalatest._
import org.scalatest.funsuite.AsyncFunSuite

class DeferredTests extends AsyncFunSuite with Matchers with EitherValues {
class DeferredTests extends AsyncFunSuite with Matchers {

implicit override def executionContext: ExecutionContext = ExecutionContext.Implicits.global
implicit val timer: cats.effect.Timer[IO] = IO.timer(executionContext)
Expand All @@ -45,7 +45,7 @@ class DeferredTests extends AsyncFunSuite with Matchers with EitherValues {
pc[Int].flatMap { p =>
p.complete(0) *> p.complete(1).attempt product p.get
}.unsafeToFuture.map { case (err, value) =>
err.left.value shouldBe an[IllegalStateException]
err.swap.toOption.get shouldBe an[IllegalStateException]
value shouldBe 0
}
}
Expand Down
8 changes: 4 additions & 4 deletions laws/jvm/src/test/scala/cats/effect/IOJVMTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class IOJVMTests extends AnyFunSuite with Matchers {
override def run() =
cb(Right(Thread.currentThread().getName))
}
()
}

val test = for {
Expand Down Expand Up @@ -104,9 +105,8 @@ class IOJVMTests extends AnyFunSuite with Matchers {
}

test("long synchronous loops that are forked are cancelable") {
val thread = new AtomicReference[Thread](null)
implicit val ec = new ExecutionContext {
val thread = new AtomicReference[Thread](null)

def execute(runnable: Runnable): Unit = {
val th = new Thread(runnable)
if (!thread.compareAndSet(null, th))
Expand All @@ -132,14 +132,14 @@ class IOJVMTests extends AnyFunSuite with Matchers {
// Cancelling
c.unsafeRunSync()
// Joining thread should succeed in case of cancelation
val th = ec.thread.get()
val th = thread.get()
th.join(1000 * 10) // 10 seconds

if (th.isAlive) {
fail("thread is still active")
}
} finally {
val th = ec.thread.get()
val th = thread.get()
if (th != null && th.isAlive)
th.interrupt()
}
Expand Down
Loading

0 comments on commit cbd7a26

Please sign in to comment.