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

Crossbuild scala-3 #206

Merged
merged 2 commits into from
Jul 20, 2021
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .scalafmt.conf
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
version = "2.7.5"
style = defaultWithAlign
maxColumn = 80

Expand Down
19 changes: 10 additions & 9 deletions athema/src/main/scala/higherkindness/athema/expr.scala
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,16 @@ object Div {
private[athema] sealed trait ExprInstances {
implicit def traverseExpr[V]: Traverse[Expr[V, *]] =
new DefaultTraverse[Expr[V, *]] {
def traverse[G[_]: Applicative, A, B](fa: Expr[V, A])(
f: A => G[B]): G[Expr[V, B]] = fa match {
case v: Var[_, B @unchecked] => (v: Expr[V, B]).pure[G]
case c: Const[_, B @unchecked] => (c: Expr[V, B]).pure[G]
case e: Neg[V, A] => f(e.x) map (Neg(_))
case e: Add[V, A] => (f(e.x), f(e.y)) mapN (Add(_, _))
case e: Sub[V, A] => (f(e.x), f(e.y)) mapN (Sub(_, _))
case e: Prod[V, A] => (f(e.x), f(e.y)) mapN (Prod(_, _))
case e: Div[V, A] => (f(e.x), f(e.y)) mapN (Div(_, _))
def traverse[G[_]: Applicative, A, B](
fa: Expr[V, A]
)(f: A => G[B]): G[Expr[V, B]] = fa match {
case v: Var[V, A] => (v.asInstanceOf[Expr[V, B]]).pure[G]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

scala3 reports this match as non-exhaustive with the @unchecked annotations in there.

case c: Const[V, A] => (c.asInstanceOf[Expr[V, B]]).pure[G]
case e: Neg[V, A] => f(e.x) map (Neg(_))
case e: Add[V, A] => (f(e.x), f(e.y)) mapN (Add(_, _))
case e: Sub[V, A] => (f(e.x), f(e.y)) mapN (Sub(_, _))
case e: Prod[V, A] => (f(e.x), f(e.y)) mapN (Prod(_, _))
case e: Div[V, A] => (f(e.x), f(e.y)) mapN (Div(_, _))
Comment on lines +63 to +67

Choose a reason for hiding this comment

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

As a BTW, are we still too keen on infix syntax?

Suggested change
case e: Neg[V, A] => f(e.x) map (Neg(_))
case e: Add[V, A] => (f(e.x), f(e.y)) mapN (Add(_, _))
case e: Sub[V, A] => (f(e.x), f(e.y)) mapN (Sub(_, _))
case e: Prod[V, A] => (f(e.x), f(e.y)) mapN (Prod(_, _))
case e: Div[V, A] => (f(e.x), f(e.y)) mapN (Div(_, _))
case e: Neg[V, A] => f(e.x) map (Neg(_))
case e: Add[V, A] => (f(e.x), f(e.y)).mapN(Add(_, _))
case e: Sub[V, A] => (f(e.x), f(e.y)).mapN(Sub(_, _))
case e: Prod[V, A] => (f(e.x), f(e.y)).mapN(Prod(_, _))
case e: Div[V, A] => (f(e.x), f(e.y)).mapN(Div(_, _))

specially if it saves no parentheses.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm personally not keen on it, I just left things as they were mainly and how scalafmt left them

}
}
}
5 changes: 3 additions & 2 deletions athema/src/main/scala/higherkindness/athema/parser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ object ExprParser {
case TSub => shunt(op, 1).flatMap(_.traverse(enqueue))
case TProd => shunt(op, 2).flatMap(_.traverse(enqueue))
case TDiv => shunt(op, 2).flatMap(_.traverse(enqueue))
}).as(tail.asLeft)
}).map(_ => tail.asLeft)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

as doesn't resolve, for some reason, in scala3. No idea why.

Choose a reason for hiding this comment

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

I think it was proposed, at some point, as a replacement for the @ in pattern matching. I had some comments about that.

