Skip to content

Commit f7797dd

Browse files
committed
fix #9873: move scala.Enum to scala.reflect.Enum
scala.reflect.Enum is now a universal super trait. Also avoid using derivesFrom(defn.EnumClass) and instead look for enum flag.
1 parent 4b8a1de commit f7797dd

19 files changed

+76
-100
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ object desugar {
403403
val isCaseObject = mods.is(Case) && isObject
404404
val isEnum = mods.isEnumClass && !mods.is(Module)
405405
def isEnumCase = mods.isEnumCase
406+
def isNonEnumCase = !isEnumCase && (isCaseClass || isCaseObject)
406407
val isValueClass = parents.nonEmpty && isAnyVal(parents.head)
407408
// This is not watertight, but `extends AnyVal` will be replaced by `inline` later.
408409

@@ -621,10 +622,10 @@ object desugar {
621622
var parents1 = parents
622623
if (isEnumCase && parents.isEmpty)
623624
parents1 = enumClassTypeRef :: Nil
624-
if (isCaseClass | isCaseObject)
625+
if (isNonEnumCase && !isEnum)
625626
parents1 = parents1 :+ scalaDot(str.Product.toTypeName) :+ scalaDot(nme.Serializable.toTypeName)
626627
if (isEnum)
627-
parents1 = parents1 :+ ref(defn.EnumClass.typeRef)
628+
parents1 = parents1 :+ ref(defn.EnumClass)
628629

629630
// derived type classes of non-module classes go to their companions
630631
val (clsDerived, companionDerived) =

compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,10 +282,10 @@ object DesugarEnums {
282282
private def isJavaEnum(using Context): Boolean = enumClass.derivesFrom(defn.JavaEnumClass)
283283

284284
def ordinalMeth(body: Tree)(using Context): DefDef =
285-
DefDef(nme.ordinal, Nil, Nil, TypeTree(defn.IntType), body)
285+
DefDef(nme.ordinal, Nil, Nil, TypeTree(defn.IntType), body).withAddedFlags(Synthetic)
286286

287287
def enumLabelMeth(body: Tree)(using Context): DefDef =
288-
DefDef(nme.enumLabel, Nil, Nil, TypeTree(defn.StringType), body)
288+
DefDef(nme.enumLabel, Nil, Nil, TypeTree(defn.StringType), body).withAddedFlags(Synthetic)
289289

290290
def ordinalMethLit(ord: Int)(using Context): DefDef =
291291
ordinalMeth(Literal(Constant(ord)))

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,7 @@ class Definitions {
754754
@tu lazy val SomeClass: ClassSymbol = requiredClass("scala.Some")
755755
@tu lazy val NoneModule: Symbol = requiredModule("scala.None")
756756

757-
@tu lazy val EnumClass: ClassSymbol = requiredClass("scala.Enum")
757+
@tu lazy val EnumClass: ClassSymbol = requiredClass("scala.reflect.Enum")
758758

759759
@tu lazy val EnumValueSerializationProxyClass: ClassSymbol = requiredClass("scala.runtime.EnumValueSerializationProxy")
760760
@tu lazy val EnumValueSerializationProxyConstructor: TermSymbol =

compiler/src/dotty/tools/dotc/transform/SymUtils.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,9 @@ object SymUtils {
171171
self
172172
}
173173

174+
def isEnum(using Context): Boolean = self.is(Enum, butNot=JavaDefined)
175+
def isEnumClass(using Context): Boolean = isEnum && !self.is(Case)
176+
174177
/** Does this symbol refer to anonymous classes synthesized by enum desugaring? */
175178
def isEnumAnonymClass(using Context): Boolean =
176179
self.isAnonymousClass && (self.owner.name.eq(nme.DOLLAR_NEW) || self.owner.is(CaseVal))

compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
9494
lazy val accessors =
9595
if (isDerivedValueClass(clazz)) clazz.paramAccessors.take(1) // Tail parameters can only be `erased`
9696
else clazz.caseAccessors
97-
val isEnumCase = clazz.derivesFrom(defn.EnumClass) && clazz != defn.EnumClass
98-
val isEnumValue = isEnumCase && clazz.isAnonymousClass && clazz.classParents.head.classSymbol.is(Enum)
97+
val isEnumValue = clazz.isAnonymousClass && clazz.classParents.head.classSymbol.is(Enum)
9998
val isNonJavaEnumValue = isEnumValue && !clazz.derivesFrom(defn.JavaEnumClass)
10099

101100
val symbolsToSynthesize: List[Symbol] =

compiler/src/dotty/tools/dotc/typer/Checking.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1094,7 +1094,7 @@ trait Checking {
10941094
// Since enums are classes and Namer checks that classes don't extend multiple classes, we only check the class
10951095
// parent.
10961096
//
1097-
// Unlike firstParent.derivesFrom(defn.EnumClass), this test allows inheriting from `Enum` by hand;
1097+
// this test allows inheriting from `Enum` by hand;
10981098
// see enum-List-control.scala.
10991099
report.error(ClassCannotExtendEnum(cls, firstParent), cdef.srcPos)
11001100
}

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2106,7 +2106,8 @@ class Typer extends Namer
21062106
val constr1 = typed(constr).asInstanceOf[DefDef]
21072107
val parentsWithClass = ensureFirstTreeIsClass(parents.mapconserve(typedParent).filterConserve(!_.isEmpty), cdef.nameSpan)
21082108
val parents1 = ensureConstrCall(cls, parentsWithClass)(using superCtx)
2109-
val firstParent = parents1.head.tpe.dealias.typeSymbol
2109+
val firstParentTpe = parents1.head.tpe.dealias
2110+
val firstParent = firstParentTpe.typeSymbol
21102111

21112112
checkEnumParent(cls, firstParent)
21122113

@@ -2123,7 +2124,7 @@ class Typer extends Namer
21232124
.withType(dummy.termRef)
21242125
if (!cls.isOneOf(AbstractOrTrait) && !ctx.isAfterTyper)
21252126
checkRealizableBounds(cls, cdef.sourcePos.withSpan(cdef.nameSpan))
2126-
if cls.derivesFrom(defn.EnumClass) then
2127+
if cls.isEnum || firstParentTpe.classSymbol.isEnum then
21272128
checkEnum(cdef, cls, firstParent)
21282129
val cdef1 = assignType(cpy.TypeDef(cdef)(name, impl1), cls)
21292130

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
package scala
22

33
/** A base trait of all enum classes */
4-
trait Enum extends Product, Serializable:
5-
6-
/** A string uniquely identifying a case of an enum */
7-
def enumLabel: String
8-
9-
/** A number uniquely identifying a case of an enum */
10-
def ordinal: Int
4+
@deprecated("scala.Enum has moved to scala.reflect.Enum", "3.0.0-M1")
5+
type Enum = scala.reflect.Enum
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package scala.reflect
2+
3+
/** A base trait of all enum classes */
4+
super trait Enum extends Any, Product, Serializable:
5+
6+
/** A string uniquely identifying a case of an enum */
7+
def enumLabel: String
8+
9+
/** A number uniquely identifying a case of an enum */
10+
def ordinal: Int

library/src-non-bootstrapped/scala/Enum.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,8 @@ package scala
33
/** A base trait of all enum classes */
44
trait Enum extends Product, Serializable:
55

6+
/** A string uniquely identifying a case of an enum */
7+
def enumLabel: String
8+
69
/** A number uniquely identifying a case of an enum */
710
def ordinal: Int

library/src-non-bootstrapped/scala/runtime/EnumValueSerializationProxy.java

Lines changed: 0 additions & 36 deletions
This file was deleted.

library/src-non-bootstrapped/scala/runtime/EnumValues.scala

Lines changed: 0 additions & 21 deletions
This file was deleted.

tests/neg/enumsLabel-overrides.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
trait Mixin { def enumLabel: String = "mixin" }
2+
3+
enum Mixed extends Mixin {
4+
case B // error: overriding method enumLabel in trait Mixin of type => String;
5+
}
6+
7+
enum MixedAlso {
8+
case C extends MixedAlso with Mixin // error: overriding method enumLabel in trait Mixin of type => String;
9+
}
10+
11+
trait HasEnumLabel { def enumLabel: String }
12+
13+
enum MyEnum extends HasEnumLabel {
14+
case D // ok
15+
}

tests/neg/enumsLabel-singleimpl.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
enum Labelled {
2+
3+
case A // error: method enumLabel of type => String needs `override` modifier
4+
5+
def enumLabel: String = "nolabel"
6+
7+
}
8+
9+
enum Ordinalled {
10+
11+
case A // error: method ordinal of type => Int needs `override` modifier
12+
13+
def ordinal: Int = -1
14+
15+
}

tests/neg/enumsLabelDef.scala

Lines changed: 0 additions & 22 deletions
This file was deleted.

tests/neg/supertraits.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,14 @@ case object b
1111
val y = if ??? then a else b
1212
val y1: Product = y // error
1313
val y2: Serializable = y // error
14+
15+
enum Color {
16+
case Red, Green, Blue
17+
}
18+
19+
enum Nucleobase {
20+
case A, C, G, T
21+
}
22+
23+
val z = if ??? then Color.Red else Nucleobase.G
24+
val z1: reflect.Enum = z // error: Found: (z : Object) Required: reflect.Enum

tests/patmat/i7186.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import MIPS._
22

3+
import deriving.Mirror.SumOf
4+
35
object MIPS {
46
type Labels = Label | ControlLabel
57
type Src = Register | Constant
@@ -233,8 +235,8 @@ object printMips {
233235
def getScopedLabel(s: Scoped): String =
234236
"L" + getScopedId(s)
235237

236-
def printEnum[E](e: String => Enum, t: E, code: String) = {
237-
val num = e(t.toString).ordinal
238+
def printEnum[E: SumOf](e: String => E, t: E, code: String) = {
239+
val num = summon[SumOf[E]].ordinal(e(t.toString))
238240
s"$code$num"
239241
}
240242
}

tests/pos/enum-List-control.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
abstract sealed class List[T] extends Enum
1+
abstract sealed class List[T] extends reflect.Enum
22
object List {
33
final class Cons[T](x: T, xs: List[T]) extends List[T] {
44
def ordinal = 0

tests/run/generic/Enum.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ object runtime {
2222
}
2323
def values: Iterable[E] = myMap.values
2424
}
25-
}
25+
}

0 commit comments

Comments
 (0)