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

2.13.0-RC1 #2792

Merged
merged 15 commits into from
Apr 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jdk:

scala_version_211: &scala_version_211 2.11.12
scala_version_212: &scala_version_212 2.12.7
scala_version_213: &scala_version_213 2.13.0-M5
scala_version_213: &scala_version_213 2.13.0-RC1

before_install:
- export PATH=${PATH}:./vendor/bundle
Expand Down
20 changes: 11 additions & 9 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,13 @@ lazy val catsSettings = Seq(
"bintray/non".at("http://dl.bintray.com/non/maven")
),
libraryDependencies ++= Seq(
"org.typelevel" %%% "machinist" % "0.6.6",
compilerPlugin("org.spire-math" %% "kind-projector" % "0.9.9")
"org.typelevel" %%% "machinist" % "0.6.7",
compilerPlugin("org.typelevel" %% "kind-projector" % "0.10.0")
) ++ macroDependencies(scalaVersion.value),
) ++ commonSettings ++ publishSettings ++ scoverageSettings ++ simulacrumSettings

lazy val simulacrumSettings = Seq(
libraryDependencies += "com.github.mpilquist" %%% "simulacrum" % "0.15.0" % Provided,
libraryDependencies += "com.github.mpilquist" %%% "simulacrum" % "0.16.0" % Provided,
pomPostProcess := { (node: xml.Node) =>
new RuleTransformer(new RewriteRule {
override def transform(node: xml.Node): Seq[xml.Node] = node match {
Expand Down Expand Up @@ -151,20 +151,19 @@ lazy val includeGeneratedSrc: Setting[_] = {
}
}

def scalatestVersion(scalaVersion: String): String =
if (priorTo2_13(scalaVersion)) "3.0.5" else "3.0.6-SNAP5"
val scalatestVersion = "3.0.8-RC2"

val scalaCheckVersion = "1.14.0"

val disciplineVersion = "0.10.0"
val disciplineVersion = "0.11.1"

lazy val disciplineDependencies = Seq(
libraryDependencies += "org.scalacheck" %%% "scalacheck" % scalaCheckVersion,
libraryDependencies += "org.typelevel" %%% "discipline" % disciplineVersion
)

lazy val testingDependencies = Seq(
libraryDependencies += "org.scalatest" %%% "scalatest" % scalatestVersion(scalaVersion.value) % "test"
libraryDependencies += "org.scalatest" %%% "scalatest" % scalatestVersion % "test"
)

lazy val docsMappingsAPIDir = settingKey[String]("Name of subdirectory in site target directory for api docs")
Expand Down Expand Up @@ -549,6 +548,7 @@ lazy val tests = crossProject(JSPlatform, JVMPlatform)
.settings(noPublishSettings)
.jsSettings(commonJsSettings)
.jvmSettings(commonJvmSettings)
.settings(scalacOptions in Test := (scalacOptions in Test).value.filter(_ != "-Xfatal-warnings"))

lazy val testkit = crossProject(JSPlatform, JVMPlatform)
.crossType(CrossType.Pure)
Expand All @@ -558,9 +558,10 @@ lazy val testkit = crossProject(JSPlatform, JVMPlatform)
.settings(moduleName := "cats-testkit")
.settings(catsSettings)
.settings(disciplineDependencies)
.settings(libraryDependencies += "org.scalatest" %%% "scalatest" % scalatestVersion(scalaVersion.value))
.settings(libraryDependencies += "org.scalatest" %%% "scalatest" % scalatestVersion)
.jsSettings(commonJsSettings)
.jvmSettings(commonJvmSettings)
.settings(scalacOptions := scalacOptions.value.filter(_ != "-Xfatal-warnings"))

lazy val alleycatsCore = crossProject(JSPlatform, JVMPlatform)
.crossType(CrossType.Pure)
Expand Down Expand Up @@ -596,6 +597,7 @@ lazy val alleycatsTests = crossProject(JSPlatform, JVMPlatform)
.settings(noPublishSettings)
.jsSettings(commonJsSettings)
.jvmSettings(commonJvmSettings)
.settings(scalacOptions in Test := (scalacOptions in Test).value.filter(_ != "-Xfatal-warnings"))

// bench is currently JVM-only

Expand Down Expand Up @@ -628,7 +630,7 @@ lazy val binCompatTest = project
else //We are not testing BC on Scala 2.13 yet.
"org.typelevel" %% "cats-core" % version.value % Provided
},
"org.scalatest" %%% "scalatest" % scalatestVersion(scalaVersion.value) % Test
"org.scalatest" %%% "scalatest" % scalatestVersion % Test
)
)
.dependsOn(core.jvm % Test)
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/cats/ApplicativeError.scala
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ trait ApplicativeError[F[_], E] extends Applicative[F] {
* `F[A]` values.
*/
def recover[A](fa: F[A])(pf: PartialFunction[E, A]): F[A] =
handleErrorWith(fa)(e => (pf.andThen(pure)).applyOrElse(e, raiseError))
handleErrorWith(fa)(e => (pf.andThen(pure _)).applyOrElse(e, raiseError _))

/**
* Recover from certain errors by mapping them to an `F[A]` value.
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/cats/MonadError.scala
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ trait MonadError[F[_], E] extends ApplicativeError[F, E] with Monad[F] {
* ApplicativeError in Cats 2.0: see [[https://github.com/typelevel/cats/issues/2685]]
*/
def adaptError[A](fa: F[A])(pf: PartialFunction[E, E]): F[A] =
recoverWith(fa)(pf.andThen(raiseError))
recoverWith(fa)(pf.andThen(raiseError[A] _))

/**
* Inverse of `attempt`
Expand Down
3 changes: 3 additions & 0 deletions core/src/main/scala/cats/data/WriterT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,9 @@ sealed private[data] trait WriterTFlatMap1[F[_], L] extends WriterTApply[F, L] w
implicit override def F0: FlatMap[F]
implicit def L0: Monoid[L]

override def ap[A, B](f: WriterT[F, L, A => B])(fa: WriterT[F, L, A]): WriterT[F, L, B] =
Copy link
Contributor

Choose a reason for hiding this comment

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

Just curious, was this an optimization opportunity you happen to come across or was it broken on RC1?
Also would it be simpler to just call fa.ap(f)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is from @SethTisue's commit, but the issue is that 2.13 sees the ap definitions in FlatMap and WriterTApply as conflicting. I personally think picking out the appropriate implementation via super is the right thing to do in this case, but I also don't think it matters much, and am happy to change it to fa.ap(f) if you'd prefer.

super[WriterTApply].ap(f)(fa)

def flatMap[A, B](fa: WriterT[F, L, A])(f: A => WriterT[F, L, B]): WriterT[F, L, B] =
fa.flatMap(f)

Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/cats/instances/sortedMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,10 @@ class SortedMapHash[K, V](implicit V: Hash[V], O: Order[K], K: Hash[K])
var c = 1
x.foreach {
case (k, v) =>
val h = StaticMethods.product2Hash(K.hash(k), V.hash(v))
val h = StaticMethods.product2HashWithPrefix(K.hash(k), V.hash(v), "Tuple2")
a += h
b ^= h
if (h != 0) c *= h
c = StaticMethods.updateUnorderedHashC(c, h)
n += 1
}
var h = mapSeed
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/cats/instances/sortedSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ class SortedSetHash[A: Order: Hash] extends Hash[SortedSet[A]] {
val h = Hash[A].hash(x)
a += h
b ^= h
if (h != 0) c *= h
c = cats.kernel.instances.StaticMethods.updateUnorderedHashC(c, h)
n += 1
}
var h = setSeed
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/cats/syntax/applicativeError.scala
Original file line number Diff line number Diff line change
Expand Up @@ -123,5 +123,5 @@ final class ApplicativeErrorOps[F[_], E, A](private val fa: F[A]) extends AnyVal
* to `ApplicativeError` in Cats 2.0: see [[https://github.com/typelevel/cats/issues/2685]]
*/
def adaptErr(pf: PartialFunction[E, E])(implicit F: ApplicativeError[F, E]): F[A] =
F.recoverWith(fa)(pf.andThen(F.raiseError))
F.recoverWith(fa)(pf.andThen(F.raiseError[A] _))
}
2 changes: 1 addition & 1 deletion core/src/main/scala/cats/syntax/monadError.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ final class MonadErrorOps[F[_], E, A](private val fa: F[A]) extends AnyVal {
*/
def reject(pf: PartialFunction[A, E])(implicit F: MonadError[F, E]): F[A] =
F.flatMap(fa) { a =>
pf.andThen(F.raiseError[A]).applyOrElse(a, (_: A) => fa)
pf.andThen(F.raiseError[A] _).applyOrElse(a, (_: A) => fa)
}

def adaptError(pf: PartialFunction[E, E])(implicit F: MonadError[F, E]): F[A] =
Expand Down
53 changes: 53 additions & 0 deletions kernel/src/main/scala-2.12-/cats/kernel/compat/HashCompat.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package cats
package kernel
package compat

private[kernel] class HashCompat {
// Adapted from scala.util.hashing.MurmurHash#productHash.
private[kernel] def product1HashWithPrefix(_1Hash: Int, prefix: String): Int = {
import scala.util.hashing.MurmurHash3._
var h = productSeed
h = mix(h, _1Hash)
finalizeHash(h, 1)
}

// Adapted from scala.util.hashing.MurmurHash#productHash.
private[cats] def product2HashWithPrefix(_1Hash: Int, _2Hash: Int, prefix: String): Int = {
import scala.util.hashing.MurmurHash3._
var h = productSeed
h = mix(h, _1Hash)
h = mix(h, _2Hash)
finalizeHash(h, 2)
}

private[cats] def updateUnorderedHashC(c: Int, h: Int): Int = if (h != 0) c * h else c

// adapted from [[scala.util.hashing.MurmurHash3]],
// but modified standard `Any#hashCode` to `ev.hash`.
def listHash[A](x: List[A])(implicit A: Hash[A]): Int = {
import scala.util.hashing.MurmurHash3._
var n = 0
var h = seqSeed
var elems = x
while (!elems.isEmpty) {
val head = elems.head
val tail = elems.tail
h = mix(h, A.hash(head))
n += 1
elems = tail
}
finalizeHash(h, n)
}

// adapted from scala.util.hashing.MurmurHash3
def orderedHash[A](xs: TraversableOnce[A])(implicit A: Hash[A]): Int = {
import scala.util.hashing.MurmurHash3._
var n = 0
var h = seqSeed
xs.foreach { x =>
h = mix(h, A.hash(x))
n += 1
}
finalizeHash(h, n)
}
}
116 changes: 116 additions & 0 deletions kernel/src/main/scala-2.13+/cats/kernel/compat/HashCompat.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package cats
package kernel
package compat

private[kernel] class HashCompat {
// Adapted from scala.util.hashing.MurmurHash#productHash.
private[kernel] def product1HashWithPrefix(_1Hash: Int, prefix: String): Int = {
import scala.util.hashing.MurmurHash3._
var h = productSeed
h = mix(h, prefix.hashCode)
h = mix(h, _1Hash)
finalizeHash(h, 1)
}

// Adapted from scala.util.hashing.MurmurHash#productHash.
private[cats] def product2HashWithPrefix(_1Hash: Int, _2Hash: Int, prefix: String): Int = {
import scala.util.hashing.MurmurHash3._
var h = productSeed
h = mix(h, prefix.hashCode)
h = mix(h, _1Hash)
h = mix(h, _2Hash)
finalizeHash(h, 2)
}

private[cats] def updateUnorderedHashC(c: Int, h: Int): Int = c * (h | 1)

// adapted from [[scala.util.hashing.MurmurHash3]],
// but modified standard `Any#hashCode` to `ev.hash`.
def listHash[A](x: List[A])(implicit A: Hash[A]): Int = {
import scala.util.hashing.MurmurHash3.{finalizeHash, mix, rangeHash, seqSeed}
var n = 0
var h = seqSeed
var rangeState = 0 // 0 = no data, 1 = first elem read, 2 = has valid diff, 3 = invalid
var rangeDiff = 0
var prev = 0
var initial = 0
var elems = x
while (!elems.isEmpty) {
val head = elems.head
val tail = elems.tail
val hash = A.hash(head)
h = mix(h, hash)
rangeState match {
case 0 =>
initial = hash
rangeState = 1
case 1 =>
rangeDiff = hash - prev
rangeState = 2
case 2 =>
if (rangeDiff != hash - prev) rangeState = 3
case _ =>
}
prev = hash
n += 1
elems = tail
}
if (rangeState == 2) rangeHash(initial, rangeDiff, prev, seqSeed)
else finalizeHash(h, n)
}

// adapted from scala.util.hashing.MurmurHash3
def orderedHash[A](xs: TraversableOnce[A])(implicit A: Hash[A]): Int = {
import scala.util.hashing.MurmurHash3.{finalizeHash, mix, seqSeed}

val it = xs.iterator
var h = seqSeed
// scalastyle:off
if (!it.hasNext) return finalizeHash(h, 0)
// scalastyle:on
val x0 = it.next()
// scalastyle:off
if (!it.hasNext) return finalizeHash(mix(h, A.hash(x0)), 1)
// scalastyle:on
val x1 = it.next()

val initial = A.hash(x0)
h = mix(h, initial)
val h0 = h
var prev = A.hash(x1)
val rangeDiff = prev - initial
var i = 2
while (it.hasNext) {
h = mix(h, prev)
val hash = A.hash(it.next())
if (rangeDiff != hash - prev) {
h = mix(h, hash)
i += 1
while (it.hasNext) {
h = mix(h, A.hash(it.next()))
i += 1
}
// scalastyle:off
return finalizeHash(h, i)
// scalastyle:on
}
prev = hash
i += 1
}
avalanche(mix(mix(h0, rangeDiff), prev))
}

// adapted from scala.util.hashing.MurmurHash3
/** Force all bits of the hash to avalanche. Used for finalizing the hash. */
final protected def avalanche(hash: Int): Int = {
var h = hash

h ^= h >>> 16
h *= 0x85ebca6b
h ^= h >>> 13
h *= 0xc2b2ae35
h ^= h >>> 16

h
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ import scala.collection.mutable

abstract private[kernel] class WrappedMutableMapBase[K, V](m: mutable.Map[K, V]) extends Map[K, V] with Serializable {
def updated[V2 >: V](key: K, value: V2): Map[K, V2] = m.toMap + ((key, value))
def remove(key: K): Map[K, V] = m.toMap - key
def removed(key: K): Map[K, V] = m.toMap - key
}
32 changes: 1 addition & 31 deletions kernel/src/main/scala/cats/kernel/instances/StaticMethods.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ package instances

import scala.collection.mutable

object StaticMethods {
object StaticMethods extends cats.kernel.compat.HashCompat {

def wrapMutableMap[K, V](m: mutable.Map[K, V]): Map[K, V] =
new WrappedMutableMap(m)
Expand Down Expand Up @@ -96,34 +96,4 @@ object StaticMethods {
h = mix(h, _2Hash)
finalizeHash(h, 2)
}

// adapted from [[scala.util.hashing.MurmurHash3]],
// but modified standard `Any#hashCode` to `ev.hash`.
def listHash[A](x: List[A])(implicit A: Hash[A]): Int = {
import scala.util.hashing.MurmurHash3._
var n = 0
var h = seqSeed
var elems = x
while (!elems.isEmpty) {
val head = elems.head
val tail = elems.tail
h = mix(h, A.hash(head))
n += 1
elems = tail
}
finalizeHash(h, n)
}

// adapted from scala.util.hashing.MurmurHash3
def orderedHash[A](xs: TraversableOnce[A])(implicit A: Hash[A]): Int = {
import scala.util.hashing.MurmurHash3._
var n = 0
var h = seqSeed
xs.foreach { x =>
h = mix(h, A.hash(x))
n += 1
}
finalizeHash(h, n)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class EitherEq[A, B](implicit A: Eq[A], B: Eq[B]) extends Eq[Either[A, B]] {
class EitherHash[A, B](implicit A: Hash[A], B: Hash[B]) extends EitherEq[A, B] with Hash[Either[A, B]] {
def hash(x: Either[A, B]): Int =
x match {
case Left(xx) => StaticMethods.product1Hash(A.hash(xx))
case Right(xx) => StaticMethods.product1Hash(B.hash(xx))
case Left(xx) => StaticMethods.product1HashWithPrefix(A.hash(xx), "Left")
case Right(xx) => StaticMethods.product1HashWithPrefix(B.hash(xx), "Right")
}
}
4 changes: 2 additions & 2 deletions kernel/src/main/scala/cats/kernel/instances/map/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ class MapHash[K, V](implicit V: Hash[V]) extends MapEq[K, V]()(V) with Hash[Map[
x.foreach {
case (k, v) =>
// use the default hash on keys because that's what Scala's Map does
val h = StaticMethods.product2Hash(k.hashCode(), V.hash(v))
val h = StaticMethods.product2HashWithPrefix(k.hashCode(), V.hash(v), "Tuple2")
a += h
b ^= h
if (h != 0) c *= h
c = StaticMethods.updateUnorderedHashC(c, h)
n += 1
}
var h = mapSeed
Expand Down
Loading