case Nil =>
for {
s0 <- StateT.get[FF, SS]
Expand Down Expand Up @@ -87,7 +87,8 @@ object ExprParser {
private def binary(
f: (
Expr.Fixed[BigDecimal],
Expr.Fixed[BigDecimal]) => Expr.Fixed[BigDecimal]
Expr.Fixed[BigDecimal]
) => Expr.Fixed[BigDecimal]
): StateT[FF, Output, Unit] =
StateT.modifyF { output0 =>
val y = output0.head
Expand Down
115 changes: 78 additions & 37 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import ProjectPlugin.ScalaV
import ProjectPlugin.on
import ProjectPlugin.onVersion

lazy val root = (project in file("."))
.settings(noPublishSettings)
.aggregate(coreJVM, coreJS)
Expand All @@ -9,7 +13,9 @@ lazy val root = (project in file("."))
.aggregate(testsJVM, testsJS)
.aggregate(athemaJVM, athemaJS)
.aggregate(readme)
.settings(crossScalaVersions := List()) // work around https://github.com/sbt/sbt/issues/4181
.settings(
crossScalaVersions := List()
) // work around https://github.com/sbt/sbt/issues/4181

lazy val publish = (project in file(".publish"))
.settings(noPublishSettings)
Expand All @@ -22,7 +28,11 @@ lazy val publish = (project in file(".publish"))
.aggregate(testsJVM, testsJS)

lazy val coverage = (project in file(".coverage"))
.settings(noPublishSettings)
.settings(
noPublishSettings,
crossScalaVersions := Seq(ScalaV.v212, ScalaV.v213),
scalaVersion := ScalaV.v213
)
.settings(coverageEnabled := true)
.aggregate(coreJVM)
.aggregate(metaJVM)
Expand All @@ -44,10 +54,14 @@ lazy val V = new {
lazy val meta = module("meta")
.settings(
mimaPreviousArtifacts := Set(
organization.value %%% moduleName.value % V.drostePrev),
libraryDependencies ++= Seq(
"org.scala-lang" % "scala-reflect" % scalaVersion.value,
"org.scala-lang" % "scala-compiler" % scalaVersion.value % "provided")
organization.value %%% moduleName.value % V.drostePrev
),
libraryDependencies ++= onVersion(2)(version =>
Seq(
"org.scala-lang" % "scala-reflect" % version,
"org.scala-lang" % "scala-compiler" % version % "provided"
)
).value.flatten
)

lazy val metaJVM = meta.jvm
Expand All @@ -57,31 +71,40 @@ lazy val core = module("core")
.dependsOn(meta)
.settings(
mimaPreviousArtifacts := Set(
organization.value %%% moduleName.value % V.drostePrev),
organization.value %%% moduleName.value % V.drostePrev
),
mimaBinaryIssueFilters ++= {
import com.typesafe.tools.mima.core.IncompatibleSignatureProblem
import com.typesafe.tools.mima.core.ProblemFilters.exclude
// See https://github.com/lightbend/mima/issues/423
Seq(
exclude[IncompatibleSignatureProblem](
"higherkindness.droste.Basis#Default.unapply"),
"higherkindness.droste.Basis#Default.unapply"
),
exclude[IncompatibleSignatureProblem](
"higherkindness.droste.GAlgebra#Gathered.unapply"),
"higherkindness.droste.GAlgebra#Gathered.unapply"
),
exclude[IncompatibleSignatureProblem](
"higherkindness.droste.GAlgebraArrow.algebra"),
"higherkindness.droste.GAlgebraArrow.algebra"
),
exclude[IncompatibleSignatureProblem](
"higherkindness.droste.GAlgebraM#Gathered.unapply"),
"higherkindness.droste.GAlgebraM#Gathered.unapply"
),
exclude[IncompatibleSignatureProblem](
"higherkindness.droste.GCoalgebra#Scattered.unapply"),
"higherkindness.droste.GCoalgebra#Scattered.unapply"
),
exclude[IncompatibleSignatureProblem](
"higherkindness.droste.GCoalgebraArrow.algebra"),
"higherkindness.droste.GCoalgebraArrow.algebra"
),
exclude[IncompatibleSignatureProblem](
"higherkindness.droste.GCoalgebraM#Scattered.unapply")
"higherkindness.droste.GCoalgebraM#Scattered.unapply"
)
)
},
libraryDependencies ++= Seq(
"org.typelevel" %%% "cats-core" % V.cats,
"org.typelevel" %%% "cats-free" % V.cats)
"org.typelevel" %%% "cats-free" % V.cats
)
)

