-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Fix #9011: Make single enum values inherit from Product #9018
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
Changes from all commits
1e13a92
ba466e9
67f0786
323d228
29ac3a6
1003adb
9a887fe
6bd846a
8832569
3a352e6
1cd85bc
74cc1b1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package scala | ||
|
||
/** A base trait of all enum classes */ | ||
trait Enum extends Product, Serializable: | ||
|
||
/** A number uniquely identifying a case of an enum */ | ||
def ordinal: Int | ||
protected def $ordinal: Int | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,8 @@ | ||
package scala | ||
|
||
/** A base trait of all enum classes */ | ||
trait Enum { | ||
trait Enum: | ||
|
||
/** A number uniquely identifying a case of an enum */ | ||
def ordinal: Int | ||
protected def $ordinal: Int | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package scala.runtime | ||
|
||
trait EnumValue extends Product, Serializable: | ||
override def canEqual(that: Any) = this eq that.asInstanceOf[AnyRef] | ||
override def productArity: Int = 0 | ||
override def productPrefix: String = toString | ||
override def productElement(n: Int): Any = | ||
throw IndexOutOfBoundsException(n.toString) | ||
override def productElementName(n: Int): String = | ||
throw IndexOutOfBoundsException(n.toString) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
object main { | ||
object _main { | ||
def i0 = { | ||
class i1 { | ||
private[i0] var i2: _ > 0 private def i3: List[Int] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
enum Color: | ||
case Red, Green, Blue | ||
|
||
enum Option[+T]: | ||
case None extends Option[Nothing] | ||
|
||
import scala.runtime.EnumValue | ||
|
||
@main def Test(c: Boolean) = | ||
// Verify that enum constants don't leak the scala.runtime.EnumValue trait | ||
val x: EnumValue = if c then Color.Red else Color.Blue // error // error | ||
val y: EnumValue = Color.Green // error | ||
val z: EnumValue = Option.None // error | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
package test; | ||
|
||
object main { | ||
object _main { | ||
|
||
class a { | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
object main { | ||
object _main { | ||
def main(args: Array[String]) = { | ||
val b = true; | ||
while (b == true) { } | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
object main { // don't do this at home | ||
object _main { // don't do this at home | ||
|
||
trait Impl | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
enum Opt[+T] derives Eq: | ||
case Sm(t: T) | ||
case Nn | ||
|
||
import scala.deriving._ | ||
import scala.compiletime.{erasedValue, summonInline} | ||
|
||
trait Eq[T] { | ||
def eqv(x: T, y: T): Boolean | ||
} | ||
|
||
object Eq { | ||
given Eq[Int] { | ||
def eqv(x: Int, y: Int) = x == y | ||
} | ||
|
||
inline def summonAll[T <: Tuple]: List[Eq[_]] = inline erasedValue[T] match { | ||
case _: Unit => Nil | ||
case _: (t *: ts) => summonInline[Eq[t]] :: summonAll[ts] | ||
} | ||
|
||
def check(elem: Eq[_])(x: Any, y: Any): Boolean = | ||
elem.asInstanceOf[Eq[Any]].eqv(x, y) | ||
|
||
def iterator[T](p: T) = p.asInstanceOf[Product].productIterator | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Going back to the original issue (#9011), is this cast actually safe?
If this isn't actually guaranteed, then the documentation needs to be updated to not rely on this cast in an example. |
||
|
||
def eqSum[T](s: Mirror.SumOf[T], elems: List[Eq[_]]): Eq[T] = | ||
new Eq[T] { | ||
def eqv(x: T, y: T): Boolean = { | ||
val ordx = s.ordinal(x) | ||
(s.ordinal(y) == ordx) && check(elems(ordx))(x, y) | ||
} | ||
} | ||
|
||
def eqProduct[T](p: Mirror.ProductOf[T], elems: List[Eq[_]]): Eq[T] = | ||
new Eq[T] { | ||
def eqv(x: T, y: T): Boolean = | ||
iterator(x).zip(iterator(y)).zip(elems.iterator).forall { | ||
case ((x, y), elem) => check(elem)(x, y) | ||
} | ||
} | ||
|
||
inline given derived[T](using m: Mirror.Of[T]) as Eq[T] = { | ||
val elemInstances = summonAll[m.MirroredElemTypes] | ||
inline m match { | ||
case s: Mirror.SumOf[T] => eqSum(s, elemInstances) | ||
case p: Mirror.ProductOf[T] => eqProduct(p, elemInstances) | ||
} | ||
} | ||
} | ||
|
||
object Test extends App { | ||
import Opt._ | ||
val eqoi = summon[Eq[Opt[Int]]] | ||
assert(eqoi.eqv(Sm(23), Sm(23))) | ||
assert(eqoi.eqv(Nn, Nn)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure we should leave dead code like this around without a clear idea of what we want to do with it. Is this something you're planning to experiment with more? I think it would make sense to use this mechanism for getting rid of Serializable and Product so that they don't show up when lubbing case classes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #9028.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice, thanks! Can you leave a reference to this issue number in the comment?