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

Mix scala 2 and 3 macros #395

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
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
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ jobs:
- java: 11
scala: 2.12.18
- java: 11
scala: 2.13.11
scala: 2.13.13
- java: 11
scala: 3.3.0
scala: 3.3.4
runs-on: ubuntu-latest
env:
SCALAJS_TEST_OPT: full
Expand All @@ -36,7 +36,7 @@ jobs:
shell: bash
run: |
case ${{ matrix.scala }} in
2.13.11)
2.13.13)
sbt -v "++${{ matrix.scala }} scalafmtCheck" "++${{ matrix.scala }} scalafmtSbtCheck" "++${{ matrix.scala }} test:compile" "++${{ matrix.scala }} test:doc"
sbt -v "coverage" "++${{ matrix.scala }} test" "++${{ matrix.scala }} coverageReport"
sbt -v "++${{ matrix.scala }} coverageAggregate"
Expand All @@ -52,7 +52,7 @@ jobs:
find $HOME/.cache/coursier/v1 -name "ivydata-*.properties" -delete || true
find $HOME/.sbt -name "*.lock" -delete || true
- name: Upload coverage to Codecov
if: ${{ matrix.scala == '2.13.11' }}
if: ${{ matrix.scala == '2.13.13' }}
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
Expand Down
2 changes: 1 addition & 1 deletion .scalafmt.conf
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version = 3.7.8
version = 3.7.10
runner.dialect = Scala213Source3
style = defaultWithAlign
maxColumn = 100
Expand Down
19 changes: 11 additions & 8 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import sbtbuildinfo.BuildInfoPlugin.autoImport._
import sbtcrossproject.CrossPlugin.autoImport.{CrossType, crossProject}

lazy val scala_2_12Version = "2.12.18"
lazy val scala_2_13Version = "2.13.11"
lazy val scala_3Version = "3.3.0"
lazy val scala_2_13Version = "2.13.13"
lazy val scala_3Version = "3.3.4"
lazy val scalaVersionsAll = Seq(scala_2_12Version, scala_2_13Version, scala_3Version)