lazy val coreJVM = core.jvm
Expand All @@ -91,9 +114,21 @@ lazy val macros = module("macros")
.dependsOn(core)
.settings(
mimaPreviousArtifacts := Set(
organization.value %%% moduleName.value % V.drostePrev),
libraryDependencies ++= on(2, 12)(compilerPlugin(
"org.scalamacros" %% "paradise" % "2.1.1" cross CrossVersion.patch)).value,
organization.value %%% moduleName.value % V.drostePrev
),
libraryDependencies ++= on(2, 12)(
compilerPlugin(
"org.scalamacros" %% "paradise" % "2.1.1" cross CrossVersion.patch
)
).value,
// For some reason dependencies using `%%%` don't work with our 'on' method.
// They give 'error: Illegal dynamic dependency'
libraryDependencies ++=
(CrossVersion.partialVersion(scalaVersion.value) match {
case Some((3, _)) =>
Seq("org.typelevel" %%% "shapeless3-deriving" % "3.0.1")
case _ => Nil
}),
scalacOptions ++= on(2, 13)("-Ymacro-annotations").value
)

Expand All @@ -102,20 +137,24 @@ lazy val macrosJS = macros.js

lazy val reftree = jvmModule("reftree")
.dependsOn(coreJVM)
.settings(noScala213Settings)
.settings(
mimaPreviousArtifacts := Set(
organization.value %% moduleName.value % V.drostePrev),
libraryDependencies ++= Seq("io.github.stanch" %% "reftree" % "1.4.0")
organization.value %% moduleName.value % V.drostePrev
),
libraryDependencies ++= on(2, 12)(
"io.github.stanch" %% "reftree" % "1.4.0"
).value
)

lazy val scalacheck = module("scalacheck")
.dependsOn(core)
.settings(
mimaPreviousArtifacts := Set(
organization.value %%% moduleName.value % V.drostePrev),
organization.value %%% moduleName.value % V.drostePrev
),
libraryDependencies ++= Seq(
"org.scalacheck" %%% "scalacheck" % V.scalacheck)
"org.scalacheck" %%% "scalacheck" % V.scalacheck
)
)

lazy val scalacheckJVM = scalacheck.jvm
Expand All @@ -125,9 +164,11 @@ lazy val laws = module("laws")
.dependsOn(core)
.settings(
mimaPreviousArtifacts := Set(
organization.value %%% moduleName.value % V.drostePrev),
organization.value %%% moduleName.value % V.drostePrev
),
libraryDependencies ++= Seq(
"org.scalacheck" %%% "scalacheck" % V.scalacheck)
"org.scalacheck" %%% "scalacheck" % V.scalacheck
)
)

lazy val lawsJVM = laws.jvm
Expand All @@ -145,9 +186,14 @@ lazy val tests = module("tests")
"eu.timepit" %%% "refined-scalacheck" % V.refined,
"org.scala-lang.modules" %%% "scala-collection-compat" % V.collectionCompat % Test
),
libraryDependencies ++= on(2, 12)(compilerPlugin(
"org.scalamacros" %% "paradise" % "2.1.1" cross CrossVersion.patch)).value,
scalacOptions ++= on(2, 13)("-Ymacro-annotations").value
libraryDependencies ++= on(2, 12)(
compilerPlugin(
"org.scalamacros" %% "paradise" % "2.1.1" cross CrossVersion.patch
)
).value,
scalacOptions ++= on(2, 13)("-Ymacro-annotations").value,
// 'nowarn' doesn't work on scala3 yet, make warnings not fatal.
scalacOptions --= on(3)("-Xfatal-warnings").value
Comment on lines +195 to +196
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 pretty important

)

lazy val testsJVM = tests.jvm
Expand All @@ -165,7 +211,10 @@ lazy val athema = module("athema", prefix = "")
) ++
Seq(
"org.scalacheck" %%% "scalacheck" % V.scalacheck
).map(_ % "test"))
).map(_ % "test"),
// 'nowarn' doesn't work on scala3 yet, make warnings not fatal.
scalacOptions --= on(3)("-Xfatal-warnings").value
Copy link
Member

Choose a reason for hiding this comment

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

👍🏻

)

lazy val athemaJVM = athema.jvm
lazy val athemaJS = athema.js
Expand Down Expand Up @@ -203,12 +252,4 @@ addCommandAlias(
)
addCommandAlias("ci-docs", ";github;mdoc")

def on[A](major: Int, minor: Int)(a: A): Def.Initialize[Seq[A]] =
Def.setting {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some(v) if v == (major, minor) => Seq(a)
case _ => Nil
}
}

ThisBuild / resolvers += Resolver.sonatypeRepo("public")
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import cats.syntax.functor._
import cats.syntax.traverse._

import meta.Meta
import data.prelude._
import util.DefaultTraverse
import higherkindness.droste.data.prelude._
import higherkindness.droste.util.DefaultTraverse
Comment on lines +13 to +14
Copy link
Contributor Author

@Daenyth Daenyth Jul 14, 2021

Choose a reason for hiding this comment

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

I ran into issues with things not resolving using relative imports; I'll double check whether this is still needed now that everything compiles.

Edit: it is, don't know why

Copy link
Member

Choose a reason for hiding this comment

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

Hm... I thought we had a scalafix rule to prevent relative imports to be used, and always use absolute ones...


object AttrF {
def apply[F[_], A, B](ask: A, lower: F[B]): AttrF[F, A, B] =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import cats.syntax.functor._
import cats.syntax.traverse._

import meta.Meta
import util.DefaultTraverse
import higherkindness.droste.util.DefaultTraverse

object CoattrF {
def apply[F[_], A, B](f: Either[A, F[B]]): CoattrF[F, A, B] =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ object Fix {

def algebra[F[_]]: Algebra[F, Fix[F]] = Algebra(apply(_))
def coalgebra[F[_]]: Coalgebra[F, Fix[F]] = Coalgebra(un(_))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package higherkindness.droste
package data

import cats.Comonad
import cats.Eval
import cats.Functor

import cats.syntax.functor._

import prelude._

object Attr {
def apply[F[_], A](head: A, tail: F[Attr[F, A]]): Attr[F, A] =
apply((head, tail))
def apply[F[_], A](f: (A, F[Attr[F, A]])): Attr[F, A] = f.asInstanceOf
def un[F[_], A](f: Attr[F, A]): (A, F[Attr[F, A]]) = f.asInstanceOf
Comment on lines +15 to +16
Copy link
Contributor Author

Choose a reason for hiding this comment

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

For this and the other data types, the main difference is the apply/un things.

I might try to reduce some of the duplication, but we'll see if that proves worthwhile

def unapply[F[_], A](f: Attr[F, A]): Some[(A, F[Attr[F, A]])] = Some(un(f))

def algebra[F[_], A]: Algebra[AttrF[F, A, *], Attr[F, A]] =
Algebra(fa => Attr(AttrF.un(fa)))

def coalgebra[F[_], A]: Coalgebra[AttrF[F, A, *], Attr[F, A]] =
Coalgebra(a => AttrF(Attr.un(a)))

def fromCats[F[_]: Functor, A](cofree: cats.free.Cofree[F, A]): Attr[F, A] =
ana(cofree)(_.tail.value, _.head)

def unfold[F[_]: Functor, A](a: A)(coalgebra: A => F[A]): Attr[F, A] =
ana(a)(coalgebra, identity)

/** An inlined anamorphism to `Attr` with a fused map */
def ana[F[_]: Functor, A, C](
a: A
)(coalgebra: A => F[A], f: A => C): Attr[F, C] =
Attr(f(a), coalgebra(a).map(ana(_)(coalgebra, f)))
}

private[data] trait AttrImplicits {
implicit final class AttrOps[F[_], A](attr: Attr[F, A]) {
def tuple: (A, F[Attr[F, A]]) = Attr.un(attr)
def head: A = tuple._1
def tail: F[Attr[F, A]] = tuple._2

def toCats(implicit ev: Functor[F]): cats.free.Cofree[F, A] =
cats.free.Cofree(head, Eval.later(tail.map(_.toCats)))

def forget(implicit ev: Functor[F]): Fix[F] =
Fix(tail.map(_.forget))
}

implicit def drosteAttrComonad[F[_]: Functor]: Comonad[Attr[F, *]] =
new AttrComonad[F]
}

private[data] final class AttrComonad[F[_]: Functor]
extends Comonad[Attr[F, *]] {
def coflatMap[A, B](fa: Attr[F, A])(f: Attr[F, A] => B): Attr[F, B] =
Attr.ana(fa)(_.tail, f)

def extract[A](fa: Attr[F, A]): A = fa.head

def map[A, B](fa: Attr[F, A])(f: A => B): Attr[F, B] =
Attr(f(fa.head), fa.tail.map(_.map(f)))
}