lazy val theScalaVersion = scala_2_12Version
Expand Down Expand Up @@ -108,11 +108,14 @@ lazy val macros = crossProject(JSPlatform, JVMPlatform, NativePlatform)
name := "enumeratum-macros",
version := Versions.Macros.head,
crossScalaVersions := scalaVersionsAll, // eventually move this to aggregateProject once more 2.13 libs are out
libraryDependencies += {
libraryDependencies ++= {
if (scalaBinaryVersion.value == "3") {
"org.scala-lang" %% "scala3-compiler" % scalaVersion.value % Provided
Seq(
"org.scala-lang" %% "scala3-compiler" % scalaVersion.value % Provided,
"org.scala-lang" % "scala-reflect" % scala_2_13Version,
Copy link
Owner

Choose a reason for hiding this comment

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

Curious if there's a way to make this additional dependency

  • Contingent on actually using the mix mode macro
  • Only a compile time constraint?

Copy link
Author

Choose a reason for hiding this comment

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

Unfortunately I think only the consumer of the library knows if the mixed mode macro is being used, from here, sbt only knows that it's a scala3 build.

I believe we could mark this as Provided too, but then all consumers would need to explicitly provide it. Marking it provided here means I also need to add it as Provided in core. It would only need to be added as a normal/runtime dep if the project was using the mixed mode because I think this is only needed for the scala 2 portion of the build.

Copy link
Author

Choose a reason for hiding this comment

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

@lloydmeta let me know if you have a preference here.

)
} else {
"org.scala-lang" % "scala-reflect" % scalaVersion.value
Seq("org.scala-lang" % "scala-reflect" % scalaVersion.value)
}
},
libraryDependencies += scalaXmlTest
Expand Down Expand Up @@ -141,7 +144,7 @@ lazy val core = crossProject(JSPlatform, JVMPlatform, NativePlatform)
if (useLocalVersion) {
Seq.empty
} else {
Seq("com.beachape" %% "enumeratum-macros" % Versions.Macros.stable)
Seq("com.beachape" %% "enumeratum-macros" % Versions.Macros.head)
}
},
libraryDependencies += scalaXmlTest
Expand Down Expand Up @@ -461,7 +464,7 @@ lazy val enumeratumScalacheck = crossProject(JSPlatform, JVMPlatform, NativePlat
version := Versions.Core.head,
crossScalaVersions := scalaVersionsAll,
libraryDependencies ++= {
val (ver, mod, ver2) = ("1.18.0", "scalacheck-1-18", "3.2.19.0")
val (ver, mod, ver2) = ("1.18.1", "scalacheck-1-18", "3.2.19.0")

Seq(
"org.scalacheck" %%% "scalacheck" % ver,
Expand Down Expand Up @@ -685,7 +688,7 @@ lazy val compilerSettings = Seq(

val base = {
if (scalaBinaryVersion.value == "3") {
minimal :+ "-deprecation"
minimal :+ "-Wconf:cat=deprecation:s"
Copy link
Owner

Choose a reason for hiding this comment

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

Curious why this was needed?

Copy link
Author

Choose a reason for hiding this comment

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

[error] -- Error: /home/gregg/lucid/enumeratum/macros/src/main/scala/enumeratum/compat/EnumMacros.scala:109:32 
[error] 109 |        val enclosingModule = c.enclosingClass match {
[error]     |                              ^^^^^^^^^^^^^^^^
[error]     |method enclosingClass in trait Enclosures is deprecated since 2.11.0: c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information

and a few more identical errors

} else {
minimal ++ Seq(
// "-Ywarn-adapted-args",
Expand Down
4 changes: 2 additions & 2 deletions enumeratum-cats/src/main/scala/enumeratum/values/Cats.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ object Cats {
/** Builds an `Eq` instance which differentiates all enum values as it's based on universal
* equals.
*/
def eqForEnum[A <: ValueEnumEntry[_]]: Eq[A] = Eq.fromUniversalEquals[A]
def eqForEnum[A <: ValueEnumEntry[?]]: Eq[A] = Eq.fromUniversalEquals[A]
Copy link
Owner

Choose a reason for hiding this comment

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

Was this needed?


/** Builds an `Eq` instance which acts accordingly to the given `Eq` on the value type. Allows to
* implement different behaviour than [[eqForEnum]], for example grouping several enum values in
Expand All @@ -17,7 +17,7 @@ object Cats {

/** Builds a `Show` instance based on `toString`.
*/
def showForEnum[A <: ValueEnumEntry[_]]: Show[A] = Show.fromToString[A]
def showForEnum[A <: ValueEnumEntry[?]]: Show[A] = Show.fromToString[A]

/** Builds a `Show` instance from the given `Show` on the value type.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ trait CatsCustomOrderValueEnum[ValueType, EntryType <: ValueEnumEntry[ValueType]
/** Builds a `Order` instance from the given `Order` (see [[valueTypeOrder]] on the value type.
*/
implicit val orderInstance: Order[EntryType] =
Cats.valueOrderForEnum[EntryType, ValueType](valueTypeOrder)
Cats.valueOrderForEnum[EntryType, ValueType](using valueTypeOrder)

}

Expand Down
2 changes: 2 additions & 0 deletions enumeratum-core/src/main/scala-2/enumeratum/EnumCompat.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import scala.collection.immutable.IndexedSeq

import scala.language.experimental.macros

import _root_.enumeratum.compat.EnumMacros

private[enumeratum] trait EnumCompat[A <: EnumEntry] { _: Enum[A] =>

/** Returns a Seq of [[A]] objects that the macro was able to find.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import scala.language.experimental.macros

import scala.collection.immutable.IndexedSeq

import _root_.enumeratum.{EnumMacros, ValueEnumMacros}
import _root_.enumeratum.compat.{EnumMacros, ValueEnumMacros}

private[enumeratum] trait IntEnumCompanion {

Expand Down
6 changes: 6 additions & 0 deletions enumeratum-core/src/main/scala-3/enumeratum/EnumCompat.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package enumeratum

import _root_.enumeratum.compat
import scala.language.experimental.macros

private[enumeratum] trait EnumCompat[A <: EnumEntry] { _enum: Enum[A] =>

// format: off
Expand All @@ -9,6 +12,7 @@ private[enumeratum] trait EnumCompat[A <: EnumEntry] { _enum: Enum[A] =>
* aren't using this method... why are you even bothering with this lib?
*/
inline def findValues: IndexedSeq[A] = ${ EnumMacros.findValuesImpl[A] }
def findValues: IndexedSeq[A] = macro compat.EnumMacros.findValuesImpl[A]
// format: on

/** The sequence of values for your [[Enum]]. You will typically want to implement this in your
Expand All @@ -26,6 +30,8 @@ private[enumeratum] trait EnumCompanion {
/** Finds the `Enum` companion object for a particular `EnumEntry`. */
implicit inline def materializeEnum[A <: EnumEntry]: Enum[A] =
${ EnumMacros.materializeEnumImpl[A, Enum[A]] }
implicit def materializeEnum[A <: EnumEntry]: Enum[A] = macro
compat.EnumMacros.materializeEnumImpl[A]
// format: on

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ package enumeratum.values
import scala.language.experimental.macros

import _root_.enumeratum.{Enum, EnumMacros, ValueEnumMacros}
import _root_.enumeratum.compat

private[enumeratum] trait IntEnumCompanion {

/** Materializes an `IntEnum` for a given `IntEnumEntry`. */
implicit inline def materialiseIntValueEnum[EntryType <: IntEnumEntry]: IntEnum[EntryType] = ${
EnumMacros.materializeEnumImpl[EntryType, IntEnum[EntryType]]
}
implicit def materialiseIntValueEnum[EntryType <: IntEnumEntry]: IntEnum[EntryType] = macro
compat.EnumMacros.materializeEnumImpl[EntryType]
}

private[enumeratum] trait IntEnumCompat[A <: IntEnumEntry] { _enum: IntEnum[A] =>
Expand All @@ -22,6 +25,7 @@ private[enumeratum] trait IntEnumCompat[A <: IntEnumEntry] { _enum: IntEnum[A] =
*/
protected inline def findValues: IndexedSeq[A] =
${ ValueEnumMacros.findIntValueEntriesImpl[A] }
protected def findValues: IndexedSeq[A] = macro compat.ValueEnumMacros.findIntValueEntriesImpl[A]
// format: on
}

Expand All @@ -32,6 +36,8 @@ private[enumeratum] trait LongEnumCompanion {
implicit inline def materialiseLongValueEnum[EntryType <: LongEnumEntry]: LongEnum[EntryType] = ${
EnumMacros.materializeEnumImpl[EntryType, LongEnum[EntryType]]
}
implicit def materialiseLongValueEnum[EntryType <: LongEnumEntry]: LongEnum[EntryType] = macro
compat.EnumMacros.materializeEnumImpl[EntryType]
}

private[enumeratum] trait LongEnumCompat[A <: LongEnumEntry] { _enum: LongEnum[A] =>
Expand All @@ -43,6 +49,7 @@ private[enumeratum] trait LongEnumCompat[A <: LongEnumEntry] { _enum: LongEnum[A
* aren't using this method...why are you even bothering with this lib?
*/
protected inline def findValues: IndexedSeq[A] = ${ ValueEnumMacros.findLongValueEntriesImpl[A] }
protected def findValues: IndexedSeq[A] = macro compat.ValueEnumMacros.findLongValueEntriesImpl[A]
// format: on
}

Expand All @@ -54,6 +61,8 @@ private[enumeratum] trait ShortEnumCompanion {
${
EnumMacros.materializeEnumImpl[EntryType, ShortEnum[EntryType]]
}
implicit def materialiseShortValueEnum[EntryType <: ShortEnumEntry]: ShortEnum[EntryType] = macro
compat.EnumMacros.materializeEnumImpl[EntryType]
}

private[enumeratum] trait ShortEnumCompat[A <: ShortEnumEntry] { _enum: ShortEnum[A] =>
Expand All @@ -66,6 +75,8 @@ private[enumeratum] trait ShortEnumCompat[A <: ShortEnumEntry] { _enum: ShortEnu
protected inline def findValues: IndexedSeq[A] = ${
ValueEnumMacros.findShortValueEntriesImpl[A]
}
protected def findValues: IndexedSeq[A] = macro
compat.ValueEnumMacros.findShortValueEntriesImpl[A]
}

private[enumeratum] trait StringEnumCompanion {
Expand All @@ -76,6 +87,9 @@ private[enumeratum] trait StringEnumCompanion {
: StringEnum[EntryType] = ${
EnumMacros.materializeEnumImpl[EntryType, StringEnum[EntryType]]
}
implicit def materialiseStringValueEnum[EntryType <: StringEnumEntry]: StringEnum[
EntryType
] = macro compat.EnumMacros.materializeEnumImpl[EntryType]
}

private[enumeratum] trait StringEnumCompat[A <: StringEnumEntry] { _enum: StringEnum[A] =>
Expand All @@ -89,6 +103,8 @@ private[enumeratum] trait StringEnumCompat[A <: StringEnumEntry] { _enum: String
protected inline def findValues: IndexedSeq[A] = ${
ValueEnumMacros.findStringValueEntriesImpl[A]
}
protected def findValues: IndexedSeq[A] = macro
compat.ValueEnumMacros.findStringValueEntriesImpl[A]
// format: on
}

Expand All @@ -99,6 +115,8 @@ private[enumeratum] trait ByteEnumCompanion {
implicit inline def materialiseByteValueEnum[EntryType <: ByteEnumEntry]: ByteEnum[EntryType] = ${
EnumMacros.materializeEnumImpl[EntryType, ByteEnum[EntryType]]
}
implicit def materialiseByteValueEnum[EntryType <: ByteEnumEntry]: ByteEnum[EntryType] = macro
compat.EnumMacros.materializeEnumImpl[EntryType]
}

private[enumeratum] trait ByteEnumCompat[A <: ByteEnumEntry] { _enum: ByteEnum[A] =>
Expand All @@ -112,6 +130,7 @@ private[enumeratum] trait ByteEnumCompat[A <: ByteEnumEntry] { _enum: ByteEnum[A
protected inline def findValues: IndexedSeq[A] = ${
ValueEnumMacros.findByteValueEntriesImpl[A]
}
protected def findValues: IndexedSeq[A] = macro compat.ValueEnumMacros.findByteValueEntriesImpl[A]
// format: on
}

Expand All @@ -122,6 +141,8 @@ private[enumeratum] trait CharEnumCompanion {
implicit inline def materialiseCharValueEnum[EntryType <: CharEnumEntry]: CharEnum[EntryType] = ${
EnumMacros.materializeEnumImpl[EntryType, CharEnum[EntryType]]
}
implicit def materialiseCharValueEnum[EntryType <: CharEnumEntry]: CharEnum[EntryType] = macro
compat.EnumMacros.materializeEnumImpl[EntryType]
}

private[enumeratum] trait CharEnumCompat[A <: CharEnumEntry] { _enum: CharEnum[A] =>
Expand All @@ -135,5 +156,6 @@ private[enumeratum] trait CharEnumCompat[A <: CharEnumEntry] { _enum: CharEnum[A
protected inline def findValues: IndexedSeq[A] = ${
ValueEnumMacros.findCharValueEntriesImpl[A]
}
protected def findValues: IndexedSeq[A] = macro compat.ValueEnumMacros.findCharValueEntriesImpl[A]
// format: on
}
18 changes: 9 additions & 9 deletions enumeratum-core/src/main/scala/enumeratum/EnumEntry.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ trait EnumEntry {
*/
def entryName: String = stableEntryName

private[this] lazy val stableEntryName: String = toString
private lazy val stableEntryName: String = toString
Copy link
Owner

Choose a reason for hiding this comment

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

Was this (and below) removals of this needed?

Copy link
Author

Choose a reason for hiding this comment

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

the scala 3 build fails without removing these (deprecated feature)


}

Expand Down Expand Up @@ -62,39 +62,39 @@ object EnumEntry {
trait CapitalSnakecase extends EnumEntry {
override def entryName: String = stableEntryName

private[this] lazy val stableEntryName: String = camel2WordArray(super.entryName).mkString("_")
private lazy val stableEntryName: String = camel2WordArray(super.entryName).mkString("_")
}

/** Stackable trait to convert the entryName to Capital-Hyphen-Case.
*/
trait CapitalHyphencase extends EnumEntry {
override def entryName: String = stableEntryName

private[this] lazy val stableEntryName: String = camel2WordArray(super.entryName).mkString("-")
private lazy val stableEntryName: String = camel2WordArray(super.entryName).mkString("-")
}

/** Stackable trait to convert the entryName to Capital.Dot.Case.
*/
trait CapitalDotcase extends EnumEntry {
override def entryName: String = stableEntryName

private[this] lazy val stableEntryName: String = camel2WordArray(super.entryName).mkString(".")
private lazy val stableEntryName: String = camel2WordArray(super.entryName).mkString(".")
}

/** Stackable trait to convert the entryName to Capital Words.
*/
trait CapitalWords extends EnumEntry {
override def entryName: String = stableEntryName

private[this] lazy val stableEntryName: String = camel2WordArray(super.entryName).mkString(" ")
private lazy val stableEntryName: String = camel2WordArray(super.entryName).mkString(" ")
}

/** Stackable trait to convert the entryName to CamelCase.
*/
trait Camelcase extends EnumEntry {
override def entryName: String = stableEntryName

private[this] lazy val stableEntryName: String =
private lazy val stableEntryName: String =
camel2WordArray(super.entryName).map(s => capitalise(s.toLowerCase)).mkString
}

Expand All @@ -103,23 +103,23 @@ object EnumEntry {
trait Uppercase extends EnumEntry {
override def entryName: String = stableEntryName

private[this] lazy val stableEntryName: String = super.entryName.toUpperCase
private lazy val stableEntryName: String = super.entryName.toUpperCase
}

/** Stackable trait to convert the entryName to lowercase.
*/
trait Lowercase extends EnumEntry {
override def entryName: String = stableEntryName

private[this] lazy val stableEntryName: String = super.entryName.toLowerCase
private lazy val stableEntryName: String = super.entryName.toLowerCase
}

/** Stackable trait to uncapitalise the first letter of the entryName.
*/
trait Uncapitalised extends EnumEntry {
override def entryName: String = stableEntryName

private[this] lazy val stableEntryName: String = uncapitalise(super.entryName)
private lazy val stableEntryName: String = uncapitalise(super.entryName)
}

/** Stackable trait to convert the entryName to snake_case.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ sealed trait ValueEnumEntry[ValueType] {

object ValueEnumEntry {

implicit class ValueEnumOps[A <: ValueEnumEntry[_]](val enumEntry: A) extends AnyVal {
implicit class ValueEnumOps[A <: ValueEnumEntry[?]](val enumEntry: A) extends AnyVal {

/** Checks if the current enum value is contained by the set of enum values in the parameter
* list.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import play.api.data.{FormError, Mapping, Forms => PlayForms}
*/
object Forms extends FormsCompat {

protected[this] def formatter[ValueType, EntryType <: ValueEnumEntry[
protected def formatter[ValueType, EntryType <: ValueEnumEntry[
Copy link
Owner

Choose a reason for hiding this comment

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

?

ValueType
], EnumType <: ValueEnum[ValueType, EntryType]](
baseFormatter: Formatter[ValueType]
Expand Down
1 change: 1 addition & 0 deletions macros/compat/src/main/scala-3
4 changes: 2 additions & 2 deletions macros/src/main/scala-3/enumeratum/EnumMacros.scala
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ object EnumMacros:

val repr = TypeRepr.of[T](using tpe)

if (!repr.classSymbol.exists(_.flags is Flags.Sealed)) {
if (!repr.classSymbol.exists(_.flags.is(Flags.Sealed))) {
report.errorAndAbort(
"You can only use findValues on sealed traits or classes"
)
Expand Down Expand Up @@ -201,7 +201,7 @@ object EnumMacros:
val values = Expr.ofSeq(valueExprs)

'{
IndexedSeq[T](${ values }: _*)
IndexedSeq[T](${ values }*)
}
}
}
Expand Down
Loading